You could access this page securely.

mpg123 - Fast console MPEG Audio Player and decoder library

The mpg123 distribution contains a real time MPEG 1.0/2.0/2.5 audio player/decoder for layers 1,2 and 3 (most commonly MPEG 1.0 layer 3 aka MP3), as well as re-usable decoding and output libraries. Among others, it works on GNU/Linux, MacOSX, the BSDs, Solaris, AIX, HPUX, SGI Irix, OS/2 and Cygwin or plain MS Windows (not all more exotic platforms tested regularily, but patches welcome). You may jump to the non-exhaustive list of features.

It is free software licensed under LGPL 2.1 .

Note that nowadays, the mpg123 decoder core can work with floating point or integer math and with some tuning between accuracy and performance at build-time, using assembly optimizations for several platforms, depending on your build configuration. There is detection and selection of assembly optimisations on x86, x86-64, and ARM at program runtime. It's fast, it's high-quality. Just use it;-)

Top News

After somewhat longer than usual gestation, here comes the next feature release of mpg123. Only small build and installation fixes followed the first public release candiate. The final 1.26.0 is identical to 1.26rc3.

Compared to the previous stable version, quite a numer of changes arrived. Lots of housekeeping and as a major addition, a signal generation and format conversion library born out of the test signal code from the out123 program. See the libsyn123 API for what it has to offer. Something only a bit insane is a fairly-efficient low-latency resampler using IIR filtering, which I wanted to design just because everyone else does it differently;-) This resampler now replaces libmpg123's internal drop-sample NtoM decoder by default when you fix an output rate in the mpg123 program.

  • Starting to intentionally use C99 in the codebase. API headers are still supposed to be compatible to C89.
  • There is a make check target now that tests some text transformations. It is an open question how that should be developed in relation to the external regression and compliance test suite.
  • Finally silenced memory checkers about leaking memory from getlopt() (main code overwriting values without freeing strdup() strings).
  • AUTHORS now in UTF-8;-)
  • CMake build files in ports/cmake, as an alternative to create MSVC project files and the like (thanks to Vitaly Kirsanov)
  • Default build with proper integer rounding (--enable-int-quality) now.
  • Cygwin/midipix autoconf fixes (thanks to Redfoxmoon).
  • Updated Windows build script, notably renaming .dll.def to .def. Requires an argument now for build type, an optional one for parallel make (not that useful on MinGW).
  • Rework library dependency handling to avoid unnecessary linking for lib*123. Also add proper Libs.private to .pc files to enable static usage (especially on Windows with shlwapi).
  • Updated support for OS/2 in the form of ArcaOS.
  • Removed outdated Pascal port (ports/mpg123_.pas). There are others out there.
  • Updated man pages, been a while.
  • mpg123:
    • Fixed-rate playback now prefers the libsyn123 resampler instead of NtoM in libmpg123, see --resample parameter.
    • Drop --STDOUT (never properly implemented, use pipe to out123 instead).
    • Make --streamdump use unintr_write() to avoid inconsistencies.
    • Now sets non-zero exit code when any one track of the playlist fails to either produce at least one frame of playback, if there is data that should produce such (i.e. /dev/zero is bad, /dev/null is fine). See man page for details.
    • Print out MPEG header info for each frame for mpg123 -vvvv.
    • Added --no-visual to disable cursor/inverse video games explicitly.
    • Clear progress bar before printing updated metadata within a stream.
    • Filter control/non-printable characters from user data printout, reduce ID3v1 data to 7-bit ASCII (no way to know correct 8-bit encoding for sure). This should cover bug 267.
    • Set MPG123_NO_PEEK_END when opening special file '-' (standard input). That helps Windows where attempting to seek on the non-seekable stream is undefined behaviour (bug 285).
    • Print errors in player code also for --quiet operation (just no messages from the libraries).
    • Ignore ID3v1 once a Frankenstein stream was detected.
    • Prevent a cosmetic use-after-free in audio playback during program abortion just after starting playback (prebuffer still in use, implication a blip of bad sound and a complaining sanitizer).
    • Reformat audio capabilities table, more condensed, fits into 80 columns. Forced rate on a separated line.
    • Make --pitch actually work, not just interactive changes. Pitching uses a resampler now if a fixed output rate is specified.
    • Added --no-frankenstein.
    • Frameflags as long variable, 32 bits are needed since some time now.
  • out123:
    • Document --STDOUT, make it more robust regarding fwrite() interruptions.
    • Removed the implicit phase shift that made generated waves exactly at Nyquist freq non-silent, but made little sense overall.
    • Less high-frequency shifts to make waves fit into the table (not insisting on even number of samples).
    • Option to work without wave table (setting the limit to zero).
    • Added --wave-direction to also enable backward time without phase shift.
    • Waves now generated by re-usable little synthethizer library dubbed libsyn123.
    • Pink noise from libsyn123 added (using code from Phil Burk).
    • White noise from libsyn123.
    • Geiger-Mueller counter simulation from libsyn123.
    • Wave sweep generator from libsyn123.
    • Some rearrangement in help text.
    • Changed output of --test-encodings to list of encoding names instead of raw bitmask value.
    • Added --endian, --inputend, and --byteswap.
  • libsyn123:
    • Created the library to host some simple signal generators for testing output.
    • It also hosts sample format conversions as a necessity to be able to directly produce the format output devices need.
    • Well, also channel mixing while we're at it.
    • Oh, and a minimal-latency-and-reasonably-efficient resampler that only took me over a year to figure out. I should write a paper about it.
  • libout123:
    • Added out123_free() for the benefit of library wrappers. (bug 276)
    • Removed change of effective user ID in the WAV/RAW/AU/CDR writer. This was intended as a safeguard to avoid creating files with root priviledges. But: Other output modules still allowed root-level access to various devices and files, so it was never safe to do something awful like installing mpg123 with suid bit or configure sudo to allow users to run mpg123 with arbitrary arguments. You should treat out123_open() just like the regular open(): You can write to any file/device depending on your permissions.
    • Finally maybe fixed the damaged playback when using pulse hidden behind the ALSA API (on Ubuntu, for example) by setting a high value for device start threshold.
    • Fixed out_play() abortion logic to better detect fatal situations (broken pipe). Needed on FreeBSD, while Linux buffers the issue away. Should resolve bug 283.
    • Limit size of buffer block being written in out123_play to 16K, avoiding unnecessary failure with ALSA at least.
    • Using SDL2 now if found. Output module code unchanged.
    • Added hex and txt (plain text) printout.
    • Eliminated spots where error messages would still be printed also for OUT123_QUIET being effect.
    • Dummy output accepts any encoding now.
  • libmpg123:
    • Added mpg123_open_fixed() to ease API for applications that just want to decode well-behaved local files.
    • The user buffers for audio output data are now declared as void* for mpg123_read(), mpg123_decode(), and mpg123_replace_buffer() to avoid the useless need for casting your nice int16_t buffer to unsigned char for decoding MPG123_ENC_SIGNED_16 data to it.
    • Added mpg123_free() for the benefit of library wrappers. (bug 276)
    • Add mpg123_format2() and mpg123_fmt2() supporting special value 0 for all rates.
    • Fix changing of decoder (and output format along with that) after stream opening. This was never recommened and only now should work at all.
    • Also mpg123_decode_frame() now sets return buffer to NULL and returned byte count to zero in case of MPG123_NEED_MORE (or any other early abort).
    • MPG123_NEED_MORE not returned anymore for non-feeder streams. Got in there for generic partial frame body reads, but was only intended for feeder API.
    • Added mpg123_set_moreinfo() to support the Lame project's frame analyzer, disabled by ./configure --disable-moreinfo.
    • Added optional storage and retrieval of raw ID3 data.
    • Fix skipping of ID3v2 footers (too much was attempted to be skipped). This is of not much practical consequence as a tag with footer would appear on the end of files anyway and files with ID3v2 tags at the end seem to be rather rare.
    • Add mpg123_new_string() and mpg123_delete_string() to avoid confusion about what mpg123_init_string() and mpg123_free_string() do.
    • Make mpg123_resize_string() terminate the string if shrinking (fill now limited to new size).
    • Improve layer III frame parsing/error reporting for bad part2_3_length.
    • Fix crashing on stupidly low NtoM rates (exceeding downsampling factor 31). This was only triggered by you specifying a forced sampling rate below 1550 Hz.
    • Do not remove CRC bits twice from possibly available bit reservoir. This move needed recomputation of the layer3is reference data for 8 and 24 kHz. Old mpg123 is wrong in the first few frames.
    • Generally more tight control and early bail out on reading bits of frame data for all layers. This reduces the count of error messages on badly damaged files a lot and feels a lot safer, too. Note that we already silently returned zero bytes instead of actually over-reading the frame buffer before, but now it happens with diagnostics and more checks before it may happen.
    • Optionally enforce output endianess (big/little) away from native.
    • Fix build without error messages.
    • Fix build without gapless decoding.
    • Disable buffer when neither mmap nor shm functions detected (fixes build for Android, thanks to vquicksilver).
    • Some support for extremely small streams (below 128 bytes). Those are too short to contain anything useful besides some tiny metadata, but serve to find/reproduce parser bugs.
    • Fix mpg123_read() for builds without feeder. It calls mpg123_decode() without feeding input, which was disabled by mistake. The use of mpg123_read() (instead of mpg123_decode_frame()) with mpg123_open() was broken in feederless builds since those were fixed in version 1.15.
    • Fix ID3v2 parser logic for multiple ID3v2 tags being encountered in one stream. New tags replace old data instead of appending to it when the extended header update flag is not set (ID3v2.4). Update tags only replace data that shall be unique. So far, I have never seen an update tag in the wild, so the check for the flag is untested. The mechanism of replacing parts of existing tag data has been tested, though. Note that the updated libmpg123 also avoids a growing ID3 data structure when repeatedly seeking back to the beginning in a file with disabled seek index.
    • Eliminated a spots where error messages would still be printed also for MPG123_QUIET being effect.
    • Now actually try floating point encoding if format matrix allows it (can be disabled by unsetting MPG123_FLOAT_FALLBACK).
    • Added mpg123_feature2() also added feature queries for floating point output.

