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}