mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Initial AudioParam bindings
This commit is contained in:
parent
885addfaae
commit
7380f69f77
8 changed files with 187 additions and 55 deletions
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
},
|
||||
|
|
|
@ -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()),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
|
|
|
@ -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,24 +93,12 @@ impl OscillatorNode {
|
|||
}
|
||||
}
|
||||
|
||||
/*impl OscillatorNodeMethods for OscillatorNode {
|
||||
fn SetPeriodicWave(&self, periodic_wave: PeriodicWave) {
|
||||
// XXX
|
||||
impl OscillatorNodeMethods for OscillatorNode {
|
||||
fn Frequency(&self) -> DomRoot<AudioParam> {
|
||||
DomRoot::from_ref(&self.frequency)
|
||||
}
|
||||
}
|
||||
|
||||
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<'a> From<&'a OscillatorOptions> for ServoMediaOscillatorOptions {
|
||||
fn from(options: &'a OscillatorOptions) -> Self {
|
||||
Self {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue