Skip to main content

script/dom/audio/
periodicwave.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 dom_struct::dom_struct;
6use js::context::JSContext;
7use js::gc::HandleObject;
8use script_bindings::codegen::GenericBindings::PeriodicWaveBinding::PeriodicWaveMethods;
9use script_bindings::num::Finite;
10use script_bindings::reflector::{Reflector, reflect_dom_object_with_proto};
11use servo_media::audio::periodic_wave::{
12    PeriodicWave as ServoMediaPeriodicWave, PeriodicWaveOptions as ServoMediaPeriodicWaveOptions,
13};
14
15use crate::conversions::Convert;
16use crate::dom::audio::baseaudiocontext::BaseAudioContext;
17use crate::dom::bindings::codegen::Bindings::PeriodicWaveBinding::PeriodicWaveOptions;
18use crate::dom::bindings::error::{Error, Fallible};
19use crate::dom::bindings::root::{Dom, DomRoot};
20use crate::dom::window::Window;
21
22#[dom_struct]
23pub(crate) struct PeriodicWave {
24    reflector_: Reflector,
25    context: Dom<BaseAudioContext>,
26    /// <https://webaudio.github.io/web-audio-api/#dom-periodicwave-imag-slot>
27    imag: Vec<Finite<f32>>,
28    /// <https://webaudio.github.io/web-audio-api/#dom-periodicwave-real-slot>
29    real: Vec<Finite<f32>>,
30    /// <https://webaudio.github.io/web-audio-api/#dom-periodicwave-imag-slot>
31    normalize: bool,
32}
33
34impl PeriodicWaveMethods<crate::DomTypeHolder> for PeriodicWave {
35    /// <https://webaudio.github.io/web-audio-api/#dom-periodicwave-periodicwave>
36    fn Constructor(
37        cx: &mut JSContext,
38        window: &Window,
39        proto: Option<HandleObject>,
40        context: &BaseAudioContext,
41        options: &PeriodicWaveOptions,
42    ) -> Fallible<DomRoot<PeriodicWave>> {
43        let (real, imag) = match (options.real.as_ref(), options.imag.as_ref()) {
44            // If both options.real and options.imag are present
45            (Some(real), Some(imag)) => {
46                let mut real = real.to_vec();
47                let mut imag = imag.to_vec();
48                // If the lengths of options.real and options.imag are different or if either length is less than 2,
49                // throw an IndexSizeError and abort this algorithm
50                if real.len() != imag.len() {
51                    return Err(Error::IndexSize(Some(String::from(
52                        "real and imag coefficients have different lengths",
53                    ))));
54                }
55                if real.len() < 2 || imag.len() < 2 {
56                    return Err(Error::IndexSize(Some(String::from(
57                        "At least one of real or imag coefficients have length less than 2",
58                    ))));
59                }
60                // Set the DC component to 0
61                real[0] = Finite::wrap(0.0);
62                imag[0] = Finite::wrap(0.0);
63                (real, imag)
64            },
65            // If only options.real is present
66            (Some(real), None) => {
67                let mut real = real.to_vec();
68                // If length of options.real is less than 2, throw an IndexSizeError and abort this algorithm
69                if real.len() < 2 {
70                    return Err(Error::IndexSize(Some(String::from(
71                        "real coefficients have length less than 2",
72                    ))));
73                }
74                // Set [[real]] and [[imag]] to arrays with the same length as options.real
75                let real_len = real.len();
76                // Set the DC component to 0
77                real[0] = Finite::wrap(0.0);
78                // set [[imag]] to all zeros
79                (real, vec![Finite::wrap(0.0); real_len])
80            },
81            // If only options.imag is present
82            (None, Some(imag)) => {
83                let mut imag = imag.to_vec();
84                // If length of options.imag is less than 2, throw an IndexSizeError and abort this algorithm
85                if imag.len() < 2 {
86                    return Err(Error::IndexSize(Some(String::from(
87                        "imag coefficients have length less than 2",
88                    ))));
89                }
90                // Set [[real]] and [[imag]] to arrays with the same length as options.imag
91                let imag_len = imag.len();
92                // Set the DC component to 0
93                imag[0] = Finite::wrap(0.0);
94                // set [[real]] to all zeros
95                (vec![Finite::wrap(0.0); imag_len], imag)
96            },
97            (None, None) => (
98                // Set [[real]] and [[imag]] to zero-filled arrays of length 2
99                vec![Finite::wrap(0.0); 2],
100                // Set element at index 1 of [[imag]] to 1
101                vec![Finite::wrap(0.0), Finite::wrap(1.0)],
102            ),
103        };
104        Ok(reflect_dom_object_with_proto(
105            cx,
106            Box::new(PeriodicWave {
107                reflector_: Reflector::new(),
108                context: Dom::from_ref(context),
109                real,
110                imag,
111                // Initialize [[normalize]] to the inverse of the disableNormalization attribute of
112                // the PeriodicWaveConstraints on the PeriodicWaveOptions
113                normalize: !options.parent.disableNormalization,
114            }),
115            window,
116            proto,
117        ))
118    }
119}
120
121impl Convert<ServoMediaPeriodicWave> for &PeriodicWave {
122    fn convert(self) -> ServoMediaPeriodicWave {
123        ServoMediaPeriodicWave::new(ServoMediaPeriodicWaveOptions::new(
124            self.imag.iter().map(|x| **x).collect(),
125            self.real.iter().map(|x| **x).collect(),
126            !self.normalize,
127        ))
128    }
129}