Oh, I'm giving in to the lack of enthusiasm about the new merged mailing list. I'm closing it again and we continue to use mpg123-users and mpg123-devel.

Head over to the download section for getting your hands on the release.

For older news see the news archive

ISO MPEG compliance

This is a rough log of an automated compliance test on the mpg123 webserver (Xeon E3, GNU/Linux), using the test bitstreams from the ISO MPEG reference set. At least the floating point output should really be close enough to the reference.

Regarding the method: This is comparing mpg123's output (with gapless code deactivated) from reference bitstreams to the reference output. A simple RMS error measure is employed, relative to full scale, just summing over mono or stereo data indiscriminently. This is my interpretation of the rules... maximum allowed RMS=8.80967e-06, maximum signal difference 6.10352e-05.

compliance test for mpg123-20200529022201 on Linux x86_64
First decoder in this list will be tested first, then generic: 
Supported decoders: AVX x86-64 generic generic_dither

Testing default decoder...

==== Layer 1 ====
--> 16 bit signed integer output
fl1.bit:	RMS=4.364373e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl2.bit:	RMS=4.353138e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl3.bit:	RMS=4.348759e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl4.bit:	RMS=4.403421e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl5.bit:	RMS=4.323446e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl6.bit:	RMS=4.389607e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl7.bit:	RMS=3.826083e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl8.bit:	RMS=4.362205e-06 (PASS) maxdiff=7.629395e-06 (PASS)
--> 32 bit integer output
fl1.bit:	RMS=1.967634e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.969954e-08 (PASS) maxdiff=1.117587e-07 (PASS)
fl3.bit:	RMS=2.001651e-08 (PASS) maxdiff=1.341105e-07 (PASS)
fl4.bit:	RMS=1.903406e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=3.651337e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl6.bit:	RMS=3.117874e-08 (PASS) maxdiff=2.086163e-07 (PASS)
fl7.bit:	RMS=1.768833e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl8.bit:	RMS=1.857696e-08 (PASS) maxdiff=8.428469e-08 (PASS)
--> 24 bit integer output
fl1.bit:	RMS=4.096055e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl2.bit:	RMS=4.154692e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl3.bit:	RMS=4.127229e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl4.bit:	RMS=4.100170e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl5.bit:	RMS=4.573922e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl6.bit:	RMS=3.918939e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl7.bit:	RMS=4.186568e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl8.bit:	RMS=4.105456e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
fl1.bit:	RMS=1.967635e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.969944e-08 (PASS) maxdiff=1.117587e-07 (PASS)
fl3.bit:	RMS=2.001658e-08 (PASS) maxdiff=1.341105e-07 (PASS)
fl4.bit:	RMS=1.903395e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=3.651337e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl6.bit:	RMS=3.117872e-08 (PASS) maxdiff=2.086163e-07 (PASS)
fl7.bit:	RMS=1.768828e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl8.bit:	RMS=1.857700e-08 (PASS) maxdiff=8.428469e-08 (PASS)

==== Layer 2 ====
--> 16 bit signed integer output
fl10.bit:	RMS=3.512100e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl11.bit:	RMS=3.837267e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl12.bit:	RMS=3.901071e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl13.bit:	RMS=4.379583e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl14.bit:	RMS=4.112578e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl15.bit:	RMS=4.388579e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl16.bit:	RMS=4.147495e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
fl10.bit:	RMS=1.777285e-08 (PASS) maxdiff=8.475035e-08 (PASS)
fl11.bit:	RMS=1.789150e-08 (PASS) maxdiff=9.685755e-08 (PASS)
fl12.bit:	RMS=1.780872e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl13.bit:	RMS=1.760690e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=3.361258e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=2.418801e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl16.bit:	RMS=1.924891e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 24 bit integer output
fl10.bit:	RMS=4.085486e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl11.bit:	RMS=4.098320e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl12.bit:	RMS=4.095125e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl13.bit:	RMS=4.108581e-08 (PASS) maxdiff=5.960464e-08 (PASS)
fl14.bit:	RMS=4.444728e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=4.087458e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl16.bit:	RMS=4.146825e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
fl10.bit:	RMS=1.777284e-08 (PASS) maxdiff=8.475035e-08 (PASS)
fl11.bit:	RMS=1.789151e-08 (PASS) maxdiff=9.685755e-08 (PASS)
fl12.bit:	RMS=1.780868e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl13.bit:	RMS=1.760693e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=3.361258e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=2.418793e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl16.bit:	RMS=1.924847e-08 (PASS) maxdiff=1.192093e-07 (PASS)

