Repository navigation
The crate is split in two. nanomp3-core is the frame decoder that used to be nanomp3; nanomp3 re-exports it and adds a port of minimp3's minimp3_ex helpers. Both crates are versioned together, and nanomp3 depends on exactly the same nanomp3-core version.
Breaking changes
Decoder::decodenow returns(usize, Result<FrameInfo, DecodeError>)instead of(usize, Option<FrameInfo>).DecodeErrorsays why no audio came out (NoFrame,ReservoirUnavailable,Corrupt,UnsupportedLayer) and, for all butNoFrame, carries the frame'sFrameInfo. Code that usedif let Some(info)becomesif let Ok(info).Decoder::decodeis generic over the output sample type (f32,i8,u8,i16,u16,i32,u32). Buffers whose element type was only pinned down by the old&mut [f32]signature (such asvec![0.0; n]) need an explicit type.FrameInfois#[non_exhaustive]and has a newlayerfield.- The minimum supported Rust version is 1.89 (1.80 without the
widefeature).
Behavior changes
- Mono/stereo switches decode correctly. The original translation used minimp3's
MINIMP3_NONSTANDARD_BUT_LOGICALfilterbank update, which deviates from the ISO reference on streams that switch between mono and stereo (51 dB PSNR on the conformance vector, versus 117 dB now). Output now matches minimp3's standard build bit for bit. - MPEG Layer I and II (MP1/MP2) frames are decoded (feature
layer12, on by default). Previously they were skipped. i16rounding is fixed. minimp3 rounds samples in (−1.5, −0.5] to 0 instead of −1; nanomp3 now rounds half away from zero.Decoder::new_minimp3_compat()restores minimp3's exact output.- Inputs shorter than 4 bytes, and several malformed inputs, no longer panic.
Added
nanomp3:Reader(over anyRead + Seek) andSliceReader(over bytes in memory): seekable, sample-accurate readers that skip tags, trim the encoder delay and padding for gapless playback, and know the stream length.Optionsconfigures them, includingminimp3_compat.nanomp3:decode_all/decode_all_readerdecode a whole stream into aVec.nanomp3:frames/for_each_frame_readeriterate over frames without decoding;VbrTagparses Xing/Info/LAME tags;detect/detect_readerrecognize MPEG audio;strip_tags,strip_trailing_tagsandid3v2_lenhandle ID3v2, ID3v1 and APEv2 tags.Decoder::new_minimp3_compat(),Sample,DecodeError.- Cargo features:
wide(SIMD via thewidecrate) andlayer12in both crates;allocandstdinnanomp3.
Fixed minimp3_ex bugs
The minimp3_ex port matches minimp3_ex exactly with Options::minimp3_compat. By default, these bugs are fixed, and the I/O reader behaves exactly like the in-memory one:
- Header-less APEv2 tags are over-trimmed by 32 bytes of audio.
- The I/O reader strips trailing tags again every time it reaches the end of the stream.
- Junk longer than the 128 KiB read buffer ends the I/O scan early (short length, incomplete seek index).
- The I/O frame iterator overstates the bytes available to the decoder.
- An I/O seek fails when a frame it needs is cut short by the end of the file.
- After a failed seek, minimp3_ex's next read returns memory past its buffer; nanomp3 stays in its error state until the next successful seek.
Internal
- No
unsafe: both crates are#![forbid(unsafe_code)]. - Decoding is 36–79% faster than 0.1 and faster than minimp3's own SIMD build, with output still bit-identical to minimp3's reference build.
parity/compares nanomp3 against upstream minimp3 and minimp3_ex (a git submodule) bit for bit;fuzz/has differential and robustness fuzz targets.- Items marked
#[doc(hidden)](nanomp3_core::__private,nanomp3::__compat,nanomp3::__Raw,__raw(),Sample::from_synth) are internal and not covered by semver.