Open Youlean opened 2 years ago
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.
Hi, is there a way for dr_wav to append data to a wav file when writing instead of rewriting the file?