dr_libs
dr_libs copied to clipboard
dr_wav append write?
Hi, is there a way for dr_wav to append data to a wav file when writing instead of rewriting the file?
No, unfortunately appending is not supported. The writing API was only really designed for basic use cases.
Thanks. It might be complex to implement it to dr_wav. I have looked and I will have to have a deep understanding of the lib to be able to implement it.
The way to do it:
open file seek to the end of the file write new data read old wav header create a new wav header and overwrite the old one
This lib is doing exactly that: https://github.com/justinfrankel/WDL/blob/master/WDL/wavwrite.h
Yeah I'm not against adding support or anything. I'll mark this as a feature request and get to it when I can, but it could be a ways away.
I qm already working on it. Might have it ready in a couple of hours
I think I got it. I will need to do more testing, but so far it works great.
Here are the changes/additions:
typedef enum
{
drwav_seek_origin_start,
drwav_seek_origin_current,
drwav_seek_origin_end
} drwav_seek_origin;
DRWAV_PRIVATE drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
{
drwav_uint32 seekOrigin = SEEK_SET;
if (origin == drwav_seek_origin_current)
seekOrigin = SEEK_CUR;
if (origin == drwav_seek_origin_end)
seekOrigin = SEEK_END;
return fseek((FILE*)pUserData, offset, seekOrigin) == 0;
}
DRWAV_API drwav_bool32 drwav_init_file_write_append(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
{
return drwav_init_file_write_append__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
}
DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_append__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
{
/* Open the file and get current data chunk size */
drwav_uint64 dataChunkDataSize = 0;
drwav_uint64 dataChunkDataPos = 0;
drwav_bool32 appendToFile = DRWAV_FALSE;
/* Open file for writing */
FILE* pFile;
if (drwav_fopen(&pFile, filename, "r+b") == DRWAV_SUCCESS)
{
if (drwav_init_file(pWav, filename, NULL)) {
dataChunkDataSize = pWav->dataChunkDataSize;
dataChunkDataPos = pWav->dataChunkDataPos;
appendToFile = DRWAV_TRUE;
}
drwav_uninit(pWav);
drwav_bool32 result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (result != DRWAV_TRUE) {
fclose(pFile);
return result;
}
pWav->container = pFormat->container;
pWav->channels = (drwav_uint16)pFormat->channels;
pWav->sampleRate = pFormat->sampleRate;
pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
if (appendToFile)
{
pWav->dataChunkDataSize = dataChunkDataSize;
pWav->dataChunkDataPos = dataChunkDataPos;
if (pWav->onSeek) {
pWav->onSeek(pWav->pUserData, 0, drwav_seek_origin::drwav_seek_origin_end);
}
}
return result;
}
else if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS)
{
return DRWAV_FALSE;
}
/* This takes ownership of the FILE* object. */
return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
}
drwav_init_file_write_append__internal was made a bit more complicated but in this way falling to call drwav_uninit won't render the file unreadable.
That basically means, if you create and write 3 seconds successfully, then close the file and open it again to append audio to it, but for some reason app crashes while writing data, and you don't call drwav_uninit (header data is not updated), the file will be still readable, and you will be able to play the first 3 seconds just fine. That is a pretty super feature to have. :)
I have run some tests today, and it seems it's working as expected.
Thanks for that sample code. I'll review this when I get a chance.