1use std::cell::Cell;
6use std::f32;
7
8use dom_struct::dom_struct;
9use js::rust::HandleObject;
10use servo_media::audio::biquad_filter_node::{
11 BiquadFilterNodeMessage, BiquadFilterNodeOptions, FilterType,
12};
13use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioNodeType};
14use servo_media::audio::param::ParamType;
15
16use crate::conversions::Convert;
17use crate::dom::audio::audionode::{AudioNode, AudioNodeOptionsHelper};
18use crate::dom::audio::audioparam::AudioParam;
19use crate::dom::audio::baseaudiocontext::BaseAudioContext;
20use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
21 ChannelCountMode, ChannelInterpretation,
22};
23use crate::dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
24use crate::dom::bindings::codegen::Bindings::BiquadFilterNodeBinding::{
25 BiquadFilterNodeMethods, BiquadFilterOptions, BiquadFilterType,
26};
27use crate::dom::bindings::error::Fallible;
28use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
29use crate::dom::bindings::root::{Dom, DomRoot};
30use crate::dom::window::Window;
31use crate::script_runtime::CanGc;
32
33#[dom_struct]
34pub(crate) struct BiquadFilterNode {
35 node: AudioNode,
36 gain: Dom<AudioParam>,
37 frequency: Dom<AudioParam>,
38 q: Dom<AudioParam>,
39 detune: Dom<AudioParam>,
40 filter: Cell<BiquadFilterType>,
41}
42
43impl BiquadFilterNode {
44 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
45 pub(crate) fn new_inherited(
46 window: &Window,
47 context: &BaseAudioContext,
48 options: &BiquadFilterOptions,
49 can_gc: CanGc,
50 ) -> Fallible<BiquadFilterNode> {
51 let node_options =
52 options
53 .parent
54 .unwrap_or(2, ChannelCountMode::Max, ChannelInterpretation::Speakers);
55 let filter = Cell::new(options.type_);
56 let options = options.convert();
57 let node = AudioNode::new_inherited(
58 AudioNodeInit::BiquadFilterNode(options),
59 context,
60 node_options,
61 1, 1, )?;
64 let gain = AudioParam::new(
65 window,
66 context,
67 node.node_id(),
68 AudioNodeType::BiquadFilterNode,
69 ParamType::Gain,
70 AutomationRate::A_rate,
71 options.gain, f32::MIN, f32::MAX, can_gc,
75 );
76 let q = AudioParam::new(
77 window,
78 context,
79 node.node_id(),
80 AudioNodeType::BiquadFilterNode,
81 ParamType::Q,
82 AutomationRate::A_rate,
83 options.q, f32::MIN, f32::MAX, can_gc,
87 );
88 let frequency = AudioParam::new(
89 window,
90 context,
91 node.node_id(),
92 AudioNodeType::BiquadFilterNode,
93 ParamType::Frequency,
94 AutomationRate::A_rate,
95 options.frequency, f32::MIN, f32::MAX, can_gc,
99 );
100 let detune = AudioParam::new(
101 window,
102 context,
103 node.node_id(),
104 AudioNodeType::BiquadFilterNode,
105 ParamType::Detune,
106 AutomationRate::A_rate,
107 options.detune, f32::MIN, f32::MAX, can_gc,
111 );
112 Ok(BiquadFilterNode {
113 node,
114 filter,
115 gain: Dom::from_ref(&gain),
116 q: Dom::from_ref(&q),
117 frequency: Dom::from_ref(&frequency),
118 detune: Dom::from_ref(&detune),
119 })
120 }
121
122 pub(crate) fn new(
123 window: &Window,
124 context: &BaseAudioContext,
125 options: &BiquadFilterOptions,
126 can_gc: CanGc,
127 ) -> Fallible<DomRoot<BiquadFilterNode>> {
128 Self::new_with_proto(window, None, context, options, can_gc)
129 }
130
131 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
132 fn new_with_proto(
133 window: &Window,
134 proto: Option<HandleObject>,
135 context: &BaseAudioContext,
136 options: &BiquadFilterOptions,
137 can_gc: CanGc,
138 ) -> Fallible<DomRoot<BiquadFilterNode>> {
139 let node = BiquadFilterNode::new_inherited(window, context, options, can_gc)?;
140 Ok(reflect_dom_object_with_proto(
141 Box::new(node),
142 window,
143 proto,
144 can_gc,
145 ))
146 }
147}
148
149impl BiquadFilterNodeMethods<crate::DomTypeHolder> for BiquadFilterNode {
150 fn Constructor(
152 window: &Window,
153 proto: Option<HandleObject>,
154 can_gc: CanGc,
155 context: &BaseAudioContext,
156 options: &BiquadFilterOptions,
157 ) -> Fallible<DomRoot<BiquadFilterNode>> {
158 BiquadFilterNode::new_with_proto(window, proto, context, options, can_gc)
159 }
160
161 fn Gain(&self) -> DomRoot<AudioParam> {
163 DomRoot::from_ref(&self.gain)
164 }
165
166 fn Q(&self) -> DomRoot<AudioParam> {
168 DomRoot::from_ref(&self.q)
169 }
170
171 fn Detune(&self) -> DomRoot<AudioParam> {
173 DomRoot::from_ref(&self.detune)
174 }
175
176 fn Frequency(&self) -> DomRoot<AudioParam> {
178 DomRoot::from_ref(&self.frequency)
179 }
180
181 fn Type(&self) -> BiquadFilterType {
183 self.filter.get()
184 }
185
186 fn SetType(&self, filter: BiquadFilterType) {
188 self.filter.set(filter);
189 self.node.message(AudioNodeMessage::BiquadFilterNode(
190 BiquadFilterNodeMessage::SetFilterType(filter.convert()),
191 ));
192 }
193}
194
195impl Convert<BiquadFilterNodeOptions> for &BiquadFilterOptions {
196 fn convert(self) -> BiquadFilterNodeOptions {
197 BiquadFilterNodeOptions {
198 gain: *self.gain,
199 q: *self.Q,
200 frequency: *self.frequency,
201 detune: *self.detune,
202 filter: self.type_.convert(),
203 }
204 }
205}
206
207impl Convert<FilterType> for BiquadFilterType {
208 fn convert(self) -> FilterType {
209 match self {
210 BiquadFilterType::Lowpass => FilterType::LowPass,
211 BiquadFilterType::Highpass => FilterType::HighPass,
212 BiquadFilterType::Bandpass => FilterType::BandPass,
213 BiquadFilterType::Lowshelf => FilterType::LowShelf,
214 BiquadFilterType::Highshelf => FilterType::HighShelf,
215 BiquadFilterType::Peaking => FilterType::Peaking,
216 BiquadFilterType::Allpass => FilterType::AllPass,
217 BiquadFilterType::Notch => FilterType::Notch,
218 }
219 }
220}