mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
createBufferSource and buffer setter on buffer source node
This commit is contained in:
parent
25a74a75ea
commit
356d7fd7a6
9 changed files with 152 additions and 62 deletions
|
@ -14,8 +14,8 @@ use dom_struct::dom_struct;
|
|||
use js::jsapi::{Heap, JSContext, JSObject, JS_StealArrayBufferContents};
|
||||
use js::rust::CustomAutoRooterGuard;
|
||||
use js::typedarray::{CreateWith, Float32Array};
|
||||
use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer;
|
||||
use std::ptr::{self, NonNull};
|
||||
use std::slice;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
type JSAudioChannel = Heap<*mut JSObject>;
|
||||
|
@ -25,7 +25,7 @@ pub struct AudioBuffer {
|
|||
reflector_: Reflector,
|
||||
js_channels: DomRefCell<Vec<JSAudioChannel>>,
|
||||
#[ignore_malloc_size_of = "Arc"]
|
||||
shared_channels: Arc<Mutex<Vec<Vec<f32>>>>,
|
||||
shared_channels: Arc<Mutex<ServoMediaAudioBuffer>>,
|
||||
sample_rate: f32,
|
||||
length: u32,
|
||||
duration: f64,
|
||||
|
@ -53,11 +53,12 @@ impl AudioBuffer {
|
|||
AudioBuffer {
|
||||
reflector_: Reflector::new(),
|
||||
js_channels: DomRefCell::new(js_channels),
|
||||
shared_channels: Arc::new(Mutex::new(vec![vec![0.; length as usize]; number_of_channels as usize])),
|
||||
sample_rate: sample_rate,
|
||||
length: length,
|
||||
duration: length as f64 / sample_rate as f64,
|
||||
number_of_channels: number_of_channels,
|
||||
shared_channels: Arc::new(Mutex::new(
|
||||
ServoMediaAudioBuffer::new(number_of_channels as u8, length as usize))),
|
||||
sample_rate: sample_rate,
|
||||
length: length,
|
||||
duration: length as f64 / sample_rate as f64,
|
||||
number_of_channels: number_of_channels,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +89,7 @@ impl AudioBuffer {
|
|||
|
||||
// Move the channel data from shared_channels to js_channels.
|
||||
rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>());
|
||||
let shared_channel = (*self.shared_channels.lock().unwrap()).remove(i);
|
||||
let shared_channel = (*self.shared_channels.lock().unwrap()).buffers.remove(i);
|
||||
if unsafe {
|
||||
Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut())
|
||||
}.is_err() {
|
||||
|
@ -102,7 +103,7 @@ impl AudioBuffer {
|
|||
|
||||
/// https://webaudio.github.io/web-audio-api/#acquire-the-content
|
||||
#[allow(unsafe_code)]
|
||||
pub fn acquire_contents(&self) -> Option<Arc<Mutex<Vec<Vec<f32>>>>> {
|
||||
pub fn acquire_contents(&self) -> Option<Arc<Mutex<ServoMediaAudioBuffer>>> {
|
||||
let cx = self.global().get_cx();
|
||||
for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() {
|
||||
// Step 1.
|
||||
|
@ -112,17 +113,25 @@ impl AudioBuffer {
|
|||
|
||||
// Step 2.
|
||||
let channel_data = unsafe {
|
||||
slice::from_raw_parts(
|
||||
JS_StealArrayBufferContents(cx, channel.handle()) as *mut f32,
|
||||
self.length as usize
|
||||
).to_vec()
|
||||
typedarray!(in(cx) let array: Float32Array = channel.get());
|
||||
if let Ok(array) = array {
|
||||
// XXX TypedArrays API does not expose a way to steal the buffer's
|
||||
// content.
|
||||
let data = array.to_vec();
|
||||
let _ = JS_StealArrayBufferContents(cx, channel.handle());
|
||||
data
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
channel.set(ptr::null_mut());
|
||||
|
||||
// Step 3 and part of 4 (which will complete turning shared_channels
|
||||
// data into js_channels ArrayBuffers in restore_js_channel_data).
|
||||
(*self.shared_channels.lock().unwrap())[i] = channel_data;
|
||||
// Step 3.
|
||||
(*self.shared_channels.lock().unwrap()).buffers[i] = channel_data;
|
||||
|
||||
// Step 4 will complete turning shared_channels
|
||||
// data into js_channels ArrayBuffers in restore_js_channel_data.
|
||||
}
|
||||
|
||||
self.js_channels.borrow_mut().clear();
|
||||
|
@ -167,16 +176,18 @@ impl AudioBufferMethods for AudioBuffer {
|
|||
}
|
||||
|
||||
fn CopyFromChannel(&self,
|
||||
destination: CustomAutoRooterGuard<Float32Array>,
|
||||
channel_number: u32,
|
||||
start_in_channel: u32) -> Fallible<()> {
|
||||
_destination: CustomAutoRooterGuard<Float32Array>,
|
||||
_channel_number: u32,
|
||||
_start_in_channel: u32) -> Fallible<()> {
|
||||
// XXX
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn CopyToChannel(&self,
|
||||
source: CustomAutoRooterGuard<Float32Array>,
|
||||
channel_number: u32,
|
||||
start_in_channel: u32) -> Fallible<()> {
|
||||
_source: CustomAutoRooterGuard<Float32Array>,
|
||||
_channel_number: u32,
|
||||
_start_in_channel: u32) -> Fallible<()> {
|
||||
// XXX
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,12 @@ use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferS
|
|||
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::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
|
||||
use dom::bindings::error::{Error, Fallible};
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::num::Finite;
|
||||
use dom::bindings::reflector::reflect_dom_object;
|
||||
use dom::bindings::root::DomRoot;
|
||||
use dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
use dom::window::Window;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_media::audio::buffer_source_node::AudioBufferSourceNodeMessage;
|
||||
|
@ -33,8 +35,8 @@ audio_param_impl!(Detune, AudioBufferSourceNode, AudioBufferSourceNodeMessage, S
|
|||
|
||||
#[dom_struct]
|
||||
pub struct AudioBufferSourceNode {
|
||||
node: AudioScheduledSourceNode,
|
||||
// buffer: Option<DomRoot<AudioBuffer>>,
|
||||
source_node: AudioScheduledSourceNode,
|
||||
buffer: MutNullableDom<AudioBuffer>,
|
||||
playback_rate: DomRoot<AudioParam>,
|
||||
detune: DomRoot<AudioParam>,
|
||||
loop_enabled: Cell<bool>,
|
||||
|
@ -54,28 +56,29 @@ impl AudioBufferSourceNode {
|
|||
node_options.channelCount = Some(2);
|
||||
node_options.channelCountMode = Some(ChannelCountMode::Max);
|
||||
node_options.channelInterpretation = Some(ChannelInterpretation::Speakers);
|
||||
let node = AudioScheduledSourceNode::new_inherited(
|
||||
let source_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 node_id = source_node.node().node_id();
|
||||
let playback_rate = PlaybackRate::new(context.audio_context_impl(), 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 = Detune::new(context.audio_context_impl(), node_id);
|
||||
let detune = AudioParam::new(&window,
|
||||
Box::new(detune),
|
||||
AutomationRate::K_rate,
|
||||
*options.detune,
|
||||
f32::MIN, f32::MAX);
|
||||
AudioBufferSourceNode {
|
||||
node,
|
||||
// buffer: options.buffer,
|
||||
source_node,
|
||||
buffer: Default::default(),
|
||||
playback_rate,
|
||||
detune,
|
||||
loop_enabled: Cell::new(options.loop_),
|
||||
|
@ -104,6 +107,31 @@ impl AudioBufferSourceNode {
|
|||
}
|
||||
|
||||
impl AudioBufferSourceNodeMethods for AudioBufferSourceNode {
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer
|
||||
fn GetBuffer(&self) -> Fallible<Option<DomRoot<AudioBuffer>>> {
|
||||
Ok(self.buffer.get())
|
||||
}
|
||||
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer
|
||||
fn SetBuffer(&self, new_buffer: Option<&AudioBuffer>) -> Fallible<()> {
|
||||
if new_buffer.is_some() && self.buffer.get().is_some() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
|
||||
self.buffer.set(new_buffer);
|
||||
|
||||
if self.source_node.started() {
|
||||
if let Some(buffer) = self.buffer.get() {
|
||||
let buffer = buffer.acquire_contents();
|
||||
self.source_node.node().message(
|
||||
AudioNodeMessage::AudioBufferSourceNode(
|
||||
AudioBufferSourceNodeMessage::SetBuffer(buffer)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn PlaybackRate(&self) -> DomRoot<AudioParam> {
|
||||
DomRoot::from_ref(&self.playback_rate)
|
||||
}
|
||||
|
@ -136,8 +164,17 @@ impl AudioBufferSourceNodeMethods for AudioBufferSourceNode {
|
|||
self.loop_end.set(*loop_end)
|
||||
}
|
||||
|
||||
fn Start(&self, when: Finite<f64>, offset: Option<Finite<f64>>, duration: Option<Finite<f64>>) {
|
||||
// XXX
|
||||
fn Start(&self,
|
||||
when: Finite<f64>,
|
||||
_offset: Option<Finite<f64>>,
|
||||
_duration: Option<Finite<f64>>) -> Fallible<()> {
|
||||
if let Some(buffer) = self.buffer.get() {
|
||||
let buffer = buffer.acquire_contents();
|
||||
self.source_node.node().message(
|
||||
AudioNodeMessage::AudioBufferSourceNode(
|
||||
AudioBufferSourceNodeMessage::SetBuffer(buffer)));
|
||||
}
|
||||
self.source_node.upcast::<AudioScheduledSourceNode>().Start(when)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,17 @@ use dom::audionode::AudioNode;
|
|||
use dom::baseaudiocontext::BaseAudioContext;
|
||||
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
|
||||
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
|
||||
use dom::bindings::error::{Error, Fallible};
|
||||
use dom::bindings::num::Finite;
|
||||
use dom_struct::dom_struct;
|
||||
use servo_media::audio::graph::NodeId;
|
||||
use servo_media::audio::node::{AudioNodeMessage, AudioNodeType, AudioScheduledSourceNodeMessage};
|
||||
use std::cell::Cell;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct AudioScheduledSourceNode {
|
||||
node: AudioNode,
|
||||
started: Cell<bool>,
|
||||
stopped: Cell<bool>,
|
||||
}
|
||||
|
||||
impl AudioScheduledSourceNode {
|
||||
|
@ -24,11 +27,17 @@ impl AudioScheduledSourceNode {
|
|||
AudioScheduledSourceNode {
|
||||
node: AudioNode::new_inherited(node_type, None /* node_id */,
|
||||
context, options, number_of_inputs, number_of_outputs),
|
||||
started: Cell::new(false),
|
||||
stopped: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_id(&self) -> NodeId {
|
||||
self.node.node_id()
|
||||
pub fn node(&self) -> &AudioNode {
|
||||
&self.node
|
||||
}
|
||||
|
||||
pub fn started(&self) -> bool {
|
||||
self.started.get()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,16 +46,26 @@ impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode {
|
|||
event_handler!(ended, GetOnended, SetOnended);
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start
|
||||
fn Start(&self, when: Finite<f64>) {
|
||||
fn Start(&self, when: Finite<f64>) -> Fallible<()> {
|
||||
if self.started.get() || self.stopped.get() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
self.started.set(true);
|
||||
self.node.message(
|
||||
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(*when))
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop
|
||||
fn Stop(&self, when: Finite<f64>) {
|
||||
fn Stop(&self, when: Finite<f64>) -> Fallible<()> {
|
||||
if !self.started.get() {
|
||||
return Err(Error::InvalidState);
|
||||
}
|
||||
self.stopped.set(true);
|
||||
self.node.message(
|
||||
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Stop(*when))
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,18 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use dom::audiobuffer::AudioBuffer;
|
||||
use dom::audiobuffersourcenode::AudioBufferSourceNode;
|
||||
use dom::audiodestinationnode::AudioDestinationNode;
|
||||
use dom::audionode::MAX_CHANNEL_COUNT;
|
||||
use dom::bindings::cell::DomRefCell;
|
||||
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceOptions;
|
||||
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
|
||||
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
|
||||
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextMethods;
|
||||
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState;
|
||||
use dom::bindings::codegen::Bindings::GainNodeBinding::GainOptions;
|
||||
use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorOptions;
|
||||
use dom::bindings::error::{Error, ErrorResult};
|
||||
use dom::bindings::error::{Error, ErrorResult, Fallible};
|
||||
use dom::bindings::inheritance::Castable;
|
||||
use dom::bindings::num::Finite;
|
||||
use dom::bindings::refcounted::Trusted;
|
||||
|
@ -207,23 +210,23 @@ impl BaseAudioContext {
|
|||
}
|
||||
|
||||
impl BaseAudioContextMethods for BaseAudioContext {
|
||||
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate
|
||||
fn SampleRate(&self) -> Finite<f32> {
|
||||
Finite::wrap(self.sample_rate)
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime
|
||||
fn CurrentTime(&self) -> Finite<f64> {
|
||||
let current_time = self.audio_context_impl.current_time();
|
||||
Finite::wrap(current_time)
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state
|
||||
fn State(&self) -> AudioContextState {
|
||||
self.state.get()
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume
|
||||
#[allow(unrooted_must_root)]
|
||||
fn Resume(&self) -> Rc<Promise> {
|
||||
// Step 1.
|
||||
|
@ -255,14 +258,15 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
promise
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
|
||||
fn Destination(&self) -> DomRoot<AudioDestinationNode> {
|
||||
DomRoot::from_ref(self.destination.as_ref().unwrap())
|
||||
}
|
||||
|
||||
// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
|
||||
event_handler!(statechange, GetOnstatechange, SetOnstatechange);
|
||||
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createoscillator
|
||||
#[allow(unsafe_code)]
|
||||
fn CreateOscillator(&self) -> DomRoot<OscillatorNode> {
|
||||
let global = self.global();
|
||||
|
@ -271,6 +275,7 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
OscillatorNode::new(&window, &self, &options)
|
||||
}
|
||||
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-creategain
|
||||
#[allow(unsafe_code)]
|
||||
fn CreateGain(&self) -> DomRoot<GainNode> {
|
||||
let global = self.global();
|
||||
|
@ -279,12 +284,27 @@ impl BaseAudioContextMethods for BaseAudioContext {
|
|||
GainNode::new(&window, &self, &options)
|
||||
}
|
||||
|
||||
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
|
||||
fn CreateBuffer(&self,
|
||||
number_of_channels: u32,
|
||||
length: u32,
|
||||
sample_rate: Finite<f32>) -> DomRoot<AudioBuffer> {
|
||||
sample_rate: Finite<f32>) -> Fallible<DomRoot<AudioBuffer>> {
|
||||
if number_of_channels <= 0 ||
|
||||
number_of_channels > MAX_CHANNEL_COUNT ||
|
||||
length <= 0 ||
|
||||
*sample_rate <= 0. {
|
||||
return Err(Error::NotSupported);
|
||||
}
|
||||
let global = self.global();
|
||||
AudioBuffer::new(&global.as_window(), number_of_channels, length, *sample_rate)
|
||||
Ok(AudioBuffer::new(&global.as_window(), number_of_channels, length, *sample_rate))
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
fn CreateBufferSource(&self) -> DomRoot<AudioBufferSourceNode> {
|
||||
let global = self.global();
|
||||
// XXX Can we do this implementing Default?
|
||||
let options = unsafe { AudioBufferSourceOptions::empty(global.get_cx()) };
|
||||
AudioBufferSourceNode::new(&global.as_window(), &self, &options)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ use offscreen_gl_context::GLLimits;
|
|||
use parking_lot::RwLock;
|
||||
use profile_traits::mem::ProfilerChan as MemProfilerChan;
|
||||
use profile_traits::time::ProfilerChan as TimeProfilerChan;
|
||||
use servo_media::audio::buffer_source_node::AudioBuffer;
|
||||
use servo_media::audio::context::AudioContext;
|
||||
use servo_media::audio::graph::NodeId;
|
||||
use script_layout_interface::OpaqueStyleAndLayoutData;
|
||||
|
@ -432,6 +433,7 @@ unsafe_no_jsmanaged_fields!(InteractiveWindow);
|
|||
unsafe_no_jsmanaged_fields!(CanvasId);
|
||||
unsafe_no_jsmanaged_fields!(SourceSet);
|
||||
unsafe_no_jsmanaged_fields!(AudioGraph);
|
||||
unsafe_no_jsmanaged_fields!(AudioBuffer);
|
||||
unsafe_no_jsmanaged_fields!(AudioContext);
|
||||
unsafe_no_jsmanaged_fields!(NodeId);
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ audio_param_impl!(Detune, OscillatorNode, OscillatorNodeMessage, SetDetune);
|
|||
|
||||
#[dom_struct]
|
||||
pub struct OscillatorNode {
|
||||
node: AudioScheduledSourceNode,
|
||||
source_node: AudioScheduledSourceNode,
|
||||
oscillator_type: OscillatorType,
|
||||
frequency: DomRoot<AudioParam>,
|
||||
detune: DomRoot<AudioParam>,
|
||||
|
@ -48,26 +48,27 @@ impl OscillatorNode {
|
|||
node_options.channelCount = Some(2);
|
||||
node_options.channelCountMode = Some(ChannelCountMode::Max);
|
||||
node_options.channelInterpretation = Some(ChannelInterpretation::Speakers);
|
||||
let node = AudioScheduledSourceNode::new_inherited(
|
||||
let source_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 node_id = source_node.node().node_id();
|
||||
let frequency = Frequency::new(context.audio_context_impl(), node_id);
|
||||
let frequency = AudioParam::new(window,
|
||||
Box::new(frequency),
|
||||
AutomationRate::A_rate,
|
||||
440., f32::MIN, f32::MAX);
|
||||
let detune = Detune::new(context.audio_context_impl(), node.node_id());
|
||||
let detune = Detune::new(context.audio_context_impl(), node_id);
|
||||
let detune = AudioParam::new(window,
|
||||
Box::new(detune),
|
||||
AutomationRate::A_rate,
|
||||
0., -440. / 2., 440. / 2.);
|
||||
|
||||
OscillatorNode {
|
||||
node,
|
||||
source_node,
|
||||
oscillator_type: oscillator_options.type_,
|
||||
frequency,
|
||||
detune,
|
||||
|
|
|
@ -18,13 +18,13 @@ dictionary AudioBufferSourceOptions {
|
|||
[Exposed=Window,
|
||||
Constructor (BaseAudioContext context, optional AudioBufferSourceOptions options)]
|
||||
interface AudioBufferSourceNode : AudioScheduledSourceNode {
|
||||
// attribute AudioBuffer? buffer;
|
||||
[Throws] 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);
|
||||
[Throws] void start(optional double when = 0,
|
||||
optional double offset,
|
||||
optional double duration);
|
||||
};
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
[Exposed=Window]
|
||||
interface AudioScheduledSourceNode : AudioNode {
|
||||
attribute EventHandler onended;
|
||||
void start(optional double when = 0);
|
||||
void stop(optional double when = 0);
|
||||
[Throws] void start(optional double when = 0);
|
||||
[Throws] void stop(optional double when = 0);
|
||||
};
|
||||
|
|
|
@ -24,13 +24,13 @@ interface BaseAudioContext : EventTarget {
|
|||
readonly attribute AudioContextState state;
|
||||
Promise<void> resume();
|
||||
attribute EventHandler onstatechange;
|
||||
AudioBuffer createBuffer(unsigned long numberOfChannels,
|
||||
unsigned long length,
|
||||
float sampleRate);
|
||||
[Throws] AudioBuffer createBuffer(unsigned long numberOfChannels,
|
||||
unsigned long length,
|
||||
float sampleRate);
|
||||
// Promise<AudioBuffer> decodeAudioData(ArrayBuffer audioData,
|
||||
// optional DecodeSuccessCallback successCallback,
|
||||
// optional DecodeErrorCallback errorCallback);
|
||||
// AudioBufferSourceNode createBufferSource();
|
||||
AudioBufferSourceNode createBufferSource();
|
||||
// ConstantSourceNode createConstantSource();
|
||||
// ScriptProcessorNode createScriptProcessor(optional unsigned long bufferSize = 0,
|
||||
// optional unsigned long numberOfInputChannels = 2,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue