symphonia_core/
sample.rs

1// Symphonia
2// Copyright (c) 2019-2022 The Project Symphonia Developers.
3//
4// This Source Code Form is subject to the terms of the Mozilla Public
5// License, v. 2.0. If a copy of the MPL was not distributed with this
6// file, You can obtain one at https://mozilla.org/MPL/2.0/.
7
8//! The `sample` module defines the core audio sample trait and any non-primitive sample data types.
9
10use std::fmt;
11
12use crate::util::clamp::{clamp_f32, clamp_f64, clamp_i24, clamp_u24};
13
14/// SampleFormat describes the data encoding for an audio sample.
15#[derive(Copy, Clone, Debug)]
16pub enum SampleFormat {
17    /// Unsigned 8-bit integer.
18    U8,
19    /// Unsigned 16-bit integer.
20    U16,
21    /// Unsigned 24-bit integer.
22    U24,
23    /// Unsigned 32-bit integer.
24    U32,
25    /// Signed 8-bit integer.
26    S8,
27    /// Signed 16-bit integer.
28    S16,
29    /// Signed 24-bit integer.
30    S24,
31    /// Signed 32-bit integer.
32    S32,
33    /// Single precision (32-bit) floating point.
34    F32,
35    /// Double precision (64-bit) floating point.
36    F64,
37}
38
39/// `Sample` provides a common interface for manipulating sample's regardless of the
40/// underlying data type. Additionally, `Sample` provides information regarding the
41/// format of underlying data types representing the sample when in memory, but also
42/// when exported.
43pub trait Sample:
44    Copy
45    + Clone
46    + core::ops::Add<Output = Self>
47    + core::ops::Sub<Output = Self>
48    + Default
49    + PartialOrd
50    + PartialEq
51    + Sized
52{
53    /// A unique enum value representing the sample format. This constant may be used to dynamically
54    /// choose how to process the sample at runtime.
55    const FORMAT: SampleFormat;
56
57    /// The effective number of bits of the valid (clamped) sample range. Quantifies the dynamic
58    /// range of the sample format in bits.
59    const EFF_BITS: u32;
60
61    /// The mid-point value between the maximum and minimum sample value. If a sample is set to this
62    /// value it is silent.
63    const MID: Self;
64
65    /// If the sample format does not use the full range of the underlying data type, returns the
66    /// sample clamped to the valid range. Otherwise, returns the sample unchanged.
67    fn clamped(self) -> Self;
68}
69
70/// An unsigned 24-bit integer sample with an internal unsigned 32-bit integer representation.
71///
72/// There are **no** guarantees the sample is within the valid range 24-bit range. Use the
73/// [`Sample::clamped`] function to clamp the sample to the valid range.
74#[allow(non_camel_case_types)]
75#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
76pub struct u24(pub u32);
77
78/// A signed 24-bit integer sample with an internal signed 32-bit integer representation.
79///
80/// There are **no** guarantees the sample is within the valid range 24-bit range. Use the
81/// [`Sample::clamped`] function to clamp the sample to the valid range.
82#[allow(non_camel_case_types)]
83#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
84pub struct i24(pub i32);
85
86impl Sample for u8 {
87    const FORMAT: SampleFormat = SampleFormat::U8;
88    const EFF_BITS: u32 = 8;
89    const MID: u8 = 128;
90
91    #[inline(always)]
92    fn clamped(self) -> Self {
93        self
94    }
95}
96
97impl Sample for i8 {
98    const FORMAT: SampleFormat = SampleFormat::S8;
99    const EFF_BITS: u32 = 8;
100    const MID: i8 = 0;
101
102    #[inline(always)]
103    fn clamped(self) -> Self {
104        self
105    }
106}
107
108impl Sample for u16 {
109    const FORMAT: SampleFormat = SampleFormat::U16;
110    const EFF_BITS: u32 = 16;
111    const MID: u16 = 32_768;
112
113    #[inline(always)]
114    fn clamped(self) -> Self {
115        self
116    }
117}
118
119impl Sample for i16 {
120    const FORMAT: SampleFormat = SampleFormat::S16;
121    const EFF_BITS: u32 = 16;
122    const MID: i16 = 0;
123
124    #[inline(always)]
125    fn clamped(self) -> Self {
126        self
127    }
128}
129
130impl Sample for u24 {
131    const FORMAT: SampleFormat = SampleFormat::U24;
132    const EFF_BITS: u32 = 24;
133    const MID: u24 = u24(8_388_608);
134
135    #[inline(always)]
136    fn clamped(self) -> Self {
137        u24(clamp_u24(self.0))
138    }
139}
140
141impl Sample for i24 {
142    const FORMAT: SampleFormat = SampleFormat::S24;
143    const EFF_BITS: u32 = 24;
144    const MID: i24 = i24(0);
145
146    #[inline(always)]
147    fn clamped(self) -> Self {
148        i24(clamp_i24(self.0))
149    }
150}
151
152impl Sample for u32 {
153    const FORMAT: SampleFormat = SampleFormat::U32;
154    const EFF_BITS: u32 = 32;
155    const MID: u32 = 2_147_483_648;
156
157    #[inline(always)]
158    fn clamped(self) -> Self {
159        self
160    }
161}
162
163impl Sample for i32 {
164    const FORMAT: SampleFormat = SampleFormat::S32;
165    const EFF_BITS: u32 = 32;
166    const MID: i32 = 0;
167
168    #[inline(always)]
169    fn clamped(self) -> Self {
170        self
171    }
172}
173
174impl Sample for f32 {
175    const FORMAT: SampleFormat = SampleFormat::F32;
176    const EFF_BITS: u32 = 24;
177    const MID: f32 = 0.0;
178
179    #[inline(always)]
180    fn clamped(self) -> Self {
181        clamp_f32(self)
182    }
183}
184
185impl Sample for f64 {
186    const FORMAT: SampleFormat = SampleFormat::F64;
187    const EFF_BITS: u32 = 53;
188    const MID: f64 = 0.0;
189
190    #[inline(always)]
191    fn clamped(self) -> Self {
192        clamp_f64(self)
193    }
194}
195
196// Helper macros
197
198macro_rules! shl_impl {
199    ($t:ident, $f:ty) => {
200        impl core::ops::Shl<$f> for $t {
201            type Output = $t;
202
203            #[inline]
204            fn shl(self, other: $f) -> $t {
205                $t(self.0 << other)
206            }
207        }
208    };
209}
210
211macro_rules! shr_impl {
212    ($t:ident, $f:ty) => {
213        impl core::ops::Shr<$f> for $t {
214            type Output = $t;
215
216            #[inline]
217            fn shr(self, other: $f) -> $t {
218                $t(self.0 >> other)
219            }
220        }
221    };
222}
223
224macro_rules! impl_shifts {
225    ($t:ident, $f:ty) => {
226        shl_impl! { $t, $f }
227        shr_impl! { $t, $f }
228    };
229}
230
231// Implementation for i24
232
233impl i24 {
234    /// The largest value that can be represented by this integer type.
235    pub const MAX: i24 = i24(8_388_607);
236    /// The smallest value that can be represented by this integer type..
237    pub const MIN: i24 = i24(-8_388_608);
238
239    /// Get the underlying `i32` backing this `i24`.
240    #[inline(always)]
241    #[deprecated = "Superseded by `inner`."]
242    pub fn into_i32(self) -> i32 {
243        self.0
244    }
245
246    /// Get the underlying `i32` backing this `i24`.
247    #[inline(always)]
248    pub fn inner(self) -> i32 {
249        self.0
250    }
251
252    /// Return the memory representation of this `i24` as a byte array in native byte order.
253    #[inline]
254    pub fn to_ne_bytes(self) -> [u8; 3] {
255        let b = self.0.to_ne_bytes();
256
257        if cfg!(target_endian = "little") {
258            // In little-endian the MSB is the last byte. Drop it.
259            [b[0], b[1], b[2]]
260        }
261        else {
262            // In big-endian the MSB is the first byte. Drop it.
263            [b[1], b[2], b[3]]
264        }
265    }
266}
267
268impl fmt::Display for i24 {
269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270        write!(f, "{}", self.0)
271    }
272}
273
274impl From<i32> for i24 {
275    fn from(val: i32) -> Self {
276        i24(clamp_i24(val))
277    }
278}
279
280impl From<i16> for i24 {
281    fn from(val: i16) -> Self {
282        i24(i32::from(val))
283    }
284}
285
286impl From<i8> for i24 {
287    fn from(val: i8) -> Self {
288        i24(i32::from(val))
289    }
290}
291
292impl core::ops::Add<i24> for i24 {
293    type Output = i24;
294
295    #[inline]
296    fn add(self, other: Self) -> Self {
297        i24(self.0 + other.0)
298    }
299}
300
301impl core::ops::Sub<i24> for i24 {
302    type Output = i24;
303
304    #[inline]
305    fn sub(self, other: Self) -> Self {
306        i24(self.0 - other.0)
307    }
308}
309
310impl core::ops::Mul<i24> for i24 {
311    type Output = i24;
312
313    #[inline]
314    fn mul(self, other: Self) -> Self {
315        i24(self.0 * other.0)
316    }
317}
318
319impl core::ops::Div<i24> for i24 {
320    type Output = i24;
321
322    #[inline]
323    fn div(self, other: Self) -> Self {
324        i24(self.0 / other.0)
325    }
326}
327
328impl core::ops::Not for i24 {
329    type Output = i24;
330
331    #[inline]
332    fn not(self) -> Self {
333        i24(!self.0)
334    }
335}
336
337impl core::ops::Rem<i24> for i24 {
338    type Output = i24;
339
340    #[inline]
341    fn rem(self, other: Self) -> Self {
342        i24(self.0 % other.0)
343    }
344}
345
346impl core::ops::Shl<i24> for i24 {
347    type Output = i24;
348
349    #[inline]
350    fn shl(self, other: Self) -> Self {
351        i24(self.0 << other.0)
352    }
353}
354
355impl core::ops::Shr<i24> for i24 {
356    type Output = i24;
357
358    #[inline]
359    fn shr(self, other: Self) -> Self {
360        i24(self.0 >> other.0)
361    }
362}
363
364impl_shifts! { i24, u8 }
365impl_shifts! { i24, u16 }
366impl_shifts! { i24, u32 }
367impl_shifts! { i24, u64 }
368impl_shifts! { i24, u128 }
369impl_shifts! { i24, usize }
370
371impl_shifts! { i24, i8 }
372impl_shifts! { i24, i16 }
373impl_shifts! { i24, i32 }
374impl_shifts! { i24, i64 }
375impl_shifts! { i24, i128 }
376impl_shifts! { i24, isize }
377
378impl core::ops::BitAnd<i24> for i24 {
379    type Output = i24;
380
381    #[inline]
382    fn bitand(self, other: Self) -> Self {
383        i24(self.0 & other.0)
384    }
385}
386
387impl core::ops::BitOr<i24> for i24 {
388    type Output = i24;
389
390    #[inline]
391    fn bitor(self, other: Self) -> Self {
392        i24(self.0 | other.0)
393    }
394}
395
396impl core::ops::BitXor<i24> for i24 {
397    type Output = i24;
398
399    #[inline]
400    fn bitxor(self, other: Self) -> Self {
401        i24(self.0 ^ other.0)
402    }
403}
404
405// Implementation for u24
406
407impl u24 {
408    /// The largest value that can be represented by this integer type.
409    pub const MAX: u24 = u24(16_777_215);
410    /// The smallest value that can be represented by this integer type.
411    pub const MIN: u24 = u24(0);
412
413    /// Get the underlying `u32` backing this `u24`.
414    #[inline(always)]
415    #[deprecated = "Superseded by `inner`."]
416    pub fn into_u32(self) -> u32 {
417        self.0
418    }
419
420    /// Get the underlying `u32` backing this `u24`.
421    #[inline(always)]
422    pub fn inner(self) -> u32 {
423        self.0
424    }
425
426    /// Return the memory representation of this `u24` as a byte array in native byte order.
427    #[inline]
428    pub fn to_ne_bytes(self) -> [u8; 3] {
429        let b = self.0.to_ne_bytes();
430
431        if cfg!(target_endian = "little") {
432            // In little-endian the MSB is the last byte. Drop it.
433            [b[0], b[1], b[2]]
434        }
435        else {
436            // In big-endian the MSB is the first byte. Drop it.
437            [b[1], b[2], b[3]]
438        }
439    }
440}
441
442impl fmt::Display for u24 {
443    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444        write!(f, "{}", self.0)
445    }
446}
447
448impl From<u32> for u24 {
449    fn from(val: u32) -> Self {
450        u24(clamp_u24(val))
451    }
452}
453
454impl From<u16> for u24 {
455    fn from(val: u16) -> Self {
456        u24(u32::from(val))
457    }
458}
459
460impl From<u8> for u24 {
461    fn from(val: u8) -> Self {
462        u24(u32::from(val))
463    }
464}
465
466impl core::ops::Add<u24> for u24 {
467    type Output = u24;
468
469    #[inline]
470    fn add(self, other: Self) -> Self {
471        u24(self.0 + other.0)
472    }
473}
474
475impl core::ops::Sub<u24> for u24 {
476    type Output = u24;
477
478    #[inline]
479    fn sub(self, other: Self) -> Self {
480        u24(self.0 - other.0)
481    }
482}
483
484impl core::ops::Mul<u24> for u24 {
485    type Output = u24;
486
487    #[inline]
488    fn mul(self, other: Self) -> Self {
489        u24(self.0 * other.0)
490    }
491}
492
493impl core::ops::Div<u24> for u24 {
494    type Output = u24;
495
496    #[inline]
497    fn div(self, other: Self) -> Self {
498        u24(self.0 / other.0)
499    }
500}
501
502impl core::ops::Not for u24 {
503    type Output = u24;
504
505    #[inline]
506    fn not(self) -> Self {
507        u24(!self.0)
508    }
509}
510
511impl core::ops::Rem<u24> for u24 {
512    type Output = u24;
513
514    #[inline]
515    fn rem(self, other: Self) -> Self {
516        u24(self.0 % other.0)
517    }
518}
519
520impl core::ops::Shl<u24> for u24 {
521    type Output = u24;
522
523    #[inline]
524    fn shl(self, other: Self) -> Self {
525        u24(self.0 << other.0)
526    }
527}
528
529impl core::ops::Shr<u24> for u24 {
530    type Output = u24;
531
532    #[inline]
533    fn shr(self, other: Self) -> Self {
534        u24(self.0 >> other.0)
535    }
536}
537
538impl_shifts! { u24, u8 }
539impl_shifts! { u24, u16 }
540impl_shifts! { u24, u32 }
541impl_shifts! { u24, u64 }
542impl_shifts! { u24, u128 }
543impl_shifts! { u24, usize }
544
545impl_shifts! { u24, i8 }
546impl_shifts! { u24, i16 }
547impl_shifts! { u24, i32 }
548impl_shifts! { u24, i64 }
549impl_shifts! { u24, i128 }
550impl_shifts! { u24, isize }
551
552impl core::ops::BitAnd<u24> for u24 {
553    type Output = u24;
554
555    #[inline]
556    fn bitand(self, other: Self) -> Self {
557        u24(self.0 & other.0)
558    }
559}
560
561impl core::ops::BitOr<u24> for u24 {
562    type Output = u24;
563
564    #[inline]
565    fn bitor(self, other: Self) -> Self {
566        u24(self.0 | other.0)
567    }
568}
569
570impl core::ops::BitXor<u24> for u24 {
571    type Output = u24;
572
573    #[inline]
574    fn bitxor(self, other: Self) -> Self {
575        u24(self.0 ^ other.0)
576    }
577}