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