Ogg Vorbis decoder
This page has been superseded. The current location of the project is in the stb header-file library github repository.
Sponsorship
RAD Game Tools sponsored
the development of this software with the understanding I would place
it in the public domain.
Source code
Ogg Vorbis decoder: C source file
Limitations
- Currently no true seeking API
- Can only contain one Vorbis stream (not multiple independent streams concatenated)
- Does not support lossless deletion of samples from the front
- Does not implement "floor 0", which is apparently used by some
old Vorbis files
The API for using the library is documented in the source code,
specifically in the "header file" section of the file. Generally,
there are three ways to give it data:
- Hand it a block of memory with the entire Ogg Vorbis stream
- Hand if a FILE * (or a filename) from which it will stream
- Hand it blocks of data at a time that you get from any source
you like
Generally, there are three ways to get data from it:
- Ask it for the entire file decoded into an interleaved 16-bit buffer
malloc()ed by the library
- Ask it for (an internal, unpredictably-sized) frame at a time, in
floats or 16-bit ints
- Ask it for N samples at a time, in floats or 16-bits
This directory includes some sample code,
sample.c, which demonstrates a number of variations of the API.
Also provided are several test ogg files at varying levels of
compression.
stb_vorbis is provided as a single .C file. You can extract the
header file from it and use it in several possible ways.
If you don't want to use stdio or one of the pushdata or pulldata apis,
there are particular #defines you can define globally to disable them;
see the source code.
You can also suppress all usage of the C runtime library, but you will
need to provide replacement functions and #defines, documented below.
- If you want to use it "normally"
- cut-and-paste the 'header file' section out into a header file
- compile stb_vorbis.c as is
- If you want to use it wrapped (only one file will call it)
- create a wrapper C/C++ file
- #include "stb_vorbis.c"
- write your wrappers right there (note, you have to avoid
namespace conflicts with statics in stb_vorbis.c)
- no header file is needed
- Using it without using the CRT
- cut-and-paste the 'header file' section into a header file
- make a wrapper C/C++ file
- #define STB_VORBIS_NO_CRT
- create #defines or static functions implementing everything needed (see below)
- #include "stb_vorbis.c"
You can also avoid having to cut-and-paste the header file with new
releases by doing the following:
- create 'stb_vorbis.h'
- #define STB_VORBIS_HEADER_ONLY
- #include "stb_vorbis.c"
Most new releases don't change the header file (except to add new
items to it), the same as any other library system, so this shouldn't
be necessary in general, but if you like the feeling of security from
it, go for it.
C Runtime Library usage
If you use STB_VORBIS_NO_CRT, you'll need to provide a wrapper file
with definitions like the following:
#define STB_VORBIS_NO_CRT
#define assert(x) // or MyAssert(x)
#define malloc my_allocator
#define free my_deallocator
#define pow my_pow
#define floor my_floor
#ifdef ALWAYS_USE_STB_VORBIS_ALLOC
#define alloca(a) 0 // and don't use the alloca() path!
#else // use malloc/free instead of alloca
#define alloca(a) malloc(a) // this is actually the macro above
#define dealloca(p) free(p) // this is actually the macro above
#endif
void memset(void *base, int val, int len)
{
int i;
for (i=0; i < len; ++i) ((char *) base)[i] = val;
}
int memcmp(void *p1, void *p2, int len)
{
unsigned char *q1 = (unsigned char *) p1;
unsigned char *q2 = (unsigned char *) p2;
int i;
for (i=0; i < len; ++i)
if (q1[i] < q2[i]) return -1;
else if (q1[i] > q2[i]) return 1;
return 0;
}
void memcpy(void *dest, void *src, int num)
{
int i;
for (i=0; i < num; ++i)
((char *)dest)[i] = ((char *) src)[i];
}
float
ldexp(float Value, int Exponent)
{
return((float)((double)Value * pow(2.0, (double)Exponent)));
}
void qsort (void *base, unsigned num, unsigned width,
int (*comp)(const void *, const void *))
{
...
}
#include "stb_vorbis.c"
You may have issues with the compiler generating float-to-int conversions
(e.g. in MSVC, _ftol). You can avoid this by defining your floor() macro
to call a float-to-int function; all float-to-int conversions in stb_vorbis.c
are (supposed to be) wrapped in a call to floor() for this reason.
Internals documentation
These documents may be of use in people trying to modify the source code.
- vorbis_codebook.txt
- Implementation of regular and sparse codebooks
- vorbis_input.txt
- How input is processed, especially pushdata versus normal
I, Sean Barrett, single-handedly wrote the decoder, and as the
legal author (it was not a
"work for hire")
placed it in the public domain in April, 2007.
That means I have disclaimed copyright of it. You can take the
source code and use it for any purpose, commercial or non-commercial,
copyrighted, open-source, Free, free, or public domain, with no
legal obligation to acknowledge the borrowing/copying in any way.
Commentary:
The difference between public domain and, say, a Creative Commons
commercial / non-share-alike / attribution license is solely the requirement
for attribution. (Similarly the BSD license and such.)
While I would appreciate acknowledgement and attribution, I believe
that it is foolish to place a legal encumberment (i.e. a license) on the
software solely to get attribution.
For example, consider that actual person-hours must have been
invested in making sure this
page properly covered all Valve's legal issues with regards to attribution-required
software. (Information needed to propogate from the programmers who
incorporated the libraries to whoever maintains that web page.) Those person-hours cost the company actual money, despite the fact that nobody is ever going to look at this or care.
In other words, I'm arguing that PD is superior to the BSD license and the Creative Commons 'Attribution' license. If the license offers anything besides attribution -- as does, e.g., CC NonCommercial-ShareAlike, or the GPL -- that's an entirely different story.
Bugs
There are almost certainly bugs in the current version. I
welcome reports of bugs (especially with accompanying .ogg files that
exhibit the bugs), and will be happy to attempt to fix bugs and provide
updated versions. My email address is 'sean' care of this domain name.
No Warranty
This software is in the public domain. You are not entering into a
contract with me or anyone else when you use this software. It is a
gift. As such, various laws regarding warranties express or implied
do not apply in any way. Nevertheless, in case there is any
doubt, I do not offer you any warranty, express or implied, for its
behavior, nor fitness of purpose towards any application. If it manages to
decode some Ogg Vorbis streams for you, count yourself lucky.
- 0.99996 - bracket #include <malloc.h> for macintosh compilation by Laurent Gomila
- 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem
- 0.99994 - change fast-float-to-int to work in single-precision FPU mode, remove endian-dependence
- 0.99993 - remove assert that fired on legal files with empty tables
- 0.99992 - rewind-to-start
- 0.99991 - bugfix to stb_vorbis_get_samples_short by Bernhard Wodo
- 0.9999 - (should have been 0.99990) fix no-CRT support, compiling as C++
- 0.9998 - add a full-decode function with a memory source
- 0.9997 - fix a bug in the read-from-FILE case in 0.9996 addition
- 0.9996 - query length of vorbis stream in samples/seconds
- 0.9995 - bugfix to another optimization that only happened in certain files
- 0.9994 - bugfix to one of the optimizations that caused significant (but inaudible?) errors
- 0.9993 - performance improvements; runs in 99% to 104% of time of reference implementation
- 0.9992 - performance improvement of IMDCT; now performs close to reference implementation
- 0.9991 - performance improvement of IMDCT
- 0.999 - (should have been 0.9990) performance improvement of IMDCT
- 0.998 - no-CRT support from Casey Muratori
- 0.997 - bugfixes for bugs found by Terje Mathisen
- 0.996 - bugfix: fast-huffman decode initialized incorrectly for sparse codebooks; fixing gives 10% speedup - found by Terje Mathisen
- 0.995 - bugfix: fix to 'effective' overrun detection - found by Terje Mathisen
- 0.994 - bugfix: garbage decode on final VQ symbol of a non-multiple - found by Terje Mathisen
- 0.993 - bugfix: pushdata API required 1 extra byte for empty page (failed to consume final page if empty) - found by Terje Mathisen
- 0.992 - fixes for MinGW warning
- 0.991 - turn fast-float-conversion on by default
- 0.990 - fix push-mode seek recovery if you seek into the headers
- 0.98b - fix to bad release of 0.98
- 0.98 - fix push-mode seek recovery; robustify float-to-int and support non-fast mode
- 0.97 - builds under c++ (typecasting, don't use 'class' keyword)
- 0.96 - somehow MY 0.95 was right, but the web one was wrong, so here's my 0.95 rereleased as 0.96, fixes a typo in the clamping code
- 0.95 - clamping code for 16-bit functions
- 0.94 - not publically released
- 0.93 - fixed all-zero-floor case (was decoding garbage)
- 0.92 - fixed a memory leak
- 0.91 - conditional compiles to omit parts of the API and the infrastructure
to support them: STB_VORBIS_NO_PULLDATA_API, STB_VORBIS_NO_PUSHDATA_API,
STB_VORBIS_NO_STDIO, STB_VORBIS_NO_INTEGER_CONVERSION
- 0.90 - first public release
It is my intent that this implementation does not infringe the copyrights
or other intellectual property of anyone. In particular, I did not look
at the source code to the Ogg Vorbis reference implementation by Xiph.org.
The implementation was primarily created from the Ogg and Vorbis specifications
available on the Xiph.org website, and related documents linked by them.
Documents referenced in the log above:
- ogg spec:
- http://xiph.org/vorbis/doc/framing.html
- http://xiph.org/vorbis/doc/oggstream.html
- vorbis spec:
- http://xiph.org/vorbis/doc/Vorbis_I_spec.html
- Sporer et al:
- The
use of multirate filter banks for coding of high quality digital audio,
Th.Sporer, Kh.Brandenburg, B.Edler. (Note that there are errors in the fast-IMDCT
implementation in this paper, even the corrected version.)
-
- wikipedia MDCT:
- http://en.wikipedia.org/wiki/Modified_discrete_cosine_transform
Additionally, I did some further optimization of the MDCT from the original code,
after I stopped keeping the log. This optimization process roughly doubled the
speed of the MDCT. The following files show how the old version was optimized
step by step from the naive 'as written by Sporer et al'.
- mdct_01.txt - original naive implementation using original variable names
- mdct_02.txt - v. 0.90: "optimized" to use only one temporary buffer
- mdct_03.txt - v. 0.999: de-sparsify from using only odd slots; bitreverse in table; skip initial mirroring step
- mdct_04.txt - (inner loop only) optimizing the inner loop of step 3 by making index calculations explicit
- mdct_05.txt - (comments only) notes on optimizing all but the last iteration of step 3
- mdct_06.txt - after splitting off the first iteration, and making a separate case with r nested inside s instead of vice versa, and after doing heavy unrolling/pointer-walk optimizations (I didn't save the intermediate step before optimizing)
- mdct_07.txt - fairly small change: pulling out floating-point add sub-expressions (e.g. X+Y is used twice)
- mdct_08.txt - v. 0.9991: making most steps in-place; combining steps 5+6+7
- mdct_09.txt - (todo description of diffs)
- mdct_10.txt - (todo description of diffs)
- mdct_11.txt - (todo description of diffs)
- mdct_12.txt - (todo description of diffs)
- mdct_13.txt - v. 0.9992: (todo description of diffs)
Versions startings at mdct_11.txt exhibit some error due to a bug in the unrolling of 'step 2' which was fixed in version 0.9994.
Reference data
The Vorbis specification involves the creation of a large quantity of "intermediate
state" that is then transformed (by the IMDCT) into final output. When the final
output of my algorithm was wrong due to bugs in my code, it would have been extremely difficult to
work backwards and decipher where it was going wrong. Instead, I had a friend
generate reference data with the intermediate state defined by the specification.
This data was generated from the Xiph reference implementation; however,
all the generated data is defined by the specification, and beyond this
data there was no information transferred to me about the Xiph implementation.
- test1.ogg
- One of the test files used to generate the reference data; this is what I sent out.
- test1.log (170 KB)
- The output reference data for the test.ogg file. (This consists of the symbols decoded for codebooks, and the various floor, residue, coupled residue, spectral envelope, and post-IMDCT buffers.) This is what I received.
- tests.7z (23 MB)
- The data dump files output containing the reference data for all five test ogg files (I cannot provide the other ogg files for copyright reasons). This is the entirety of what I received.
- muratorigo.log
- muratorigo.xml
- The log of the IM conversation I had instructing my friend
in what I wanted him to output to the reference files. This was our entire conversation
about Ogg Vorbis, so you can verify that no information about the code or its
structure leaked from him to me in the course of this effort. (These files were
created by the IM client Trillian. I do not know why muratorigo.log contains
binary characters.)