aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorraysan5 <raysan5@gmail.com>2016-12-26 10:52:57 +0100
committerraysan5 <raysan5@gmail.com>2016-12-26 10:52:57 +0100
commit5da815234c850dd1f1517e89854bbbed4eeb02e8 (patch)
tree142103e7580b9c284f08db9fdc839e956f3d6f9e /src
parenta27be5f2a96810e5dd23cccf52c7a461431ee32c (diff)
downloadraylib-5da815234c850dd1f1517e89854bbbed4eeb02e8.tar.gz
raylib-5da815234c850dd1f1517e89854bbbed4eeb02e8.zip
Improved FLAC audio support
Diffstat (limited to 'src')
-rw-r--r--src/audio.c25
-rw-r--r--src/external/dr_flac.h323
2 files changed, 255 insertions, 93 deletions
diff --git a/src/audio.c b/src/audio.c
index 04ff90da..3a4ca3df 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -593,6 +593,7 @@ Music LoadMusicStream(const char *fileName)
music->ctxType = MUSIC_AUDIO_OGG;
music->loop = true; // We loop by default
+ TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate);
TraceLog(DEBUG, "[%s] OGG channels: %i", fileName, info.channels);
TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
@@ -606,11 +607,12 @@ Music LoadMusicStream(const char *fileName)
else
{
music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels);
- music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount;
+ music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount/music->ctxFlac->channels;
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_AUDIO_FLAC;
music->loop = true; // We loop by default
+ TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate);
TraceLog(DEBUG, "[%s] FLAC bits per sample: %i", fileName, music->ctxFlac->bitsPerSample);
TraceLog(DEBUG, "[%s] FLAC channels: %i", fileName, music->ctxFlac->channels);
@@ -745,9 +747,7 @@ void UpdateMusicStream(Music music)
case MUSIC_AUDIO_FLAC:
{
// NOTE: Returns the number of samples to process
- unsigned int numSamplesFlac = (unsigned int)drflac_read_s32(music->ctxFlac, numSamples/2, (int *)pcm);
-
- // TODO: Samples should be provided as 16 bit instead of 32 bit!
+ unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, numSamples*music->stream.channels, (short *)pcm);
} break;
case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, numSamples); break;
@@ -1145,21 +1145,14 @@ static Wave LoadFLAC(const char *fileName)
// Decode an entire FLAC file in one go
uint64_t totalSampleCount;
- wave.data = drflac_open_and_decode_file_s32(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
-
- wave.sampleCount = (int)totalSampleCount;
- wave.sampleSize = 32; // 32 bit per sample (float)
+ wave.data = drflac_open_and_decode_file_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
- // NOTE: By default, dr_flac returns 32bit float samples, needs to be converted to 16bit
- WaveFormat(&wave, wave.sampleRate, 16, wave.channels);
+ wave.sampleCount = (int)totalSampleCount/wave.channels;
+ wave.sampleSize = 16;
// NOTE: Only support up to 2 channels (mono, stereo)
- if (wave.channels > 2)
- {
- WaveFormat(&wave, wave.sampleRate, wave.sampleSize, 2);
- TraceLog(WARNING, "[%s] FLAC channels number (%i) not supported, converted to 2 channels", fileName, wave.channels);
- }
-
+ if (wave.channels > 2) TraceLog(WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels);
+
if (wave.data == NULL) TraceLog(WARNING, "[%s] FLAC data could not be loaded", fileName);
else TraceLog(INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h
index d7b66f20..d2bebea5 100644
--- a/src/external/dr_flac.h
+++ b/src/external/dr_flac.h
@@ -1,5 +1,5 @@
// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file.
-// dr_flac - v0.4 - 2016-09-29
+// dr_flac - v0.4c - 2016-12-26
//
// David Reid - mackron@gmail.com
@@ -105,18 +105,32 @@
#include <stdint.h>
#include <stddef.h>
-#ifndef DR_BOOL_DEFINED
-#define DR_BOOL_DEFINED
-#ifdef _WIN32
-typedef char drBool8;
-typedef int drBool32;
+#ifndef DR_SIZED_TYPES_DEFINED
+#define DR_SIZED_TYPES_DEFINED
+#if defined(_MSC_VER) && _MSC_VER < 1600
+typedef signed char dr_int8;
+typedef unsigned char dr_uint8;
+typedef signed short dr_int16;
+typedef unsigned short dr_uint16;
+typedef signed int dr_int32;
+typedef unsigned int dr_uint32;
+typedef signed __int64 dr_int64;
+typedef unsigned __int64 dr_uint64;
#else
#include <stdint.h>
-typedef int8_t drBool8;
-typedef int32_t drBool32;
+typedef int8_t dr_int8;
+typedef uint8_t dr_uint8;
+typedef int16_t dr_int16;
+typedef uint16_t dr_uint16;
+typedef int32_t dr_int32;
+typedef uint32_t dr_uint32;
+typedef int64_t dr_int64;
+typedef uint64_t dr_uint64;
#endif
-#define DR_TRUE 1
-#define DR_FALSE 0
+typedef dr_int8 dr_bool8;
+typedef dr_int32 dr_bool32;
+#define DR_TRUE 1
+#define DR_FALSE 0
#endif
// As data is read from the client it is placed into an internal buffer for fast access. This controls the
@@ -262,7 +276,7 @@ typedef struct
{
char catalog[128];
uint64_t leadInSampleCount;
- drBool32 isCD;
+ dr_bool32 isCD;
uint8_t trackCount;
const uint8_t* pTrackData;
} cuesheet;
@@ -305,7 +319,7 @@ typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t by
//
// The offset will never be negative. Whether or not it is relative to the beginning or current position is determined
// by the "origin" parameter which will be either drflac_seek_origin_start or drflac_seek_origin_current.
-typedef drBool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
+typedef dr_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
// Callback for when a metadata block is read.
//
@@ -546,6 +560,10 @@ void drflac_close(drflac* pFlac);
// seeked.
uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBufferOut);
+// Same as drflac_read_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. Note
+// that this is lossey.
+uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut);
+
// Seeks to the sample at the given index.
//
// pFlac [in] The decoder.
@@ -558,7 +576,7 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBuffer
//
// When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with
// something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels)))
-drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
+dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
@@ -607,14 +625,17 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl
//
// Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
#ifndef DR_FLAC_NO_STDIO
// Same as drflac_open_and_decode_s32() except opens the decoder from a file.
int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
#endif
// Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory.
int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
// Frees data returned by drflac_open_and_decode_*().
void drflac_free(void* pSampleDataReturnedByOpenAndDecode);
@@ -684,7 +705,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui
//// Endian Management ////
-static DRFLAC_INLINE drBool32 drflac__is_little_endian()
+static DRFLAC_INLINE dr_bool32 drflac__is_little_endian()
{
int n = 1;
return (*(char*)&n) == 1;
@@ -817,7 +838,7 @@ static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n)
#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
-static DRFLAC_INLINE drBool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
+static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
{
// Fast path. Try loading straight from L2.
if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
@@ -871,7 +892,7 @@ static DRFLAC_INLINE drBool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
}
}
-static drBool32 drflac__reload_cache(drflac_bs* bs)
+static dr_bool32 drflac__reload_cache(drflac_bs* bs)
{
// Fast path. Try just moving the next value in the L2 cache to the L1 cache.
if (drflac__reload_l1_cache_from_l2(bs)) {
@@ -907,7 +928,7 @@ static void drflac__reset_cache(drflac_bs* bs)
bs->unalignedCache = 0;
}
-static drBool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
+static dr_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
{
if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
bs->consumedBits += bitsToSeek;
@@ -958,7 +979,7 @@ static drBool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
}
}
-static drBool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
+static dr_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
{
assert(bs != NULL);
assert(pResultOut != NULL);
@@ -999,7 +1020,7 @@ static drBool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32
}
}
-static drBool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult)
+static dr_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1018,7 +1039,7 @@ static drBool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t
return DR_TRUE;
}
-static drBool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut)
+static dr_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut)
{
assert(bitCount <= 64);
assert(bitCount > 32);
@@ -1039,7 +1060,7 @@ static drBool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64
// Function below is unused, but leaving it here in case I need to quickly add it again.
#if 0
-static drBool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut)
+static dr_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut)
{
assert(bitCount <= 64);
@@ -1056,7 +1077,7 @@ static drBool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t
}
#endif
-static drBool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult)
+static dr_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1072,7 +1093,7 @@ static drBool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16
return DR_TRUE;
}
-static drBool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult)
+static dr_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1088,7 +1109,7 @@ static drBool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t
return DR_TRUE;
}
-static drBool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult)
+static dr_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1104,7 +1125,7 @@ static drBool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t
return DR_TRUE;
}
-static drBool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult)
+static dr_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1121,7 +1142,7 @@ static drBool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t*
}
-static inline drBool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
+static inline dr_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
{
unsigned int zeroCounter = 0;
while (bs->cache == 0) {
@@ -1169,7 +1190,7 @@ static inline drBool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned in
-static drBool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
+static dr_bool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
{
assert(bs != NULL);
assert(offsetFromStart > 0);
@@ -1214,7 +1235,7 @@ static drBool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
}
-static drBool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut)
+static dr_bool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut)
{
assert(bs != NULL);
assert(pNumberOut != NULL);
@@ -1267,7 +1288,7 @@ static drBool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberO
-static DRFLAC_INLINE drBool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m)
+static DRFLAC_INLINE dr_bool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m)
{
unsigned int unused;
if (!drflac__seek_past_next_set_bit(bs, &unused)) {
@@ -1520,7 +1541,7 @@ static DRFLAC_INLINE int32_t drflac__calculate_prediction_64(uint32_t order, int
// iteration. The prediction is done at the end, and there's an annoying branch I'd like to avoid so the main function is defined
// as a #define - sue me!
#define DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(funcName, predictionFunc) \
-static drBool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \
+static dr_bool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \
{ \
assert(bs != NULL); \
assert(count > 0); \
@@ -1630,7 +1651,7 @@ DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_res
// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes.
-static drBool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam)
+static dr_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam)
{
assert(bs != NULL);
assert(count > 0);
@@ -1644,7 +1665,7 @@ static drBool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t cou
return DR_TRUE;
}
-static drBool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut)
+static dr_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut)
{
assert(bs != NULL);
assert(count > 0);
@@ -1671,7 +1692,7 @@ static drBool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, u
// Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
-static drBool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
{
assert(bs != NULL);
assert(blockSize != 0);
@@ -1755,7 +1776,7 @@ static drBool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bit
// Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
-static drBool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order)
+static dr_bool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order)
{
assert(bs != NULL);
assert(blockSize != 0);
@@ -1823,7 +1844,7 @@ static drBool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize
}
-static drBool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
{
// Only a single sample needs to be decoded here.
int32_t sample;
@@ -1840,7 +1861,7 @@ static drBool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSi
return DR_TRUE;
}
-static drBool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
{
for (uint32_t i = 0; i < blockSize; ++i) {
int32_t sample;
@@ -1854,7 +1875,7 @@ static drBool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSi
return DR_TRUE;
}
-static drBool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
{
short lpcCoefficientsTable[5][4] = {
{0, 0, 0, 0},
@@ -1882,7 +1903,7 @@ static drBool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize,
return DR_TRUE;
}
-static drBool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
{
// Warm up samples.
for (uint8_t i = 0; i < lpcOrder; ++i) {
@@ -1925,7 +1946,7 @@ static drBool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, u
}
-static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header)
+static dr_bool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header)
{
assert(bs != NULL);
assert(header != NULL);
@@ -1983,7 +2004,7 @@ static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfo
}
- drBool32 isVariableBlockSize = blockingStrategy == 1;
+ dr_bool32 isVariableBlockSize = blockingStrategy == 1;
if (isVariableBlockSize) {
uint64_t sampleNumber;
if (!drflac__read_utf8_coded_number(bs, &sampleNumber)) {
@@ -2055,7 +2076,7 @@ static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfo
return DR_TRUE;
}
-static drBool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
+static dr_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
{
uint8_t header;
if (!drflac__read_uint8(bs, 8, &header)) {
@@ -2105,7 +2126,7 @@ static drBool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSu
return DR_TRUE;
}
-static drBool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut)
+static dr_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut)
{
assert(bs != NULL);
assert(frame != NULL);
@@ -2155,7 +2176,7 @@ static drBool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int
return DR_TRUE;
}
-static drBool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
+static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
{
assert(bs != NULL);
assert(frame != NULL);
@@ -2249,7 +2270,7 @@ static DRFLAC_INLINE uint8_t drflac__get_channel_count_from_channel_assignment(i
return lookup[channelAssignment];
}
-static drBool32 drflac__decode_frame(drflac* pFlac)
+static dr_bool32 drflac__decode_frame(drflac* pFlac)
{
// This function should be called while the stream is sitting on the first byte after the frame header.
memset(pFlac->currentFrame.subframes, 0, sizeof(pFlac->currentFrame.subframes));
@@ -2273,7 +2294,7 @@ static drBool32 drflac__decode_frame(drflac* pFlac)
return DR_TRUE;
}
-static drBool32 drflac__seek_frame(drflac* pFlac)
+static dr_bool32 drflac__seek_frame(drflac* pFlac)
{
int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
for (int i = 0; i < channelCount; ++i)
@@ -2287,7 +2308,7 @@ static drBool32 drflac__seek_frame(drflac* pFlac)
return drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16);
}
-static drBool32 drflac__read_and_decode_next_frame(drflac* pFlac)
+static dr_bool32 drflac__read_and_decode_next_frame(drflac* pFlac)
{
assert(pFlac != NULL);
@@ -2324,24 +2345,24 @@ static void drflac__get_current_frame_sample_range(drflac* pFlac, uint64_t* pFir
}
}
-static drBool32 drflac__seek_to_first_frame(drflac* pFlac)
+static dr_bool32 drflac__seek_to_first_frame(drflac* pFlac)
{
assert(pFlac != NULL);
- drBool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos);
+ dr_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos);
memset(&pFlac->currentFrame, 0, sizeof(pFlac->currentFrame));
return result;
}
-static DRFLAC_INLINE drBool32 drflac__seek_to_next_frame(drflac* pFlac)
+static DRFLAC_INLINE dr_bool32 drflac__seek_to_next_frame(drflac* pFlac)
{
// This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section.
assert(pFlac != NULL);
return drflac__seek_frame(pFlac);
}
-static drBool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex)
+static dr_bool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex)
{
assert(pFlac != NULL);
@@ -2372,7 +2393,7 @@ static drBool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t
return DR_TRUE;
}
-static drBool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex)
+static dr_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex)
{
if (!drflac__seek_to_frame_containing_sample(pFlac, sampleIndex)) {
return DR_FALSE;
@@ -2398,7 +2419,7 @@ static drBool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t samp
}
-static drBool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex)
+static dr_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex)
{
assert(pFlac != NULL);
@@ -2508,7 +2529,7 @@ typedef struct
uint64_t totalSampleCount;
uint16_t maxBlockSize;
uint64_t runningFilePos;
- drBool32 hasMetadataBlocks;
+ dr_bool32 hasMetadataBlocks;
#ifndef DR_FLAC_NO_OGG
uint32_t oggSerial;
@@ -2525,7 +2546,7 @@ static DRFLAC_INLINE void drflac__decode_block_header(uint32_t blockHeader, uint
*blockSize = (blockHeader & 0xFFFFFF);
}
-static DRFLAC_INLINE drBool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
+static DRFLAC_INLINE dr_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
{
uint32_t blockHeader;
if (onRead(pUserData, &blockHeader, 4) != 4) {
@@ -2536,7 +2557,7 @@ static DRFLAC_INLINE drBool32 drflac__read_and_decode_block_header(drflac_read_p
return DR_TRUE;
}
-drBool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
+dr_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
{
// min/max block size.
uint32_t blockSizes;
@@ -2579,7 +2600,7 @@ drBool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drfla
return DR_TRUE;
}
-drBool32 drflac__read_and_decode_metadata(drflac* pFlac)
+dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac)
{
assert(pFlac != NULL);
@@ -2823,7 +2844,7 @@ drBool32 drflac__read_and_decode_metadata(drflac* pFlac)
return DR_TRUE;
}
-drBool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+dr_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
{
(void)onSeek;
@@ -2869,7 +2890,7 @@ drBool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc
}
#ifndef DR_FLAC_NO_OGG
-static DRFLAC_INLINE drBool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4])
+static DRFLAC_INLINE dr_bool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4])
{
return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
}
@@ -2889,7 +2910,7 @@ static DRFLAC_INLINE uint32_t drflac_ogg__get_page_body_size(drflac_ogg_page_hea
return pageBodySize;
}
-drBool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+dr_bool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
{
if (onRead(pUserData, &pHeader->structureVersion, 1) != 1 || pHeader->structureVersion != 0) {
return DR_FALSE; // Unknown structure version. Possibly corrupt stream.
@@ -2920,7 +2941,7 @@ drBool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onR
return DR_TRUE;
}
-drBool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+dr_bool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
{
uint8_t id[4];
if (onRead(pUserData, id, 4) != 4) {
@@ -2961,7 +2982,7 @@ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut,
return bytesActuallyRead;
}
-static drBool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin)
+static dr_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin)
{
if (origin == drflac_seek_origin_start)
{
@@ -3000,7 +3021,7 @@ static drBool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset
}
}
-static drBool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs)
+static dr_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs)
{
drflac_ogg_page_header header;
for (;;)
@@ -3049,12 +3070,12 @@ static uint8_t drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, uint
return iSeg;
}
-static drBool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
+static dr_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
{
// The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page.
for (;;) // <-- Loop over pages.
{
- drBool32 atEndOfPage = DR_FALSE;
+ dr_bool32 atEndOfPage = DR_FALSE;
uint8_t bytesRemainingInSeg;
uint8_t iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
@@ -3099,7 +3120,7 @@ static drBool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
}
}
-static drBool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
+static dr_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
{
// The bitstream should be sitting on the first byte just after the header of the frame.
@@ -3148,7 +3169,7 @@ static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytes
return bytesRead;
}
-static drBool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
assert(oggbs != NULL);
@@ -3204,7 +3225,7 @@ static drBool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_ori
return DR_TRUE;
}
-drBool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
+dr_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
{
drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
@@ -3327,7 +3348,7 @@ drBool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
}
-drBool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
{
// Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern.
@@ -3491,7 +3512,7 @@ drBool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onR
}
#endif
-drBool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+dr_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
{
if (pInit == NULL || onRead == NULL || onSeek == NULL) {
return DR_FALSE;
@@ -3610,7 +3631,7 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
}
-static drBool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
{
assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
@@ -3651,7 +3672,7 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
return (size_t)bytesRead;
}
-static drBool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
{
assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
@@ -3727,7 +3748,7 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by
return bytesToRead;
}
-static drBool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
assert(memoryStream != NULL);
@@ -4107,7 +4128,32 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO
return samplesRead;
}
-drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
+uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut)
+{
+ // This reads samples in 2 passes and can probably be optimized.
+ uint64_t samplesRead = 0;
+
+ while (samplesToRead > 0) {
+ int32_t samples32[4096];
+ uint64_t samplesJustRead = drflac_read_s32(pFlac, samplesToRead > 4096 ? 4096 : samplesToRead, samples32);
+ if (samplesJustRead == 0) {
+ break; // Reached the end.
+ }
+
+ // s32 -> s16
+ for (uint64_t i = 0; i < samplesJustRead; ++i) {
+ pBufferOut[i] = (int16_t)(samples32[i] >> 16);
+ }
+
+ samplesRead += samplesJustRead;
+ samplesToRead -= samplesJustRead;
+ pBufferOut += samplesJustRead;
+ }
+
+ return samplesRead;
+}
+
+dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
{
if (pFlac == NULL) {
return DR_FALSE;
@@ -4147,7 +4193,7 @@ drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
//// High Level APIs ////
-int32_t* drflac__full_decode_and_close(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+int32_t* drflac__full_decode_and_close_s32(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
{
assert(pFlac != NULL);
@@ -4218,6 +4264,77 @@ on_error:
return NULL;
}
+int16_t* drflac__full_decode_and_close_s16(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+{
+ assert(pFlac != NULL);
+
+ int16_t* pSampleData = NULL;
+ uint64_t totalSampleCount = pFlac->totalSampleCount;
+
+ if (totalSampleCount == 0)
+ {
+ int16_t buffer[4096];
+
+ size_t sampleDataBufferSize = sizeof(buffer);
+ pSampleData = (int16_t*)malloc(sampleDataBufferSize);
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesRead;
+ while ((samplesRead = (uint64_t)drflac_read_s16(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0)
+ {
+ if (((totalSampleCount + samplesRead) * sizeof(int16_t)) > sampleDataBufferSize) {
+ sampleDataBufferSize *= 2;
+ int16_t* pNewSampleData = (int16_t*)realloc(pSampleData, sampleDataBufferSize);
+ if (pNewSampleData == NULL) {
+ free(pSampleData);
+ goto on_error;
+ }
+
+ pSampleData = pNewSampleData;
+ }
+
+ memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int16_t)));
+ totalSampleCount += samplesRead;
+ }
+
+ // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to
+ // protect those ears from random noise!
+ memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int16_t)));
+ }
+ else
+ {
+ uint64_t dataSize = totalSampleCount * sizeof(int16_t);
+ if (dataSize > SIZE_MAX) {
+ goto on_error; // The decoded data is too big.
+ }
+
+ pSampleData = (int16_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above.
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesDecoded = drflac_read_s16(pFlac, pFlac->totalSampleCount, pSampleData);
+ if (samplesDecoded != pFlac->totalSampleCount) {
+ free(pSampleData);
+ goto on_error; // Something went wrong when decoding the FLAC stream.
+ }
+ }
+
+
+ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;
+ if (channelsOut) *channelsOut = pFlac->channels;
+ if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount;
+
+ drflac_close(pFlac);
+ return pSampleData;
+
+on_error:
+ drflac_close(pFlac);
+ return NULL;
+}
+
int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
{
// Safety.
@@ -4230,7 +4347,22 @@ int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc on
return NULL;
}
- return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ // Safety.
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open(onRead, onSeek, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
}
#ifndef DR_FLAC_NO_STDIO
@@ -4245,7 +4377,21 @@ int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* cha
return NULL;
}
- return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_file(filename);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
}
#endif
@@ -4260,7 +4406,21 @@ int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, un
return NULL;
}
- return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_memory(data, dataSize);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
}
void drflac_free(void* pSampleDataReturnedByOpenAndDecode)
@@ -4305,6 +4465,15 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui
// REVISION HISTORY
//
+// v0.4c - 2016-12-26
+// - Add support for signed 16-bit integer PCM decoding.
+//
+// v0.4b - 2016-10-23
+// - A minor change to dr_bool8 and dr_bool32 types.
+//
+// v0.4a - 2016-10-11
+// - Rename drBool32 to dr_bool32 for styling consistency.
+//
// v0.4 - 2016-09-29
// - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32()