diff --git a/components/script/dom/audiobuffersourcenode.rs b/components/script/dom/audiobuffersourcenode.rs new file mode 100644 index 00000000000..931e86ad21c --- /dev/null +++ b/components/script/dom/audiobuffersourcenode.rs @@ -0,0 +1,155 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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::audiobuffer::AudioBuffer; +use dom::audioparam::{AudioParam, AudioParamImpl}; +use dom::audioscheduledsourcenode::AudioScheduledSourceNode; +use dom::baseaudiocontext::BaseAudioContext; +use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding; +use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceOptions; +use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceNodeMethods; +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::error::Fallible; +use dom::bindings::num::Finite; +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::buffer_source_node::AudioBufferSourceNodeMessage; +use servo_media::audio::buffer_source_node::AudioBufferSourceNodeOptions; +use servo_media::audio::context::AudioContext; +use servo_media::audio::graph::NodeId; +use servo_media::audio::node::{AudioNodeMessage, AudioNodeType}; +use servo_media::audio::param::{UserAutomationEvent, RampKind}; +use std::cell::Cell; +use std::f32; +use std::rc::Rc; + +audio_param_impl!(PlaybackRate, AudioBufferSourceNode, AudioBufferSourceNodeMessage, SetPlaybackRate); +audio_param_impl!(Detune, AudioBufferSourceNode, AudioBufferSourceNodeMessage, SetDetune); + +#[dom_struct] +pub struct AudioBufferSourceNode { + node: AudioScheduledSourceNode, + // buffer: Option>, + playback_rate: DomRoot, + detune: DomRoot, + loop_enabled: Cell, + loop_start: Cell, + loop_end: Cell, +} + +impl AudioBufferSourceNode { + #[allow(unrooted_must_root)] + #[allow(unsafe_code)] + fn new_inherited( + window: &Window, + context: &BaseAudioContext, + options: &AudioBufferSourceOptions, + ) -> AudioBufferSourceNode { + let mut node_options = unsafe { AudioNodeOptions::empty(window.get_cx()) }; + node_options.channelCount = Some(2); + node_options.channelCountMode = Some(ChannelCountMode::Max); + node_options.channelInterpretation = Some(ChannelInterpretation::Speakers); + let node = AudioScheduledSourceNode::new_inherited( + AudioNodeType::AudioBufferSourceNode(options.into()), + context, + &node_options, + 0 /* inputs */, + 1 /* outputs */, + ); + let playback_rate = PlaybackRate::new(context.audio_context_impl(), node.node_id()); + let playback_rate = AudioParam::new(&window, + Box::new(playback_rate), + AutomationRate::K_rate, + *options.playbackRate, + f32::MIN, f32::MAX); + let detune = Detune::new(context.audio_context_impl(), node.node_id()); + let detune = AudioParam::new(&window, + Box::new(detune), + AutomationRate::K_rate, + *options.detune, + f32::MIN, f32::MAX); + AudioBufferSourceNode { + node, + // buffer: options.buffer, + playback_rate, + detune, + loop_enabled: Cell::new(options.loop_), + loop_start: Cell::new(*options.loopStart), + loop_end: Cell::new(*options.loopEnd), + } + } + + #[allow(unrooted_must_root)] + pub fn new( + window: &Window, + context: &BaseAudioContext, + options: &AudioBufferSourceOptions, + ) -> DomRoot { + let node = AudioBufferSourceNode::new_inherited(window, context, options); + reflect_dom_object(Box::new(node), window, AudioBufferSourceNodeBinding::Wrap) + } + + pub fn Constructor( + window: &Window, + context: &BaseAudioContext, + options: &AudioBufferSourceOptions, + ) -> Fallible> { + Ok(AudioBufferSourceNode::new(window, context, options)) + } +} + +impl AudioBufferSourceNodeMethods for AudioBufferSourceNode { + fn PlaybackRate(&self) -> DomRoot { + DomRoot::from_ref(&self.playback_rate) + } + + fn Detune(&self) -> DomRoot { + DomRoot::from_ref(&self.detune) + } + + fn Loop(&self) -> bool { + self.loop_enabled.get() + } + + fn SetLoop(&self, should_loop: bool) { + self.loop_enabled.set(should_loop); + } + + fn LoopStart(&self) -> Finite { + Finite::wrap(self.loop_start.get()) + } + + fn SetLoopStart(&self, loop_start: Finite) { + self.loop_start.set(*loop_start); + } + + fn LoopEnd(&self) -> Finite { + Finite::wrap(self.loop_end.get()) + } + + fn SetLoopEnd(&self, loop_end: Finite) { + self.loop_end.set(*loop_end) + } + + fn Start(&self, when: Finite, offset: Option>, duration: Option>) { + // XXX + } +} + +impl<'a> From<&'a AudioBufferSourceOptions> for AudioBufferSourceNodeOptions { + fn from(options: &'a AudioBufferSourceOptions) -> Self { + Self { + buffer: None, + detune: *options.detune, + loop_enabled: options.loop_, + loop_end: Some(*options.loopEnd), + loop_start: Some(*options.loopStart), + playback_rate: *options.playbackRate, + } + } +} diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index f616922fce6..39273745417 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -217,6 +217,7 @@ pub mod abstractworkerglobalscope; pub mod activation; pub mod attr; pub mod audiobuffer; +pub mod audiobuffersourcenode; pub mod audiocontext; pub mod audiodestinationnode; pub mod audionode; diff --git a/components/script/dom/webidls/AudioBufferSourceNode.webidl b/components/script/dom/webidls/AudioBufferSourceNode.webidl new file mode 100644 index 00000000000..45358fbaad8 --- /dev/null +++ b/components/script/dom/webidls/AudioBufferSourceNode.webidl @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ +/* + * The origin of this IDL file is + * https://webaudio.github.io/web-audio-api/#AudioBufferSourceNode + */ + +dictionary AudioBufferSourceOptions { +// AudioBuffer? buffer; + float detune = 0; + boolean loop = false; + double loopEnd = 0; + double loopStart = 0; + float playbackRate = 1; +}; + +[Exposed=Window, + Constructor (BaseAudioContext context, optional AudioBufferSourceOptions options)] +interface AudioBufferSourceNode : AudioScheduledSourceNode { + // attribute AudioBuffer? buffer; + readonly attribute AudioParam playbackRate; + readonly attribute AudioParam detune; + attribute boolean loop; + attribute double loopStart; + attribute double loopEnd; + void start(optional double when = 0, + optional double offset, + optional double duration); +};