Skip to main content

script/dom/audio/
biquadfilternode.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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::biquad_filter_node::{
13    BiquadFilterNodeMessage, BiquadFilterNodeOptions, FilterType,
14};
15use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioNodeType};
16use servo_media::audio::param::ParamType;
17
18use crate::conversions::Convert;
19use crate::dom::audio::audionode::{AudioNode, AudioNodeOptionsHelper};
20use crate::dom::audio::audioparam::AudioParam;
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::BiquadFilterNodeBinding::{
27    BiquadFilterNodeMethods, BiquadFilterOptions, BiquadFilterType,
28};
29use crate::dom::bindings::error::Fallible;
30use crate::dom::bindings::root::{Dom, DomRoot};
31use crate::dom::window::Window;
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, expect(crown::unrooted_must_root))]
45    pub(crate) fn new_inherited(
46        cx: &mut JSContext,
47        window: &Window,
48        context: &BaseAudioContext,
49        options: &BiquadFilterOptions,
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            cx,
59            AudioNodeInit::BiquadFilterNode(options),
60            context,
61            node_options,
62            1, // inputs
63            1, // outputs
64        )?;
65        let gain = AudioParam::new(
66            cx,
67            window,
68            context,
69            node.node_id(),
70            AudioNodeType::BiquadFilterNode,
71            ParamType::Gain,
72            AutomationRate::A_rate,
73            options.gain, // default value
74            f32::MIN,     // min value
75            f32::MAX,     // max value
76        );
77        let q = AudioParam::new(
78            cx,
79            window,
80            context,
81            node.node_id(),
82            AudioNodeType::BiquadFilterNode,
83            ParamType::Q,
84            AutomationRate::A_rate,
85            options.q, // default value
86            f32::MIN,  // min value
87            f32::MAX,  // max value
88        );
89        let frequency = AudioParam::new(
90            cx,
91            window,
92            context,
93            node.node_id(),
94            AudioNodeType::BiquadFilterNode,
95            ParamType::Frequency,
96            AutomationRate::A_rate,
97            options.frequency, // default value
98            f32::MIN,          // min value
99            f32::MAX,          // max value
100        );
101        let detune = AudioParam::new(
102            cx,
103            window,
104            context,
105            node.node_id(),
106            AudioNodeType::BiquadFilterNode,
107            ParamType::Detune,
108            AutomationRate::A_rate,
109            options.detune, // default value
110            f32::MIN,       // min value
111            f32::MAX,       // max value
112        );
113        Ok(BiquadFilterNode {
114            node,
115            filter,
116            gain: Dom::from_ref(&gain),
117            q: Dom::from_ref(&q),
118            frequency: Dom::from_ref(&frequency),
119            detune: Dom::from_ref(&detune),
120        })
121    }
122
123    pub(crate) fn new(
124        cx: &mut JSContext,
125        window: &Window,
126        context: &BaseAudioContext,
127        options: &BiquadFilterOptions,
128    ) -> Fallible<DomRoot<BiquadFilterNode>> {
129        Self::new_with_proto(cx, window, None, context, options)
130    }
131
132    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
133    fn new_with_proto(
134        cx: &mut JSContext,
135        window: &Window,
136        proto: Option<HandleObject>,
137        context: &BaseAudioContext,
138        options: &BiquadFilterOptions,
139    ) -> Fallible<DomRoot<BiquadFilterNode>> {
140        let node = BiquadFilterNode::new_inherited(cx, window, context, options)?;
141        Ok(reflect_dom_object_with_proto_and_cx(
142            Box::new(node),
143            window,
144            proto,
145            cx,
146        ))
147    }
148}
149
150impl BiquadFilterNodeMethods<crate::DomTypeHolder> for BiquadFilterNode {
151    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-biquadfilternode-context-options>
152    fn Constructor(
153        cx: &mut JSContext,
154        window: &Window,
155        proto: Option<HandleObject>,
156        context: &BaseAudioContext,
157        options: &BiquadFilterOptions,
158    ) -> Fallible<DomRoot<BiquadFilterNode>> {
159        BiquadFilterNode::new_with_proto(cx, window, proto, context, options)
160    }
161
162    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-gain>
163    fn Gain(&self) -> DomRoot<AudioParam> {
164        DomRoot::from_ref(&self.gain)
165    }
166
167    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-q>
168    fn Q(&self) -> DomRoot<AudioParam> {
169        DomRoot::from_ref(&self.q)
170    }
171
172    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-detune>
173    fn Detune(&self) -> DomRoot<AudioParam> {
174        DomRoot::from_ref(&self.detune)
175    }
176
177    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-frequency>
178    fn Frequency(&self) -> DomRoot<AudioParam> {
179        DomRoot::from_ref(&self.frequency)
180    }
181
182    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-type>
183    fn Type(&self) -> BiquadFilterType {
184        self.filter.get()
185    }
186
187    /// <https://webaudio.github.io/web-audio-api/#dom-biquadfilternode-type>
188    fn SetType(&self, filter: BiquadFilterType) {
189        self.filter.set(filter);
190        self.node.message(AudioNodeMessage::BiquadFilterNode(
191            BiquadFilterNodeMessage::SetFilterType(filter.convert()),
192        ));
193    }
194}
195
196impl Convert<BiquadFilterNodeOptions> for &BiquadFilterOptions {
197    fn convert(self) -> BiquadFilterNodeOptions {
198        BiquadFilterNodeOptions {
199            gain: *self.gain,
200            q: *self.Q,
201            frequency: *self.frequency,
202            detune: *self.detune,
203            filter: self.type_.convert(),
204        }
205    }
206}
207
208impl Convert<FilterType> for BiquadFilterType {
209    fn convert(self) -> FilterType {
210        match self {
211            BiquadFilterType::Lowpass => FilterType::LowPass,
212            BiquadFilterType::Highpass => FilterType::HighPass,
213            BiquadFilterType::Bandpass => FilterType::BandPass,
214            BiquadFilterType::Lowshelf => FilterType::LowShelf,
215            BiquadFilterType::Highshelf => FilterType::HighShelf,
216            BiquadFilterType::Peaking => FilterType::Peaking,
217            BiquadFilterType::Allpass => FilterType::AllPass,
218            BiquadFilterType::Notch => FilterType::Notch,
219        }
220    }
221}