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_and_cx;
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_and_cx(
95 Box::new(node),
96 window,
97 proto,
98 cx,
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 len = frequency_hz.len();
123 if len != mag_response.len() || len != phase_response.len() {
124 return Err(Error::InvalidAccess(None));
125 }
126 let feedforward: Vec<f64> = (self.feedforward.iter().map(|v| **v).collect_vec()).to_vec();
127 let feedback: Vec<f64> = (self.feedback.iter().map(|v| **v).collect_vec()).to_vec();
128 let frequency_hz_vec = frequency_hz.to_vec();
129 let mut mag_response_vec = mag_response.to_vec();
130 let mut phase_response_vec = phase_response.to_vec();
131 IIRFilter::get_frequency_response(
132 &feedforward,
133 &feedback,
134 &frequency_hz_vec,
135 &mut mag_response_vec,
136 &mut phase_response_vec,
137 );
138
139 mag_response.update(&mag_response_vec);
140 phase_response.update(&phase_response_vec);
141
142 Ok(())
143 }
144}
145
146impl Convert<IIRFilterNodeOptions> for IIRFilterOptions {
147 fn convert(self) -> IIRFilterNodeOptions {
148 let feedforward: Vec<f64> = (*self.feedforward.iter().map(|v| **v).collect_vec()).to_vec();
149 let feedback: Vec<f64> = (*self.feedback.iter().map(|v| **v).collect_vec()).to_vec();
150 IIRFilterNodeOptions {
151 feedforward: Arc::new(feedforward),
152 feedback: Arc::new(feedback),
153 }
154 }
155}