1#[cfg(not(test))]
13use crate::math::Libm;
14
15use crate::chan::Channel;
16use core::f32::consts::FRAC_PI_2;
17use core::fmt::Debug;
18use core::ops::{Add, Mul, Neg, Sub};
19
20#[repr(transparent)]
24#[derive(Copy, Clone, Debug, PartialEq)]
25pub struct Frame<Chan: Channel, const CH: usize>([Chan; CH]);
26
27impl<Chan: Channel, const CH: usize> Default for Frame<Chan, CH> {
28    fn default() -> Self {
29        Frame([Chan::default(); CH])
30    }
31}
32
33impl<Chan: Channel, const CH: usize> Frame<Chan, CH> {
34    #[inline(always)]
36    pub fn channels_mut(&mut self) -> &mut [Chan; CH] {
37        &mut self.0
38    }
39
40    #[inline(always)]
42    pub fn channels(&self) -> &[Chan; CH] {
43        &self.0
44    }
45
46    #[inline(always)]
51    pub fn pan<C: Channel + Into<Chan>>(self, channel: C, angle: f32) -> Self {
52        match CH {
53            1 => self.pan_1(channel.into(), angle.rem_euclid(1.0)),
54            2 => self.pan_2(channel.into(), angle.rem_euclid(1.0)),
55            3 => self.pan_3(channel.into(), angle.rem_euclid(1.0)),
56            4 => self.pan_4(channel.into(), angle.rem_euclid(1.0)),
57            5 => self.pan_5(channel.into(), angle.rem_euclid(1.0)),
58            6 => self.pan_6(channel.into(), angle.rem_euclid(1.0)),
59            7 => self.pan_7(channel.into(), angle.rem_euclid(1.0)),
60            8 => self.pan_8(channel.into(), angle.rem_euclid(1.0)),
61            _ => unreachable!(),
62        }
63    }
64
65    #[inline(always)]
68    pub fn gain(&mut self, gain: f32) {
69        for x in self.0.iter_mut() {
70            *x = (x.to_f32() * gain).into();
71        }
72    }
73
74    #[inline(always)]
76    pub fn lerp(&mut self, rhs: Self, t: f32) {
77        for (out, rhs) in self.0.iter_mut().zip(rhs.0.iter()) {
78            *out = out.lerp(*rhs, t.into());
79        }
80    }
81
82    #[inline(always)]
84    pub fn to<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
85        match CH {
86            1 => self.to_1(),
87            2 => self.to_2(),
88            3 => self.to_3(),
89            4 => self.to_4(),
90            5 => self.to_5(),
91            6 => self.to_6(),
92            7 => self.to_7(),
93            8 => self.to_8(),
94            _ => unreachable!(),
95        }
96    }
97
98    #[inline(always)]
99    fn pan_1(mut self, chan: Chan, _x: f32) -> Self {
100        const MONO: usize = 0;
101
102        self.0[MONO] += chan;
103
104        self
105    }
106
107    #[inline(always)]
108    fn pan_2(mut self, chan: Chan, x: f32) -> Self {
109        const LEFT: usize = 0;
110        const RIGHT: usize = 1;
111
112        let x = (x + 0.25) * core::f32::consts::PI;
114        self.0[LEFT] += chan * x.cos().into();
116        self.0[RIGHT] += chan * x.sin().into();
117
118        self
119    }
120
121    #[inline(always)]
122    fn pan_3(mut self, chan: Chan, x: f32) -> Self {
123        const LEFT: usize = 0;
124        const RIGHT: usize = 1;
125        const CENTER: usize = 2;
126
127        match (x.fract() + 1.0).fract() {
129            x if x < 0.25 => {
131                let x = 4.0 * x * FRAC_PI_2;
132                self.0[CENTER] += chan * x.cos().into();
133                self.0[RIGHT] += chan * x.sin().into();
134            }
135            x if x < 0.5 => {
137                let x = 4.0 * (x - 0.25) * FRAC_PI_2;
138                self.0[RIGHT] += chan * x.cos().into();
139                self.0[CENTER] += chan * x.sin().into();
140            }
141            x if x < 0.75 => {
143                let x = 4.0 * (x - 0.50) * FRAC_PI_2;
144                self.0[CENTER] += chan * x.cos().into();
145                self.0[LEFT] += chan * x.sin().into();
146            }
147            x => {
149                let x = 4.0 * (x - 0.75) * FRAC_PI_2;
150                self.0[LEFT] += chan * x.cos().into();
151                self.0[CENTER] += chan * x.sin().into();
152            }
153        }
154
155        self
156    }
157
158    #[inline(always)]
159    fn pan_4(mut self, chan: Chan, x: f32) -> Self {
160        const FRONT_L: usize = 0;
161        const FRONT_R: usize = 1;
162        const SURROUND_L: usize = 2;
163        const SURROUND_R: usize = 3;
164
165        match (x.fract() + 1.0 + 1.0 / 12.0).fract() {
167            x if x < 60.0 / 360.0 => {
169                let x = (360.0 / 60.0) * x * FRAC_PI_2;
170                self.0[FRONT_L] += chan * x.cos().into();
171                self.0[FRONT_R] += chan * x.sin().into();
172            }
173            x if x < 140.0 / 360.0 => {
175                let x = (360.0 / 80.0) * (x - 60.0 / 360.0) * FRAC_PI_2;
176                self.0[FRONT_R] += chan * x.cos().into();
177                self.0[SURROUND_R] += chan * x.sin().into();
178            }
179            x if x < 280.0 / 360.0 => {
181                let x = (360.0 / 140.0) * (x - 140.0 / 360.0) * FRAC_PI_2;
182                self.0[SURROUND_R] += chan * x.cos().into();
183                self.0[SURROUND_L] += chan * x.sin().into();
184            }
185            x => {
187                let x = (360.0 / 80.0) * (x - 280.0 / 360.0) * FRAC_PI_2;
188                self.0[SURROUND_L] += chan * x.cos().into();
189                self.0[FRONT_L] += chan * x.sin().into();
190            }
191        }
192
193        self
194    }
195
196    #[inline(always)]
197    fn pan_5(mut self, chan: Chan, x: f32) -> Self {
198        const FRONT_L: usize = 0;
199        const FRONT_R: usize = 1;
200        const FRONT: usize = 2;
201        const SURROUND_L: usize = 3;
202        const SURROUND_R: usize = 4;
203
204        match (x.fract() + 1.0).fract() {
205            x if x < 30.0 / 360.0 => {
207                let x = (360.0 / 30.0) * x * FRAC_PI_2;
208                self.0[FRONT] += chan * x.cos().into();
209                self.0[FRONT_R] += chan * x.sin().into();
210            }
211            x if x < 110.0 / 360.0 => {
213                let x = (360.0 / 80.0) * (x - 30.0 / 360.0) * FRAC_PI_2;
214                self.0[FRONT_R] += chan * x.cos().into();
215                self.0[SURROUND_R] += chan * x.sin().into();
216            }
217            x if x < 250.0 / 360.0 => {
219                let x = (360.0 / 140.0) * (x - 110.0 / 360.0) * FRAC_PI_2;
220                self.0[SURROUND_R] += chan * x.cos().into();
221                self.0[SURROUND_L] += chan * x.sin().into();
222            }
223            x if x < 330.0 / 360.0 => {
225                let x = (360.0 / 80.0) * (x - 250.0 / 360.0) * FRAC_PI_2;
226                self.0[SURROUND_L] += chan * x.cos().into();
227                self.0[FRONT_L] += chan * x.sin().into();
228            }
229            x => {
231                let x = (360.0 / 30.0) * (x - 330.0 / 360.0) * FRAC_PI_2;
232                self.0[FRONT_L] += chan * x.cos().into();
233                self.0[FRONT] += chan * x.sin().into();
234            }
235        }
236
237        self
238    }
239
240    #[inline(always)]
241    fn pan_6(mut self, chan: Chan, x: f32) -> Self {
242        const FRONT_L: usize = 0;
243        const FRONT_R: usize = 1;
244        const FRONT: usize = 2;
245
246        const SURROUND_L: usize = 4;
247        const SURROUND_R: usize = 5;
248
249        match (x.fract() + 1.0).fract() {
250            x if x < 30.0 / 360.0 => {
252                let x = (360.0 / 30.0) * x * FRAC_PI_2;
253                self.0[FRONT] += chan * x.cos().into();
254                self.0[FRONT_R] += chan * x.sin().into();
255            }
256            x if x < 110.0 / 360.0 => {
258                let x = (360.0 / 80.0) * (x - 30.0 / 360.0) * FRAC_PI_2;
259                self.0[FRONT_R] += chan * x.cos().into();
260                self.0[SURROUND_R] += chan * x.sin().into();
261            }
262            x if x < 250.0 / 360.0 => {
264                let x = (360.0 / 140.0) * (x - 110.0 / 360.0) * FRAC_PI_2;
265                self.0[SURROUND_R] += chan * x.cos().into();
266                self.0[SURROUND_L] += chan * x.sin().into();
267            }
268            x if x < 330.0 / 360.0 => {
270                let x = (360.0 / 80.0) * (x - 250.0 / 360.0) * FRAC_PI_2;
271                self.0[SURROUND_L] += chan * x.cos().into();
272                self.0[FRONT_L] += chan * x.sin().into();
273            }
274            x => {
276                let x = (360.0 / 30.0) * (x - 330.0 / 360.0) * FRAC_PI_2;
277                self.0[FRONT_L] += chan * x.cos().into();
278                self.0[FRONT] += chan * x.sin().into();
279            }
280        }
281
282        self
283    }
284
285    #[inline(always)]
286    fn pan_7(mut self, chan: Chan, x: f32) -> Self {
287        const FRONT_L: usize = 0;
288        const FRONT_R: usize = 1;
289        const FRONT: usize = 2;
290
291        const BACK: usize = 4;
292        const LEFT: usize = 5;
293        const RIGHT: usize = 6;
294
295        match (x.fract() + 1.0).fract() {
296            x if x < 30.0 / 360.0 => {
298                let x = (360.0 / 30.0) * x * FRAC_PI_2;
299                self.0[FRONT] += chan * x.cos().into();
300                self.0[FRONT_R] += chan * x.sin().into();
301            }
302            x if x < 90.0 / 360.0 => {
304                let x = (360.0 / 60.0) * (x - 30.0 / 360.0) * FRAC_PI_2;
305                self.0[FRONT_R] += chan * x.cos().into();
306                self.0[RIGHT] += chan * x.sin().into();
307            }
308            x if x < 180.0 / 360.0 => {
310                let x = (360.0 / 90.0) * (x - 90.0 / 360.0) * FRAC_PI_2;
311                self.0[RIGHT] += chan * x.cos().into();
312                self.0[BACK] += chan * x.sin().into();
313            }
314            x if x < 270.0 / 360.0 => {
316                let x = (360.0 / 90.0) * (x - 180.0 / 360.0) * FRAC_PI_2;
317                self.0[BACK] += chan * x.cos().into();
318                self.0[LEFT] += chan * x.sin().into();
319            }
320            x if x < 330.0 / 360.0 => {
322                let x = (360.0 / 60.0) * (x - 270.0 / 360.0) * FRAC_PI_2;
323                self.0[LEFT] += chan * x.cos().into();
324                self.0[FRONT_L] += chan * x.sin().into();
325            }
326            x => {
328                let x = (360.0 / 30.0) * (x - 330.0 / 360.0) * FRAC_PI_2;
329                self.0[FRONT_L] += chan * x.cos().into();
330                self.0[FRONT] += chan * x.sin().into();
331            }
332        }
333
334        self
335    }
336
337    #[inline(always)]
338    fn pan_8(mut self, chan: Chan, x: f32) -> Self {
339        const FRONT_L: usize = 0;
340        const FRONT_R: usize = 1;
341        const FRONT: usize = 2;
342
343        const BACK_L: usize = 4;
344        const BACK_R: usize = 5;
345        const LEFT: usize = 6;
346        const RIGHT: usize = 7;
347
348        match (x.fract() + 1.0).fract() {
349            x if x < 30.0 / 360.0 => {
351                let x = (360.0 / 30.0) * x * FRAC_PI_2;
352                self.0[FRONT] += chan * x.cos().into();
353                self.0[FRONT_R] += chan * x.sin().into();
354            }
355            x if x < 90.0 / 360.0 => {
357                let x = (360.0 / 60.0) * (x - 30.0 / 360.0) * FRAC_PI_2;
358                self.0[FRONT_R] += chan * x.cos().into();
359                self.0[RIGHT] += chan * x.sin().into();
360            }
361            x if x < 150.0 / 360.0 => {
363                let x = (360.0 / 60.0) * (x - 90.0 / 360.0) * FRAC_PI_2;
364                self.0[RIGHT] += chan * x.cos().into();
365                self.0[BACK_R] += chan * x.sin().into();
366            }
367            x if x < 210.0 / 360.0 => {
369                let x = (360.0 / 60.0) * (x - 150.0 / 360.0) * FRAC_PI_2;
370                self.0[BACK_R] += chan * x.cos().into();
371                self.0[BACK_L] += chan * x.sin().into();
372            }
373            x if x < 270.0 / 360.0 => {
375                let x = (360.0 / 60.0) * (x - 210.0 / 360.0) * FRAC_PI_2;
376                self.0[BACK_L] += chan * x.cos().into();
377                self.0[LEFT] += chan * x.sin().into();
378            }
379            x if x < 330.0 / 360.0 => {
381                let x = (360.0 / 60.0) * (x - 270.0 / 360.0) * FRAC_PI_2;
382                self.0[LEFT] += chan * x.cos().into();
383                self.0[FRONT_L] += chan * x.sin().into();
384            }
385            x => {
387                let x = (360.0 / 30.0) * (x - 330.0 / 360.0) * FRAC_PI_2;
388                self.0[FRONT_L] += chan * x.cos().into();
389                self.0[FRONT] += chan * x.sin().into();
390            }
391        }
392
393        self
394    }
395
396    #[inline(always)]
397    fn to_1<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
398        const MONO: usize = 0;
399
400        let mut frame = Frame::<C, N>::default();
401        let mono = self.0[MONO].into();
402        frame.0[0] = mono;
403        if N == 1 {
404        } else {
405            frame.0[1] = mono;
407        }
408        frame
409    }
410
411    #[inline(always)]
412    fn to_2<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
413        const LEFT: usize = 0;
414        const RIGHT: usize = 1;
415
416        let mut frame = Frame::<C, N>::default();
417        let left = self.0[LEFT].into();
418        let right = self.0[RIGHT].into();
419        if N == 1 {
420            let half = 0.5.into();
421            frame.0[0] = left * half + right * half;
422        } else {
423            frame.0[0] = left;
425            frame.0[1] = right;
426        }
427        frame
428    }
429
430    #[inline(always)]
431    fn to_3<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
432        const LEFT: usize = 0;
433        const RIGHT: usize = 1;
434        const CENTER: usize = 2;
435
436        let mut frame = Frame::<C, N>::default();
437        let left = self.0[LEFT].into();
438        let right = self.0[RIGHT].into();
439        let center = self.0[CENTER].into();
440        match N {
441            1 => {
442                frame.0[0] = left * (1.0 / 3.0).into()
443                    + right * (1.0 / 3.0).into()
444                    + center * (1.0 / 3.0).into()
445            }
446            2 => {
447                frame.0[0] =
448                    left * (2.0 / 3.0).into() + center * (1.0 / 3.0).into();
449                frame.0[1] =
450                    right * (2.0 / 3.0).into() + center * (1.0 / 3.0).into();
451            }
452            4 => {
453                frame.0[0] =
454                    left * (2.0 / 3.0).into() + center * (1.0 / 3.0).into();
455                frame.0[1] =
456                    right * (2.0 / 3.0).into() + center * (1.0 / 3.0).into();
457                frame.0[2] = frame.0[0];
458                frame.0[3] = frame.0[1];
459            }
460            _ => {
461                frame.0[0] = left;
462                frame.0[1] = right;
463                frame.0[2] = center;
464            }
465        }
466        frame
467    }
468
469    #[inline(always)]
470    fn to_4<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
471        const FRONT_L: usize = 0;
472        const FRONT_R: usize = 1;
473        const SURROUND_L: usize = 2;
474        const SURROUND_R: usize = 3;
475
476        let front_l = self.0[FRONT_L];
478        let front_r = self.0[FRONT_R];
479        let surround_l = self.0[SURROUND_L];
480        let surround_r = self.0[SURROUND_R];
481        let amplitude = (N as f32 / 4.0).min(1.0);
483        Frame::<C, N>::default()
484            .pan(front_l * amplitude.into(), -30.0 / 360.0)
485            .pan(front_r * amplitude.into(), 30.0 / 360.0)
486            .pan(surround_l * amplitude.into(), -110.0 / 360.0)
487            .pan(surround_r * amplitude.into(), 110.0 / 360.0)
488    }
489
490    #[inline(always)]
491    fn to_5<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
492        const FRONT_L: usize = 0;
493        const FRONT_R: usize = 1;
494        const FRONT: usize = 2;
495        const SURROUND_L: usize = 3;
496        const SURROUND_R: usize = 4;
497
498        let front_l = self.0[FRONT_L];
500        let front_r = self.0[FRONT_R];
501        let surround_l = self.0[SURROUND_L];
502        let surround_r = self.0[SURROUND_R];
503        let front = self.0[FRONT];
504        let amplitude = (N as f32 / 5.0).min(1.0);
506        Frame::<C, N>::default()
507            .pan(front_l * amplitude.into(), -30.0 / 360.0)
508            .pan(front_r * amplitude.into(), 30.0 / 360.0)
509            .pan(surround_l * amplitude.into(), -110.0 / 360.0)
510            .pan(surround_r * amplitude.into(), 110.0 / 360.0)
511            .pan(front * amplitude.into(), 0.0)
512    }
513
514    #[inline(always)]
515    fn to_6<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
516        const FRONT_L: usize = 0;
517        const FRONT_R: usize = 1;
518        const FRONT: usize = 2;
519        const LFE: usize = 3;
520        const SURROUND_L: usize = 4;
521        const SURROUND_R: usize = 5;
522
523        let front_l = self.0[FRONT_L];
525        let front_r = self.0[FRONT_R];
526        let surround_l = self.0[SURROUND_L];
527        let surround_r = self.0[SURROUND_R];
528        let front = self.0[FRONT];
529        let lfe = self.0[LFE];
530        let amplitude = (N as f32 / 5.0).min(1.0);
532        let mut frame = Frame::<C, N>::default()
533            .pan(front_l * amplitude.into(), -30.0 / 360.0)
534            .pan(front_r * amplitude.into(), 30.0 / 360.0)
535            .pan(surround_l * amplitude.into(), -110.0 / 360.0)
536            .pan(surround_r * amplitude.into(), 110.0 / 360.0)
537            .pan(front * amplitude.into(), 0.0);
538        if N < 5 {
540            frame.pan(lfe * amplitude.into(), 0.5)
541        } else {
542            frame.0[3] = (lfe * amplitude.into()).into();
543            frame
544        }
545    }
546
547    #[inline(always)]
548    fn to_7<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
549        const FRONT_L: usize = 0;
550        const FRONT_R: usize = 1;
551        const FRONT: usize = 2;
552        const LFE: usize = 3;
553        const BACK: usize = 4;
554        const LEFT: usize = 5;
555        const RIGHT: usize = 6;
556
557        let front_l = self.0[FRONT_L];
559        let front_r = self.0[FRONT_R];
560        let left = self.0[LEFT];
561        let right = self.0[RIGHT];
562        let front = self.0[FRONT];
563        let lfe = self.0[LFE];
564        let back = self.0[BACK];
565        let amplitude = (N as f32 / 6.0).min(1.0);
567        let mut frame = Frame::<C, N>::default()
568            .pan(front_l * amplitude.into(), -30.0 / 360.0)
569            .pan(front_r * amplitude.into(), 30.0 / 360.0)
570            .pan(left * amplitude.into(), -90.0 / 360.0)
571            .pan(right * amplitude.into(), 90.0 / 360.0)
572            .pan(front * amplitude.into(), 0.0)
573            .pan(back * amplitude.into(), 0.5);
574        if N < 5 {
576            frame.pan(lfe * amplitude.into(), 0.5)
577        } else {
578            frame.0[3] = (lfe * amplitude.into()).into();
579            frame
580        }
581    }
582
583    #[inline(always)]
584    fn to_8<C: Channel + From<Chan>, const N: usize>(self) -> Frame<C, N> {
585        const FRONT_L: usize = 0;
586        const FRONT_R: usize = 1;
587        const FRONT: usize = 2;
588        const LFE: usize = 3;
589        const BACK_L: usize = 4;
590        const BACK_R: usize = 5;
591        const LEFT: usize = 6;
592        const RIGHT: usize = 7;
593
594        let front_l = self.0[FRONT_L];
596        let front_r = self.0[FRONT_R];
597        let left = self.0[LEFT];
598        let right = self.0[RIGHT];
599        let front = self.0[FRONT];
600        let lfe = self.0[LFE];
601        let back_l = self.0[BACK_L];
602        let back_r = self.0[BACK_R];
603        let amplitude = (N as f32 / 7.0).min(1.0);
605        let mut frame = Frame::<C, N>::default()
606            .pan(front_l * amplitude.into(), -30.0 / 360.0)
607            .pan(front_r * amplitude.into(), 30.0 / 360.0)
608            .pan(left * amplitude.into(), -90.0 / 360.0)
609            .pan(right * amplitude.into(), 90.0 / 360.0)
610            .pan(front * amplitude.into(), 0.0)
611            .pan(back_l * amplitude.into(), -150.0 / 360.0)
612            .pan(back_r * amplitude.into(), 150.0 / 360.0);
613        if N < 5 {
615            frame.pan(lfe * amplitude.into(), 0.5)
616        } else {
617            frame.0[3] = (lfe * amplitude.into()).into();
618            frame
619        }
620    }
621}
622
623impl<Chan: Channel> Frame<Chan, 1> {
624    #[inline(always)]
626    pub fn new(mono: Chan) -> Self {
627        Self([mono])
628    }
629}
630
631impl<Chan: Channel> Frame<Chan, 2> {
632    #[inline(always)]
634    pub fn new(left: Chan, right: Chan) -> Self {
635        Self([left, right])
636    }
637}
638
639impl<Chan: Channel> Frame<Chan, 3> {
640    #[inline(always)]
642    pub fn new(left: Chan, right: Chan, center: Chan) -> Self {
643        Self([left, right, center])
644    }
645}
646
647impl<Chan: Channel> Frame<Chan, 4> {
648    #[inline(always)]
650    pub fn new(
651        left: Chan,
652        right: Chan,
653        back_left: Chan,
654        back_right: Chan,
655    ) -> Self {
656        Self([left, right, back_left, back_right])
657    }
658}
659
660impl<Chan: Channel> Frame<Chan, 5> {
661    #[inline(always)]
663    pub fn new(
664        left: Chan,
665        right: Chan,
666        center: Chan,
667        back_left: Chan,
668        back_right: Chan,
669    ) -> Self {
670        Self([left, right, center, back_left, back_right])
671    }
672}
673
674impl<Chan: Channel> Frame<Chan, 6> {
675    #[inline(always)]
677    pub fn new(
678        left: Chan,
679        right: Chan,
680        center: Chan,
681        lfe: Chan,
682        back_left: Chan,
683        back_right: Chan,
684    ) -> Self {
685        Self([left, right, center, lfe, back_left, back_right])
686    }
687}
688
689impl<Chan: Channel> Frame<Chan, 7> {
690    #[inline(always)]
692    pub fn new(
693        left: Chan,
694        right: Chan,
695        center: Chan,
696        lfe: Chan,
697        back: Chan,
698        side_left: Chan,
699        side_right: Chan,
700    ) -> Self {
701        Self([left, right, center, lfe, back, side_left, side_right])
702    }
703}
704
705impl<Chan: Channel> Frame<Chan, 8> {
706    #[inline(always)]
708    #[allow(clippy::too_many_arguments)]
709    pub fn new(
710        left: Chan,
711        right: Chan,
712        center: Chan,
713        lfe: Chan,
714        back_left: Chan,
715        back_right: Chan,
716        side_left: Chan,
717        side_right: Chan,
718    ) -> Self {
719        Self([
720            left, right, center, lfe, back_left, back_right, side_left,
721            side_right,
722        ])
723    }
724}
725
726impl<Chan: Channel, const CH: usize> From<f32> for Frame<Chan, CH> {
727    fn from(rhs: f32) -> Self {
728        Frame([Chan::from(rhs); CH])
729    }
730}
731
732impl<Chan: Channel, const CH: usize> Add for Frame<Chan, CH> {
733    type Output = Self;
734
735    #[inline(always)]
736    fn add(mut self, other: Self) -> Self {
737        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
738            *a += *b;
739        }
740        self
741    }
742}
743
744impl<Chan: Channel, const CH: usize> Sub for Frame<Chan, CH> {
745    type Output = Self;
746
747    #[inline(always)]
748    fn sub(mut self, other: Self) -> Self {
749        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
750            *a -= *b;
751        }
752        self
753    }
754}
755
756impl<Chan: Channel, const CH: usize> Mul for Frame<Chan, CH> {
757    type Output = Self;
758
759    #[inline(always)]
760    fn mul(mut self, other: Self) -> Self {
761        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
762            *a *= *b;
763        }
764        self
765    }
766}
767
768impl<Chan: Channel, const CH: usize> Neg for Frame<Chan, CH> {
769    type Output = Self;
770
771    #[inline(always)]
772    fn neg(mut self) -> Self {
773        for chan in self.0.iter_mut() {
774            *chan = -*chan;
775        }
776        self
777    }
778}