[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 jaakko.keranen@iki.fi[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 jaakko.keranen@iki.fi[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 <SDL_audio.h>[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 <the_Foundation/buffer.h>[m
#include <the_Foundation/thread.h>[m
#include <SDL_audio.h>[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 <stdio.h>[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 <stdio.h>[m
[32m+[m[32m#endif[m
[32m+[m
[32m+[m[32m#ifndef STB_VORBIS_NO_CRT[m
[32m+[m[32m #include <stdlib.h>[m
[32m+[m[32m #include <string.h>[m
[32m+[m[32m #include <assert.h>[m
[32m+[m[32m #include <math.h>[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 <malloc.h>[m
[32m+[m[32m #endif[m
[32m+[m[32m #if defined(linux) || defined(__linux) || defined(EMSCRIPTEN) || defined(NEWLIB)[m
[32m+[m[32m #include <alloca.h>[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 <limits.h>[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 <crtdbg.h>[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(4kM_PI/n);[m
[32m+[m[32m A[k2+1] = (float) -sin(4kM_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-
text/plain
This content has been proxied by September (ba2dc).