==== Layer 3 ====
--> 16 bit signed integer output
compl.bit:	RMS=4.300912e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
compl.bit:	RMS=2.105351e-08 (PASS) maxdiff=1.881272e-07 (PASS)
--> 24 bit integer output
compl.bit:	RMS=4.172895e-08 (PASS) maxdiff=2.384186e-07 (PASS)
--> 32 bit floating point output
compl.bit:	RMS=2.105351e-08 (PASS) maxdiff=1.881272e-07 (PASS)

==== Layer 3 intensity stereo ====
   (no official reference, comparing to mpg123 generic 24 bit)
--> 16 bit signed integer output
drumshort08kHz.bit:	RMS=4.348691e-06 (PASS) maxdiff=7.629395e-06 (PASS)
drumshort24kHz.bit:	RMS=4.365980e-06 (PASS) maxdiff=7.629395e-06 (PASS)
drumshort48kHz.bit:	RMS=4.375106e-06 (PASS) maxdiff=8.106232e-06 (PASS)
--> 32 bit integer output
drumshort08kHz.bit:	RMS=3.274575e-08 (PASS) maxdiff=5.937181e-08 (PASS)
drumshort24kHz.bit:	RMS=3.277976e-08 (PASS) maxdiff=5.937181e-08 (PASS)
drumshort48kHz.bit:	RMS=4.066349e-08 (PASS) maxdiff=6.854534e-07 (PASS)
--> 24 bit integer output
drumshort08kHz.bit:	RMS=0.000000e+00 (PASS) maxdiff=0.000000e+00 (PASS)
drumshort24kHz.bit:	RMS=0.000000e+00 (PASS) maxdiff=0.000000e+00 (PASS)
drumshort48kHz.bit:	RMS=2.915400e-08 (PASS) maxdiff=7.152557e-07 (PASS)
--> 32 bit floating point output
drumshort08kHz.bit:	RMS=3.274569e-08 (PASS) maxdiff=5.948616e-08 (PASS)
drumshort24kHz.bit:	RMS=3.277980e-08 (PASS) maxdiff=5.948719e-08 (PASS)
drumshort48kHz.bit:	RMS=4.066347e-08 (PASS) maxdiff=6.854534e-07 (PASS)

