Library / SDK
lieff/minimp3 avatar
lieff/minimp3

minimp3: a single-header MP3 decoder for C applications

Minimalistic MP3 decoder single header library

1,975 stars272 forksCCC0-1.0

At a glance

What is it?
minimp3 is a small, floating-point MP3 decoding library distributed as a C header. It suits applications that need direct control over input buffering and PCM output, but its frame-based API places synchronization and buffer management on the caller.
Who is it for?
Adopt minimp3 when a C project benefits from adding MP3 decoding through one header and accepts responsibility for buffering, stream synchronization, and output handling. Do not choose it as a drop-in audio playback library or if fixed-point decoding is mandatory.
Can I use it commercially?
Yes. CC0-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 88 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • lieff/minimp31,975 ★ · +2
Star history
Repository2026-10-162026-10-23
lieff/minimp32k2k

2 Stars in the last 7 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The problem minimp3 solves inside a C project

minimp3 addresses the need to decode MP3 audio without adopting a larger multimedia framework or a collection of separately installed libraries. Its intended users are C developers embedding playback or audio-processing features into applications, tools, games, or device software. The repository identifies it as a minimalistic, single-header library, with the implementation centered in `minimp3.h`.

The library handles MPEG Layer 3 decoding directly and can also retain MPEG Layer 1 and Layer 2 decoding unless `MINIMP3_ONLY_MP3` is defined. That choice matters when binary size is a concern. It also supports already split MP3 streams, including data obtained after MP4 demuxing, although the input constraints for that mode are more exacting than the ordinary buffered path.

This is not a complete player abstraction. The repository layout includes a `player/` directory, but the documented core interface exposes decoded frames and byte-consumption metadata rather than audio devices, playback timing, seeking, resampling, or file handling. Applications remain responsible for those layers.

The README describes the implementation as floating point, with optional SIMD optimizations for SSE and NEON. It says generic code is always enabled on x64 and Arm64 targets, while `MINIMP3_NO_SIMD` can disable platform-specific SIMD paths. The project therefore targets the narrow problem of obtaining decoded PCM from an MP3 bitstream, not the broader problem of shipping a complete audio experience.

How minimp3 turns buffered MP3 bytes into PCM

The central interface is frame-oriented. First, the application creates a `mp3dec_t` decoder state and initializes it with `mp3dec_init()`. It then supplies an input buffer to `mp3dec_decode_frame()`. The function analyzes the bytes to find an MP3 frame, decodes it, writes PCM into an application-provided `short` array, and fills `mp3dec_frame_info_t` with frame metadata.

The return value represents decoded sample count. It can be `0` when no MP3 data was found, `384` for Layer 1, `576` for MPEG 2 Layer 3, or `1152` otherwise. The accompanying `frame_bytes` value is equally important because it tells the caller how much encoded data was consumed. The caller must remove that many bytes before invoking the decoder again.

The function combines decoding progress with stream synchronization. According to the README, it can skip ID3 data and invalid data. It does not simply begin decoding at byte zero and assume that the caller has isolated a valid frame. A buffer containing several frames gives the synchronization procedure more evidence, so the README recommends supplying as many as 10 consecutive MP3 frames, approximately 16KB.

There is a specific trade-off here. Smaller buffers reduce memory use, but the README warns that short buffers may cause false synchronization and produce squealing artifacts. That makes buffer sizing part of the decoder integration, not an incidental application detail. When `frame_bytes` is zero, the metadata fields may remain unavailable, so an application must not interpret every return of zero samples in the same way. A zero return with positive `frame_bytes` means bytes were skipped, while a zero return with zero `frame_bytes` means more data is required.

Adding minimp3.h and decoding the first frame

The repository does not document a package-manager installation command or a versioned release artifact. The documented installation method is source inclusion: place `minimp3.h` with the project and include it from C source files. There are no GitHub releases, so a release-specific version cannot be selected from the repository README.

Define `MINIMP3_IMPLEMENTATION` in exactly one translation unit. Other files may include `minimp3.h` without that definition. This arrangement keeps the implementation in one compiled source file while allowing declarations elsewhere. The documented setup is:

c
//#define MINIMP3_ONLY_MP3
//#define MINIMP3_ONLY_SIMD
//#define MINIMP3_NO_SIMD
//#define MINIMP3_NONSTANDARD_BUT_LOGICAL
//#define MINIMP3_FLOAT_OUTPUT
#define MINIMP3_IMPLEMENTATION
#include "minimp3.h"

The first line is commented in the README, so `MINIMP3_ONLY_MP3` is optional. With the file included, initialize persistent decoder state and request the first frame:

c
static mp3dec_t mp3d;
mp3dec_init(&mp3d);

The state should remain available across calls because frame decoding is sequential. The README says calling `mp3dec_init()` is not necessary between ordinary frames, although it may be used when the decode position changes.

Next, provide encoded bytes and a PCM destination. The documented output type is `short`, with room for the largest supported frame:

c
mp3dec_frame_info_t info;
short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
/*unsigned char *input_buf; - input byte stream*/
samples = mp3dec_decode_frame(&mp3d, input_buf, buf_size, pcm, &info);

`input_buf` and `buf_size` are application-provided inputs, while `samples` receives the decoded sample count. After the call, inspect `info.frame_bytes`, remove exactly that many encoded bytes from the front of the input buffer, and retain any remainder for the next call. A successful result has positive samples and positive `frame_bytes`. Do not treat metadata other than `frame_bytes` as valid when it is zero.

Configuration choices that change minimp3's behavior

