=> 4bf163ecfac27c3dd86dff96df6f4647f9afe021
[1mdiff --git a/CMakeLists.txt b/CMakeLists.txt[m [1mindex 15ff9a0a..263942e3 100644[m [1m--- a/CMakeLists.txt[m [1m+++ b/CMakeLists.txt[m [36m@@ -106,8 +106,11 @@[m [mset (SOURCES[m src/visited.c[m src/visited.h[m # Audio playback:[m [32m+[m[32m src/audio/buf.c[m [32m+[m[32m src/audio/buf.h[m src/audio/player.c[m src/audio/player.h[m [32m+[m[32m src/audio/stb_vorbis.c[m # User interface:[m src/ui/color.c[m src/ui/color.h[m [1mdiff --git a/src/audio/buf.c b/src/audio/buf.c[m [1mnew file mode 100644[m [1mindex 00000000..e61164d4[m [1m--- /dev/null[m [1m+++ b/src/audio/buf.c[m [36m@@ -0,0 +1,107 @@[m [32m+[m[32m/* Copyright 2020 Jaakko Keränen[m [32m+[m [32m+[m[32mRedistribution and use in source and binary forms, with or without[m [32m+[m[32mmodification, are permitted provided that the following conditions are met:[m [32m+[m [32m+[m[32m1. Redistributions of source code must retain the above copyright notice, this[m [32m+[m[32m list of conditions and the following disclaimer.[m [32m+[m[32m2. Redistributions in binary form must reproduce the above copyright notice,[m [32m+[m[32m this list of conditions and the following disclaimer in the documentation[m [32m+[m[32m and/or other materials provided with the distribution.[m [32m+[m [32m+[m[32mTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND[m [32m+[m[32mANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED[m [32m+[m[32mWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE[m [32m+[m[32mDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR[m [32m+[m[32mANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES[m [32m+[m[32m(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;[m [32m+[m[32mLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON[m [32m+[m[32mANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT[m [32m+[m[32m(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS[m [32m+[m[32mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m [32m+[m [32m+[m[32m#include "buf.h"[m [32m+[m [32m+[m[32miDefineTypeConstruction(InputBuf)[m [32m+[m [32m+[m[32mvoid init_InputBuf(iInputBuf *d) {[m [32m+[m[32m init_Mutex(&d->mtx);[m [32m+[m[32m init_Condition(&d->changed);[m [32m+[m[32m init_Block(&d->data, 0);[m [32m+[m[32m d->isComplete = iTrue;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid deinit_InputBuf(iInputBuf *d) {[m [32m+[m[32m deinit_Block(&d->data);[m [32m+[m[32m deinit_Condition(&d->changed);[m [32m+[m[32m deinit_Mutex(&d->mtx);[m [32m+[m[32m}[m [32m+[m [32m+[m[32msize_t size_InputBuf(const iInputBuf *d) {[m [32m+[m[32m return size_Block(&d->data);[m [32m+[m[32m}[m [32m+[m [32m+[m[32m/*----------------------------------------------------------------------------------------------*/[m [32m+[m [32m+[m[32miDefineTypeConstructionArgs(SampleBuf, (SDL_AudioFormat format, size_t numChannels, size_t count),[m [32m+[m[32m format, numChannels, count)[m [32m+[m [32m+[m[32mvoid init_SampleBuf(iSampleBuf *d, SDL_AudioFormat format, size_t numChannels, size_t count) {[m [32m+[m[32m d->format = format;[m [32m+[m[32m d->numChannels = numChannels;[m [32m+[m[32m d->sampleSize = SDL_AUDIO_BITSIZE(format) / 8 * numChannels;[m [32m+[m[32m d->count = count + 1; /* considered empty if head==tail */[m [32m+[m[32m d->data = malloc(d->sampleSize * d->count);[m [32m+[m[32m d->head = 0;[m [32m+[m[32m d->tail = 0;[m [32m+[m[32m init_Condition(&d->moreNeeded);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid deinit_SampleBuf(iSampleBuf *d) {[m [32m+[m[32m deinit_Condition(&d->moreNeeded);[m [32m+[m[32m free(d->data);[m [32m+[m[32m}[m [32m+[m [32m+[m[32msize_t size_SampleBuf(const iSampleBuf *d) {[m [32m+[m[32m return d->head - d->tail;[m [32m+[m[32m}[m [32m+[m [32m+[m[32msize_t vacancy_SampleBuf(const iSampleBuf *d) {[m [32m+[m[32m return d->count - size_SampleBuf(d) - 1;[m [32m+[m[32m}[m [32m+[m [32m+[m[32miBool isFull_SampleBuf(const iSampleBuf *d) {[m [32m+[m[32m return vacancy_SampleBuf(d) == 0;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid write_SampleBuf(iSampleBuf *d, const void *samples, const size_t n) {[m [32m+[m[32m iAssert(n <= vacancy_SampleBuf(d));[m [32m+[m[32m const size_t headPos = d->head % d->count;[m [32m+[m[32m const size_t avail = d->count - headPos;[m [32m+[m[32m if (n > avail) {[m [32m+[m[32m const char *in = samples;[m [32m+[m[32m memcpy(ptr_SampleBuf_(d, headPos), in, d->sampleSize * avail);[m [32m+[m[32m in += d->sampleSize * avail;[m [32m+[m[32m memcpy(ptr_SampleBuf_(d, 0), in, d->sampleSize * (n - avail));[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m memcpy(ptr_SampleBuf_(d, headPos), samples, d->sampleSize * n);[m [32m+[m[32m }[m [32m+[m[32m d->head += n;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid read_SampleBuf(iSampleBuf *d, const size_t n, void *samples_out) {[m [32m+[m[32m iAssert(n <= size_SampleBuf(d));[m [32m+[m[32m const size_t tailPos = d->tail % d->count;[m [32m+[m[32m const size_t avail = d->count - tailPos;[m [32m+[m[32m if (n > avail) {[m [32m+[m[32m char *out = samples_out;[m [32m+[m[32m memcpy(out, ptr_SampleBuf_(d, tailPos), d->sampleSize * avail);[m [32m+[m[32m out += d->sampleSize * avail;[m [32m+[m[32m memcpy(out, ptr_SampleBuf_(d, 0), d->sampleSize * (n - avail));[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m memcpy(samples_out, ptr_SampleBuf_(d, tailPos), d->sampleSize * n);[m [32m+[m[32m }[m [32m+[m[32m d->tail += n;[m [32m+[m[32m}[m [1mdiff --git a/src/audio/buf.h b/src/audio/buf.h[m [1mnew file mode 100644[m [1mindex 00000000..de123481[m [1m--- /dev/null[m [1m+++ b/src/audio/buf.h[m [36m@@ -0,0 +1,74 @@[m [32m+[m[32m/* Copyright 2020 Jaakko Keränen [m [32m+[m [32m+[m[32mRedistribution and use in source and binary forms, with or without[m [32m+[m[32mmodification, are permitted provided that the following conditions are met:[m [32m+[m [32m+[m[32m1. Redistributions of source code must retain the above copyright notice, this[m [32m+[m[32m list of conditions and the following disclaimer.[m [32m+[m[32m2. Redistributions in binary form must reproduce the above copyright notice,[m [32m+[m[32m this list of conditions and the following disclaimer in the documentation[m [32m+[m[32m and/or other materials provided with the distribution.[m [32m+[m [32m+[m[32mTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND[m [32m+[m[32mANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED[m [32m+[m[32mWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE[m [32m+[m[32mDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR[m [32m+[m[32mANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES[m [32m+[m[32m(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;[m [32m+[m[32mLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON[m [32m+[m[32mANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT[m [32m+[m[32m(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS[m [32m+[m[32mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m [32m+[m [32m+[m[32m#pragma once[m [32m+[m [32m+[m[32m#include "the_Foundation/block.h"[m [32m+[m[32m#include "the_Foundation/mutex.h"[m [32m+[m [32m+[m[32m#include [m [32m+[m [32m+[m[32miDeclareType(InputBuf)[m [32m+[m[32miDeclareType(SampleBuf)[m [32m+[m [32m+[m[32m#if !defined (AUDIO_S24LSB)[m [32m+[m[32m# define AUDIO_S24LSB 0x8018 /* 24-bit integer samples */[m [32m+[m[32m#endif[m [32m+[m[32m#if !defined (AUDIO_F64LSB)[m [32m+[m[32m# define AUDIO_F64LSB 0x8140 /* 64-bit floating point samples */[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32mstruct Impl_InputBuf {[m [32m+[m[32m iMutex mtx;[m [32m+[m[32m iCondition changed;[m [32m+[m[32m iBlock data;[m [32m+[m[32m iBool isComplete;[m [32m+[m[32m};[m [32m+[m [32m+[m[32miDeclareTypeConstruction(InputBuf)[m [32m+[m [32m+[m[32msize_t size_InputBuf (const iInputBuf *);[m [32m+[m [32m+[m[32m/*----------------------------------------------------------------------------------------------*/[m [32m+[m [32m+[m[32mstruct Impl_SampleBuf {[m [32m+[m[32m SDL_AudioFormat format;[m [32m+[m[32m uint8_t numChannels;[m [32m+[m[32m uint8_t sampleSize; /* as bytes; one sample includes values for all channels */[m [32m+[m[32m void * data;[m [32m+[m[32m size_t count;[m [32m+[m[32m size_t head, tail;[m [32m+[m[32m iCondition moreNeeded;[m [32m+[m[32m};[m [32m+[m [32m+[m[32miDeclareTypeConstructionArgs(SampleBuf, SDL_AudioFormat format, size_t numChannels, size_t count)[m [32m+[m [32m+[m[32msize_t size_SampleBuf (const iSampleBuf *);[m [32m+[m[32miBool isFull_SampleBuf (const iSampleBuf *);[m [32m+[m[32msize_t vacancy_SampleBuf (const iSampleBuf *);[m [32m+[m [32m+[m[32miLocalDef void *ptr_SampleBuf_(iSampleBuf *d, size_t pos) {[m [32m+[m[32m return ((char *) d->data) + (d->sampleSize * pos);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mvoid write_SampleBuf (iSampleBuf *, const void *samples, const size_t n);[m [32m+[m[32mvoid read_SampleBuf (iSampleBuf *, const size_t n, void *samples_out);[m [1mdiff --git a/src/audio/player.c b/src/audio/player.c[m [1mindex 07f41f01..0825dabd 100644[m [1m--- a/src/audio/player.c[m [1m+++ b/src/audio/player.c[m [36m@@ -21,146 +21,38 @@[m [mANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT[m SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */[m [m #include "player.h"[m [32m+[m[32m#include "buf.h"[m [32m+[m [32m+[m[32m#define STB_VORBIS_HEADER_ONLY[m [32m+[m[32m#include "stb_vorbis.c"[m [m #include [m #include [m #include [m [m [31m-iDeclareType(InputBuf)[m [31m-[m [31m-#if !defined (AUDIO_S24LSB)[m [31m-# define AUDIO_S24LSB 0x8018 /* 24-bit integer samples */[m [31m-#endif[m [31m-#if !defined (AUDIO_F64LSB)[m [31m-# define AUDIO_F64LSB 0x8140 /* 64-bit floating point samples */[m [31m-#endif[m [31m-[m [31m-struct Impl_InputBuf {[m [31m- iMutex mtx;[m [31m- iCondition changed;[m [31m- iBlock data;[m [31m- iBool isComplete;[m [31m-};[m [31m-[m [31m-void init_InputBuf(iInputBuf *d) {[m [31m- init_Mutex(&d->mtx);[m [31m- init_Condition(&d->changed);[m [31m- init_Block(&d->data, 0);[m [31m- d->isComplete = iTrue;[m [31m-}[m [31m-[m [31m-void deinit_InputBuf(iInputBuf *d) {[m [31m- deinit_Block(&d->data);[m [31m- deinit_Condition(&d->changed);[m [31m- deinit_Mutex(&d->mtx);[m [31m-}[m [31m-[m [31m-size_t size_InputBuf(const iInputBuf *d) {[m [31m- return size_Block(&d->data);[m [31m-}[m [31m-[m [31m-iDefineTypeConstruction(InputBuf)[m [31m-[m [31m-/*----------------------------------------------------------------------------------------------*/[m [31m-[m [31m-iDeclareType(SampleBuf)[m [31m-[m [31m-struct Impl_SampleBuf {[m [31m- SDL_AudioFormat format;[m [31m- uint8_t numChannels;[m [31m- uint8_t sampleSize; /* as bytes; one sample includes values for all channels */[m [31m- void * data;[m [31m- size_t count;[m [31m- size_t head, tail;[m [31m- iCondition moreNeeded;[m [31m-};[m [31m-[m [31m-void init_SampleBuf(iSampleBuf *d, SDL_AudioFormat format, size_t numChannels, size_t count) {[m [31m- d->format = format;[m [31m- d->numChannels = numChannels;[m [31m- d->sampleSize = SDL_AUDIO_BITSIZE(format) / 8 * numChannels;[m [31m- d->count = count + 1; /* considered empty if head==tail */[m [31m- d->data = malloc(d->sampleSize * d->count);[m [31m- d->head = 0;[m [31m- d->tail = 0;[m [31m- init_Condition(&d->moreNeeded);[m [31m-}[m [31m-[m [31m-void deinit_SampleBuf(iSampleBuf *d) {[m [31m- deinit_Condition(&d->moreNeeded);[m [31m- free(d->data);[m [31m-}[m [31m-[m [31m-size_t size_SampleBuf(const iSampleBuf *d) {[m [31m- return d->head - d->tail;[m [31m-}[m [31m-[m [31m-size_t vacancy_SampleBuf(const iSampleBuf *d) {[m [31m- return d->count - size_SampleBuf(d) - 1;[m [31m-}[m [31m-[m [31m-iBool isFull_SampleBuf(const iSampleBuf *d) {[m [31m- return vacancy_SampleBuf(d) == 0;[m [31m-}[m [31m-[m [31m-iLocalDef void *ptr_SampleBuf_(iSampleBuf *d, size_t pos) {[m [31m- return ((char *) d->data) + (d->sampleSize * pos);[m [31m-}[m [31m-[m [31m-void write_SampleBuf(iSampleBuf *d, const void *samples, const size_t n) {[m [31m- iAssert(n <= vacancy_SampleBuf(d));[m [31m- const size_t headPos = d->head % d->count;[m [31m- const size_t avail = d->count - headPos;[m [31m- if (n > avail) {[m [31m- const char *in = samples;[m [31m- memcpy(ptr_SampleBuf_(d, headPos), in, d->sampleSize * avail);[m [31m- in += d->sampleSize * avail;[m [31m- memcpy(ptr_SampleBuf_(d, 0), in, d->sampleSize * (n - avail));[m [31m- }[m [31m- else {[m [31m- memcpy(ptr_SampleBuf_(d, headPos), samples, d->sampleSize * n);[m [31m- }[m [31m- d->head += n;[m [31m-}[m [31m-[m [31m-void read_SampleBuf(iSampleBuf *d, const size_t n, void *samples_out) {[m [31m- iAssert(n <= size_SampleBuf(d));[m [31m- const size_t tailPos = d->tail % d->count;[m [31m- const size_t avail = d->count - tailPos;[m [31m- if (n > avail) {[m [31m- char *out = samples_out;[m [31m- memcpy(out, ptr_SampleBuf_(d, tailPos), d->sampleSize * avail);[m [31m- out += d->sampleSize * avail;[m [31m- memcpy(out, ptr_SampleBuf_(d, 0), d->sampleSize * (n - avail));[m [31m- }[m [31m- else {[m [31m- memcpy(samples_out, ptr_SampleBuf_(d, tailPos), d->sampleSize * n);[m [31m- }[m [31m- d->tail += n;[m [31m-}[m [31m-[m /*----------------------------------------------------------------------------------------------*/[m [m iDeclareType(ContentSpec)[m [m [31m-struct Impl_ContentSpec {[m [31m- SDL_AudioFormat inputFormat;[m [31m- SDL_AudioSpec output;[m [31m- size_t totalInputSize;[m [31m- uint64_t totalSamples;[m [31m- iRanges wavData;[m [31m-};[m [31m-[m [31m-iDeclareType(Decoder)[m [31m-[m enum iDecoderType {[m none_DecoderType,[m wav_DecoderType,[m [31m- mpeg_DecoderType,[m vorbis_DecoderType,[m [32m+[m[32m mpeg_DecoderType,[m midi_DecoderType,[m };[m [m [32m+[m[32mstruct Impl_ContentSpec {[m [32m+[m[32m enum iDecoderType type;[m [32m+[m[32m SDL_AudioFormat inputFormat;[m [32m+[m[32m SDL_AudioSpec output;[m [32m+[m[32m size_t totalInputSize;[m [32m+[m[32m uint64_t totalSamples;[m [32m+[m[32m iRanges dataRange;[m [32m+[m[32m};[m [32m+[m [32m+[m[32miDeclareType(Decoder)[m [32m+[m struct Impl_Decoder {[m enum iDecoderType type;[m float gain;[m [36m@@ -176,12 +68,12 @@[m [mstruct Impl_Decoder {[m iRanges wavData;[m };[m [m [31m-enum iDecoderParseStatus {[m [31m- ok_DecoderParseStatus,[m [31m- needMoreInput_DecoderParseStatus,[m [32m+[m[32menum iDecoderStatus {[m [32m+[m[32m ok_DecoderStatus,[m [32m+[m[32m needMoreInput_DecoderStatus,[m };[m [m [31m-static enum iDecoderParseStatus parseWav_Decoder_(iDecoder *d, iRanges inputRange) {[m [32m+[m[32mstatic enum iDecoderStatus decodeWav_Decoder_(iDecoder *d, iRanges inputRange) {[m const uint8_t numChannels = d->output.numChannels;[m const size_t inputSampleSize = numChannels * SDL_AUDIO_BITSIZE(d->inputFormat) / 8;[m const size_t vacancy = vacancy_SampleBuf(&d->output);[m [36m@@ -189,11 +81,11 @@[m [mstatic enum iDecoderParseStatus parseWav_Decoder_(iDecoder *d, iRanges inputRang[m const size_t avail =[m iMin(inputRange.end - inputBytePos, d->wavData.end - inputBytePos) / inputSampleSize;[m if (avail == 0) {[m [31m- return needMoreInput_DecoderParseStatus;[m [32m+[m[32m return needMoreInput_DecoderStatus;[m }[m const size_t n = iMin(vacancy, avail);[m if (n == 0) {[m [31m- return ok_DecoderParseStatus;[m [32m+[m[32m return ok_DecoderStatus;[m }[m void *samples = malloc(inputSampleSize * n);[m /* Get a copy of the input for mixing. */ {[m [36m@@ -259,7 +151,7 @@[m [mstatic enum iDecoderParseStatus parseWav_Decoder_(iDecoder *d, iRanges inputRang[m iGuardMutex(&d->outputMutex, write_SampleBuf(&d->output, samples, n));[m d->currentSample += n;[m free(samples);[m [31m- return ok_DecoderParseStatus;[m [32m+[m[32m return ok_DecoderStatus;[m }[m [m static iThreadResult run_Decoder_(iThread *thread) {[m [36m@@ -273,17 +165,17 @@[m [mstatic iThreadResult run_Decoder_(iThread *thread) {[m iAssert(inputRange.start <= inputRange.end);[m if (!d->type) break;[m /* Have data to work on and a place to save output? */[m [31m- enum iDecoderParseStatus status = ok_DecoderParseStatus;[m [32m+[m[32m enum iDecoderStatus status = ok_DecoderStatus;[m if (!isEmpty_Range(&inputRange)) {[m switch (d->type) {[m case wav_DecoderType:[m [31m- status = parseWav_Decoder_(d, inputRange);[m [32m+[m[32m status = decodeWav_Decoder_(d, inputRange);[m break;[m default:[m break;[m }[m }[m [31m- if (status == needMoreInput_DecoderParseStatus) {[m [32m+[m[32m if (status == needMoreInput_DecoderStatus) {[m lock_Mutex(&d->input->mtx);[m if (size_InputBuf(d->input) == inputSize) {[m wait_Condition(&d->input->changed, &d->input->mtx);[m [36m@@ -302,10 +194,10 @@[m [mstatic iThreadResult run_Decoder_(iThread *thread) {[m }[m [m void init_Decoder(iDecoder *d, iInputBuf *input, const iContentSpec *spec) {[m [31m- d->type = wav_DecoderType;[m [32m+[m[32m d->type = spec->type;[m d->gain = 0.5f;[m d->input = input;[m [31m- d->inputPos = spec->wavData.start;[m [32m+[m[32m d->inputPos = spec->dataRange.start;[m d->inputFormat = spec->inputFormat;[m d->totalInputSize = spec->totalInputSize;[m init_SampleBuf(&d->output,[m [36m@@ -330,16 +222,22 @@[m [mvoid deinit_Decoder(iDecoder *d) {[m deinit_SampleBuf(&d->output);[m }[m [m [32m+[m[32mstatic void start_Decoder_(iDecoder *d) {[m [32m+[m[32m if (!d->thread && d->type != none_DecoderType) {[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m iDefineTypeConstructionArgs(Decoder, (iInputBuf *input, const iContentSpec *spec),[m input, spec)[m [m /*----------------------------------------------------------------------------------------------*/[m [m struct Impl_Player {[m [31m- SDL_AudioSpec spec;[m [32m+[m[32m SDL_AudioSpec spec;[m SDL_AudioDeviceID device;[m [31m- iInputBuf *data;[m [31m- iDecoder *decoder;[m [32m+[m[32m iString mime;[m [32m+[m[32m iInputBuf * data;[m [32m+[m[32m iDecoder * decoder;[m };[m [m iDefineTypeConstruction(Player)[m [36m@@ -358,8 +256,8 @@[m [mstatic iContentSpec contentSpec_Player_(const iPlayer *d) {[m const size_t dataSize = size_InputBuf(d->data);[m iBuffer *buf = iClob(new_Buffer());[m open_Buffer(buf, &d->data->data);[m [31m- enum iDecoderType decType = wav_DecoderType; /* TODO: from MIME */[m [31m- if (decType == wav_DecoderType && dataSize >= 44) {[m [32m+[m[32m content.type = wav_DecoderType; /* TODO: from MIME */[m [32m+[m[32m if (content.type == wav_DecoderType && dataSize >= 44) {[m /* Read the RIFF/WAVE header. */[m iStream *is = stream_Buffer(buf);[m char magic[4];[m [36m@@ -428,8 +326,8 @@[m [mstatic iContentSpec contentSpec_Player_(const iPlayer *d) {[m }[m }[m else if (memcmp(magic, "data", 4) == 0) {[m [31m- content.wavData = (iRanges){ pos_Stream(is), pos_Stream(is) + size };[m [31m- content.totalSamples = (uint64_t) size_Range(&content.wavData) / blockAlign;[m [32m+[m[32m content.dataRange = (iRanges){ pos_Stream(is), pos_Stream(is) + size };[m [32m+[m[32m content.totalSamples = (uint64_t) size_Range(&content.dataRange) / blockAlign;[m break;[m }[m else {[m [36m@@ -462,6 +360,7 @@[m [mstatic void writeOutputSamples_Player_(void *plr, Uint8 *stream, int len) {[m [m void init_Player(iPlayer *d) {[m iZap(d->spec);[m [32m+[m[32m init_String(&d->mime);[m d->device = 0;[m d->decoder = NULL;[m d->data = new_InputBuf();[m [36m@@ -470,6 +369,7 @@[m [mvoid init_Player(iPlayer *d) {[m void deinit_Player(iPlayer *d) {[m stop_Player(d);[m delete_InputBuf(d->data);[m [32m+[m[32m deinit_String(&d->mime);[m }[m [m iBool isStarted_Player(const iPlayer *d) {[m [36m@@ -481,13 +381,14 @@[m [miBool isPaused_Player(const iPlayer *d) {[m return SDL_GetAudioDeviceStatus(d->device) == SDL_AUDIO_PAUSED;[m }[m [m [31m-void setFormatHint_Player(iPlayer *d, const char *hint) {[m [31m-}[m [31m-[m [31m-void updateSourceData_Player(iPlayer *d, const iBlock *data, enum iPlayerUpdate update) {[m [32m+[m[32mvoid updateSourceData_Player(iPlayer *d, const iString *mimeType, const iBlock *data,[m [32m+[m[32m enum iPlayerUpdate update) {[m /* TODO: Add MIME as argument */[m iInputBuf *input = d->data;[m lock_Mutex(&input->mtx);[m [32m+[m[32m if (mimeType) {[m [32m+[m[32m set_String(&d->mime, mimeType);[m [32m+[m[32m }[m switch (update) {[m case replace_PlayerUpdate:[m set_Block(&input->data, data);[m [36m@@ -515,7 +416,7 @@[m [miBool start_Player(iPlayer *d) {[m if (isStarted_Player(d)) {[m return iFalse;[m }[m [31m- iContentSpec content = contentSpec_Player_(d);[m [32m+[m[32m iContentSpec content = contentSpec_Player_(d);[m content.output.callback = writeOutputSamples_Player_;[m content.output.userdata = d;[m d->device = SDL_OpenAudioDevice(NULL, SDL_FALSE /* playback */, &content.output, &d->spec, 0);[m [1mdiff --git a/src/audio/player.h b/src/audio/player.h[m [1mindex fe6717b0..720f2d78 100644[m [1m--- a/src/audio/player.h[m [1m+++ b/src/audio/player.h[m [36m@@ -33,8 +33,8 @@[m [menum iPlayerUpdate {[m complete_PlayerUpdate,[m };[m [m [31m-void setFormatHint_Player (iPlayer *, const char *hint);[m [31m-void updateSourceData_Player (iPlayer *, const iBlock *data, enum iPlayerUpdate update);[m [32m+[m[32mvoid updateSourceData_Player (iPlayer *, const iString *mimeType, const iBlock *data,[m [32m+[m[32m enum iPlayerUpdate update);[m [m iBool start_Player (iPlayer *);[m void setPaused_Player (iPlayer *, iBool isPaused);[m [1mdiff --git a/src/audio/stb_vorbis.c b/src/audio/stb_vorbis.c[m [1mnew file mode 100644[m [1mindex 00000000..a8cbfa6c[m [1m--- /dev/null[m [1m+++ b/src/audio/stb_vorbis.c[m [36m@@ -0,0 +1,5563 @@[m [32m+[m[32m// Ogg Vorbis audio decoder - v1.20 - public domain[m [32m+[m[32m// http://nothings.org/stb_vorbis/[m [32m+[m[32m//[m [32m+[m[32m// Original version written by Sean Barrett in 2007.[m [32m+[m[32m//[m [32m+[m[32m// Originally sponsored by RAD Game Tools. Seeking implementation[m [32m+[m[32m// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker,[m [32m+[m[32m// Elias Software, Aras Pranckevicius, and Sean Barrett.[m [32m+[m[32m//[m [32m+[m[32m// LICENSE[m [32m+[m[32m//[m [32m+[m[32m// See end of file for license information.[m [32m+[m[32m//[m [32m+[m[32m// Limitations:[m [32m+[m[32m//[m [32m+[m[32m// - floor 0 not supported (used in old ogg vorbis files pre-2004)[m [32m+[m[32m// - lossless sample-truncation at beginning ignored[m [32m+[m[32m// - cannot concatenate multiple vorbis streams[m [32m+[m[32m// - sample positions are 32-bit, limiting seekable 192Khz[m [32m+[m[32m// files to around 6 hours (Ogg supports 64-bit)[m [32m+[m[32m//[m [32m+[m[32m// Feature contributors:[m [32m+[m[32m// Dougall Johnson (sample-exact seeking)[m [32m+[m[32m//[m [32m+[m[32m// Bugfix/warning contributors:[m [32m+[m[32m// Terje Mathisen Niklas Frykholm Andy Hill[m [32m+[m[32m// Casey Muratori John Bolton Gargaj[m [32m+[m[32m// Laurent Gomila Marc LeBlanc Ronny Chevalier[m [32m+[m[32m// Bernhard Wodo Evan Balster github:alxprd[m [32m+[m[32m// Tom Beaumont Ingo Leitgeb Nicolas Guillemot[m [32m+[m[32m// Phillip Bennefall Rohit Thiago Goulart[m [32m+[m[32m// github:manxorist saga musix github:infatum[m [32m+[m[32m// Timur Gagiev Maxwell Koo Peter Waller[m [32m+[m[32m// github:audinowho Dougall Johnson David Reid[m [32m+[m[32m// github:Clownacy Pedro J. Estebanez Remi Verschelde[m [32m+[m[32m//[m [32m+[m[32m// Partial history:[m [32m+[m[32m// 1.20 - 2020-07-11 - several small fixes[m [32m+[m[32m// 1.19 - 2020-02-05 - warnings[m [32m+[m[32m// 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc.[m [32m+[m[32m// 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure)[m [32m+[m[32m// 1.16 - 2019-03-04 - fix warnings[m [32m+[m[32m// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found[m [32m+[m[32m// 1.14 - 2018-02-11 - delete bogus dealloca usage[m [32m+[m[32m// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully)[m [32m+[m[32m// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files[m [32m+[m[32m// 1.11 - 2017-07-23 - fix MinGW compilation[m [32m+[m[32m// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory[m [32m+[m[32m// 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version[m [32m+[m[32m// 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame[m [32m+[m[32m// 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const[m [32m+[m[32m// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson)[m [32m+[m[32m// some crash fixes when out of memory or with corrupt files[m [32m+[m[32m// fix some inappropriately signed shifts[m [32m+[m[32m// 1.05 - 2015-04-19 - don't define __forceinline if it's redundant[m [32m+[m[32m// 1.04 - 2014-08-27 - fix missing const-correct case in API[m [32m+[m[32m// 1.03 - 2014-08-07 - warning fixes[m [32m+[m[32m// 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows[m [32m+[m[32m// 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct)[m [32m+[m[32m// 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel;[m [32m+[m[32m// (API change) report sample rate for decode-full-file funcs[m [32m+[m[32m//[m [32m+[m[32m// See end of file for full version history.[m [32m+[m [32m+[m [32m+[m[32m//////////////////////////////////////////////////////////////////////////////[m [32m+[m[32m//[m [32m+[m[32m// HEADER BEGINS HERE[m [32m+[m[32m//[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H[m [32m+[m[32m#define STB_VORBIS_INCLUDE_STB_VORBIS_H[m [32m+[m [32m+[m[32m#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)[m [32m+[m[32m#define STB_VORBIS_NO_STDIO 1[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m#include [m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#ifdef __cplusplus[m [32m+[m[32mextern "C" {[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m/////////// THREAD SAFETY[m [32m+[m [32m+[m[32m// Individual stb_vorbis* handles are not thread-safe; you cannot decode from[m [32m+[m[32m// them from multiple threads at the same time. However, you can have multiple[m [32m+[m[32m// stb_vorbis* handles and decode from them independently in multiple thrads.[m [32m+[m [32m+[m [32m+[m[32m/////////// MEMORY ALLOCATION[m [32m+[m [32m+[m[32m// normally stb_vorbis uses malloc() to allocate memory at startup,[m [32m+[m[32m// and alloca() to allocate temporary memory during a frame on the[m [32m+[m[32m// stack. (Memory consumption will depend on the amount of setup[m [32m+[m[32m// data in the file and how you set the compile flags for speed[m [32m+[m[32m// vs. size. In my test files the maximal-size usage is ~150KB.)[m [32m+[m[32m//[m [32m+[m[32m// You can modify the wrapper functions in the source (setup_malloc,[m [32m+[m[32m// setup_temp_malloc, temp_malloc) to change this behavior, or you[m [32m+[m[32m// can use a simpler allocation model: you pass in a buffer from[m [32m+[m[32m// which stb_vorbis will allocate _all_ its memory (including the[m [32m+[m[32m// temp memory). "open" may fail with a VORBIS_outofmem if you[m [32m+[m[32m// do not pass in enough data; there is no way to determine how[m [32m+[m[32m// much you do need except to succeed (at which point you can[m [32m+[m[32m// query get_info to find the exact amount required. yes I know[m [32m+[m[32m// this is lame).[m [32m+[m[32m//[m [32m+[m[32m// If you pass in a non-NULL buffer of the type below, allocation[m [32m+[m[32m// will occur from it as described above. Otherwise just pass NULL[m [32m+[m[32m// to use malloc()/alloca()[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m char *alloc_buffer;[m [32m+[m[32m int alloc_buffer_length_in_bytes;[m [32m+[m[32m} stb_vorbis_alloc;[m [32m+[m [32m+[m [32m+[m[32m/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES[m [32m+[m [32m+[m[32mtypedef struct stb_vorbis stb_vorbis;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m unsigned int sample_rate;[m [32m+[m[32m int channels;[m [32m+[m [32m+[m[32m unsigned int setup_memory_required;[m [32m+[m[32m unsigned int setup_temp_memory_required;[m [32m+[m[32m unsigned int temp_memory_required;[m [32m+[m [32m+[m[32m int max_frame_size;[m [32m+[m[32m} stb_vorbis_info;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m char *vendor;[m [32m+[m [32m+[m[32m int comment_list_length;[m [32m+[m[32m char **comment_list;[m [32m+[m[32m} stb_vorbis_comment;[m [32m+[m [32m+[m[32m// get general information about the file[m [32m+[m[32mextern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);[m [32m+[m [32m+[m[32m// get ogg comments[m [32m+[m[32mextern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f);[m [32m+[m [32m+[m[32m// get the last error detected (clears it, too)[m [32m+[m[32mextern int stb_vorbis_get_error(stb_vorbis *f);[m [32m+[m [32m+[m[32m// close an ogg vorbis file and free all memory in use[m [32m+[m[32mextern void stb_vorbis_close(stb_vorbis *f);[m [32m+[m [32m+[m[32m// this function returns the offset (in samples) from the beginning of the[m [32m+[m[32m// file that will be returned by the next decode, if it is known, or -1[m [32m+[m[32m// otherwise. after a flush_pushdata() call, this may take a while before[m [32m+[m[32m// it becomes valid again.[m [32m+[m[32m// NOT WORKING YET after a seek with PULLDATA API[m [32m+[m[32mextern int stb_vorbis_get_sample_offset(stb_vorbis *f);[m [32m+[m [32m+[m[32m// returns the current seek point within the file, or offset from the beginning[m [32m+[m[32m// of the memory buffer. In pushdata mode it returns 0.[m [32m+[m[32mextern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);[m [32m+[m [32m+[m[32m/////////// PUSHDATA API[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_PUSHDATA_API[m [32m+[m [32m+[m[32m// this API allows you to get blocks of data from any source and hand[m [32m+[m[32m// them to stb_vorbis. you have to buffer them; stb_vorbis will tell[m [32m+[m[32m// you how much it used, and you have to give it the rest next time;[m [32m+[m[32m// and stb_vorbis may not have enough data to work with and you will[m [32m+[m[32m// need to give it the same data again PLUS more. Note that the Vorbis[m [32m+[m[32m// specification does not bound the size of an individual frame.[m [32m+[m [32m+[m[32mextern stb_vorbis *stb_vorbis_open_pushdata([m [32m+[m[32m const unsigned char * datablock, int datablock_length_in_bytes,[m [32m+[m[32m int *datablock_memory_consumed_in_bytes,[m [32m+[m[32m int *error,[m [32m+[m[32m const stb_vorbis_alloc *alloc_buffer);[m [32m+[m[32m// create a vorbis decoder by passing in the initial data block containing[m [32m+[m[32m// the ogg&vorbis headers (you don't need to do parse them, just provide[m [32m+[m[32m// the first N bytes of the file--you're told if it's not enough, see below)[m [32m+[m[32m// on success, returns an stb_vorbis *, does not set error, returns the amount of[m [32m+[m[32m// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;[m [32m+[m[32m// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed[m [32m+[m[32m// if returns NULL and *error is VORBIS_need_more_data, then the input block was[m [32m+[m[32m// incomplete and you need to pass in a larger block from the start of the file[m [32m+[m [32m+[m[32mextern int stb_vorbis_decode_frame_pushdata([m [32m+[m[32m stb_vorbis *f,[m [32m+[m[32m const unsigned char *datablock, int datablock_length_in_bytes,[m [32m+[m[32m int *channels, // place to write number of float * buffers[m [32m+[m[32m float ***output, // place to write float ** array of float * buffers[m [32m+[m[32m int *samples // place to write number of output samples[m [32m+[m[32m );[m [32m+[m[32m// decode a frame of audio sample data if possible from the passed-in data block[m [32m+[m[32m//[m [32m+[m[32m// return value: number of bytes we used from datablock[m [32m+[m[32m//[m [32m+[m[32m// possible cases:[m [32m+[m[32m// 0 bytes used, 0 samples output (need more data)[m [32m+[m[32m// N bytes used, 0 samples output (resynching the stream, keep going)[m [32m+[m[32m// N bytes used, M samples output (one frame of data)[m [32m+[m[32m// note that after opening a file, you will ALWAYS get one N-bytes,0-sample[m [32m+[m[32m// frame, because Vorbis always "discards" the first frame.[m [32m+[m[32m//[m [32m+[m[32m// Note that on resynch, stb_vorbis will rarely consume all of the buffer,[m [32m+[m[32m// instead only datablock_length_in_bytes-3 or less. This is because it wants[m [32m+[m[32m// to avoid missing parts of a page header if they cross a datablock boundary,[m [32m+[m[32m// without writing state-machiney code to record a partial detection.[m [32m+[m[32m//[m [32m+[m[32m// The number of channels returned are stored in *channels (which can be[m [32m+[m[32m// NULL--it is always the same as the number of channels reported by[m [32m+[m[32m// get_info). *output will contain an array of float* buffers, one per[m [32m+[m[32m// channel. In other words, (*output)[0][0] contains the first sample from[m [32m+[m[32m// the first channel, and (*output)[1][0] contains the first sample from[m [32m+[m[32m// the second channel.[m [32m+[m [32m+[m[32mextern void stb_vorbis_flush_pushdata(stb_vorbis *f);[m [32m+[m[32m// inform stb_vorbis that your next datablock will not be contiguous with[m [32m+[m[32m// previous ones (e.g. you've seeked in the data); future attempts to decode[m [32m+[m[32m// frames will cause stb_vorbis to resynchronize (as noted above), and[m [32m+[m[32m// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it[m [32m+[m[32m// will begin decoding the _next_ frame.[m [32m+[m[32m//[m [32m+[m[32m// if you want to seek using pushdata, you need to seek in your file, then[m [32m+[m[32m// call stb_vorbis_flush_pushdata(), then start calling decoding, then once[m [32m+[m[32m// decoding is returning you data, call stb_vorbis_get_sample_offset, and[m [32m+[m[32m// if you don't like the result, seek your file again and repeat.[m [32m+[m[32m#endif[m [32m+[m [32m+[m [32m+[m[32m////////// PULLING INPUT API[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_PULLDATA_API[m [32m+[m[32m// This API assumes stb_vorbis is allowed to pull data from a source--[m [32m+[m[32m// either a block of memory containing the _entire_ vorbis stream, or a[m [32m+[m[32m// FILE * that you or it create, or possibly some other reading mechanism[m [32m+[m[32m// if you go modify the source to replace the FILE * case with some kind[m [32m+[m[32m// of callback to your code. (But if you don't support seeking, you may[m [32m+[m[32m// just want to go ahead and use pushdata.)[m [32m+[m [32m+[m[32m#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)[m [32m+[m[32mextern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);[m [32m+[m[32m#endif[m [32m+[m[32m#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)[m [32m+[m[32mextern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);[m [32m+[m[32m#endif[m [32m+[m[32m// decode an entire file and output the data interleaved into a malloc()ed[m [32m+[m[32m// buffer stored in *output. The return value is the number of samples[m [32m+[m[32m// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.[m [32m+[m[32m// When you're done with it, just free() the pointer returned in *output.[m [32m+[m [32m+[m[32mextern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,[m [32m+[m[32m int *error, const stb_vorbis_alloc *alloc_buffer);[m [32m+[m[32m// create an ogg vorbis decoder from an ogg vorbis stream in memory (note[m [32m+[m[32m// this must be the entire stream!). on failure, returns NULL and sets *error[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32mextern stb_vorbis * stb_vorbis_open_filename(const char *filename,[m [32m+[m[32m int *error, const stb_vorbis_alloc *alloc_buffer);[m [32m+[m[32m// create an ogg vorbis decoder from a filename via fopen(). on failure,[m [32m+[m[32m// returns NULL and sets *error (possibly to VORBIS_file_open_failure).[m [32m+[m [32m+[m[32mextern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,[m [32m+[m[32m int *error, const stb_vorbis_alloc *alloc_buffer);[m [32m+[m[32m// create an ogg vorbis decoder from an open FILE *, looking for a stream at[m [32m+[m[32m// the _current_ seek point (ftell). on failure, returns NULL and sets *error.[m [32m+[m[32m// note that stb_vorbis must "own" this stream; if you seek it in between[m [32m+[m[32m// calls to stb_vorbis, it will become confused. Moreover, if you attempt to[m [32m+[m[32m// perform stb_vorbis_seek_*() operations on this file, it will assume it[m [32m+[m[32m// owns the _entire_ rest of the file after the start point. Use the next[m [32m+[m[32m// function, stb_vorbis_open_file_section(), to limit it.[m [32m+[m [32m+[m[32mextern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,[m [32m+[m[32m int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);[m [32m+[m[32m// create an ogg vorbis decoder from an open FILE *, looking for a stream at[m [32m+[m[32m// the _current_ seek point (ftell); the stream will be of length 'len' bytes.[m [32m+[m[32m// on failure, returns NULL and sets *error. note that stb_vorbis must "own"[m [32m+[m[32m// this stream; if you seek it in between calls to stb_vorbis, it will become[m [32m+[m[32m// confused.[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32mextern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);[m [32m+[m[32mextern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);[m [32m+[m[32m// these functions seek in the Vorbis file to (approximately) 'sample_number'.[m [32m+[m[32m// after calling seek_frame(), the next call to get_frame_*() will include[m [32m+[m[32m// the specified sample. after calling stb_vorbis_seek(), the next call to[m [32m+[m[32m// stb_vorbis_get_samples_* will start with the specified sample. If you[m [32m+[m[32m// do not need to seek to EXACTLY the target sample when using get_samples_*,[m [32m+[m[32m// you can also use seek_frame().[m [32m+[m [32m+[m[32mextern int stb_vorbis_seek_start(stb_vorbis *f);[m [32m+[m[32m// this function is equivalent to stb_vorbis_seek(f,0)[m [32m+[m [32m+[m[32mextern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);[m [32m+[m[32mextern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);[m [32m+[m[32m// these functions return the total length of the vorbis stream[m [32m+[m [32m+[m[32mextern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);[m [32m+[m[32m// decode the next frame and return the number of samples. the number of[m [32m+[m[32m// channels returned are stored in *channels (which can be NULL--it is always[m [32m+[m[32m// the same as the number of channels reported by get_info). *output will[m [32m+[m[32m// contain an array of float* buffers, one per channel. These outputs will[m [32m+[m[32m// be overwritten on the next call to stb_vorbis_get_frame_*.[m [32m+[m[32m//[m [32m+[m[32m// You generally should not intermix calls to stb_vorbis_get_frame_*()[m [32m+[m[32m// and stb_vorbis_get_samples_*(), since the latter calls the former.[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_INTEGER_CONVERSION[m [32m+[m[32mextern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);[m [32m+[m[32mextern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);[m [32m+[m[32m#endif[m [32m+[m[32m// decode the next frame and return the number of *samples* per channel.[m [32m+[m[32m// Note that for interleaved data, you pass in the number of shorts (the[m [32m+[m[32m// size of your array), but the return value is the number of samples per[m [32m+[m[32m// channel, not the total number of samples.[m [32m+[m[32m//[m [32m+[m[32m// The data is coerced to the number of channels you request according to the[m [32m+[m[32m// channel coercion rules (see below). You must pass in the size of your[m [32m+[m[32m// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.[m [32m+[m[32m// The maximum buffer size needed can be gotten from get_info(); however,[m [32m+[m[32m// the Vorbis I specification implies an absolute maximum of 4096 samples[m [32m+[m[32m// per channel.[m [32m+[m [32m+[m[32m// Channel coercion rules:[m [32m+[m[32m// Let M be the number of channels requested, and N the number of channels present,[m [32m+[m[32m// and Cn be the nth channel; let stereo L be the sum of all L and center channels,[m [32m+[m[32m// and stereo R be the sum of all R and center channels (channel assignment from the[m [32m+[m[32m// vorbis spec).[m [32m+[m[32m// M N output[m [32m+[m[32m// 1 k sum(Ck) for all k[m [32m+[m[32m// 2 * stereo L, stereo R[m [32m+[m[32m// k l k > l, the first l channels, then 0s[m [32m+[m[32m// k l k <= l, the first k channels[m [32m+[m[32m// Note that this is not _good_ surround etc. mixing at all! It's just so[m [32m+[m[32m// you get something useful.[m [32m+[m [32m+[m[32mextern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);[m [32m+[m[32mextern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);[m [32m+[m[32m// gets num_samples samples, not necessarily on a frame boundary--this requires[m [32m+[m[32m// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.[m [32m+[m[32m// Returns the number of samples stored per channel; it may be less than requested[m [32m+[m[32m// at the end of the file. If there are no more samples in the file, returns 0.[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_INTEGER_CONVERSION[m [32m+[m[32mextern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);[m [32m+[m[32mextern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);[m [32m+[m[32m#endif[m [32m+[m[32m// gets num_samples samples, not necessarily on a frame boundary--this requires[m [32m+[m[32m// buffering so you have to supply the buffers. Applies the coercion rules above[m [32m+[m[32m// to produce 'channels' channels. Returns the number of samples stored per channel;[m [32m+[m[32m// it may be less than requested at the end of the file. If there are no more[m [32m+[m[32m// samples in the file, returns 0.[m [32m+[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m//////// ERROR CODES[m [32m+[m [32m+[m[32menum STBVorbisError[m [32m+[m[32m{[m [32m+[m[32m VORBIS__no_error,[m [32m+[m [32m+[m[32m VORBIS_need_more_data=1, // not a real error[m [32m+[m [32m+[m[32m VORBIS_invalid_api_mixing, // can't mix API modes[m [32m+[m[32m VORBIS_outofmem, // not enough memory[m [32m+[m[32m VORBIS_feature_not_supported, // uses floor 0[m [32m+[m[32m VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small[m [32m+[m[32m VORBIS_file_open_failure, // fopen() failed[m [32m+[m[32m VORBIS_seek_without_length, // can't seek in unknown-length file[m [32m+[m [32m+[m[32m VORBIS_unexpected_eof=10, // file is truncated?[m [32m+[m[32m VORBIS_seek_invalid, // seek past EOF[m [32m+[m [32m+[m[32m // decoding errors (corrupt/invalid stream) -- you probably[m [32m+[m[32m // don't care about the exact details of these[m [32m+[m [32m+[m[32m // vorbis errors:[m [32m+[m[32m VORBIS_invalid_setup=20,[m [32m+[m[32m VORBIS_invalid_stream,[m [32m+[m [32m+[m[32m // ogg errors:[m [32m+[m[32m VORBIS_missing_capture_pattern=30,[m [32m+[m[32m VORBIS_invalid_stream_structure_version,[m [32m+[m[32m VORBIS_continued_packet_flag_invalid,[m [32m+[m[32m VORBIS_incorrect_stream_serial_number,[m [32m+[m[32m VORBIS_invalid_first_page,[m [32m+[m[32m VORBIS_bad_packet_type,[m [32m+[m[32m VORBIS_cant_find_last_page,[m [32m+[m[32m VORBIS_seek_failed,[m [32m+[m[32m VORBIS_ogg_skeleton_not_supported[m [32m+[m[32m};[m [32m+[m [32m+[m [32m+[m[32m#ifdef __cplusplus[m [32m+[m[32m}[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H[m [32m+[m[32m//[m [32m+[m[32m// HEADER ENDS HERE[m [32m+[m[32m//[m [32m+[m[32m//////////////////////////////////////////////////////////////////////////////[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_HEADER_ONLY[m [32m+[m [32m+[m[32m// global configuration settings (e.g. set these in the project/makefile),[m [32m+[m[32m// or just set them in this file at the top (although ideally the first few[m [32m+[m[32m// should be visible when the header file is compiled too, although it's not[m [32m+[m[32m// crucial)[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_PUSHDATA_API[m [32m+[m[32m// does not compile the code for the various stb_vorbis_*_pushdata()[m [32m+[m[32m// functions[m [32m+[m[32m// #define STB_VORBIS_NO_PUSHDATA_API[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_PULLDATA_API[m [32m+[m[32m// does not compile the code for the non-pushdata APIs[m [32m+[m[32m// #define STB_VORBIS_NO_PULLDATA_API[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_STDIO[m [32m+[m[32m// does not compile the code for the APIs that use FILE *s internally[m [32m+[m[32m// or externally (implied by STB_VORBIS_NO_PULLDATA_API)[m [32m+[m[32m// #define STB_VORBIS_NO_STDIO[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_INTEGER_CONVERSION[m [32m+[m[32m// does not compile the code for converting audio sample data from[m [32m+[m[32m// float to integer (implied by STB_VORBIS_NO_PULLDATA_API)[m [32m+[m[32m// #define STB_VORBIS_NO_INTEGER_CONVERSION[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_FAST_SCALED_FLOAT[m [32m+[m[32m// does not use a fast float-to-int trick to accelerate float-to-int on[m [32m+[m[32m// most platforms which requires endianness be defined correctly.[m [32m+[m[32m//#define STB_VORBIS_NO_FAST_SCALED_FLOAT[m [32m+[m [32m+[m [32m+[m[32m// STB_VORBIS_MAX_CHANNELS [number][m [32m+[m[32m// globally define this to the maximum number of channels you need.[m [32m+[m[32m// The spec does not put a restriction on channels except that[m [32m+[m[32m// the count is stored in a byte, so 255 is the hard limit.[m [32m+[m[32m// Reducing this saves about 16 bytes per value, so using 16 saves[m [32m+[m[32m// (255-16)*16 or around 4KB. Plus anything other memory usage[m [32m+[m[32m// I forgot to account for. Can probably go as low as 8 (7.1 audio),[m [32m+[m[32m// 6 (5.1 audio), or 2 (stereo only).[m [32m+[m[32m#ifndef STB_VORBIS_MAX_CHANNELS[m [32m+[m[32m#define STB_VORBIS_MAX_CHANNELS 16 // enough for anyone?[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m// STB_VORBIS_PUSHDATA_CRC_COUNT [number][m [32m+[m[32m// after a flush_pushdata(), stb_vorbis begins scanning for the[m [32m+[m[32m// next valid page, without backtracking. when it finds something[m [32m+[m[32m// that looks like a page, it streams through it and verifies its[m [32m+[m[32m// CRC32. Should that validation fail, it keeps scanning. But it's[m [32m+[m[32m// possible that _while_ streaming through to check the CRC32 of[m [32m+[m[32m// one candidate page, it sees another candidate page. This #define[m [32m+[m[32m// determines how many "overlapping" candidate pages it can search[m [32m+[m[32m// at once. Note that "real" pages are typically ~4KB to ~8KB, whereas[m [32m+[m[32m// garbage pages could be as big as 64KB, but probably average ~16KB.[m [32m+[m[32m// So don't hose ourselves by scanning an apparent 64KB page and[m [32m+[m[32m// missing a ton of real ones in the interim; so minimum of 2[m [32m+[m[32m#ifndef STB_VORBIS_PUSHDATA_CRC_COUNT[m [32m+[m[32m#define STB_VORBIS_PUSHDATA_CRC_COUNT 4[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m// STB_VORBIS_FAST_HUFFMAN_LENGTH [number][m [32m+[m[32m// sets the log size of the huffman-acceleration table. Maximum[m [32m+[m[32m// supported value is 24. with larger numbers, more decodings are O(1),[m [32m+[m[32m// but the table size is larger so worse cache missing, so you'll have[m [32m+[m[32m// to probe (and try multiple ogg vorbis files) to find the sweet spot.[m [32m+[m[32m#ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH[m [32m+[m[32m#define STB_VORBIS_FAST_HUFFMAN_LENGTH 10[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m// STB_VORBIS_FAST_BINARY_LENGTH [number][m [32m+[m[32m// sets the log size of the binary-search acceleration table. this[m [32m+[m[32m// is used in similar fashion to the fast-huffman size to set initial[m [32m+[m[32m// parameters for the binary search[m [32m+[m [32m+[m[32m// STB_VORBIS_FAST_HUFFMAN_INT[m [32m+[m[32m// The fast huffman tables are much more efficient if they can be[m [32m+[m[32m// stored as 16-bit results instead of 32-bit results. This restricts[m [32m+[m[32m// the codebooks to having only 65535 possible outcomes, though.[m [32m+[m[32m// (At least, accelerated by the huffman table.)[m [32m+[m[32m#ifndef STB_VORBIS_FAST_HUFFMAN_INT[m [32m+[m[32m#define STB_VORBIS_FAST_HUFFMAN_SHORT[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH[m [32m+[m[32m// If the 'fast huffman' search doesn't succeed, then stb_vorbis falls[m [32m+[m[32m// back on binary searching for the correct one. This requires storing[m [32m+[m[32m// extra tables with the huffman codes in sorted order. Defining this[m [32m+[m[32m// symbol trades off space for speed by forcing a linear search in the[m [32m+[m[32m// non-fast case, except for "sparse" codebooks.[m [32m+[m[32m// #define STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH[m [32m+[m [32m+[m[32m// STB_VORBIS_DIVIDES_IN_RESIDUE[m [32m+[m[32m// stb_vorbis precomputes the result of the scalar residue decoding[m [32m+[m[32m// that would otherwise require a divide per chunk. you can trade off[m [32m+[m[32m// space for time by defining this symbol.[m [32m+[m[32m// #define STB_VORBIS_DIVIDES_IN_RESIDUE[m [32m+[m [32m+[m[32m// STB_VORBIS_DIVIDES_IN_CODEBOOK[m [32m+[m[32m// vorbis VQ codebooks can be encoded two ways: with every case explicitly[m [32m+[m[32m// stored, or with all elements being chosen from a small range of values,[m [32m+[m[32m// and all values possible in all elements. By default, stb_vorbis expands[m [32m+[m[32m// this latter kind out to look like the former kind for ease of decoding,[m [32m+[m[32m// because otherwise an integer divide-per-vector-element is required to[m [32m+[m[32m// unpack the index. If you define STB_VORBIS_DIVIDES_IN_CODEBOOK, you can[m [32m+[m[32m// trade off storage for speed.[m [32m+[m[32m//#define STB_VORBIS_DIVIDES_IN_CODEBOOK[m [32m+[m [32m+[m[32m#ifdef STB_VORBIS_CODEBOOK_SHORTS[m [32m+[m[32m#error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m// STB_VORBIS_DIVIDE_TABLE[m [32m+[m[32m// this replaces small integer divides in the floor decode loop with[m [32m+[m[32m// table lookups. made less than 1% difference, so disabled by default.[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_INLINE_DECODE[m [32m+[m[32m// disables the inlining of the scalar codebook fast-huffman decode.[m [32m+[m[32m// might save a little codespace; useful for debugging[m [32m+[m[32m// #define STB_VORBIS_NO_INLINE_DECODE[m [32m+[m [32m+[m[32m// STB_VORBIS_NO_DEFER_FLOOR[m [32m+[m[32m// Normally we only decode the floor without synthesizing the actual[m [32m+[m[32m// full curve. We can instead synthesize the curve immediately. This[m [32m+[m[32m// requires more memory and is very likely slower, so I don't think[m [32m+[m[32m// you'd ever want to do it except for debugging.[m [32m+[m[32m// #define STB_VORBIS_NO_DEFER_FLOOR[m [32m+[m [32m+[m [32m+[m [32m+[m [32m+[m[32m//////////////////////////////////////////////////////////////////////////////[m [32m+[m [32m+[m[32m#ifdef STB_VORBIS_NO_PULLDATA_API[m [32m+[m[32m #define STB_VORBIS_NO_INTEGER_CONVERSION[m [32m+[m[32m #define STB_VORBIS_NO_STDIO[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)[m [32m+[m[32m #define STB_VORBIS_NO_STDIO 1[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_INTEGER_CONVERSION[m [32m+[m[32m#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT[m [32m+[m [32m+[m[32m // only need endianness for fast-float-to-int, which we don't[m [32m+[m[32m // use for pushdata[m [32m+[m [32m+[m[32m #ifndef STB_VORBIS_BIG_ENDIAN[m [32m+[m[32m #define STB_VORBIS_ENDIAN 0[m [32m+[m[32m #else[m [32m+[m[32m #define STB_VORBIS_ENDIAN 1[m [32m+[m[32m #endif[m [32m+[m [32m+[m[32m#endif[m [32m+[m[32m#endif[m [32m+[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m#include [m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#ifndef STB_VORBIS_NO_CRT[m [32m+[m[32m #include [m [32m+[m[32m #include [m [32m+[m[32m #include [m [32m+[m[32m #include [m [32m+[m [32m+[m[32m // find definition of alloca if it's not in stdlib.h:[m [32m+[m[32m #if defined(_MSC_VER) || defined(__MINGW32__)[m [32m+[m[32m #include [m [32m+[m[32m #endif[m [32m+[m[32m #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__)[m [32m+[m[32m #include [m [32m+[m[32m #endif[m [32m+[m[32m#else // STB_VORBIS_NO_CRT[m [32m+[m[32m #define NULL 0[m [32m+[m[32m #define malloc(s) 0[m [32m+[m[32m #define free(s) ((void) 0)[m [32m+[m[32m #define realloc(s) 0[m [32m+[m[32m#endif // STB_VORBIS_NO_CRT[m [32m+[m [32m+[m[32m#include [m [32m+[m [32m+[m[32m#ifdef __MINGW32__[m [32m+[m[32m // eff you mingw:[m [32m+[m[32m // "fixed":[m [32m+[m[32m // http://sourceforge.net/p/mingw-w64/mailman/message/32882927/[m [32m+[m[32m // "no that broke the build, reverted, who cares about C":[m [32m+[m[32m // http://sourceforge.net/p/mingw-w64/mailman/message/32890381/[m [32m+[m[32m #ifdef __forceinline[m [32m+[m[32m #undef __forceinline[m [32m+[m[32m #endif[m [32m+[m[32m #define __forceinline[m [32m+[m[32m #ifndef alloca[m [32m+[m[32m #define alloca __builtin_alloca[m [32m+[m[32m #endif[m [32m+[m[32m#elif !defined(_MSC_VER)[m [32m+[m[32m #if __GNUC__[m [32m+[m[32m #define __forceinline inline[m [32m+[m[32m #else[m [32m+[m[32m #define __forceinline[m [32m+[m[32m #endif[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#if STB_VORBIS_MAX_CHANNELS > 256[m [32m+[m[32m#error "Value of STB_VORBIS_MAX_CHANNELS outside of allowed range"[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#if STB_VORBIS_FAST_HUFFMAN_LENGTH > 24[m [32m+[m[32m#error "Value of STB_VORBIS_FAST_HUFFMAN_LENGTH outside of allowed range"[m [32m+[m[32m#endif[m [32m+[m [32m+[m [32m+[m[32m#if 0[m [32m+[m[32m#include [m [32m+[m[32m#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])[m [32m+[m[32m#else[m [32m+[m[32m#define CHECK(f) ((void) 0)[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m#define MAX_BLOCKSIZE_LOG 13 // from specification[m [32m+[m[32m#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)[m [32m+[m [32m+[m [32m+[m[32mtypedef unsigned char uint8;[m [32m+[m[32mtypedef signed char int8;[m [32m+[m[32mtypedef unsigned short uint16;[m [32m+[m[32mtypedef signed short int16;[m [32m+[m[32mtypedef unsigned int uint32;[m [32m+[m[32mtypedef signed int int32;[m [32m+[m [32m+[m[32m#ifndef TRUE[m [32m+[m[32m#define TRUE 1[m [32m+[m[32m#define FALSE 0[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32mtypedef float codetype;[m [32m+[m [32m+[m[32m// @NOTE[m [32m+[m[32m//[m [32m+[m[32m// Some arrays below are tagged "//varies", which means it's actually[m [32m+[m[32m// a variable-sized piece of data, but rather than malloc I assume it's[m [32m+[m[32m// small enough it's better to just allocate it all together with the[m [32m+[m[32m// main thing[m [32m+[m[32m//[m [32m+[m[32m// Most of the variables are specified with the smallest size I could pack[m [32m+[m[32m// them into. It might give better performance to make them all full-sized[m [32m+[m[32m// integers. It should be safe to freely rearrange the structures or change[m [32m+[m[32m// the sizes larger--nothing relies on silently truncating etc., nor the[m [32m+[m[32m// order of variables.[m [32m+[m [32m+[m[32m#define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH)[m [32m+[m[32m#define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1)[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m int dimensions, entries;[m [32m+[m[32m uint8 *codeword_lengths;[m [32m+[m[32m float minimum_value;[m [32m+[m[32m float delta_value;[m [32m+[m[32m uint8 value_bits;[m [32m+[m[32m uint8 lookup_type;[m [32m+[m[32m uint8 sequence_p;[m [32m+[m[32m uint8 sparse;[m [32m+[m[32m uint32 lookup_values;[m [32m+[m[32m codetype *multiplicands;[m [32m+[m[32m uint32 *codewords;[m [32m+[m[32m #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT[m [32m+[m[32m int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];[m [32m+[m[32m #else[m [32m+[m[32m int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];[m [32m+[m[32m #endif[m [32m+[m[32m uint32 *sorted_codewords;[m [32m+[m[32m int *sorted_values;[m [32m+[m[32m int sorted_entries;[m [32m+[m[32m} Codebook;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint8 order;[m [32m+[m[32m uint16 rate;[m [32m+[m[32m uint16 bark_map_size;[m [32m+[m[32m uint8 amplitude_bits;[m [32m+[m[32m uint8 amplitude_offset;[m [32m+[m[32m uint8 number_of_books;[m [32m+[m[32m uint8 book_list[16]; // varies[m [32m+[m[32m} Floor0;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint8 partitions;[m [32m+[m[32m uint8 partition_class_list[32]; // varies[m [32m+[m[32m uint8 class_dimensions[16]; // varies[m [32m+[m[32m uint8 class_subclasses[16]; // varies[m [32m+[m[32m uint8 class_masterbooks[16]; // varies[m [32m+[m[32m int16 subclass_books[16][8]; // varies[m [32m+[m[32m uint16 Xlist[31*8+2]; // varies[m [32m+[m[32m uint8 sorted_order[31*8+2];[m [32m+[m[32m uint8 neighbors[31*8+2][2];[m [32m+[m[32m uint8 floor1_multiplier;[m [32m+[m[32m uint8 rangebits;[m [32m+[m[32m int values;[m [32m+[m[32m} Floor1;[m [32m+[m [32m+[m[32mtypedef union[m [32m+[m[32m{[m [32m+[m[32m Floor0 floor0;[m [32m+[m[32m Floor1 floor1;[m [32m+[m[32m} Floor;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint32 begin, end;[m [32m+[m[32m uint32 part_size;[m [32m+[m[32m uint8 classifications;[m [32m+[m[32m uint8 classbook;[m [32m+[m[32m uint8 **classdata;[m [32m+[m[32m int16 (*residue_books)[8];[m [32m+[m[32m} Residue;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint8 magnitude;[m [32m+[m[32m uint8 angle;[m [32m+[m[32m uint8 mux;[m [32m+[m[32m} MappingChannel;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint16 coupling_steps;[m [32m+[m[32m MappingChannel *chan;[m [32m+[m[32m uint8 submaps;[m [32m+[m[32m uint8 submap_floor[15]; // varies[m [32m+[m[32m uint8 submap_residue[15]; // varies[m [32m+[m[32m} Mapping;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint8 blockflag;[m [32m+[m[32m uint8 mapping;[m [32m+[m[32m uint16 windowtype;[m [32m+[m[32m uint16 transformtype;[m [32m+[m[32m} Mode;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint32 goal_crc; // expected crc if match[m [32m+[m[32m int bytes_left; // bytes left in packet[m [32m+[m[32m uint32 crc_so_far; // running crc[m [32m+[m[32m int bytes_done; // bytes processed in _current_ chunk[m [32m+[m[32m uint32 sample_loc; // granule pos encoded in page[m [32m+[m[32m} CRCscan;[m [32m+[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint32 page_start, page_end;[m [32m+[m[32m uint32 last_decoded_sample;[m [32m+[m[32m} ProbedPage;[m [32m+[m [32m+[m[32mstruct stb_vorbis[m [32m+[m[32m{[m [32m+[m[32m // user-accessible info[m [32m+[m[32m unsigned int sample_rate;[m [32m+[m[32m int channels;[m [32m+[m [32m+[m[32m unsigned int setup_memory_required;[m [32m+[m[32m unsigned int temp_memory_required;[m [32m+[m[32m unsigned int setup_temp_memory_required;[m [32m+[m [32m+[m[32m char *vendor;[m [32m+[m[32m int comment_list_length;[m [32m+[m[32m char **comment_list;[m [32m+[m [32m+[m[32m // input config[m [32m+[m[32m#ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m FILE *f;[m [32m+[m[32m uint32 f_start;[m [32m+[m[32m int close_on_free;[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m uint8 *stream;[m [32m+[m[32m uint8 *stream_start;[m [32m+[m[32m uint8 *stream_end;[m [32m+[m [32m+[m[32m uint32 stream_len;[m [32m+[m [32m+[m[32m uint8 push_mode;[m [32m+[m [32m+[m[32m // the page to seek to when seeking to start, may be zero[m [32m+[m[32m uint32 first_audio_page_offset;[m [32m+[m [32m+[m[32m // p_first is the page on which the first audio packet ends[m [32m+[m[32m // (but not necessarily the page on which it starts)[m [32m+[m[32m ProbedPage p_first, p_last;[m [32m+[m [32m+[m[32m // memory management[m [32m+[m[32m stb_vorbis_alloc alloc;[m [32m+[m[32m int setup_offset;[m [32m+[m[32m int temp_offset;[m [32m+[m [32m+[m[32m // run-time results[m [32m+[m[32m int eof;[m [32m+[m[32m enum STBVorbisError error;[m [32m+[m [32m+[m[32m // user-useful data[m [32m+[m [32m+[m[32m // header info[m [32m+[m[32m int blocksize[2];[m [32m+[m[32m int blocksize_0, blocksize_1;[m [32m+[m[32m int codebook_count;[m [32m+[m[32m Codebook *codebooks;[m [32m+[m[32m int floor_count;[m [32m+[m[32m uint16 floor_types[64]; // varies[m [32m+[m[32m Floor *floor_config;[m [32m+[m[32m int residue_count;[m [32m+[m[32m uint16 residue_types[64]; // varies[m [32m+[m[32m Residue *residue_config;[m [32m+[m[32m int mapping_count;[m [32m+[m[32m Mapping *mapping;[m [32m+[m[32m int mode_count;[m [32m+[m[32m Mode mode_config[64]; // varies[m [32m+[m [32m+[m[32m uint32 total_samples;[m [32m+[m [32m+[m[32m // decode buffer[m [32m+[m[32m float *channel_buffers[STB_VORBIS_MAX_CHANNELS];[m [32m+[m[32m float *outputs [STB_VORBIS_MAX_CHANNELS];[m [32m+[m [32m+[m[32m float *previous_window[STB_VORBIS_MAX_CHANNELS];[m [32m+[m[32m int previous_length;[m [32m+[m [32m+[m[32m #ifndef STB_VORBIS_NO_DEFER_FLOOR[m [32m+[m[32m int16 *finalY[STB_VORBIS_MAX_CHANNELS];[m [32m+[m[32m #else[m [32m+[m[32m float *floor_buffers[STB_VORBIS_MAX_CHANNELS];[m [32m+[m[32m #endif[m [32m+[m [32m+[m[32m uint32 current_loc; // sample location of next frame to decode[m [32m+[m[32m int current_loc_valid;[m [32m+[m [32m+[m[32m // per-blocksize precomputed data[m [32m+[m [32m+[m[32m // twiddle factors[m [32m+[m[32m float *A[2],*B[2],*C[2];[m [32m+[m[32m float *window[2];[m [32m+[m[32m uint16 *bit_reverse[2];[m [32m+[m [32m+[m[32m // current page/packet/segment streaming info[m [32m+[m[32m uint32 serial; // stream serial number for verification[m [32m+[m[32m int last_page;[m [32m+[m[32m int segment_count;[m [32m+[m[32m uint8 segments[255];[m [32m+[m[32m uint8 page_flag;[m [32m+[m[32m uint8 bytes_in_seg;[m [32m+[m[32m uint8 first_decode;[m [32m+[m[32m int next_seg;[m [32m+[m[32m int last_seg; // flag that we're on the last segment[m [32m+[m[32m int last_seg_which; // what was the segment number of the last seg?[m [32m+[m[32m uint32 acc;[m [32m+[m[32m int valid_bits;[m [32m+[m[32m int packet_bytes;[m [32m+[m[32m int end_seg_with_known_loc;[m [32m+[m[32m uint32 known_loc_for_packet;[m [32m+[m[32m int discard_samples_deferred;[m [32m+[m[32m uint32 samples_output;[m [32m+[m [32m+[m[32m // push mode scanning[m [32m+[m[32m int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching[m [32m+[m[32m#ifndef STB_VORBIS_NO_PUSHDATA_API[m [32m+[m[32m CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT];[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m // sample-access[m [32m+[m[32m int channel_buffer_start;[m [32m+[m[32m int channel_buffer_end;[m [32m+[m[32m};[m [32m+[m [32m+[m[32m#if defined(STB_VORBIS_NO_PUSHDATA_API)[m [32m+[m[32m #define IS_PUSH_MODE(f) FALSE[m [32m+[m[32m#elif defined(STB_VORBIS_NO_PULLDATA_API)[m [32m+[m[32m #define IS_PUSH_MODE(f) TRUE[m [32m+[m[32m#else[m [32m+[m[32m #define IS_PUSH_MODE(f) ((f)->push_mode)[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32mtypedef struct stb_vorbis vorb;[m [32m+[m [32m+[m[32mstatic int error(vorb *f, enum STBVorbisError e)[m [32m+[m[32m{[m [32m+[m[32m f->error = e;[m [32m+[m[32m if (!f->eof && e != VORBIS_need_more_data) {[m [32m+[m[32m f->error=e; // breakpoint for debugging[m [32m+[m[32m }[m [32m+[m[32m return 0;[m [32m+[m[32m}[m [32m+[m [32m+[m [32m+[m[32m// these functions are used for allocating temporary memory[m [32m+[m[32m// while decoding. if you can afford the stack space, use[m [32m+[m[32m// alloca(); otherwise, provide a temp buffer and it will[m [32m+[m[32m// allocate out of those.[m [32m+[m [32m+[m[32m#define array_size_required(count,size) (count*(sizeof(void *)+(size)))[m [32m+[m [32m+[m[32m#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))[m [32m+[m[32m#define temp_free(f,p) (void)0[m [32m+[m[32m#define temp_alloc_save(f) ((f)->temp_offset)[m [32m+[m[32m#define temp_alloc_restore(f,p) ((f)->temp_offset = (p))[m [32m+[m [32m+[m[32m#define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size)[m [32m+[m [32m+[m[32m// given a sufficiently large block of memory, make an array of pointers to subblocks of it[m [32m+[m[32mstatic void *make_block_array(void *mem, int count, int size)[m [32m+[m[32m{[m [32m+[m[32m int i;[m [32m+[m[32m void ** p = (void **) mem;[m [32m+[m[32m char *q = (char *) (p + count);[m [32m+[m[32m for (i=0; i < count; ++i) {[m [32m+[m[32m p[i] = q;[m [32m+[m[32m q += size;[m [32m+[m[32m }[m [32m+[m[32m return p;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void *setup_malloc(vorb *f, int sz)[m [32m+[m[32m{[m [32m+[m[32m sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs.[m [32m+[m[32m f->setup_memory_required += sz;[m [32m+[m[32m if (f->alloc.alloc_buffer) {[m [32m+[m[32m void *p = (char *) f->alloc.alloc_buffer + f->setup_offset;[m [32m+[m[32m if (f->setup_offset + sz > f->temp_offset) return NULL;[m [32m+[m[32m f->setup_offset += sz;[m [32m+[m[32m return p;[m [32m+[m[32m }[m [32m+[m[32m return sz ? malloc(sz) : NULL;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void setup_free(vorb *f, void *p)[m [32m+[m[32m{[m [32m+[m[32m if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack[m [32m+[m[32m free(p);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void *setup_temp_malloc(vorb *f, int sz)[m [32m+[m[32m{[m [32m+[m[32m sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs.[m [32m+[m[32m if (f->alloc.alloc_buffer) {[m [32m+[m[32m if (f->temp_offset - sz < f->setup_offset) return NULL;[m [32m+[m[32m f->temp_offset -= sz;[m [32m+[m[32m return (char *) f->alloc.alloc_buffer + f->temp_offset;[m [32m+[m[32m }[m [32m+[m[32m return malloc(sz);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void setup_temp_free(vorb *f, void *p, int sz)[m [32m+[m[32m{[m [32m+[m[32m if (f->alloc.alloc_buffer) {[m [32m+[m[32m f->temp_offset += (sz+7)&~7;[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m free(p);[m [32m+[m[32m}[m [32m+[m [32m+[m[32m#define CRC32_POLY 0x04c11db7 // from spec[m [32m+[m [32m+[m[32mstatic uint32 crc_table[256];[m [32m+[m[32mstatic void crc32_init(void)[m [32m+[m[32m{[m [32m+[m[32m int i,j;[m [32m+[m[32m uint32 s;[m [32m+[m[32m for(i=0; i < 256; i++) {[m [32m+[m[32m for (s=(uint32) i << 24, j=0; j < 8; ++j)[m [32m+[m[32m s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0);[m [32m+[m[32m crc_table[i] = s;[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic __forceinline uint32 crc32_update(uint32 crc, uint8 byte)[m [32m+[m[32m{[m [32m+[m[32m return (crc << 8) ^ crc_table[byte ^ (crc >> 24)];[m [32m+[m[32m}[m [32m+[m [32m+[m [32m+[m[32m// used in setup, and for huffman that doesn't go fast path[m [32m+[m[32mstatic unsigned int bit_reverse(unsigned int n)[m [32m+[m[32m{[m [32m+[m[32m n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1);[m [32m+[m[32m n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2);[m [32m+[m[32m n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4);[m [32m+[m[32m n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8);[m [32m+[m[32m return (n >> 16) | (n << 16);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic float square(float x)[m [32m+[m[32m{[m [32m+[m[32m return x*x;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3[m [32m+[m[32m// as required by the specification. fast(?) implementation from stb.h[m [32m+[m[32m// @OPTIMIZE: called multiple times per-packet with "constants"; move to setup[m [32m+[m[32mstatic int ilog(int32 n)[m [32m+[m[32m{[m [32m+[m[32m static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };[m [32m+[m [32m+[m[32m if (n < 0) return 0; // signed n returns 0[m [32m+[m [32m+[m[32m // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29)[m [32m+[m[32m if (n < (1 << 14))[m [32m+[m[32m if (n < (1 << 4)) return 0 + log2_4[n ];[m [32m+[m[32m else if (n < (1 << 9)) return 5 + log2_4[n >> 5];[m [32m+[m[32m else return 10 + log2_4[n >> 10];[m [32m+[m[32m else if (n < (1 << 24))[m [32m+[m[32m if (n < (1 << 19)) return 15 + log2_4[n >> 15];[m [32m+[m[32m else return 20 + log2_4[n >> 20];[m [32m+[m[32m else if (n < (1 << 29)) return 25 + log2_4[n >> 25];[m [32m+[m[32m else return 30 + log2_4[n >> 30];[m [32m+[m[32m}[m [32m+[m [32m+[m[32m#ifndef M_PI[m [32m+[m[32m #define M_PI 3.14159265358979323846264f // from CRC[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32m// code length assigned to a value with no huffman encoding[m [32m+[m[32m#define NO_CODE 255[m [32m+[m [32m+[m[32m/////////////////////// LEAF SETUP FUNCTIONS //////////////////////////[m [32m+[m[32m//[m [32m+[m[32m// these functions are only called at setup, and only a few times[m [32m+[m[32m// per file[m [32m+[m [32m+[m[32mstatic float float32_unpack(uint32 x)[m [32m+[m[32m{[m [32m+[m[32m // from the specification[m [32m+[m[32m uint32 mantissa = x & 0x1fffff;[m [32m+[m[32m uint32 sign = x & 0x80000000;[m [32m+[m[32m uint32 exp = (x & 0x7fe00000) >> 21;[m [32m+[m[32m double res = sign ? -(double)mantissa : (double)mantissa;[m [32m+[m[32m return (float) ldexp((float)res, exp-788);[m [32m+[m[32m}[m [32m+[m [32m+[m [32m+[m[32m// zlib & jpeg huffman tables assume that the output symbols[m [32m+[m[32m// can either be arbitrarily arranged, or have monotonically[m [32m+[m[32m// increasing frequencies--they rely on the lengths being sorted;[m [32m+[m[32m// this makes for a very simple generation algorithm.[m [32m+[m[32m// vorbis allows a huffman table with non-sorted lengths. This[m [32m+[m[32m// requires a more sophisticated construction, since symbols in[m [32m+[m[32m// order do not map to huffman codes "in order".[m [32m+[m[32mstatic void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values)[m [32m+[m[32m{[m [32m+[m[32m if (!c->sparse) {[m [32m+[m[32m c->codewords [symbol] = huff_code;[m [32m+[m[32m } else {[m [32m+[m[32m c->codewords [count] = huff_code;[m [32m+[m[32m c->codeword_lengths[count] = len;[m [32m+[m[32m values [count] = symbol;[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)[m [32m+[m[32m{[m [32m+[m[32m int i,k,m=0;[m [32m+[m[32m uint32 available[32];[m [32m+[m [32m+[m[32m memset(available, 0, sizeof(available));[m [32m+[m[32m // find the first entry[m [32m+[m[32m for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;[m [32m+[m[32m if (k == n) { assert(c->sorted_entries == 0); return TRUE; }[m [32m+[m[32m // add to the list[m [32m+[m[32m add_entry(c, 0, k, m++, len[k], values);[m [32m+[m[32m // add all available leaves[m [32m+[m[32m for (i=1; i <= len[k]; ++i)[m [32m+[m[32m available[i] = 1U << (32-i);[m [32m+[m[32m // note that the above code treats the first case specially,[m [32m+[m[32m // but it's really the same as the following code, so they[m [32m+[m[32m // could probably be combined (except the initial code is 0,[m [32m+[m[32m // and I use 0 in available[] to mean 'empty')[m [32m+[m[32m for (i=k+1; i < n; ++i) {[m [32m+[m[32m uint32 res;[m [32m+[m[32m int z = len[i], y;[m [32m+[m[32m if (z == NO_CODE) continue;[m [32m+[m[32m // find lowest available leaf (should always be earliest,[m [32m+[m[32m // which is what the specification calls for)[m [32m+[m[32m // note that this property, and the fact we can never have[m [32m+[m[32m // more than one free leaf at a given level, isn't totally[m [32m+[m[32m // trivial to prove, but it seems true and the assert never[m [32m+[m[32m // fires, so![m [32m+[m[32m while (z > 0 && !available[z]) --z;[m [32m+[m[32m if (z == 0) { return FALSE; }[m [32m+[m[32m res = available[z];[m [32m+[m[32m assert(z >= 0 && z < 32);[m [32m+[m[32m available[z] = 0;[m [32m+[m[32m add_entry(c, bit_reverse(res), i, m++, len[i], values);[m [32m+[m[32m // propagate availability up the tree[m [32m+[m[32m if (z != len[i]) {[m [32m+[m[32m assert(len[i] >= 0 && len[i] < 32);[m [32m+[m[32m for (y=len[i]; y > z; --y) {[m [32m+[m[32m assert(available[y] == 0);[m [32m+[m[32m available[y] = res + (1 << (32-y));[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m return TRUE;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// accelerated huffman table allows fast O(1) match of all symbols[m [32m+[m[32m// of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH[m [32m+[m[32mstatic void compute_accelerated_huffman(Codebook *c)[m [32m+[m[32m{[m [32m+[m[32m int i, len;[m [32m+[m[32m for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i)[m [32m+[m[32m c->fast_huffman[i] = -1;[m [32m+[m [32m+[m[32m len = c->sparse ? c->sorted_entries : c->entries;[m [32m+[m[32m #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT[m [32m+[m[32m if (len > 32767) len = 32767; // largest possible value we can encode![m [32m+[m[32m #endif[m [32m+[m[32m for (i=0; i < len; ++i) {[m [32m+[m[32m if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) {[m [32m+[m[32m uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i];[m [32m+[m[32m // set table entries for all bit combinations in the higher bits[m [32m+[m[32m while (z < FAST_HUFFMAN_TABLE_SIZE) {[m [32m+[m[32m c->fast_huffman[z] = i;[m [32m+[m[32m z += 1 << c->codeword_lengths[i];[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32m#ifdef _MSC_VER[m [32m+[m[32m#define STBV_CDECL __cdecl[m [32m+[m[32m#else[m [32m+[m[32m#define STBV_CDECL[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32mstatic int STBV_CDECL uint32_compare(const void *p, const void *q)[m [32m+[m[32m{[m [32m+[m[32m uint32 x = * (uint32 *) p;[m [32m+[m[32m uint32 y = * (uint32 *) q;[m [32m+[m[32m return x < y ? -1 : x > y;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int include_in_sort(Codebook *c, uint8 len)[m [32m+[m[32m{[m [32m+[m[32m if (c->sparse) { assert(len != NO_CODE); return TRUE; }[m [32m+[m[32m if (len == NO_CODE) return FALSE;[m [32m+[m[32m if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE;[m [32m+[m[32m return FALSE;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// if the fast table above doesn't work, we want to binary[m [32m+[m[32m// search them... need to reverse the bits[m [32m+[m[32mstatic void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values)[m [32m+[m[32m{[m [32m+[m[32m int i, len;[m [32m+[m[32m // build a list of all the entries[m [32m+[m[32m // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN.[m [32m+[m[32m // this is kind of a frivolous optimization--I don't see any performance improvement,[m [32m+[m[32m // but it's like 4 extra lines of code, so.[m [32m+[m[32m if (!c->sparse) {[m [32m+[m[32m int k = 0;[m [32m+[m[32m for (i=0; i < c->entries; ++i)[m [32m+[m[32m if (include_in_sort(c, lengths[i]))[m [32m+[m[32m c->sorted_codewords[k++] = bit_reverse(c->codewords[i]);[m [32m+[m[32m assert(k == c->sorted_entries);[m [32m+[m[32m } else {[m [32m+[m[32m for (i=0; i < c->sorted_entries; ++i)[m [32m+[m[32m c->sorted_codewords[i] = bit_reverse(c->codewords[i]);[m [32m+[m[32m }[m [32m+[m [32m+[m[32m qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare);[m [32m+[m[32m c->sorted_codewords[c->sorted_entries] = 0xffffffff;[m [32m+[m [32m+[m[32m len = c->sparse ? c->sorted_entries : c->entries;[m [32m+[m[32m // now we need to indicate how they correspond; we could either[m [32m+[m[32m // #1: sort a different data structure that says who they correspond to[m [32m+[m[32m // #2: for each sorted entry, search the original list to find who corresponds[m [32m+[m[32m // #3: for each original entry, find the sorted entry[m [32m+[m[32m // #1 requires extra storage, #2 is slow, #3 can use binary search![m [32m+[m[32m for (i=0; i < len; ++i) {[m [32m+[m[32m int huff_len = c->sparse ? lengths[values[i]] : lengths[i];[m [32m+[m[32m if (include_in_sort(c,huff_len)) {[m [32m+[m[32m uint32 code = bit_reverse(c->codewords[i]);[m [32m+[m[32m int x=0, n=c->sorted_entries;[m [32m+[m[32m while (n > 1) {[m [32m+[m[32m // invariant: sc[x] <= code < sc[x+n][m [32m+[m[32m int m = x + (n >> 1);[m [32m+[m[32m if (c->sorted_codewords[m] <= code) {[m [32m+[m[32m x = m;[m [32m+[m[32m n -= (n>>1);[m [32m+[m[32m } else {[m [32m+[m[32m n >>= 1;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m assert(c->sorted_codewords[x] == code);[m [32m+[m[32m if (c->sparse) {[m [32m+[m[32m c->sorted_values[x] = values[i];[m [32m+[m[32m c->codeword_lengths[x] = huff_len;[m [32m+[m[32m } else {[m [32m+[m[32m c->sorted_values[x] = i;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// only run while parsing the header (3 times)[m [32m+[m[32mstatic int vorbis_validate(uint8 *data)[m [32m+[m[32m{[m [32m+[m[32m static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' };[m [32m+[m[32m return memcmp(data, vorbis, 6) == 0;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// called from setup only, once per code book[m [32m+[m[32m// (formula implied by specification)[m [32m+[m[32mstatic int lookup1_values(int entries, int dim)[m [32m+[m[32m{[m [32m+[m[32m int r = (int) floor(exp((float) log((float) entries) / dim));[m [32m+[m[32m if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning;[m [32m+[m[32m ++r; // floor() to avoid _ftol() when non-CRT[m [32m+[m[32m if (pow((float) r+1, dim) <= entries)[m [32m+[m[32m return -1;[m [32m+[m[32m if ((int) floor(pow((float) r, dim)) > entries)[m [32m+[m[32m return -1;[m [32m+[m[32m return r;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// called twice per file[m [32m+[m[32mstatic void compute_twiddle_factors(int n, float *A, float *B, float *C)[m [32m+[m[32m{[m [32m+[m[32m int n4 = n >> 2, n8 = n >> 3;[m [32m+[m[32m int k,k2;[m [32m+[m [32m+[m[32m for (k=k2=0; k < n4; ++k,k2+=2) {[m [32m+[m[32m A[k2 ] = (float) cos(4*k*M_PI/n);[m [32m+[m[32m A[k2+1] = (float) -sin(4*k*M_PI/n);[m [32m+[m[32m B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f;[m [32m+[m[32m B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f;[m [32m+[m[32m }[m [32m+[m[32m for (k=k2=0; k < n8; ++k,k2+=2) {[m [32m+[m[32m C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);[m [32m+[m[32m C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void compute_window(int n, float *window)[m [32m+[m[32m{[m [32m+[m[32m int n2 = n >> 1, i;[m [32m+[m[32m for (i=0; i < n2; ++i)[m [32m+[m[32m window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI)));[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void compute_bitreverse(int n, uint16 *rev)[m [32m+[m[32m{[m [32m+[m[32m int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions[m [32m+[m[32m int i, n8 = n >> 3;[m [32m+[m[32m for (i=0; i < n8; ++i)[m [32m+[m[32m rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int init_blocksize(vorb *f, int b, int n)[m [32m+[m[32m{[m [32m+[m[32m int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3;[m [32m+[m[32m f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2);[m [32m+[m[32m f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2);[m [32m+[m[32m f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4);[m [32m+[m[32m if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem);[m [32m+[m[32m compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]);[m [32m+[m[32m f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2);[m [32m+[m[32m if (!f->window[b]) return error(f, VORBIS_outofmem);[m [32m+[m[32m compute_window(n, f->window[b]);[m [32m+[m[32m f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8);[m [32m+[m[32m if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem);[m [32m+[m[32m compute_bitreverse(n, f->bit_reverse[b]);[m [32m+[m[32m return TRUE;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void neighbors(uint16 *x, int n, int *plow, int *phigh)[m [32m+[m[32m{[m [32m+[m[32m int low = -1;[m [32m+[m[32m int high = 65536;[m [32m+[m[32m int i;[m [32m+[m[32m for (i=0; i < n; ++i) {[m [32m+[m[32m if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; }[m [32m+[m[32m if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; }[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m [32m+[m[32m// this has been repurposed so y is now the original index instead of y[m [32m+[m[32mtypedef struct[m [32m+[m[32m{[m [32m+[m[32m uint16 x,id;[m [32m+[m[32m} stbv__floor_ordering;[m [32m+[m [32m+[m[32mstatic int STBV_CDECL point_compare(const void *p, const void *q)[m [32m+[m[32m{[m [32m+[m[32m stbv__floor_ordering *a = (stbv__floor_ordering *) p;[m [32m+[m[32m stbv__floor_ordering *b = (stbv__floor_ordering *) q;[m [32m+[m[32m return a->x < b->x ? -1 : a->x > b->x;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m//[m [32m+[m[32m/////////////////////// END LEAF SETUP FUNCTIONS //////////////////////////[m [32m+[m [32m+[m [32m+[m[32m#if defined(STB_VORBIS_NO_STDIO)[m [32m+[m[32m #define USE_MEMORY(z) TRUE[m [32m+[m[32m#else[m [32m+[m[32m #define USE_MEMORY(z) ((z)->stream)[m [32m+[m[32m#endif[m [32m+[m [32m+[m[32mstatic uint8 get8(vorb *z)[m [32m+[m[32m{[m [32m+[m[32m if (USE_MEMORY(z)) {[m [32m+[m[32m if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; }[m [32m+[m[32m return *z->stream++;[m [32m+[m[32m }[m [32m+[m [32m+[m[32m #ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m {[m [32m+[m[32m int c = fgetc(z->f);[m [32m+[m[32m if (c == EOF) { z->eof = TRUE; return 0; }[m [32m+[m[32m return c;[m [32m+[m[32m }[m [32m+[m[32m #endif[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic uint32 get32(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m uint32 x;[m [32m+[m[32m x = get8(f);[m [32m+[m[32m x += get8(f) << 8;[m [32m+[m[32m x += get8(f) << 16;[m [32m+[m[32m x += (uint32) get8(f) << 24;[m [32m+[m[32m return x;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int getn(vorb *z, uint8 *data, int n)[m [32m+[m[32m{[m [32m+[m[32m if (USE_MEMORY(z)) {[m [32m+[m[32m if (z->stream+n > z->stream_end) { z->eof = 1; return 0; }[m [32m+[m[32m memcpy(data, z->stream, n);[m [32m+[m[32m z->stream += n;[m [32m+[m[32m return 1;[m [32m+[m[32m }[m [32m+[m [32m+[m[32m #ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m if (fread(data, n, 1, z->f) == 1)[m [32m+[m[32m return 1;[m [32m+[m[32m else {[m [32m+[m[32m z->eof = 1;[m [32m+[m[32m return 0;[m [32m+[m[32m }[m [32m+[m[32m #endif[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic void skip(vorb *z, int n)[m [32m+[m[32m{[m [32m+[m[32m if (USE_MEMORY(z)) {[m [32m+[m[32m z->stream += n;[m [32m+[m[32m if (z->stream >= z->stream_end) z->eof = 1;[m [32m+[m[32m return;[m [32m+[m[32m }[m [32m+[m[32m #ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m {[m [32m+[m[32m long x = ftell(z->f);[m [32m+[m[32m fseek(z->f, x+n, SEEK_SET);[m [32m+[m[32m }[m [32m+[m[32m #endif[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int set_file_offset(stb_vorbis *f, unsigned int loc)[m [32m+[m[32m{[m [32m+[m[32m #ifndef STB_VORBIS_NO_PUSHDATA_API[m [32m+[m[32m if (f->push_mode) return 0;[m [32m+[m[32m #endif[m [32m+[m[32m f->eof = 0;[m [32m+[m[32m if (USE_MEMORY(f)) {[m [32m+[m[32m if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) {[m [32m+[m[32m f->stream = f->stream_end;[m [32m+[m[32m f->eof = 1;[m [32m+[m[32m return 0;[m [32m+[m[32m } else {[m [32m+[m[32m f->stream = f->stream_start + loc;[m [32m+[m[32m return 1;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m #ifndef STB_VORBIS_NO_STDIO[m [32m+[m[32m if (loc + f->f_start < loc || loc >= 0x80000000) {[m [32m+[m[32m loc = 0x7fffffff;[m [32m+[m[32m f->eof = 1;[m [32m+[m[32m } else {[m [32m+[m[32m loc += f->f_start;[m [32m+[m[32m }[m [32m+[m[32m if (!fseek(f->f, loc, SEEK_SET))[m [32m+[m[32m return 1;[m [32m+[m[32m f->eof = 1;[m [32m+[m[32m fseek(f->f, f->f_start, SEEK_END);[m [32m+[m[32m return 0;[m [32m+[m[32m #endif[m [32m+[m[32m}[m [32m+[m [32m+[m [32m+[m[32mstatic uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 };[m [32m+[m [32m+[m[32mstatic int capture_pattern(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m if (0x4f != get8(f)) return FALSE;[m [32m+[m[32m if (0x67 != get8(f)) return FALSE;[m [32m+[m[32m if (0x67 != get8(f)) return FALSE;[m [32m+[m[32m if (0x53 != get8(f)) return FALSE;[m [32m+[m[32m return TRUE;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m#define PAGEFLAG_continued_packet 1[m [32m+[m[32m#define PAGEFLAG_first_page 2[m [32m+[m[32m#define PAGEFLAG_last_page 4[m [32m+[m [32m+[m[32mstatic int start_page_no_capturepattern(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m uint32 loc0,loc1,n;[m [32m+[m[32m if (f->first_decode && !IS_PUSH_MODE(f)) {[m [32m+[m[32m f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4;[m [32m+[m[32m }[m [32m+[m[32m // stream structure version[m [32m+[m[32m if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version);[m [32m+[m[32m // header flag[m [32m+[m[32m f->page_flag = get8(f);[m [32m+[m[32m // absolute granule position[m [32m+[m[32m loc0 = get32(f);[m [32m+[m[32m loc1 = get32(f);[m [32m+[m[32m // @TODO: validate loc0,loc1 as valid positions?[m [32m+[m[32m // stream serial number -- vorbis doesn't interleave, so discard[m [32m+[m[32m get32(f);[m [32m+[m[32m //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number);[m [32m+[m[32m // page sequence number[m [32m+[m[32m n = get32(f);[m [32m+[m[32m f->last_page = n;[m [32m+[m[32m // CRC32[m [32m+[m[32m get32(f);[m [32m+[m[32m // page_segments[m [32m+[m[32m f->segment_count = get8(f);[m [32m+[m[32m if (!getn(f, f->segments, f->segment_count))[m [32m+[m[32m return error(f, VORBIS_unexpected_eof);[m [32m+[m[32m // assume we _don't_ know any the sample position of any segments[m [32m+[m[32m f->end_seg_with_known_loc = -2;[m [32m+[m[32m if (loc0 != ~0U || loc1 != ~0U) {[m [32m+[m[32m int i;[m [32m+[m[32m // determine which packet is the last one that will complete[m [32m+[m[32m for (i=f->segment_count-1; i >= 0; --i)[m [32m+[m[32m if (f->segments[i] < 255)[m [32m+[m[32m break;[m [32m+[m[32m // 'i' is now the index of the _last_ segment of a packet that ends[m [32m+[m[32m if (i >= 0) {[m [32m+[m[32m f->end_seg_with_known_loc = i;[m [32m+[m[32m f->known_loc_for_packet = loc0;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m if (f->first_decode) {[m [32m+[m[32m int i,len;[m [32m+[m[32m len = 0;[m [32m+[m[32m for (i=0; i < f->segment_count; ++i)[m [32m+[m[32m len += f->segments[i];[m [32m+[m[32m len += 27 + f->segment_count;[m [32m+[m[32m f->p_first.page_end = f->p_first.page_start + len;[m [32m+[m[32m f->p_first.last_decoded_sample = loc0;[m [32m+[m[32m }[m [32m+[m[32m f->next_seg = 0;[m [32m+[m[32m return TRUE;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int start_page(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern);[m [32m+[m[32m return start_page_no_capturepattern(f);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int start_packet(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m while (f->next_seg == -1) {[m [32m+[m[32m if (!start_page(f)) return FALSE;[m [32m+[m[32m if (f->page_flag & PAGEFLAG_continued_packet)[m [32m+[m[32m return error(f, VORBIS_continued_packet_flag_invalid);[m [32m+[m[32m }[m [32m+[m[32m f->last_seg = FALSE;[m [32m+[m[32m f->valid_bits = 0;[m [32m+[m[32m f->packet_bytes = 0;[m [32m+[m[32m f->bytes_in_seg = 0;[m [32m+[m[32m // f->next_seg is now valid[m [32m+[m[32m return TRUE;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int maybe_start_packet(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m if (f->next_seg == -1) {[m [32m+[m[32m int x = get8(f);[m [32m+[m[32m if (f->eof) return FALSE; // EOF at page boundary is not an error![m [32m+[m[32m if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern);[m [32m+[m[32m if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);[m [32m+[m[32m if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);[m [32m+[m[32m if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern);[m [32m+[m[32m if (!start_page_no_capturepattern(f)) return FALSE;[m [32m+[m[32m if (f->page_flag & PAGEFLAG_continued_packet) {[m [32m+[m[32m // set up enough state that we can read this packet if we want,[m [32m+[m[32m // e.g. during recovery[m [32m+[m[32m f->last_seg = FALSE;[m [32m+[m[32m f->bytes_in_seg = 0;[m [32m+[m[32m return error(f, VORBIS_continued_packet_flag_invalid);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m return start_packet(f);[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic int next_segment(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m int len;[m [32m+[m[32m if (f->last_seg) return 0;[m [32m+[m[32m if (f->next_seg == -1) {[m [32m+[m[32m f->last_seg_which = f->segment_count-1; // in case start_page fails[m [32m+[m[32m if (!start_page(f)) { f->last_seg = 1; return 0; }[m [32m+[m[32m if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid);[m [32m+[m[32m }[m [32m+[m[32m len = f->segments[f->next_seg++];[m [32m+[m[32m if (len < 255) {[m [32m+[m[32m f->last_seg = TRUE;[m [32m+[m[32m f->last_seg_which = f->next_seg-1;[m [32m+[m[32m }[m [32m+[m[32m if (f->next_seg >= f->segment_count)[m [32m+[m[32m f->next_seg = -1;[m [32m+[m[32m assert(f->bytes_in_seg == 0);[m [32m+[m[32m f->bytes_in_seg = len;[m [32m+[m[32m return len;[m [32m+[m[32m}[m [32m+[m [32m+[m[32m#define EOP (-1)[m [32m+[m[32m#define INVALID_BITS (-1)[m [32m+[m [32m+[m[32mstatic int get8_packet_raw(vorb *f)[m [32m+[m[32m{[m [32m+[m[32m if (!f-
(truncated output; full size was 301.17 KB)
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).