Now the generic decoder:

==== Layer 1 ====
--> 16 bit signed integer output
fl1.bit:	RMS=4.364373e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl2.bit:	RMS=4.353138e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl3.bit:	RMS=4.348759e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl4.bit:	RMS=4.403421e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl5.bit:	RMS=4.323452e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl6.bit:	RMS=4.389618e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl7.bit:	RMS=3.826083e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl8.bit:	RMS=4.362205e-06 (PASS) maxdiff=7.629395e-06 (PASS)
--> 32 bit integer output
fl1.bit:	RMS=1.967648e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.975497e-08 (PASS) maxdiff=1.080334e-07 (PASS)
fl3.bit:	RMS=2.004415e-08 (PASS) maxdiff=1.359731e-07 (PASS)
fl4.bit:	RMS=1.903250e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=3.775290e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl6.bit:	RMS=3.142156e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl7.bit:	RMS=1.769605e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl8.bit:	RMS=1.856375e-08 (PASS) maxdiff=8.568168e-08 (PASS)
--> 24 bit integer output
fl1.bit:	RMS=4.116474e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl2.bit:	RMS=4.164770e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl3.bit:	RMS=4.139936e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl4.bit:	RMS=4.111906e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl5.bit:	RMS=4.703666e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl6.bit:	RMS=3.965024e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl7.bit:	RMS=4.190797e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl8.bit:	RMS=4.110265e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
fl1.bit:	RMS=1.967657e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl2.bit:	RMS=1.975463e-08 (PASS) maxdiff=1.080334e-07 (PASS)
fl3.bit:	RMS=2.004405e-08 (PASS) maxdiff=1.359731e-07 (PASS)
fl4.bit:	RMS=1.903236e-08 (PASS) maxdiff=1.266599e-07 (PASS)
fl5.bit:	RMS=3.775227e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl6.bit:	RMS=3.142155e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl7.bit:	RMS=1.769602e-08 (PASS) maxdiff=8.940697e-08 (PASS)
fl8.bit:	RMS=1.856375e-08 (PASS) maxdiff=8.568168e-08 (PASS)

