Skip to content
Permalink
Browse files

Auto merge of #230 - JHBalaji:master, r=Manishearth

 Implemented SetValueCurveAtTime

fixes #204
  • Loading branch information...
bors-servo committed Apr 4, 2019
2 parents 3fb362c + c80549a commit edfca0cd009ed97785585ae7713927e69a5ea5ce
Showing with 128 additions and 3 deletions.
  1. +34 −3 audio/param.rs
  2. +4 −0 examples/Cargo.toml
  3. +89 −0 examples/set_value_curve.rs
  4. +1 −0 media
@@ -256,25 +256,30 @@ pub enum RampKind {
Exponential,
}

#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, PartialEq, Debug)]
/// https://webaudio.github.io/web-audio-api/#dfn-automation-event
pub(crate) enum AutomationEvent {
SetValue(f32),
SetValueAtTime(f32, Tick),
RampToValueAtTime(RampKind, f32, Tick),
SetTargetAtTime(f32, Tick, /* time constant, units of Tick */ f64),
SetValueCurveAtTime(
Vec<f32>,
/* start time */ Tick,
/* duration */ Tick,
),
CancelAndHoldAtTime(Tick),
CancelScheduledValues(Tick),
}

#[derive(Clone, Copy, PartialEq, Debug)]
#[derive(Clone, PartialEq, Debug)]
/// An AutomationEvent that uses times in s instead of Ticks
pub enum UserAutomationEvent {
SetValue(f32),
SetValueAtTime(f32, /* time */ f64),
RampToValueAtTime(RampKind, f32, /* time */ f64),
SetTargetAtTime(f32, f64, /* time constant, units of s */ f64),
// SetValueCurveAtTime(Vec<f32>, Tick, /* duration */ Tick)
SetValueCurveAtTime(Vec<f32>, /* start time */ f64, /* duration */ f64),
CancelAndHoldAtTime(f64),
CancelScheduledValues(f64),
}
@@ -289,6 +294,13 @@ impl UserAutomationEvent {
UserAutomationEvent::RampToValueAtTime(kind, val, time) => {
AutomationEvent::RampToValueAtTime(kind, val, Tick::from_time(time, rate))
}
UserAutomationEvent::SetValueCurveAtTime(values, start, duration) => {
AutomationEvent::SetValueCurveAtTime(
values,
Tick::from_time(start, rate),
Tick::from_time(duration, rate),
)
}
UserAutomationEvent::SetTargetAtTime(val, start, tau) => {
AutomationEvent::SetTargetAtTime(
val,
@@ -311,6 +323,7 @@ impl AutomationEvent {
pub fn time(&self) -> Tick {
match *self {
AutomationEvent::SetValueAtTime(_, tick) => tick,
AutomationEvent::SetValueCurveAtTime(_, start, _) => start,
AutomationEvent::RampToValueAtTime(_, _, tick) => tick,
AutomationEvent::SetTargetAtTime(_, start, _) => start,
AutomationEvent::CancelAndHoldAtTime(t) => t,
@@ -324,6 +337,7 @@ impl AutomationEvent {
match *self {
AutomationEvent::SetValueAtTime(_, tick) => Some(tick),
AutomationEvent::RampToValueAtTime(_, _, tick) => Some(tick),
AutomationEvent::SetValueCurveAtTime(_, start, duration) => Some(start + duration),
AutomationEvent::SetTargetAtTime(..) => None,
AutomationEvent::CancelAndHoldAtTime(t) => Some(t),
AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) => {
@@ -336,6 +350,7 @@ impl AutomationEvent {
match *self {
AutomationEvent::SetValueAtTime(_, tick) => Some(tick),
AutomationEvent::RampToValueAtTime(..) => None,
AutomationEvent::SetValueCurveAtTime(_, start, _) => Some(start),
AutomationEvent::SetTargetAtTime(_, start, _) => Some(start),
AutomationEvent::CancelAndHoldAtTime(t) => Some(t),
AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) => {
@@ -408,6 +423,22 @@ impl AutomationEvent {
*value = val + (event_start_value - val) * exp.exp() as f32;
true
}
AutomationEvent::SetValueCurveAtTime(ref values, start, duration) => {
let mut progress = ((((current_tick.0 as f32) - (start.0 as f32)) as f32)
/ (duration.0 as f32)) as f32;
debug_assert!(progress >= 0.);
let n = values.len() as f32;
let k_float = ((n - 1.) * progress) as f32;
let k = k_float.floor();
if (k + 1.) < n {
let progress = k_float - k;
*value =
values[k as usize] * (1. - progress) + values[(k + 1.) as usize] * progress;
} else {
*value = values[(n - 1.) as usize];
}
true
}
AutomationEvent::CancelAndHoldAtTime(..) => false,
AutomationEvent::CancelScheduledValues(..) | AutomationEvent::SetValue(..) => {
unreachable!("CancelScheduledValues/SetValue should never appear in the timeline")
@@ -99,3 +99,7 @@ path = "constant_source.rs"
[[bin]]
name = "simple_webrtc"
path = "simple_webrtc.rs"

[[bin]]
name = "set_value_curve"
path = "set_value_curve.rs"
@@ -0,0 +1,89 @@
extern crate servo_media;
extern crate servo_media_auto;

use servo_media::audio::constant_source_node::ConstantSourceNodeOptions;
use servo_media::audio::gain_node::GainNodeOptions;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};
use servo_media::audio::param::{ParamType, UserAutomationEvent};
use servo_media::ServoMedia;
use std::sync::Arc;
use std::{thread, time};

fn run_example(servo_media: Arc<ServoMedia>) {
let context = servo_media.create_audio_context(Default::default());
let dest = context.dest_node();

//Initializing the values vector for SetValueCurve function
let values = vec![
0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0., 1., 1., 1., 1., 0., 0., 0., 0.,
];
let start_time = 0.;
let end_time = 5.;
let n = values.len() as f32;
let value_next = values[(n - 1.) as usize];

let cs = context.create_node(
AudioNodeInit::ConstantSourceNode(ConstantSourceNodeOptions::default()),
Default::default(),
);

let mut gain_options = GainNodeOptions::default();
gain_options.gain = 0.0;
let gain = context.create_node(
AudioNodeInit::GainNode(gain_options.clone()),
Default::default(),
);

let osc = context.create_node(
AudioNodeInit::OscillatorNode(Default::default()),
Default::default(),
);

context.connect_ports(osc.output(0), gain.input(0));
context.connect_ports(cs.output(0), gain.param(ParamType::Gain));
context.connect_ports(gain.output(0), dest.input(0));

let _ = context.resume();
context.message_node(
osc,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);

context.message_node(
gain,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);

context.message_node(
cs,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);

context.message_node(
cs,
AudioNodeMessage::SetParam(
ParamType::Offset,
UserAutomationEvent::SetValueCurveAtTime(values, start_time, end_time),
),
);

context.message_node(
osc,
AudioNodeMessage::SetParam(
ParamType::Frequency,
UserAutomationEvent::SetValueAtTime(value_next, end_time),
),
);

thread::sleep(time::Duration::from_millis(7000));
let _ = context.close();
}

fn main() {
ServoMedia::init::<servo_media_auto::Backend>();
if let Ok(servo_media) = ServoMedia::get() {
run_example(servo_media);
} else {
unreachable!();
}
}
1 media
Submodule media added at a5a849

0 comments on commit edfca0c

Please sign in to comment.
You can’t perform that action at this time.