diff options
author | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-06-29 09:11:11 +0200 |
---|---|---|
committer | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-07-30 14:21:41 +0200 |
commit | 7380f69f77608372e16659fc74b45ad8c5a72b0a (patch) | |
tree | 91d657afbd84a068d0e207b122e36b8a219e24cd /components/script | |
parent | 885addfaaeb6002c0f77e0b0d6ea640a1a69053c (diff) | |
download | servo-7380f69f77608372e16659fc74b45ad8c5a72b0a.tar.gz servo-7380f69f77608372e16659fc74b45ad8c5a72b0a.zip |
Initial AudioParam bindings
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/audionode.rs | 4 | ||||
-rw-r--r-- | components/script/dom/audioparam.rs | 75 | ||||
-rw-r--r-- | components/script/dom/audioscheduledsourcenode.rs | 5 | ||||
-rw-r--r-- | components/script/dom/baseaudiocontext.rs | 11 | ||||
-rw-r--r-- | components/script/dom/macros.rs | 53 | ||||
-rw-r--r-- | components/script/dom/oscillatornode.rs | 68 | ||||
-rw-r--r-- | components/script/dom/webidls/AudioParam.webidl | 18 | ||||
-rw-r--r-- | components/script/dom/webidls/OscillatorNode.webidl | 8 |
8 files changed, 187 insertions, 55 deletions
diff --git a/components/script/dom/audionode.rs b/components/script/dom/audionode.rs index 39685b5db87..e6eea52d5f5 100644 --- a/components/script/dom/audionode.rs +++ b/components/script/dom/audionode.rs @@ -58,7 +58,7 @@ impl AudioNode { self.context.audio_context_impl().message_node(self.node_id, message); } - pub fn node(&self) -> NodeId { + pub fn node_id(&self) -> NodeId { self.node_id } } @@ -81,7 +81,7 @@ impl AudioNodeMethods for AudioNode { // XXX Check previous connections. self.context.audio_context_impl().connect_ports( - self.node().output(output), destination.node().input(input) + self.node_id().output(output), destination.node_id().input(input) ); Ok(DomRoot::from_ref(destination)) diff --git a/components/script/dom/audioparam.rs b/components/script/dom/audioparam.rs index 1b42af0a4e5..b5bad9fcb9b 100644 --- a/components/script/dom/audioparam.rs +++ b/components/script/dom/audioparam.rs @@ -3,30 +3,44 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::bindings::codegen::Bindings::AudioParamBinding; -use dom::bindings::codegen::Bindings::AudioParamBinding::AudioParamMethods; +use dom::bindings::codegen::Bindings::AudioParamBinding::{AudioParamMethods, AutomationRate}; use dom::bindings::num::Finite; use dom::bindings::reflector::{Reflector, reflect_dom_object}; use dom::bindings::root::DomRoot; -use dom::globalscope::GlobalScope; +use dom::bindings::trace::JSTraceable; +use dom::window::Window; use dom_struct::dom_struct; +use malloc_size_of::MallocSizeOf; +use servo_media::audio::param::RampKind; use std::cell::Cell; +pub trait AudioParamImpl: JSTraceable + MallocSizeOf { + fn set_value(&self, value: f32); + fn set_value_at_time(&self, value: f32, start_time: f64); + fn ramp_to_value_at_time(&self, ramp_kind: RampKind, value: f32, end_time: f64); + fn set_target_at_time(&self, value: f32, start_time: f64, time_constant: f32); +} + #[dom_struct] pub struct AudioParam { reflector_: Reflector, - value: Cell<f32>, + param_impl: Box<AudioParamImpl>, + automation_rate: Cell<AutomationRate>, default_value: f32, min_value: f32, max_value: f32, } impl AudioParam { - pub fn new_inherited(default_value: f32, + pub fn new_inherited(param_impl: Box<AudioParamImpl>, + automation_rate: AutomationRate, + default_value: f32, min_value: f32, max_value: f32) -> AudioParam { AudioParam { reflector_: Reflector::new(), - value: Cell::new(default_value), + param_impl, + automation_rate: Cell::new(automation_rate), default_value, min_value, max_value, @@ -34,22 +48,35 @@ impl AudioParam { } #[allow(unrooted_must_root)] - pub fn new(global: &GlobalScope, + pub fn new(window: &Window, + param_impl: Box<AudioParamImpl>, + automation_rate: AutomationRate, default_value: f32, min_value: f32, max_value: f32) -> DomRoot<AudioParam> { - let audio_param = AudioParam::new_inherited(default_value, min_value, max_value); - reflect_dom_object(Box::new(audio_param), global, AudioParamBinding::Wrap) + let audio_param = AudioParam::new_inherited(param_impl, automation_rate, + default_value, min_value, max_value); + reflect_dom_object(Box::new(audio_param), window, AudioParamBinding::Wrap) } } impl AudioParamMethods for AudioParam { + fn AutomationRate(&self) -> AutomationRate { + self.automation_rate.get() + } + + fn SetAutomationRate(&self, automation_rate: AutomationRate) { + self.automation_rate.set(automation_rate); + // XXX set servo-media param automation rate + } + fn Value(&self) -> Finite<f32> { - Finite::wrap(self.value.get()) + // XXX + Finite::wrap(0.) } fn SetValue(&self, value: Finite<f32>) { - self.value.set(*value); + self.param_impl.set_value(*value); } fn DefaultValue(&self) -> Finite<f32> { @@ -63,4 +90,32 @@ impl AudioParamMethods for AudioParam { fn MaxValue(&self) -> Finite<f32> { Finite::wrap(self.max_value) } + + fn SetValueAtTime(&self, value: Finite<f32>, start_time: Finite<f64>) + -> DomRoot<AudioParam> + { + self.param_impl.set_value_at_time(*value, *start_time); + DomRoot::from_ref(self) + } + + fn LinearRampToValueAtTime(&self, value: Finite<f32>, end_time: Finite<f64>) + -> DomRoot<AudioParam> + { + self.param_impl.ramp_to_value_at_time(RampKind::Linear, *value, *end_time); + DomRoot::from_ref(self) + } + + fn ExponentialRampToValueAtTime(&self, value: Finite<f32>, end_time: Finite<f64>) + -> DomRoot<AudioParam> + { + self.param_impl.ramp_to_value_at_time(RampKind::Exponential, *value, *end_time); + DomRoot::from_ref(self) + } + + fn SetTargetAtTime(&self, target: Finite<f32>, start_time: Finite<f64>, time_constant: Finite<f32>) + -> DomRoot<AudioParam> + { + self.param_impl.set_target_at_time(*target, *start_time, *time_constant); + DomRoot::from_ref(self) + } } diff --git a/components/script/dom/audioscheduledsourcenode.rs b/components/script/dom/audioscheduledsourcenode.rs index 6e430cf8fed..8c8240fdf67 100644 --- a/components/script/dom/audioscheduledsourcenode.rs +++ b/components/script/dom/audioscheduledsourcenode.rs @@ -7,6 +7,7 @@ use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioSche use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions; use dom::bindings::num::Finite; use dom_struct::dom_struct; +use servo_media::audio::graph::NodeId; use servo_media::audio::node::{AudioNodeMessage, AudioNodeType, AudioScheduledSourceNodeMessage}; #[dom_struct] @@ -25,6 +26,10 @@ impl AudioScheduledSourceNode { context, options, number_of_inputs, number_of_outputs), } } + + pub fn node_id(&self) -> NodeId { + self.node.node_id() + } } impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode { diff --git a/components/script/dom/baseaudiocontext.rs b/components/script/dom/baseaudiocontext.rs index 16fd60c02f9..61bdbe03770 100644 --- a/components/script/dom/baseaudiocontext.rs +++ b/components/script/dom/baseaudiocontext.rs @@ -40,7 +40,7 @@ pub enum BaseAudioContextOptions { pub struct BaseAudioContext { eventtarget: EventTarget, #[ignore_malloc_size_of = "servo_media"] - audio_context_impl: AudioContext, + audio_context_impl: Rc<AudioContext>, /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination destination: Option<DomRoot<AudioDestinationNode>>, /// Resume promises which are soon to be fulfilled by a queued task. @@ -75,7 +75,7 @@ impl BaseAudioContext { let mut context = BaseAudioContext { eventtarget: EventTarget::new_inherited(), - audio_context_impl: ServoMedia::get().unwrap().create_audio_context(options.into()), + audio_context_impl: Rc::new(ServoMedia::get().unwrap().create_audio_context(options.into())), destination: None, in_flight_resume_promises_queue: Default::default(), pending_resume_promises: Default::default(), @@ -93,8 +93,8 @@ impl BaseAudioContext { context } - pub fn audio_context_impl(&self) -> &AudioContext { - &self.audio_context_impl + pub fn audio_context_impl(&self) -> Rc<AudioContext> { + self.audio_context_impl.clone() } pub fn destination_node(&self) -> NodeId { @@ -183,9 +183,8 @@ impl BaseAudioContext { this.fulfill_in_flight_resume_promises(|| { if this.state.get() != AudioContextState::Running { this.state.set(AudioContextState::Running); - //XXX this.upcast::<EventTarget>().fire_event(atom!("statechange")); + this.upcast::<EventTarget>().fire_event(atom!("statechange")); } - }); }), window.upcast()); }, diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs index b2963305aa6..1d8ea2f371d 100644 --- a/components/script/dom/macros.rs +++ b/components/script/dom/macros.rs @@ -629,3 +629,56 @@ macro_rules! handle_potential_webgl_error { handle_potential_webgl_error!($context, $call, ()); }; } + +macro_rules! audio_param_impl( + ($struct:ident, $node_type:ident, $message_type:ident, $setter:ident) => ( + #[derive(JSTraceable, MallocSizeOf)] + struct $struct { + #[ignore_malloc_size_of = "Rc"] + context: Rc<AudioContext>, + #[ignore_malloc_size_of = "servo_media"] + node: NodeId, + } + + impl $struct { + pub fn new(context: Rc<AudioContext>, + node: NodeId) -> Self { + Self { + context, + node, + } + } + } + + impl AudioParamImpl for $struct { + fn set_value(&self, _value: f32) {} + + fn set_value_at_time(&self, value: f32, start_time: f64) { + self.context.message_node( + self.node, + AudioNodeMessage::$node_type($message_type::$setter( + UserAutomationEvent::SetValueAtTime(value, start_time), + )), + ); + } + + fn ramp_to_value_at_time(&self, ramp_kind: RampKind, value: f32, end_time: f64) { + self.context.message_node( + self.node, + AudioNodeMessage::$node_type($message_type::$setter( + UserAutomationEvent::RampToValueAtTime(ramp_kind, value, end_time), + )), + ); + } + + fn set_target_at_time(&self, target: f32, start_time: f64, time_constant: f32) { + self.context.message_node( + self.node, + AudioNodeMessage::$node_type($message_type::$setter( + UserAutomationEvent::SetTargetAtTime(target, start_time, time_constant.into()), + )), + ); + } + } + ); +); diff --git a/components/script/dom/oscillatornode.rs b/components/script/dom/oscillatornode.rs index a6e65260ce1..77d169feac8 100644 --- a/components/script/dom/oscillatornode.rs +++ b/components/script/dom/oscillatornode.rs @@ -2,26 +2,38 @@ * License, v.2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use dom::audioparam::{AudioParam, AudioParamImpl}; use dom::audioscheduledsourcenode::AudioScheduledSourceNode; use dom::baseaudiocontext::BaseAudioContext; +use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate; use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions; use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation}; use dom::bindings::codegen::Bindings::OscillatorNodeBinding::{self, OscillatorOptions, OscillatorType}; +use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorNodeMethods; use dom::bindings::error::Fallible; use dom::bindings::reflector::reflect_dom_object; use dom::bindings::root::DomRoot; use dom::window::Window; use dom_struct::dom_struct; -use servo_media::audio::node::AudioNodeType; +use servo_media::audio::context::AudioContext; +use servo_media::audio::graph::NodeId; +use servo_media::audio::node::{AudioNodeMessage, AudioNodeType}; use servo_media::audio::oscillator_node::OscillatorNodeOptions as ServoMediaOscillatorOptions; use servo_media::audio::oscillator_node::OscillatorType as ServoMediaOscillatorType; +use servo_media::audio::oscillator_node::OscillatorNodeMessage; +use servo_media::audio::param::{UserAutomationEvent, RampKind}; +use std::f32; +use std::rc::Rc; + +audio_param_impl!(Frequency, OscillatorNode, OscillatorNodeMessage, SetFrequency); +//XXX audio_param_impl!(Detune, OscillatorNode, OscillatorNodeMessage, SetDetune); #[dom_struct] pub struct OscillatorNode { node: AudioScheduledSourceNode, oscillator_type: OscillatorType, - // frequency: AudioParam, - // detune: AudioParam, + frequency: DomRoot<AudioParam>, + //XXX detune: DomRoot<AudioParam>, } impl OscillatorNode { @@ -36,15 +48,29 @@ impl OscillatorNode { node_options.channelCount = Some(2); node_options.channelCountMode = Some(ChannelCountMode::Max); node_options.channelInterpretation = Some(ChannelInterpretation::Speakers); + let node = AudioScheduledSourceNode::new_inherited( + AudioNodeType::OscillatorNode(oscillator_options.into()), + context, + &node_options, + 0, /* inputs */ + 1, /* outputs */ + ); + let frequency = Frequency::new(context.audio_context_impl(), node.node_id()); + let frequency = AudioParam::new(window, + Box::new(frequency), + AutomationRate::A_rate, + 440., f32::MIN, f32::MAX); + /*XXX let detune = Detune::new(context.audio_context_impl(), node.node_id()); + let detune = AudioParam::new(window, + Box::new(detune), + AutomationRate::A_rate, + 0., -440. / 2., 440. / 2.);*/ + OscillatorNode { - node: AudioScheduledSourceNode::new_inherited( - AudioNodeType::OscillatorNode(oscillator_options.into()), - context, - &node_options, - 0, /* inputs */ - 1, /* outputs */ - ), - oscillator_type: oscillator_options.type_, + node, + oscillator_type: oscillator_options.type_, + frequency, + //XXX detune, } } @@ -67,23 +93,11 @@ impl OscillatorNode { } } -/*impl OscillatorNodeMethods for OscillatorNode { - fn SetPeriodicWave(&self, periodic_wave: PeriodicWave) { -// XXX -} - -fn Type(&self) -> OscillatorType { -self.oscillator_type -} - -fn Frequency(&self) -> DomRoot<AudioParam> { -DomRoot::from_ref(&self.frequency) -} - -fn Detune(&self) -> DomRoot<AudioParam> { -DomRoot::from_ref(&self.detune) +impl OscillatorNodeMethods for OscillatorNode { + fn Frequency(&self) -> DomRoot<AudioParam> { + DomRoot::from_ref(&self.frequency) + } } -}*/ impl<'a> From<&'a OscillatorOptions> for ServoMediaOscillatorOptions { fn from(options: &'a OscillatorOptions) -> Self { diff --git a/components/script/dom/webidls/AudioParam.webidl b/components/script/dom/webidls/AudioParam.webidl index 3c0c4870c2b..4e6c6acea04 100644 --- a/components/script/dom/webidls/AudioParam.webidl +++ b/components/script/dom/webidls/AudioParam.webidl @@ -6,18 +6,24 @@ * https://webaudio.github.io/web-audio-api/#dom-audioparam */ +enum AutomationRate { + "a-rate", + "k-rate" +}; + [Exposed=Window] interface AudioParam { attribute float value; + attribute AutomationRate automationRate; readonly attribute float defaultValue; readonly attribute float minValue; readonly attribute float maxValue; -// AudioParam setValueAtTime(float value, double startTime); -// AudioParam linearRampToValueAtTime(float value, double endTime); -// AudioParam exponentialRampToValueAtTime(float value, double endTime); -// AudioParam setTargetAtTime(float target, -// double startTime, -// float timeConstant); + AudioParam setValueAtTime(float value, double startTime); + AudioParam linearRampToValueAtTime(float value, double endTime); + AudioParam exponentialRampToValueAtTime(float value, double endTime); + AudioParam setTargetAtTime(float target, + double startTime, + float timeConstant); // AudioParam setValueCurveAtTime(sequence<float> values, // double startTime, // double duration); diff --git a/components/script/dom/webidls/OscillatorNode.webidl b/components/script/dom/webidls/OscillatorNode.webidl index 30197d2248c..c4fc2d01c22 100644 --- a/components/script/dom/webidls/OscillatorNode.webidl +++ b/components/script/dom/webidls/OscillatorNode.webidl @@ -24,11 +24,11 @@ dictionary OscillatorOptions : AudioNodeOptions { [Exposed=Window, Constructor (BaseAudioContext context, optional OscillatorOptions options)] interface OscillatorNode : AudioScheduledSourceNode { -/* [SetterThrows] - attribute OscillatorType type; +// [SetterThrows] +// attribute OscillatorType type; readonly attribute AudioParam frequency; - readonly attribute AudioParam detune; +// readonly attribute AudioParam detune; - void setPeriodicWave (PeriodicWave periodicWave);*/ +// void setPeriodicWave (PeriodicWave periodicWave); }; |