==== Layer 2 ====
--> 16 bit signed integer output
fl10.bit:	RMS=3.512100e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl11.bit:	RMS=3.837267e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl12.bit:	RMS=3.901071e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl13.bit:	RMS=4.379583e-06 (PASS) maxdiff=7.629395e-06 (PASS)
fl14.bit:	RMS=4.112584e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl15.bit:	RMS=4.388579e-06 (PASS) maxdiff=7.688999e-06 (PASS)
fl16.bit:	RMS=4.147492e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
fl10.bit:	RMS=1.779797e-08 (PASS) maxdiff=8.381903e-08 (PASS)
fl11.bit:	RMS=1.790372e-08 (PASS) maxdiff=9.126961e-08 (PASS)
fl12.bit:	RMS=1.784118e-08 (PASS) maxdiff=8.568168e-08 (PASS)
fl13.bit:	RMS=1.762796e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=3.714496e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=2.435663e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl16.bit:	RMS=1.928348e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 24 bit integer output
fl10.bit:	RMS=4.094739e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl11.bit:	RMS=4.107851e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl12.bit:	RMS=4.109502e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl13.bit:	RMS=4.124594e-08 (PASS) maxdiff=5.960464e-08 (PASS)
fl14.bit:	RMS=4.759981e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=4.114483e-08 (PASS) maxdiff=1.788139e-07 (PASS)
fl16.bit:	RMS=4.157136e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 32 bit floating point output
fl10.bit:	RMS=1.779791e-08 (PASS) maxdiff=8.381903e-08 (PASS)
fl11.bit:	RMS=1.790366e-08 (PASS) maxdiff=9.126961e-08 (PASS)
fl12.bit:	RMS=1.784114e-08 (PASS) maxdiff=8.568168e-08 (PASS)
fl13.bit:	RMS=1.762806e-08 (PASS) maxdiff=4.470348e-08 (PASS)
fl14.bit:	RMS=3.714501e-08 (PASS) maxdiff=1.192093e-07 (PASS)
fl15.bit:	RMS=2.435655e-08 (PASS) maxdiff=1.490116e-07 (PASS)
fl16.bit:	RMS=1.928318e-08 (PASS) maxdiff=1.788139e-07 (PASS)

==== Layer 3 ====
--> 16 bit signed integer output
compl.bit:	RMS=4.300914e-06 (PASS) maxdiff=7.688999e-06 (PASS)
--> 32 bit integer output
compl.bit:	RMS=2.147684e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 24 bit integer output
compl.bit:	RMS=4.202676e-08 (PASS) maxdiff=1.788139e-07 (PASS)
--> 32 bit floating point output
compl.bit:	RMS=2.147685e-08 (PASS) maxdiff=1.788139e-07 (PASS)

==== Layer 3 intensity stereo ====
   (no official reference, comparing to mpg123 generic 24 bit)
--> 16 bit signed integer output
drumshort08kHz.bit:	RMS=4.348724e-06 (PASS) maxdiff=7.748604e-06 (PASS)
drumshort24kHz.bit:	RMS=4.366059e-06 (PASS) maxdiff=7.808208e-06 (PASS)
drumshort48kHz.bit:	RMS=4.375029e-06 (PASS) maxdiff=7.748604e-06 (PASS)
--> 32 bit integer output
drumshort08kHz.bit:	RMS=3.671410e-08 (PASS) maxdiff=4.172325e-07 (PASS)
drumshort24kHz.bit:	RMS=3.878156e-08 (PASS) maxdiff=7.450581e-07 (PASS)
drumshort48kHz.bit:	RMS=3.348861e-08 (PASS) maxdiff=1.490116e-07 (PASS)
--> 24 bit integer output
drumshort08kHz.bit:	RMS=2.248197e-08 (PASS) maxdiff=4.172325e-07 (PASS)
drumshort24kHz.bit:	RMS=2.649346e-08 (PASS) maxdiff=7.748604e-07 (PASS)
drumshort48kHz.bit:	RMS=1.195123e-08 (PASS) maxdiff=1.192093e-07 (PASS)
--> 32 bit floating point output
drumshort08kHz.bit:	RMS=3.671411e-08 (PASS) maxdiff=4.172325e-07 (PASS)
drumshort24kHz.bit:	RMS=3.878154e-08 (PASS) maxdiff=7.450581e-07 (PASS)
drumshort48kHz.bit:	RMS=3.348855e-08 (PASS) maxdiff=1.490116e-07 (PASS)

