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