script/dom/audio/
iirfilternode.rs1use std::sync::Arc;
6
7use dom_struct::dom_struct;
8use itertools::Itertools;
9use js::context::JSContext;
10use js::gc::CustomAutoRooterGuard;
11use js::rust::HandleObject;
12use js::typedarray::Float32Array;
13use script_bindings::reflector::reflect_dom_object_with_proto;
14use servo_media::audio::iir_filter_node::{IIRFilterNode as IIRFilter, IIRFilterNodeOptions};
15use servo_media::audio::node::AudioNodeInit;
16
17use crate::conversions::Convert;
18use crate::dom::audio::audionode::{AudioNode, AudioNodeOptionsHelper};
19use crate::dom::audio::baseaudiocontext::BaseAudioContext;
20use crate::dom::bindings::codegen::Bindings::AudioNodeBinding::{
21 ChannelCountMode, ChannelInterpretation,
22};
23use crate::dom::bindings::codegen::Bindings::IIRFilterNodeBinding::{
24 IIRFilterNodeMethods, IIRFilterOptions,
25};
26use crate::dom::bindings::error::{Error, Fallible};
27use crate::dom::bindings::num::Finite;
28use crate::dom::bindings::root::DomRoot;
29use crate::dom::window::Window;
30
31#[dom_struct]
32pub(crate) struct IIRFilterNode {
33 node: AudioNode,
34 feedforward: Vec<Finite<f64>>,
35 feedback: Vec<Finite<f64>>,
36}
37
38impl IIRFilterNode {
39 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
40 pub(crate) fn new_inherited(
41 cx: &mut JSContext,
42 _window: &Window,
43 context: &BaseAudioContext,
44 options: &IIRFilterOptions,
45 ) -> Fallible<IIRFilterNode> {
46 if !(1..=20).contains(&options.feedforward.len()) ||
47 !(1..=20).contains(&options.feedback.len())
48 {
49 return Err(Error::NotSupported(None));
50 }
51 if options.feedforward.iter().all(|v| **v == 0.0) || *options.feedback[0] == 0.0 {
52 return Err(Error::InvalidState(None));
53 }
54 let node_options =
55 options
56 .parent
57 .unwrap_or(2, ChannelCountMode::Max, ChannelInterpretation::Speakers);
58 let feedforward = (*options.feedforward).to_vec();
59 let feedback = (*options.feedback).to_vec();
60 let init_options = options.clone().convert();
61 let node = AudioNode::new_inherited(
62 cx,
63 AudioNodeInit::IIRFilterNode(init_options),
64 context,
65 node_options,
66 1, 1, )?;
69 Ok(IIRFilterNode {
70 node,
71 feedforward,
72 feedback,
73 })
74 }
75
76 pub(crate) fn new(
77 cx: &mut JSContext,
78 window: &Window,
79 context: &BaseAudioContext,
80 options: &IIRFilterOptions,
81 ) -> Fallible<DomRoot<IIRFilterNode>> {
82 Self::new_with_proto(cx, window, None, context, options)
83 }
84
85 #[cfg_attr(crown, expect(crown::unrooted_must_root))]
86 fn new_with_proto(
87 cx: &mut JSContext,
88 window: &Window,
89 proto: Option<HandleObject>,
90 context: &BaseAudioContext,
91 options: &IIRFilterOptions,
92 ) -> Fallible<DomRoot<IIRFilterNode>> {
93 let node = IIRFilterNode::new_inherited(cx, window, context, options)?;
94 Ok(reflect_dom_object_with_proto(
95 cx,
96 Box::new(node),
97 window,
98 proto,
99 ))
100 }
101}
102
103impl IIRFilterNodeMethods<crate::DomTypeHolder> for IIRFilterNode {
104 fn Constructor(
106 cx: &mut JSContext,
107 window: &Window,
108 proto: Option<HandleObject>,
109 context: &BaseAudioContext,
110 options: &IIRFilterOptions,
111 ) -> Fallible<DomRoot<IIRFilterNode>> {
112 IIRFilterNode::new_with_proto(cx, window, proto, context, options)
113 }
114
115 fn GetFrequencyResponse(
117 &self,
118 frequency_hz: CustomAutoRooterGuard<Float32Array>,
119 mut mag_response: CustomAutoRooterGuard<Float32Array>,
120 mut phase_response: CustomAutoRooterGuard<Float32Array>,
121 ) -> Result<(), Error> {
122 let frequency_hz_vec = frequency_hz.to_vec().unwrap_or(vec![]);
123 let mut mag_response_vec = mag_response.to_vec().unwrap_or(vec![]);
124 let mut phase_response_vec = phase_response.to_vec().unwrap_or(vec![]);
125
126 let len = frequency_hz.len();
127 if len != mag_response.len() || len != phase_response.len() {
128 return Err(Error::InvalidAccess(None));
129 }
130 let feedforward: Vec<f64> = (self.feedforward.iter().map(|v| **v).collect_vec()).to_vec();
131 let feedback: Vec<f64> = (self.feedback.iter().map(|v| **v).collect_vec()).to_vec();
132 IIRFilter::get_frequency_response(
133 &feedforward,
134 &feedback,
135 &frequency_hz_vec,
136 &mut mag_response_vec,
137 &mut phase_response_vec,
138 );
139
140 mag_response.update(&mag_response_vec);
141 phase_response.update(&phase_response_vec);
142
143 Ok(())
144 }
145}
146
147impl Convert<IIRFilterNodeOptions> for IIRFilterOptions {
148 fn convert(self) -> IIRFilterNodeOptions {
149 let feedforward: Vec<f64> = (*self.feedforward.iter().map(|v| **v).collect_vec()).to_vec();
150 let feedback: Vec<f64> = (*self.feedback.iter().map(|v| **v).collect_vec()).to_vec();
151 IIRFilterNodeOptions {
152 feedforward: Arc::new(feedforward),
153 feedback: Arc::new(feedback),
154 }
155 }
156}