Depending on what integer quality mode you choose at compile time (and the decoder in use), the 16bit output can vary between PASS and LIMITED for fully or limited accuracy compliance. But keep in mind: For the integer output, you have to give +-1 for rounding... that's what I append to any integer number read from some measurement device anyway, by default. That minimum possible deviation already brings the output close (or over) the border of full compliance... that really does not mean that the output sounds bad! It shall be noted that a measure to improve subjective quality, namely the dithering before rounding to integers, can also increase the theoretical decoding error.

In the end, RMS values in the order of 10 to the power of -5 should sound just fine. To get 16bit output to PASS, you usually need to enable proper rounding using the --enable-int-quality configure flag. It is not on by default because it mostly (yeah, there are odd cases) needs somewhat more CPU time and the simple truncation is fine for most people. Note that mpg123 does have a rounding method using the specific IEEE754 floating point format, selected at build-time, which seems to be nearly as fast as simple truncation on x86-64 hardware. So, --enable-int-quality might be a no-brainer on those systems if using the generic C decoder. But then, there are the specific assembly routines (SSE, AVX), where the difference between accurate and non-accurate integer conversion can still amount to 20 % runtime increase (measured on a Core2Duo P8600 with GCC 5.3.0).

For comparisong with other decoders (as well as older incarnations of the mpg123 engine), have a read of the Underbit compliance tests. Actually, my testing method follows that example, including their quoting of ISO MPEG rules.

Regression tests

This is output from the rudimentary regression test suite (which should eventually merge several approaches we had on testing in the past), working on the periodic snapshot:

cc   -I/tmp/mpg123-svn.Yg6J7/prefix/include  -c -o helpers.o helpers.c
CC custom_io.bin
CC chomp_strings.bin
CC more_bytes_on_second_decode.bin
CC 2859531_id3_tag_not_skipped_when_NO_ID3V2_is_defined.bin
CC less_bytes_after_seek2.bin
CC seek_accuracy.bin
CC out123_passthrough.bin
CC bug201_wrong_frame_buffer.bin
CC bug201_another_one.bin
CC basic_resync.bin
CC freeformat.bin
CC out123_errorlist.bin
CC premature_decoder_change.bin
CC less_bytes_after_seek.bin
CC frame_seek_weirdness.bin
CC string_alloc.bin
CC 2950218_extra_samples_seek_last_frame.bin
Running tests.
Starting tests, look into test.log for messages.
PASS|SKIP is good, FAIL is bad.

custom_io:                                                PASS
chomp_strings:                                            PASS
more_bytes_on_second_decode:                              PASS
2859531_id3_tag_not_skipped_when_NO_ID3V2_is_defined:     PASS
less_bytes_after_seek2:                                   PASS
seek_accuracy:                                            PASS
out123_passthrough:                                       PASS
bug201_wrong_frame_buffer:                                PASS
bug201_another_one:                                       PASS
basic_resync:                                             PASS
freeformat:                                               PASS
out123_errorlist:                                         PASS
premature_decoder_change:                                 PASS
less_bytes_after_seek:                                    PASS
frame_seek_weirdness:                                     PASS
string_alloc:                                             PASS
2950218_extra_samples_seek_last_frame:                    PASS


Needed computing power

A test (GNU/Linux OS) with 0.60-beta2 showed 3 % to 4 % CPU usage on decoding high quality VBR MP3 with a pentiumII laptop with 366MHz, while a pentium 100MHz can easily handle two mpg123 instances in realtime (plus the mixing daemon that works on decoded data). Well, and more recently, A Core2Duo P8600 core can do 500 times realtime decoding (a track nearly five minutes long decoded in half a second).

Also, we have reports from such devices as nintendo DS or Sony PSP, or various embedded systems...

Michael said once upon a time

Plays Layer 3 in stereo on an AMD-486-120Mhz or (of course) a faster machine.

Just for info: mpg123 plays an average 128bps stream, with about 66% in full quality on an AMD 486-133MHz machine.

Hopefully valid HTML! Valid CSS!