#include <stdio.h>
#include <stdbool.h>
#include <emscripten.h>
#define DR_FLAC_BUFFER_SIZE (4096 * 16)
#define DR_FLAC_NO_STDIO
#define DR_FLAC_NO_OGG
#define DR_FLAC_IMPLEMENTATION
#include "dr_flac.h"
#ifdef NETWORK_DR_FLAC_FORCE_REDBOOK
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
#endif
typedef
float
float32_t;
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
typedef
struct
memrange {
uint32_t start;
struct
memrange *next;
} memrange;
typedef
struct
{
void
*buf;
unsigned blocksize;
memrange *block;
} NetworkDrFlacMem;
typedef
enum
{
NDRFLAC_SUCCESS = 0,
NDRFLAC_GENERIC_ERROR = 1,
NDRFLAC_MEM_NEED_MORE = 2,
} NetworkDrFlac_Err_Vals;
typedef
struct
{
NetworkDrFlac_Err_Vals code;
uint32_t extradata;
} NetworkDrFlac_Error;
void
*network_drflac_mem_create(
const
unsigned bufsize,
const
unsigned blocksize)
{
NetworkDrFlacMem *mem =
malloc
(
sizeof
(NetworkDrFlacMem ));
mem->buf =
malloc
(bufsize);
mem->blocksize = blocksize;
mem->block = NULL;
return
mem;
}
void
network_drflac_mem_free(NetworkDrFlacMem *pMem)
{
for
(memrange *block = pMem->block; block != NULL;)
{
memrange *nextblock = block->next;
free
(block);
block = nextblock;
}
free
(pMem->buf);
free
(pMem);
}
void
*network_drflac_mem_bufptr(
const
NetworkDrFlacMem *pMem)
{
return
pMem->buf;
}
void
network_drflac_mem_add_block(NetworkDrFlacMem *pMem,
const
uint32_t block_start)
{
memrange *block =
malloc
(
sizeof
(memrange));
block->start = block_start;
memrange **blocklist = &pMem->block;
for
(; *blocklist != NULL; blocklist = &((*blocklist)->next))
{
if
(block->start < ((*blocklist)->start))
{
break
;
}
}
memrange *nextblock = *blocklist;
*blocklist = block;
block->next = nextblock;
}
void
*network_drflac_create_error(
void
)
{
NetworkDrFlac_Error *ndrerr =
malloc
(
sizeof
(NetworkDrFlac_Error));
ndrerr->code = NDRFLAC_SUCCESS;
return
ndrerr;
}
void
network_drflac_free_error(NetworkDrFlac_Error *ndrerr)
{
free
(ndrerr);
}
uint32_t network_drflac_error_code(
const
NetworkDrFlac_Error *ndrerr)
{
return
ndrerr->code;
}
uint32_t network_drflac_extra_data(
const
NetworkDrFlac_Error *ndrerr)
{
return
ndrerr->extradata;
}
typedef
struct
{
unsigned fileoffset;
unsigned filesize;
drflac *pFlac;
NetworkDrFlac_Error *error;
const
NetworkDrFlacMem *pMem;
} NetworkDrFlac;
#define NDRFLAC_OK(xndrflac) ((xndrflac)->error->code == NDRFLAC_SUCCESS)
uint64_t network_drflac_totalPCMFrameCount(
const
NetworkDrFlac *ndrflac)
{
return
ndrflac->pFlac->totalPCMFrameCount;
}
uint32_t network_drflac_sampleRate(
const
NetworkDrFlac *ndrflac)
{
return
ndrflac->pFlac->sampleRate;
}
uint8_t network_drflac_bitsPerSample(
const
NetworkDrFlac *ndrflac)
{
return
ndrflac->pFlac->bitsPerSample;
}
uint8_t network_drflac_channels(
const
NetworkDrFlac *ndrflac)
{
return
ndrflac->pFlac->channels;
}
void
network_drflac_close(NetworkDrFlac *ndrflac)
{
drflac_close(ndrflac->pFlac);
free
(ndrflac);
}
static
drflac_bool32 on_seek_mem(
void
* pUserData,
int
offset, drflac_seek_origin origin)
{
NetworkDrFlac *ndrflac = (NetworkDrFlac *)pUserData;
if
(!NDRFLAC_OK(ndrflac))
{
printf
(
"on_seek_mem: already failed, breaking %d %u\n"
, offset, origin);
return
DRFLAC_FALSE;
}
unsigned tempoffset = ndrflac->fileoffset;
if
(origin == drflac_seek_origin_current)
{
tempoffset += offset;
}
else
{
tempoffset = offset;
}
if
((ndrflac->filesize != 0) && (tempoffset >= ndrflac->filesize))
{
printf
(
"network_drflac: seek past end of stream\n"
);
return
DRFLAC_FALSE;
}
printf
(
"seek update fileoffset %u\n"
,tempoffset );
ndrflac->fileoffset = tempoffset;
return
DRFLAC_TRUE;
}
static
bool
has_necessary_blocks(NetworkDrFlac *ndrflac,
const
size_t
bytesToRead)
{
const
unsigned blocksize = ndrflac->pMem->blocksize;
const
unsigned last_needed_byte = ndrflac->fileoffset + bytesToRead -1;
unsigned needed_block = (ndrflac->fileoffset / ndrflac->pMem->blocksize) * ndrflac->pMem->blocksize;
for
(memrange *block = ndrflac->pMem->block; block != NULL; block = block->next)
{
if
(block->start > needed_block)
{
break
;
}
else
if
(block->start == needed_block)
{
unsigned nextblock = block->start + blocksize;
if
(last_needed_byte < nextblock)
{
return
true
;
}
needed_block = nextblock;
}
}
printf
(
"NEED MORE MEM file_offset: %u lastneedbyte %u needed_block %u\n"
, ndrflac->fileoffset, last_needed_byte, needed_block);
ndrflac->error->code = NDRFLAC_MEM_NEED_MORE;
ndrflac->error->extradata = needed_block;
return
false
;
}
static
size_t
on_read_mem(
void
* pUserData,
void
* bufferOut,
size_t
bytesToRead)
{
const
size_t
ogbtr = bytesToRead;
NetworkDrFlac *nwdrflac = (NetworkDrFlac *)pUserData;
if
(!NDRFLAC_OK(nwdrflac))
{
printf
(
"on_read_mem: already failed\n"
);
return
0;
}
unsigned endoffset = nwdrflac->fileoffset+bytesToRead-1;
if
(nwdrflac->filesize > 0)
{
if
(nwdrflac->fileoffset >= nwdrflac->filesize)
{
printf
(
"network_drflac: fileoffset >= filesize %u %u\n"
, nwdrflac->fileoffset, nwdrflac->filesize);
return
0;
}
if
(endoffset >= nwdrflac->filesize)
{
unsigned newendoffset = nwdrflac->filesize - 1;
printf
(
"network_drflac: truncating endoffset from %u to %u\n"
, endoffset, newendoffset);
endoffset = newendoffset;
bytesToRead = endoffset - nwdrflac->fileoffset + 1;
}
}
if
(bytesToRead == 0)
{
printf
(
"network_drflac: reached end of stream\n"
);
return
0;
}
const
NetworkDrFlacMem *pMem = nwdrflac->pMem;
const
unsigned src_offset = nwdrflac->fileoffset;
if
(!has_necessary_blocks(nwdrflac, bytesToRead))
{
return
0;
}
uint8_t *src = (uint8_t*)(pMem->buf);
src += src_offset;
memcpy
(bufferOut, src, bytesToRead);
nwdrflac->fileoffset += bytesToRead;
return
bytesToRead;
}
void
*network_drflac_open_mem(
const
size_t
filesize,
const
NetworkDrFlacMem *pMem, NetworkDrFlac_Error *error)
{
printf
(
"network_drflac: allocating %lu\n"
,
sizeof
(NetworkDrFlac));
NetworkDrFlac *ndrflac =
malloc
(
sizeof
(NetworkDrFlac));
ndrflac->fileoffset = 0;
ndrflac->filesize = filesize;
ndrflac->error = error;
ndrflac->pFlac = NULL;
ndrflac->pMem = pMem;
drflac *pFlac = drflac_open(&on_read_mem, &on_seek_mem, ndrflac, NULL);
if
((pFlac == NULL) || (!NDRFLAC_OK(ndrflac)))
{
if
(!NDRFLAC_OK(ndrflac))
{
printf
(
"network_drflac: another error?\n"
);
if
(pFlac != NULL) drflac_close(pFlac);
}
else
{
printf
(
"network_drflac: failed to open drflac\n"
);
error->code = NDRFLAC_GENERIC_ERROR;
}
}
else
{
printf
(
"network_drflac: opened successfully\n"
);
ndrflac->pFlac = pFlac;
return
ndrflac;
}
free
(ndrflac);
return
NULL;
}
uint64_t network_drflac_read_pcm_frames_f32_mem(NetworkDrFlac *ndrflac, uint32_t start_pcm_frame, uint32_t desired_pcm_frames, float32_t *outFloat, NetworkDrFlac_Error *error)
{
drflac *pFlac = ndrflac->pFlac;
ndrflac->error = error;
printf
(
"seek to %u\n"
, start_pcm_frame);
const
uint32_t currentPCMFrame32 = pFlac->currentPCMFrame;
const
drflac_bool32 seekres = drflac_seek_to_pcm_frame(pFlac, start_pcm_frame);
if
(!NDRFLAC_OK(ndrflac))
{
printf
(
"network_drflac_read_pcm_frames_f32_mem: failed seek_to_pcm_frame NOT OK current: %u desired: %u\n"
, currentPCMFrame32, start_pcm_frame);
return
0;
}
else
if
(!seekres)
{
printf
(
"network_drflac_read_pcm_frames_f32_mem: seek failed current: %u desired: %u\n"
, currentPCMFrame32, start_pcm_frame);
error->code = NDRFLAC_GENERIC_ERROR;
return
0;
}
float32_t *data =
malloc
(pFlac->channels*
sizeof
(float32_t)*desired_pcm_frames);
uint32_t frames_decoded = drflac_read_pcm_frames_f32(pFlac, desired_pcm_frames, data);
if
(frames_decoded != desired_pcm_frames)
{
printf
(
"network_drflac_read_pcm_frames_f32_mem: expected %u decoded %u\n"
, desired_pcm_frames, frames_decoded);
}
if
(!NDRFLAC_OK(ndrflac))
{
printf
(
"network_drflac_read_pcm_frames_f32_mem: failed read_pcm_frames_f32\n"
);
free
(data);
return
0;
}
#ifdef NETWORK_DR_FLAC_FORCE_REDBOOK
if
(pFlac->sampleRate != 44100)
{
printf
(
"Converting samplerate from %u to %u\n"
, pFlac->sampleRate, 44100);
ma_resampler_config config = ma_resampler_config_init(ma_format_f32, pFlac->channels, pFlac->sampleRate, 44100, ma_resample_algorithm_linear);
ma_resampler resampler;
ma_result result = ma_resampler_init(&config, &resampler);
ma_uint64 frameCountIn = frames_decoded;
ma_uint64 frameCountOut = ma_resampler_get_expected_output_frame_count(&resampler, frameCountIn);
float32_t *pFramesOut =
malloc
(frameCountOut*pFlac->channels*
sizeof
(float32_t));
ma_result result_process = ma_resampler_process_pcm_frames(&resampler, data, &frameCountIn, pFramesOut, &frameCountOut);
free
(data);
if
(result_process != MA_SUCCESS)
{
printf
(
"network_drflac_read_pcm_frames_f32_mem: failed read_pcm_frames_f32 resample\n"
);
return
0;
}
data = pFramesOut;
frames_decoded = frameCountOut;
}
#endif
for
(unsigned i = 0; i < frames_decoded; i++)
{
for
(unsigned j = 0; j < pFlac->channels; j++)
{
unsigned chanIndex = j*frames_decoded;
float32_t sample = data[(i*pFlac->channels) + j];
outFloat[chanIndex+i] = sample;
}
}
printf
(
"returning from start_pcm_frame: %u frames_decoded %u data %p\n"
, start_pcm_frame, frames_decoded, data);
free
(data);
return
frames_decoded;
}