fon/
chan.rs

1// Copyright © 2020-2022 The Fon Contributors.
2//
3// Licensed under any of:
4// - Apache License, Version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
5// - MIT License (https://mit-license.org/)
6// - Boost Software License, Version 1.0 (https://www.boost.org/LICENSE_1_0.txt)
7// At your choosing (See accompanying files LICENSE_APACHE_2_0.txt,
8// LICENSE_MIT.txt and LICENSE_BOOST_1_0.txt).
9
10//! Audio channels (left, right, etc.).  Each channel contains a single sample.
11//!
12//! An audio [`Frame`](crate::frame::Frame) is used to group multiple channels.
13
14#[cfg(not(test))]
15use crate::math::Libm;
16
17use crate::private::Sealed;
18use core::fmt::Debug;
19use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
20
21/// Component of a speaker configuration, such as *front left*, *lfe*, *etc*.
22pub trait Channel:
23    Copy
24    + Clone
25    + Debug
26    + Default
27    + From<f32>
28    + PartialOrd
29    + Add<Output = Self>
30    + AddAssign
31    + Sub<Output = Self>
32    + SubAssign
33    + Mul<Output = Self>
34    + MulAssign
35    + Neg<Output = Self>
36    + From<Ch16>
37    + From<Ch24>
38    + From<Ch32>
39    + From<Ch64>
40    + Into<Ch16>
41    + Into<Ch24>
42    + Into<Ch32>
43    + Into<Ch64>
44    + Sealed
45    + Unpin
46    + Sized
47    + 'static
48{
49    /// Minimum value (*negative one*)
50    const MIN: Self;
51
52    /// Mid value (*zero/silence*)
53    const MID: Self;
54
55    /// Maximum value (*one*)
56    const MAX: Self;
57
58    /// Convert to `f32`
59    fn to_f32(self) -> f32;
60
61    /// Linear interpolation
62    #[inline(always)]
63    fn lerp(self, rhs: Self, t: Self) -> Self {
64        self + t * (rhs - self)
65    }
66}
67
68/// 16-bit sample [Channel](Channel).
69#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
70#[repr(transparent)]
71pub struct Ch16(i16);
72
73impl Channel for Ch16 {
74    const MIN: Ch16 = Ch16(-32_768);
75    const MID: Ch16 = Ch16(0);
76    const MAX: Ch16 = Ch16(32_767);
77
78    #[inline(always)]
79    fn to_f32(self) -> f32 {
80        const MULTIPLIER: f32 = 1.0 / 32_767.5;
81        (f32::from(self.0) + 0.5) * MULTIPLIER
82    }
83}
84
85impl Ch16 {
86    /// Create a new 16-bit [`Channel`](Channel) value.
87    #[inline(always)]
88    pub const fn new(value: i16) -> Self {
89        Self(value)
90    }
91}
92
93impl From<f32> for Ch16 {
94    #[inline(always)]
95    fn from(value: f32) -> Self {
96        Self::new((value.clamp(-1.0, 1.0) * 32_767.5).floor() as i16)
97    }
98}
99
100impl From<Ch24> for Ch16 {
101    #[inline(always)]
102    fn from(ch: Ch24) -> Self {
103        Self::new(ch.0)
104    }
105}
106
107impl From<Ch32> for Ch16 {
108    #[inline(always)]
109    fn from(ch: Ch32) -> Self {
110        Self::from(ch.0)
111    }
112}
113
114impl From<Ch64> for Ch16 {
115    #[inline(always)]
116    fn from(ch: Ch64) -> Self {
117        Self::from(ch.0 as f32)
118    }
119}
120
121impl From<Ch16> for i16 {
122    #[inline(always)]
123    fn from(ch: Ch16) -> i16 {
124        ch.0
125    }
126}
127
128impl<R: Into<Self>> Add<R> for Ch16 {
129    type Output = Self;
130
131    #[inline(always)]
132    fn add(self, rhs: R) -> Self {
133        Self::new(i16::from(self).saturating_add(i16::from(rhs.into())))
134    }
135}
136
137impl<R: Into<Self>> Sub<R> for Ch16 {
138    type Output = Self;
139
140    #[inline(always)]
141    fn sub(self, rhs: R) -> Self {
142        Self::new(i16::from(self).saturating_sub(i16::from(rhs.into())))
143    }
144}
145
146impl<R: Into<Self>> Mul<R> for Ch16 {
147    type Output = Self;
148
149    #[inline(always)]
150    fn mul(self, rhs: R) -> Self {
151        let l = i32::from(self.0);
152        let r = i32::from(rhs.into().0);
153        let v = (l * r) / 32_767;
154        Self::new(v.max(-32_768).min(32_767) as i16)
155    }
156}
157
158impl Neg for Ch16 {
159    type Output = Ch16;
160
161    #[inline(always)]
162    fn neg(self) -> Self {
163        Self::new((u16::MAX - i16::from(self) as u16) as i16)
164    }
165}
166
167/// 24-bit sample [Channel](Channel).
168#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
169#[repr(C, packed)]
170pub struct Ch24(i16, u8);
171
172impl Channel for Ch24 {
173    const MIN: Ch24 = Ch24::new(-8_388_608);
174    const MID: Ch24 = Ch24::new(0);
175    const MAX: Ch24 = Ch24::new(8_388_607);
176
177    #[inline(always)]
178    fn to_f32(self) -> f32 {
179        const MULTIPLIER: f32 = 1.0 / 8_388_607.5;
180        (i32::from(self) as f32 + 0.5) * MULTIPLIER
181    }
182}
183
184impl Ch24 {
185    /// Create a new 24-bit [`Channel`](Channel) value.
186    #[inline(always)]
187    pub const fn new(value: i32) -> Self {
188        let value = if value < -8_388_608 {
189            -8_388_608
190        } else if value > 8_388_607 {
191            8_388_607
192        } else {
193            value
194        };
195        Self((value >> 8) as i16, value as u8)
196    }
197}
198
199impl From<f32> for Ch24 {
200    #[inline(always)]
201    fn from(value: f32) -> Self {
202        Self::new((value.clamp(-1.0, 1.0) * 8_388_607.5).floor() as i32)
203    }
204}
205
206impl From<Ch16> for Ch24 {
207    #[inline(always)]
208    fn from(ch: Ch16) -> Self {
209        Self(i16::from(ch), (i16::from(ch) >> 8) as u8 ^ 0b1000_0000)
210    }
211}
212
213impl From<Ch32> for Ch24 {
214    #[inline(always)]
215    fn from(ch: Ch32) -> Self {
216        Self::from(ch.0)
217    }
218}
219
220impl From<Ch64> for Ch24 {
221    #[inline(always)]
222    fn from(ch: Ch64) -> Self {
223        Self::from(ch.0 as f32)
224    }
225}
226
227impl From<Ch24> for i32 {
228    #[inline(always)]
229    fn from(ch: Ch24) -> i32 {
230        ((ch.0 as i32) << 8) | ch.1 as i32
231    }
232}
233
234impl<R: Into<Self>> Add<R> for Ch24 {
235    type Output = Self;
236
237    #[inline(always)]
238    fn add(self, rhs: R) -> Self {
239        Self::new(i32::from(self) + i32::from(rhs.into()))
240    }
241}
242
243impl<R: Into<Self>> Sub<R> for Ch24 {
244    type Output = Self;
245
246    #[inline(always)]
247    fn sub(self, rhs: R) -> Self {
248        Self::new(i32::from(self) - i32::from(rhs.into()))
249    }
250}
251
252impl<R: Into<Self>> Mul<R> for Ch24 {
253    type Output = Self;
254
255    #[inline(always)]
256    fn mul(self, rhs: R) -> Self {
257        let l: i64 = i32::from(self).into();
258        let r: i64 = i32::from(rhs.into()).into();
259        let v = (l * r) / 8_388_607;
260        Self::new(v.max(-8_388_608).min(8_388_607) as i32)
261    }
262}
263
264impl Neg for Ch24 {
265    type Output = Ch24;
266
267    #[inline(always)]
268    fn neg(self) -> Self {
269        Self::new((u32::MAX - i32::from(self) as u32) as i32)
270    }
271}
272
273/// 32-bit sample [Channel](Channel).
274#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
275#[repr(transparent)]
276pub struct Ch32(f32);
277
278impl Channel for Ch32 {
279    const MIN: Ch32 = Ch32(-1.0);
280    const MID: Ch32 = Ch32(0.0);
281    const MAX: Ch32 = Ch32(1.0);
282
283    #[inline(always)]
284    fn to_f32(self) -> f32 {
285        self.0
286    }
287}
288
289impl Ch32 {
290    /// Create a new 32-bit [`Channel`](Channel) value.
291    #[inline(always)]
292    pub const fn new(value: f32) -> Self {
293        Self(value)
294    }
295}
296
297impl From<f32> for Ch32 {
298    #[inline(always)]
299    fn from(value: f32) -> Self {
300        Self::new(value)
301    }
302}
303
304impl From<Ch16> for Ch32 {
305    #[inline(always)]
306    fn from(ch: Ch16) -> Self {
307        Self::new(ch.to_f32())
308    }
309}
310
311impl From<Ch24> for Ch32 {
312    #[inline(always)]
313    fn from(ch: Ch24) -> Self {
314        Self::new(ch.to_f32())
315    }
316}
317
318impl From<Ch64> for Ch32 {
319    #[inline(always)]
320    fn from(ch: Ch64) -> Self {
321        Self::new(ch.to_f32())
322    }
323}
324
325impl From<Ch32> for f32 {
326    #[inline(always)]
327    fn from(ch: Ch32) -> f32 {
328        ch.0
329    }
330}
331
332impl<R: Into<Self>> Add<R> for Ch32 {
333    type Output = Self;
334
335    #[inline(always)]
336    fn add(self, rhs: R) -> Self {
337        Self::new(f32::from(self) + f32::from(rhs.into()))
338    }
339}
340
341impl<R: Into<Self>> Sub<R> for Ch32 {
342    type Output = Self;
343
344    #[inline(always)]
345    fn sub(self, rhs: R) -> Self {
346        Self::new(f32::from(self) - f32::from(rhs.into()))
347    }
348}
349
350impl<R: Into<Self>> Mul<R> for Ch32 {
351    type Output = Self;
352
353    #[inline(always)]
354    fn mul(self, rhs: R) -> Self {
355        Self::new(f32::from(self) * f32::from(rhs.into()))
356    }
357}
358
359impl Neg for Ch32 {
360    type Output = Ch32;
361
362    #[inline(always)]
363    fn neg(self) -> Self {
364        Self(-f32::from(self))
365    }
366}
367
368/// 64-bit sample [Channel](Channel).
369#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
370#[repr(transparent)]
371pub struct Ch64(f64);
372
373impl Channel for Ch64 {
374    const MIN: Ch64 = Ch64(-1.0);
375    const MID: Ch64 = Ch64(0.0);
376    const MAX: Ch64 = Ch64(1.0);
377
378    #[inline(always)]
379    fn to_f32(self) -> f32 {
380        self.0 as f32
381    }
382}
383
384impl Ch64 {
385    /// Create a new 32-bit [`Channel`](Channel) value.
386    #[inline(always)]
387    pub const fn new(value: f64) -> Self {
388        Self(value)
389    }
390}
391
392impl From<f32> for Ch64 {
393    #[inline(always)]
394    fn from(value: f32) -> Self {
395        Self::new(value as f64)
396    }
397}
398
399impl From<Ch16> for Ch64 {
400    #[inline(always)]
401    fn from(ch: Ch16) -> Self {
402        Self::new(ch.to_f32() as f64)
403    }
404}
405
406impl From<Ch24> for Ch64 {
407    #[inline(always)]
408    fn from(ch: Ch24) -> Self {
409        Self::new(ch.to_f32() as f64)
410    }
411}
412
413impl From<Ch32> for Ch64 {
414    #[inline(always)]
415    fn from(ch: Ch32) -> Self {
416        Self::new(ch.0 as f64)
417    }
418}
419
420impl From<Ch64> for f64 {
421    #[inline(always)]
422    fn from(ch: Ch64) -> f64 {
423        ch.0
424    }
425}
426
427impl<R: Into<Self>> Add<R> for Ch64 {
428    type Output = Self;
429
430    #[inline(always)]
431    fn add(self, rhs: R) -> Self {
432        Self::new(self.0 + rhs.into().0)
433    }
434}
435
436impl<R: Into<Self>> Sub<R> for Ch64 {
437    type Output = Self;
438
439    #[inline(always)]
440    fn sub(self, rhs: R) -> Self {
441        Self::new(self.0 - rhs.into().0)
442    }
443}
444
445impl<R: Into<Self>> Mul<R> for Ch64 {
446    type Output = Self;
447
448    #[inline(always)]
449    fn mul(self, rhs: R) -> Self {
450        Self::new(self.0 * rhs.into().0)
451    }
452}
453
454impl Neg for Ch64 {
455    type Output = Ch64;
456
457    #[inline(always)]
458    fn neg(self) -> Self {
459        Self(-self.0)
460    }
461}
462
463impl AddAssign for Ch16 {
464    #[inline(always)]
465    fn add_assign(&mut self, rhs: Self) {
466        *self = *self + rhs;
467    }
468}
469
470impl AddAssign for Ch24 {
471    #[inline(always)]
472    fn add_assign(&mut self, rhs: Self) {
473        *self = *self + rhs;
474    }
475}
476
477impl AddAssign for Ch32 {
478    #[inline(always)]
479    fn add_assign(&mut self, rhs: Self) {
480        *self = *self + rhs;
481    }
482}
483
484impl AddAssign for Ch64 {
485    #[inline(always)]
486    fn add_assign(&mut self, rhs: Self) {
487        *self = *self + rhs;
488    }
489}
490
491impl SubAssign for Ch16 {
492    #[inline(always)]
493    fn sub_assign(&mut self, rhs: Self) {
494        *self = *self - rhs;
495    }
496}
497
498impl SubAssign for Ch24 {
499    #[inline(always)]
500    fn sub_assign(&mut self, rhs: Self) {
501        *self = *self - rhs;
502    }
503}
504
505impl SubAssign for Ch32 {
506    #[inline(always)]
507    fn sub_assign(&mut self, rhs: Self) {
508        *self = *self - rhs;
509    }
510}
511
512impl SubAssign for Ch64 {
513    #[inline(always)]
514    fn sub_assign(&mut self, rhs: Self) {
515        *self = *self - rhs;
516    }
517}
518
519impl MulAssign for Ch16 {
520    #[inline(always)]
521    fn mul_assign(&mut self, rhs: Self) {
522        *self = *self * rhs;
523    }
524}
525
526impl MulAssign for Ch24 {
527    #[inline(always)]
528    fn mul_assign(&mut self, rhs: Self) {
529        *self = *self * rhs;
530    }
531}
532
533impl MulAssign for Ch32 {
534    #[inline(always)]
535    fn mul_assign(&mut self, rhs: Self) {
536        *self = *self * rhs;
537    }
538}
539
540impl MulAssign for Ch64 {
541    #[inline(always)]
542    fn mul_assign(&mut self, rhs: Self) {
543        *self = *self * rhs;
544    }
545}
546
547#[cfg(test)]
548mod tests {
549    use super::*;
550
551    #[test]
552    fn ch16() {
553        assert_eq!(-1.0, Ch16::MIN.to_f32());
554        assert_eq!(0.000015259022, Ch16::MID.to_f32());
555        assert_eq!(1.0, Ch16::MAX.to_f32());
556
557        assert_eq!(Ch16::MIN, Ch16::from(Ch16::MIN.to_f32()));
558        assert_eq!(Ch16::MID, Ch16::from(Ch16::MID.to_f32()));
559        assert_eq!(Ch16::MAX, Ch16::from(Ch16::MAX.to_f32()));
560    }
561
562    #[test]
563    fn ch16_roundtrip() {
564        assert_eq!(-32768, i16::from(Ch16::MIN));
565        assert_eq!(0, i16::from(Ch16::MID));
566        assert_eq!(32767, i16::from(Ch16::MAX));
567
568        assert_eq!(Ch16::MIN, Ch16::new(i16::from(Ch16::MIN)));
569        assert_eq!(Ch16::MID, Ch16::new(i16::from(Ch16::MID)));
570        assert_eq!(Ch16::MAX, Ch16::new(i16::from(Ch16::MAX)));
571    }
572
573    #[test]
574    fn ch24() {
575        assert_eq!(-1.0, Ch24::MIN.to_f32());
576        assert_eq!(0.00000005960465, Ch24::MID.to_f32());
577        assert_eq!(1.0, Ch24::MAX.to_f32());
578
579        assert_eq!(Ch24::MIN, Ch24::from(Ch24::MIN.to_f32()));
580        assert_eq!(Ch24::MID, Ch24::from(Ch24::MID.to_f32()));
581        assert_eq!(Ch24::MAX, Ch24::from(Ch24::MAX.to_f32()));
582    }
583
584    #[test]
585    fn ch24_roundtrip() {
586        assert_eq!(-8388608, i32::from(Ch24::MIN));
587        assert_eq!(0, i32::from(Ch24::MID));
588        assert_eq!(8388607, i32::from(Ch24::MAX));
589
590        assert_eq!(Ch24::MIN, Ch24::new(i32::from(Ch24::MIN)));
591        assert_eq!(Ch24::MID, Ch24::new(i32::from(Ch24::MID)));
592        assert_eq!(Ch24::MAX, Ch24::new(i32::from(Ch24::MAX)));
593    }
594
595    #[test]
596    fn ch32() {
597        assert_eq!(-1.0, Ch32::MIN.to_f32());
598        assert_eq!(0.0, Ch32::MID.to_f32());
599        assert_eq!(1.0, Ch32::MAX.to_f32());
600
601        assert_eq!(Ch32::MIN, Ch32::from(Ch32::MIN.to_f32()));
602        assert_eq!(Ch32::MID, Ch32::from(Ch32::MID.to_f32()));
603        assert_eq!(Ch32::MAX, Ch32::from(Ch32::MAX.to_f32()));
604    }
605
606    #[test]
607    fn ch64() {
608        assert_eq!(-1.0, Ch64::MIN.to_f32());
609        assert_eq!(0.0, Ch64::MID.to_f32());
610        assert_eq!(1.0, Ch64::MAX.to_f32());
611
612        assert_eq!(Ch64::MIN, Ch64::from(Ch64::MIN.to_f32()));
613        assert_eq!(Ch64::MID, Ch64::from(Ch64::MID.to_f32()));
614        assert_eq!(Ch64::MAX, Ch64::from(Ch64::MAX.to_f32()));
615    }
616
617    #[test]
618    fn ch16_to_ch24() {
619        assert_eq!(Ch24::MIN, Ch24::from(Ch16::MIN));
620        assert_eq!(Ch24::new(128), Ch24::from(Ch16::MID));
621        assert_eq!(Ch24::MAX, Ch24::from(Ch16::MAX));
622    }
623
624    #[test]
625    fn ch24_to_ch16() {
626        assert_eq!(Ch16::MIN, Ch16::from(Ch24::MIN));
627        assert_eq!(Ch16::MID, Ch16::from(Ch24::MID));
628        assert_eq!(Ch16::MAX, Ch16::from(Ch24::MAX));
629    }
630
631    #[test]
632    fn ch16_arith() {
633        // Test addition
634        assert_eq!(Ch16::new(-1), Ch16::new(-32768) + Ch16::new(32767));
635        assert_eq!(Ch16::new(8192), Ch16::new(-8192) + Ch16::new(16384));
636        assert_eq!(Ch16::MAX, Ch16::MID + Ch16::MAX);
637        assert_eq!(Ch16::MIN, Ch16::new(-16384) + Ch16::new(-16384));
638        // Test subtraction
639        assert_eq!(Ch16::new(0), Ch16::new(-32768) - Ch16::new(-32768));
640        assert_eq!(Ch16::new(0), Ch16::new(32767) - Ch16::new(32767));
641        assert_eq!(Ch16::new(-32767), Ch16::new(0) - Ch16::new(32767));
642        // Test multiplication
643        assert_eq!(Ch16::new(0), Ch16::new(0) * Ch16::new(32767));
644        assert_eq!(Ch16::new(32767), Ch16::new(32767) * Ch16::new(32767));
645        assert_eq!(Ch16::new(-32768), Ch16::new(32767) * Ch16::new(-32768));
646        assert_eq!(Ch16::new(-32768), Ch16::new(-32768) * Ch16::new(32767));
647        assert_eq!(Ch16::new(32767), Ch16::new(-32768) * Ch16::new(-32768));
648        assert_eq!(Ch16::new(-16384), Ch16::new(32767) * Ch16::new(-16384));
649        // Test negation
650        assert_eq!(Ch16::MIN, -Ch16::MAX);
651        assert_eq!(Ch16::MAX, -Ch16::MIN);
652        assert_eq!(Ch16::new(-1), -Ch16::new(0));
653        assert_eq!(Ch16::new(0), -Ch16::new(-1));
654    }
655
656    #[test]
657    fn ch24_arith() {
658        // Test addition
659        assert_eq!(Ch24::new(-1), Ch24::new(-8388608) + Ch24::new(8388607));
660        assert_eq!(
661            Ch24::new(2097152),
662            Ch24::new(-2097152) + Ch24::new(4194304)
663        );
664        assert_eq!(Ch24::MAX, Ch24::MID + Ch24::MAX);
665        assert_eq!(Ch24::MIN, Ch24::new(-4194304) + Ch24::new(-4194304));
666        // Test subtraction
667        assert_eq!(Ch24::new(0), Ch24::new(-8388608) - Ch24::new(-8388608));
668        assert_eq!(Ch24::new(0), Ch24::new(8388607) - Ch24::new(8388607));
669        assert_eq!(Ch24::new(-8388607), Ch24::new(0) - Ch24::new(8388607));
670        // Test multiplication
671        assert_eq!(Ch24::new(0), Ch24::new(0) * Ch24::new(8388607));
672        assert_eq!(Ch24::new(8388607), Ch24::new(8388607) * Ch24::new(8388607));
673        assert_eq!(
674            Ch24::new(-8388608),
675            Ch24::new(8388607) * Ch24::new(-8388608)
676        );
677        assert_eq!(
678            Ch24::new(-8388608),
679            Ch24::new(-8388608) * Ch24::new(8388607)
680        );
681        assert_eq!(
682            Ch24::new(8388607),
683            Ch24::new(-8388608) * Ch24::new(-8388608)
684        );
685        assert_eq!(
686            Ch24::new(-4194304),
687            Ch24::new(8388607) * Ch24::new(-4194304)
688        );
689        // Test negation
690        assert_eq!(Ch24::MIN, -Ch24::MAX);
691        assert_eq!(Ch24::MAX, -Ch24::MIN);
692        assert_eq!(Ch24::new(-1), -Ch24::new(0));
693        assert_eq!(Ch24::new(0), -Ch24::new(-1));
694    }
695
696    #[test]
697    fn ch32_arith() {
698        // Test addition
699        assert_eq!(Ch32::new(0.0), Ch32::new(-1.0) + Ch32::new(1.0));
700        assert_eq!(Ch32::new(0.25), Ch32::new(-0.25) + Ch32::new(0.5));
701        assert_eq!(Ch32::new(1.0), Ch32::new(0.0) + Ch32::new(1.0));
702        assert_eq!(Ch32::new(-1.0), Ch32::new(-0.5) + Ch32::new(-0.5));
703        // Test subtraction
704        assert_eq!(Ch32::new(0.0), Ch32::new(-1.0) - Ch32::new(-1.0));
705        assert_eq!(Ch32::new(0.0), Ch32::new(1.0) - Ch32::new(1.0));
706        assert_eq!(Ch32::new(-1.0), Ch32::new(0.0) - Ch32::new(1.0));
707        // Test multiplication
708        assert_eq!(Ch32::new(0.0), Ch32::new(0.0) * Ch32::new(1.0));
709        assert_eq!(Ch32::new(1.0), Ch32::new(1.0) * Ch32::new(1.0));
710        assert_eq!(Ch32::new(-1.0), Ch32::new(1.0) * Ch32::new(-1.0));
711        assert_eq!(Ch32::new(1.0), Ch32::new(-1.0) * Ch32::new(-1.0));
712        assert_eq!(Ch32::new(-0.5), Ch32::new(1.0) * Ch32::new(-0.5));
713        // Test negation
714        assert_eq!(Ch32::MIN, -Ch32::MAX);
715        assert_eq!(Ch32::MAX, -Ch32::MIN);
716        assert_eq!(Ch32::new(0.0), -Ch32::new(0.0));
717    }
718
719    #[test]
720    fn ch64_arith() {
721        // Test addition
722        assert_eq!(Ch64::new(0.0), Ch64::new(-1.0) + Ch64::new(1.0));
723        assert_eq!(Ch64::new(0.25), Ch64::new(-0.25) + Ch64::new(0.5));
724        assert_eq!(Ch64::new(1.0), Ch64::new(0.0) + Ch64::new(1.0));
725        assert_eq!(Ch64::new(-1.0), Ch64::new(-0.5) + Ch64::new(-0.5));
726        // Test subtraction
727        assert_eq!(Ch64::new(0.0), Ch64::new(-1.0) - Ch64::new(-1.0));
728        assert_eq!(Ch64::new(0.0), Ch64::new(1.0) - Ch64::new(1.0));
729        assert_eq!(Ch64::new(-1.0), Ch64::new(0.0) - Ch64::new(1.0));
730        // Test multiplication
731        assert_eq!(Ch64::new(0.0), Ch64::new(0.0) * Ch64::new(1.0));
732        assert_eq!(Ch64::new(1.0), Ch64::new(1.0) * Ch64::new(1.0));
733        assert_eq!(Ch64::new(-1.0), Ch64::new(1.0) * Ch64::new(-1.0));
734        assert_eq!(Ch64::new(1.0), Ch64::new(-1.0) * Ch64::new(-1.0));
735        assert_eq!(Ch64::new(-0.5), Ch64::new(1.0) * Ch64::new(-0.5));
736        // Test negation
737        assert_eq!(Ch64::MIN, -Ch64::MAX);
738        assert_eq!(Ch64::MAX, -Ch64::MIN);
739        assert_eq!(Ch64::new(0.0), -Ch64::new(0.0));
740    }
741
742    #[test]
743    fn ch16_saturation() {
744        assert_eq!(Ch16::MAX, Ch16::new(24576) + Ch16::new(16384));
745        assert_eq!(Ch16::MIN, Ch16::new(-16384) + Ch16::new(-24576));
746        assert_eq!(Ch16::MIN, Ch16::new(-16384) - Ch16::new(24576));
747    }
748
749    #[test]
750    fn ch24_saturation() {
751        assert_eq!(Ch24::MAX, Ch24::new(6291456) + Ch24::new(4194304));
752        assert_eq!(Ch24::MIN, Ch24::new(-4194304) + Ch24::new(-6291456));
753        assert_eq!(Ch24::MIN, Ch24::new(-4194304) - Ch24::new(6291456));
754    }
755
756    #[test]
757    fn ch32_unsaturation() {
758        assert_eq!(Ch32::new(1.25), Ch32::new(0.75) + Ch32::new(0.5));
759        assert_eq!(Ch32::new(-1.25), Ch32::new(-0.5) + Ch32::new(-0.75));
760        assert_eq!(Ch32::new(-1.25), Ch32::new(-0.5) - Ch32::new(0.75));
761    }
762
763    #[test]
764    fn ch64_unsaturation() {
765        assert_eq!(Ch64::new(1.25), Ch64::new(0.75) + Ch64::new(0.5));
766        assert_eq!(Ch64::new(-1.25), Ch64::new(-0.5) + Ch64::new(-0.75));
767        assert_eq!(Ch64::new(-1.25), Ch64::new(-0.5) - Ch64::new(0.75));
768    }
769}