1use std::cell::Cell;
6use std::f32;
7
8use dom_struct::dom_struct;
9use js::context::JSContext;
10use js::rust::HandleObject;
11use script_bindings::reflector::reflect_dom_object_with_proto_and_cx;
12use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioNodeType};
13use servo_media::audio::oscillator_node::{
14 OscillatorNodeMessage, OscillatorNodeOptions as ServoMediaOscillatorOptions,
15 OscillatorType as ServoMediaOscillatorType,
16};
17use servo_media::audio::param::ParamType;
18
19use crate::conversions::Convert;
20use crate::dom::audio::audionode::AudioNodeOptionsHelper;
21use crate::dom::audio::audioparam::AudioParam;
22use crate::dom::audio::audioscheduledsourcenode::AudioScheduledSourceNode;
23use crate::dom::audio::baseaudiocontext::BaseAudioContext;
24use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
25 ChannelCountMode, ChannelInterpretation,
26};
27use crate::dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
28use crate::dom::bindings::codegen::Bindings::OscillatorNodeBinding::{
29 OscillatorNodeMethods, OscillatorOptions, OscillatorType,
30};
31use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
32use crate::dom::bindings::root::{Dom, DomRoot};
33use crate::dom::window::Window;
34
35#[dom_struct]
36pub(crate) struct OscillatorNode {
37 source_node: AudioScheduledSourceNode,
38 detune: Dom<AudioParam>,
39 frequency: Dom<AudioParam>,
40 oscillator_type: Cell<OscillatorType>,
41}
42
43impl OscillatorNode {
44 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
45 pub(crate) fn new_inherited(
46 cx: &mut JSContext,
47 window: &Window,
48 context: &BaseAudioContext,
49 options: &OscillatorOptions,
50 ) -> Fallible<OscillatorNode> {
51 let node_options =
52 options
53 .parent
54 .unwrap_or(2, ChannelCountMode::Max, ChannelInterpretation::Speakers);
55 let source_node = AudioScheduledSourceNode::new_inherited(
56 cx,
57 AudioNodeInit::OscillatorNode(options.convert()),
58 context,
59 node_options,
60 0, 1, )?;
63 let node_id = source_node.node().node_id();
64 let frequency = AudioParam::new(
65 cx,
66 window,
67 context,
68 node_id,
69 AudioNodeType::OscillatorNode,
70 ParamType::Frequency,
71 AutomationRate::A_rate,
72 440.,
73 f32::MIN,
74 f32::MAX,
75 );
76 let detune = AudioParam::new(
77 cx,
78 window,
79 context,
80 node_id,
81 AudioNodeType::OscillatorNode,
82 ParamType::Detune,
83 AutomationRate::A_rate,
84 0.,
85 -440. / 2.,
86 440. / 2.,
87 );
88 Ok(OscillatorNode {
89 source_node,
90 oscillator_type: Cell::new(options.type_),
91 frequency: Dom::from_ref(&frequency),
92 detune: Dom::from_ref(&detune),
93 })
94 }
95
96 pub(crate) fn new(
97 cx: &mut JSContext,
98 window: &Window,
99 context: &BaseAudioContext,
100 options: &OscillatorOptions,
101 ) -> Fallible<DomRoot<OscillatorNode>> {
102 Self::new_with_proto(cx, window, None, context, options)
103 }
104
105 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
106 fn new_with_proto(
107 cx: &mut JSContext,
108 window: &Window,
109 proto: Option<HandleObject>,
110 context: &BaseAudioContext,
111 options: &OscillatorOptions,
112 ) -> Fallible<DomRoot<OscillatorNode>> {
113 let node = OscillatorNode::new_inherited(cx, window, context, options)?;
114 Ok(reflect_dom_object_with_proto_and_cx(
115 Box::new(node),
116 window,
117 proto,
118 cx,
119 ))
120 }
121}
122
123impl OscillatorNodeMethods<crate::DomTypeHolder> for OscillatorNode {
124 fn Constructor(
126 cx: &mut JSContext,
127 window: &Window,
128 proto: Option<HandleObject>,
129 context: &BaseAudioContext,
130 options: &OscillatorOptions,
131 ) -> Fallible<DomRoot<OscillatorNode>> {
132 OscillatorNode::new_with_proto(cx, window, proto, context, options)
133 }
134
135 fn Frequency(&self) -> DomRoot<AudioParam> {
137 DomRoot::from_ref(&self.frequency)
138 }
139
140 fn Detune(&self) -> DomRoot<AudioParam> {
142 DomRoot::from_ref(&self.detune)
143 }
144
145 fn Type(&self) -> OscillatorType {
147 self.oscillator_type.get()
148 }
149
150 fn SetType(&self, type_: OscillatorType) -> ErrorResult {
152 if type_ == OscillatorType::Custom {
153 return Err(Error::InvalidState(None));
154 }
155 self.oscillator_type.set(type_);
156 self.source_node
157 .node()
158 .message(AudioNodeMessage::OscillatorNode(
159 OscillatorNodeMessage::SetOscillatorType(type_.convert()),
160 ));
161 Ok(())
162 }
163}
164
165impl Convert<ServoMediaOscillatorOptions> for &OscillatorOptions {
166 fn convert(self) -> ServoMediaOscillatorOptions {
167 ServoMediaOscillatorOptions {
168 oscillator_type: self.type_.convert(),
169 freq: *self.frequency,
170 detune: *self.detune,
171 periodic_wave_options: None, }
173 }
174}
175
176impl Convert<ServoMediaOscillatorType> for OscillatorType {
177 fn convert(self) -> ServoMediaOscillatorType {
178 match self {
179 OscillatorType::Sine => ServoMediaOscillatorType::Sine,
180 OscillatorType::Square => ServoMediaOscillatorType::Square,
181 OscillatorType::Sawtooth => ServoMediaOscillatorType::Sawtooth,
182 OscillatorType::Triangle => ServoMediaOscillatorType::Triangle,
183 OscillatorType::Custom => ServoMediaOscillatorType::Custom,
184 }
185 }
186}