empy/
lib.rs

1//! Idiomatic `no_std` bindings to lieff's [minimp3](https://github.com/lieff/minimp3).
2//!
3//! # Features
4//!
5//! - `mp1-mp2`: Includes MP1 and MP2 decoding code.
6//! - `simd` *(default)*: Enables handwritten SIMD optimizations on eligible targets.
7//!
8//! # Example
9//!
10//! ```no_run
11//! # fn main() -> Result<(), Box<dyn ::std::error::Error>> {
12//! use empy::{DecoderStream, Frame};
13//!
14//! let mp3 = std::fs::read("test.mp3")?;
15//! let mut decoder = DecoderStream::new(&mp3);
16//!
17//! while let Some(frame) = decoder.next() {
18//!     // *process frame here*
19//! }
20//! # Ok(())
21//! # }
22//! ```
23//!
24//! See documentation for [`DecoderStream`] and its lower-level cousin [`Decoder`] for more info.
25
26#![deny(missing_docs)]
27#![no_std]
28
29// TODO: should the members here be pub(crate)? hope that won't need sed
30mod ffi;
31
32use core::{fmt, marker::PhantomData, mem, num, ptr, slice};
33use chlorine::c_int;
34
35/// Maximum number of samples per frame.
36pub const MAX_SAMPLES: usize = 1152 * 2;
37
38/// Describes a frame that contains audio or other (unknown) data.
39pub enum Frame<'src, 'pcm> {
40    /// A frame containing PCM data.
41    Audio(Audio<'src, 'pcm>),
42
43    /// A frame containing miscellaneous data.
44    Other(&'src [u8]),
45}
46
47/// Describes audio samples in a frame.
48#[derive(Clone)]
49pub struct Audio<'src, 'pcm> {
50    bitrate: u16,
51    channels: u8,
52    mpeg_layer: u8,
53    sample_count: u16,
54    sample_rate: u16,
55
56    src: &'src [u8],
57    pcm: Option<ptr::NonNull<f32>>,
58
59    // 👻
60    phantom: PhantomData<&'pcm [f32]>,
61}
62unsafe impl<'src, 'pcm> Send for Audio<'src, 'pcm> {}
63unsafe impl<'src, 'pcm> Sync for Audio<'src, 'pcm> {}
64
65impl<'src, 'pcm> Audio<'src, 'pcm> {
66    /// Gets the bitrate of this frame in kb/s.
67    ///
68    /// Possible values are in the interval [8, 448].
69    pub fn bitrate(&self) -> u16 {
70        // TODO check what happens with the reserved bitrates
71        self.bitrate
72    }
73
74    /// Gets how many channels are in this frame.
75    ///
76    /// Possible values are one of {1, 2}.
77    pub fn channels(&self) -> u8 {
78        self.channels
79    }
80
81    /// Gets the MPEG layer of this frame.
82    ///
83    /// Possible values are one of {1, 2, 3}.
84    pub fn mpeg_layer(&self) -> u8 {
85        // TODO check what happens when the illegal 0b00 layer is passed
86        self.mpeg_layer
87    }
88
89    /// Gets the number of samples in this frame per [channel](Self::channels).
90    ///
91    /// Possible values are in the interval (0, [`MAX_SAMPLES`]].
92    pub fn sample_count(&self) -> u16 {
93        self.sample_count
94    }
95
96    /// Gets the sample rate of this frame in Hz.
97    ///
98    /// Possible values are in the interval [8000, 44100].
99    pub fn sample_rate(&self) -> u16 {
100        // TODO what happens with the DIY ones?
101        self.sample_rate
102    }
103
104    /// Gets the slice of decoded samples.
105    ///
106    /// If the samples weren't decoded, this is an empty slice.
107    ///
108    /// Channels are interleaved, so this has the length of
109    /// [`channels`](Self::channels) * [`sample_count`](Self::sample_count),
110    /// to a maximum of [`MAX_SAMPLES`](crate::MAX_SAMPLES).
111    #[inline]
112    pub fn samples(&self) -> &'pcm [f32] {
113        if let Some(buf) = self.pcm {
114            unsafe { slice::from_raw_parts(buf.as_ptr(), usize::from(self.sample_count * self.channels as u16)) }
115        } else {
116            &[]
117        }
118    }
119
120    /// Gets the slice of the source which contains the entire frame.
121    ///
122    /// Leading garbage is omitted from the slice.
123    pub fn source(&self) -> &'src [u8] {
124        self.src
125    }
126}
127
128impl fmt::Debug for Frame<'_, '_> {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        match self {
131            Self::Audio(audio) => f.debug_tuple("Audio").field(audio).finish(),
132            Self::Other(_) => f.debug_tuple("Other").field(&format_args!("&[...]")).finish(),
133        }
134    }
135}
136
137impl fmt::Debug for Audio<'_, '_> {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        f.debug_struct("Audio")
140            .field("bitrate", &self.bitrate)
141            .field("channels", &self.channels)
142            .field("mpeg_layer", &self.mpeg_layer)
143            .field("sample_count", &self.sample_count)
144            .field("sample_rate", &self.sample_rate)
145            .field("samples", {
146                &if self.pcm.is_some() {
147                    format_args!("&[...]")
148                } else {
149                    format_args!("&[not decoded]")
150                }
151            })
152            .finish()
153    }
154}
155
156/// Low-level stateless decoder for parsing and/or decoding MPEG Audio.
157///
158/// The struct itself holds the memory (6.5KiB) for the decoding process.
159///
160/// # Examples
161///
162/// Simple example decoding frames into a big `Vec` of all the samples.
163///
164/// ```
165/// # fn main() {
166/// use empy::{Decoder, Frame};
167///
168/// let mut data: &[u8] = &[/* your file here */];
169///
170/// let mut decoder = Decoder::new();
171/// let mut buffer = [0.0; empy::MAX_SAMPLES];
172/// let mut pcm: Vec<f32> = Vec::with_capacity(1024 * 1024 * 32);
173///
174/// while let Some((frame, bytes_read)) = decoder.decode(data, Some(&mut buffer)) {
175///     match frame {
176///         Frame::Audio(audio) => {
177///             // note that you'd want to keep track of bitrate, channels, sample_rate
178///             // they can differ between adjacent frames (especially bitrate for VBR)
179///             pcm.extend_from_slice(audio.samples());
180///         },
181///         Frame::Other(_) => (/* don't care */),
182///     }
183///     data = &data[bytes_read..];
184/// }
185/// # }
186/// ```
187///
188/// You don't need to decode the samples if it's not necessary.
189/// Example computing length in minutes and seconds:
190///
191/// ```
192/// # fn main() {
193/// use empy::{Decoder, Frame};
194///
195/// let mut data: &[u8] = &[/* your file here */];
196/// let mut decoder = Decoder::new();
197/// let mut length = 0.0f64;
198///
199/// while let Some((frame, bytes_read)) = decoder.decode(data, None) {
200///     if let Frame::Audio(audio) = frame {
201///         // note here that sample_count is *per channel* so it works out
202///         length += f64::from(audio.sample_count()) / f64::from(audio.sample_rate());
203///     }
204///     data = &data[bytes_read..];
205/// }
206///
207/// println!("Length: {:.0}m{:.0}s", length / 60.0, length % 60.0);
208/// # }
209/// ```
210pub struct Decoder(mem::MaybeUninit<ffi::mp3dec_t>);
211
212impl Decoder {
213    /// Initialises a new [`Decoder`].
214    pub const fn new() -> Self {
215        Self(mem::MaybeUninit::uninit())
216    }
217
218    /// Tries to find and decode a frame in `src`.
219    ///
220    /// Decoding the samples will be skipped if `dest` is [`None`](Option::None).
221    ///
222    /// If there's some garbage present before the framesync, it will be skipped.
223    ///
224    /// On success, returns information about the [`Frame`],
225    /// and how many bytes it read total (including garbage, if any).
226    pub fn decode<'src, 'pcm>(
227        &mut self,
228        src: &'src [u8],
229        dest: Option<&'pcm mut [f32; MAX_SAMPLES]>,
230    ) -> Option<(Frame<'src, 'pcm>, usize)> {
231        let Self(state) = self;
232
233        let src_c_len = src.len().min(c_int::max_value() as usize) as c_int;
234        let dest_ptr: *mut f32 = dest.map_or(ptr::null_mut(), |x| x).cast();
235        unsafe {
236            // this is really cheap, it literally sets one integer
237            // moving this here allows new() to be const fn
238            ffi::mp3dec_init(state.as_mut_ptr());
239
240            let mut info_recv = mem::MaybeUninit::uninit();
241            let sample_count = ffi::mp3dec_decode_frame(
242                state.as_mut_ptr(),
243                src.as_ptr(),
244                src_c_len,
245                dest_ptr,
246                info_recv.as_mut_ptr(),
247            );
248            let info = &*info_recv.as_ptr();
249
250            if sample_count != 0 {
251                let audio = Audio {
252                    bitrate: info.bitrate_kbps as u16, // x ∈ [8, 448]
253                    channels: info.channels as u8,     // x ∈ {1, 2}
254                    mpeg_layer: info.layer as u8,      // x ∈ {1, 2, 3}
255                    sample_count: sample_count as u16, // x ∈ (0, MAX_SAMPLES]
256                    sample_rate: info.hz as u16,       // x ∈ [8000, 44100]
257
258                    src: frame_src(src, info),
259                    pcm: ptr::NonNull::new(dest_ptr),
260
261                    phantom: PhantomData,
262                };
263                Some((Frame::Audio(audio), info.frame_bytes as usize))
264            } else if info.frame_bytes != 0 {
265                Some((Frame::Other(frame_src(src, info)), info.frame_bytes as usize))
266            } else {
267                None
268            }
269        }
270    }
271}
272
273#[inline]
274unsafe fn frame_src<'src>(
275    data: &'src [u8],
276    info: &ffi::mp3dec_frame_info_t,
277) -> &'src [u8] {
278    data.get_unchecked(info.frame_offset as usize..info.frame_bytes as usize)
279}
280
281/// High-level streaming iterator for parsing and/or decoding MPEG Audio.
282///
283/// Convenience wrapper over [`Decoder`] to simplify general use
284/// where the entire file is already loaded in memory.
285///
286/// # Examples
287///
288/// These examples are adapted from [`Decoder`] to show the conveniences of [`DecoderStream`].
289///
290/// Simple example decoding frames into a big `Vec` of all the samples:
291///
292/// ```
293/// # fn main() {
294/// use empy::{DecoderStream, Frame};
295///
296/// let mut decoder = DecoderStream::new(&[/* your file here */]);
297/// let mut pcm: Vec<f32> = Vec::with_capacity(1024 * 1024 * 32);
298///
299/// while let Some(frame) = decoder.next() {
300///     match frame {
301///         Frame::Audio(audio) => {
302///             // note that you'd want to keep track of bitrate, channels, sample_rate
303///             // they can differ between adjacent frames (especially bitrate for VBR)
304///             pcm.extend_from_slice(audio.samples());
305///         },
306///         Frame::Other(_) => (/* don't care */),
307///     }
308/// }
309/// # }
310/// ```
311///
312/// You don't need to decode the samples if it's not necessary.
313/// Example computing length in minutes and seconds:
314///
315/// ```
316/// # fn main() {
317/// use empy::{DecoderStream, Frame};
318///
319/// let mut decoder = DecoderStream::new(&[/* your file here */]);
320/// let mut length = 0.0f64;
321///
322/// while let Some(frame) = decoder.peek() {
323///     if let Frame::Audio(audio) = frame {
324///         // note here that sample_count is *per channel* so it works out
325///         length += f64::from(audio.sample_count()) / f64::from(audio.sample_rate());
326///     }
327///     decoder.skip();
328/// }
329///
330/// println!("Length: {:.0}m{:.0}s", length / 60.0, length % 60.0);
331/// # }
332/// ```
333pub struct DecoderStream<'src> {
334    decoder: Decoder,
335    buffer: mem::MaybeUninit<[f32; MAX_SAMPLES]>,
336
337    base: &'src [u8], // entire file
338    view: &'src [u8], // offset to end
339
340    cache: Option<num::NonZeroUsize>, // bytes until next frame
341}
342
343impl<'src> DecoderStream<'src> {
344    /// Initialises a new [`DecoderStream`] over `src`.
345    pub const fn new(src: &'src [u8]) -> Self {
346        Self {
347            decoder: Decoder::new(),
348            buffer: mem::MaybeUninit::uninit(),
349            base: src,
350            view: src,
351            cache: None,
352        }
353    }
354
355    /// Decodes the next frame, skipping over potential garbage data.
356    pub fn next<'pcm>(&'pcm mut self) -> Option<Frame<'src, 'pcm>> {
357        self.cache = None;
358        unsafe {
359            let (frame, bytes_read) = self.decoder.decode(self.view, Some(&mut *self.buffer.as_mut_ptr()))?;
360            self.view = self.view.get_unchecked(bytes_read..);
361            Some(frame)
362        }
363    }
364
365    /// Parses the next frame without decoding any samples or moving forward.
366    ///
367    /// To advance, use the [`skip`](Self::skip) function.
368    pub fn peek(&mut self) -> Option<Frame<'src, 'static>> {
369        let (frame, bytes_read) = self.decoder.decode(self.view, None)?;
370        self.cache = num::NonZeroUsize::new(bytes_read);
371        Some(frame)
372    }
373
374    /// Skips the current frame, moving on to the next.
375    /// Avoids re-parsing after a previous call to [`peek`](Self::peek).
376    ///
377    /// If there was a frame to skip, returns how many bytes forward the [`DecoderStream`] advanced.
378    pub fn skip(&mut self) -> Option<usize> {
379        let bytes_to_skip = match self.cache.take() {
380            Some(amount) => amount.get(),
381            None => self.decoder.decode(self.view, None)?.1,
382        };
383        unsafe { self.view = self.view.get_unchecked(bytes_to_skip..) };
384        Some(bytes_to_skip)
385    }
386
387    /// Returns the offset in the input data from the start (0).
388    pub fn offset(&self) -> usize {
389        let base = self.base.as_ptr() as usize;
390        let view = self.view.as_ptr() as usize;
391        view - base
392    }
393
394    /// Sets the offset in the input data from the beginning.
395    ///
396    /// If `offset` is out of bounds, returns the maximum valid offset.
397    pub fn set_offset(&mut self, offset: usize) -> Result<(), usize> {
398        self.view = self.base.get(offset..).ok_or(self.base.len())?;
399        self.cache = None;
400        Ok(())
401    }
402}
403
404/// Highly optimised function for converting `f32` samples to `i16` samples.
405///
406/// # Panics
407/// Panics if `f32pcm` and `i16pcm` have a different length.
408pub fn f32_to_i16_pcm(f32pcm: &[f32], i16pcm: &mut [i16]) {
409    assert_eq!(f32pcm.len(), i16pcm.len());
410
411    // annoyingly, this API takes `c_int` like everything else so we have to get a bit creative
412    assert!(c_int::max_value() as u128 <= usize::max_value() as u128);
413    let mut remaining = f32pcm.len();
414    loop {
415        let batch_len = remaining.min(c_int::max_value() as usize);
416        unsafe { ffi::mp3dec_f32_to_s16(f32pcm.as_ptr(), i16pcm.as_mut_ptr(), batch_len as c_int) };
417        remaining -= batch_len;
418
419        if remaining == 0 {
420            break
421        }
422    }
423}