Several preprocessor definitions let the adopter trade code size or output format against capabilities. `MINIMP3_ONLY_MP3` removes MP1 and MP2 decoding code, which is appropriate when the application accepts only MPEG Layer 3 streams. `MINIMP3_ONLY_SIMD` controls generic code generation, although the README notes that generic code remains enabled on x64 and Arm64 targets. Disabling generic paths may reduce source or binary size for supported instruction-set targets.

`MINIMP3_NO_SIMD` removes platform-specific optimizations. This can simplify compilation on targets where SSE or NEON intrinsics are unavailable or unwanted, at the cost of the documented optimization paths. The README describes SSE and NEON support as part of the design, but it does not provide a universal fallback policy for every compiler and processor combination.

`MINIMP3_NONSTANDARD_BUT_LOGICAL` saves code bytes and changes the decoder's treatment of rare mono-to-stereo transitions. The README explicitly labels the behavior non-standard. This setting should not be selected merely to save a small amount of space unless the resulting output has been checked against the application's decoding requirements.

By default, `mp3dec_decode_frame()` outputs `short` PCM samples. Defining `MINIMP3_FLOAT_OUTPUT` changes that output to `float` and makes `mp3dec_f32_to_s16` available for float-to-short conversion when needed. This can be useful for processing before quantization, but the application then owns an additional conversion stage. None of these options turns minimp3 into a resampler, channel mixer, audio device interface, or file parser.

Synchronization, free format, and end-of-stream constraints

minimp3 is more tolerant of ordinary byte streams than a decoder that requires perfectly isolated frames, but its reliability depends on how much surrounding data is available. The README recommends around 16KB, represented by as many as 10 consecutive MP3 frames, because that gives the synchronization process a larger region in which to confirm frame boundaries.

At the end of a stream, the remaining buffer can be passed to the decoder, including when only one frame remains. The documentation warns that garbage at the end can interfere with synchronization in free-format streams. It therefore recommends removing ID3v1 and APE tags first. This is caller preprocessing, not behavior that can be inferred from the current buffer alone.

Free-format streams impose another minimum. At least three frames are needed: two to detect the frame length and a third to check that the detected pattern is consistent. Applications that expect arbitrary free-format input cannot use the ordinary one-frame interpretation as proof of a valid stream.

Already split MP3 streams are supported as a special case, such as after MP4 demuxing. The README states that the input buffer must contain exactly one frame in this case, but the supplied excerpt cuts off immediately after that sentence. It does not complete the contract for preserving or validating those exact one-frame buffers, so an adopter should not infer any additional guarantees from the incomplete text.

These constraints explain why minimp3 is a compact decoder rather than a simple `decode bytes to sound` abstraction. Reliable integration depends on maintaining encoded data in the shape expected by each mode and interpreting skipped input carefully.

Verification limits and the comparison with keyj minimp3

The README reports a conformance test over a set of MP3 vectors and states that the test passed with PSNR above 96dB. It also supplies a benchmark using `perf` on an i7-6700K, with I/O included and CPU speedstep concerns addressed. Those are repository-reported figures, not independent measurements, and they do not establish performance on every target, compiler, or operating system.

The README compares minimp3 with keyj's minimp3 and distinguishes their approaches. keyj's version is described as fixed point, while this version is floating point. The current implementation is listed with SSE and NEON intrinsics and free-format support, while the comparison says keyj's version has no vector optimizations and no free-format support. The listed source sizes are 70KB for the current version and 84KB for keyj's version, with both binary rows shown as 20KB compressed.

Those figures are a feature comparison, not a universal sizing rule. Compiler settings, enabled definitions, target architecture, and linker behavior can change the resulting binary. Likewise, the conformance vectors demonstrate that the project was tested against the repository's chosen cases, but they do not replace application testing with damaged files, unusual tags, short buffers, free-format input, and MP4-demuxed frames.

The repository is not archived, and its last push was on 2026-07-27. It has no GitHub releases, so upgrade planning cannot rely on release notes or a published version history. Integration should track changes to the single header and compile the resulting code for every supported C target. The `CC0-1.0` license removes the need to infer permissions from conventional open-source license wording, but applications should still review the license file and preserve any separate notices or dependencies required by their own distribution.

Editorial conclusion

Adopt minimp3 when a C project benefits from adding MP3 decoding through one header and accepts responsibility for buffering, stream synchronization, and output handling. Do not choose it as a drop-in audio playback library or if fixed-point decoding is mandatory. Before adoption, verify compilation on the required C targets, confirm that the caller can retain roughly 16KB of consecutive frames, and test malformed, tagged, free-format, and split-frame inputs against the expected application behavior.

Frequently asked questions

How do I install minimp3 in a C project?

The repository does not provide a package-manager installation command or GitHub release artifact. Its documented method is to include `minimp3.h` in the project and define `MINIMP3_IMPLEMENTATION` in exactly one source file.

How much MP3 input should I pass to mp3dec_decode_frame()?

The README recommends as many as 10 consecutive MP3 frames, approximately 16KB, because larger buffers make stream synchronization more reliable. The caller must remove exactly `frame_bytes` after each invocation.

Does minimp3 support free-format and already split MP3 streams?

The README states that free-format support is included, but proper free-format synchronization requires at least three frames. The library also supports already split streams, such as data obtained after MP4 demuxing, although the README excerpt does not finish that mode's requirements.

Official sources

  1. Issues
  2. License: CC0-1.0
  3. lieff/minimp3 on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lieff-minimp3.svg)](https://hysenlabs.com/projects/lieff-minimp3)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/lieff-minimp3.svg)](https://hysenlabs.com/projects/lieff-minimp3)

Was this useful?