Browse Source

Improved FLAC audio support

pull/211/head
raysan5 8 years ago
parent
commit
5da815234c
3 changed files with 255 additions and 93 deletions
  1. BIN
      examples/resources/audio/tanatana.flac
  2. +9
    -16
      src/audio.c
  3. +246
    -77
      src/external/dr_flac.h

BIN
examples/resources/audio/tanatana.flac View File


+ 9
- 16
src/audio.c View File

@ -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->totalSampleCounto">/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);
o">// 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");

+ 246
- 77
src/external/dr_flac.h View File

@ -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()

Loading…
Cancel
Save