Simple way to write wav to disk?

Hi, is there a simple way to save a say, std::vector<float> to disk as a WAV file? Thanks.

1 Like

I would recommend “dr_wav”. It’s a simple single file library.

dr_wav can also be used to output WAV files. This does not currently support compressed formats.

To use this, look at drwav_init_write(), drwav_init_file_write(), etc.

Use drwav_write_pcm_frames() to write samples, or drwav_write_raw() to write raw data in the “data” chunk.

    drwav_data_format format;
    format.container = drwav_container_riff;     // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
    format.format = DR_WAVE_FORMAT_PCM;          // <-- Any of the DR_WAVE_FORMAT_* codes.
    format.channels = 2;
    format.sampleRate = 44100;
    format.bitsPerSample = 16;
    drwav_init_file_write(&wav, "data/recording.wav", &format, NULL);
    ...
    drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples);
1 Like

I second that. It does not use std::vector, is uses constant float * I think.

1 Like

Yes! Squinky is right!

@JHuang If you need the float* from a std::vector<float> vec do this: &vec[0];

(not valid for empty vector)

You can use vec.data(), which is always valid: https://cplusplus.com/reference/vector/vector/data/

2 Likes

Oops, I meant std::vector<float>, edited!

I’ve tried dr_wav, but somehow I can only save short samples.

My code (which works for now) :

        int sample_count = sample_rate * 2; //sample_rate * seconds
        DEBUG("sample_count,%d", sample_count);
        float data[sample_count];
        for (int i = 0; i < sample_count; i++)
        {
            data[i] = 0.f;
        }

        drwav_data_format format;
        format.container = drwav_container_riff;   // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
        format.format = DR_WAVE_FORMAT_IEEE_FLOAT; // <-- Any of the DR_WAVE_FORMAT_* codes.
        format.channels = 1;
        format.sampleRate = sample_rate;
        DEBUG("sample rate: %d", sample_rate);
        format.bitsPerSample = 32;
        
        std::string filename = "/recording.wav";
        std::string fullpath = path + filename;
        DEBUG("save path: %s", fullpath.c_str());
        drwav wav;
        drwav_init_file_write(&wav, fullpath.c_str(), &format, NULL);
        drwav_uint64 framesWritten = drwav_write_pcm_frames(&wav, sample_count, data);
        drwav_uninit(&wav);
        DEBUG("frame written: %d", (int)framesWritten);
       

if I change int sample_count = sample_rate * 2 to

int sample_count = sample_rate * 20 //increase record time to 20s

it will give me this error

Process 10451 stopped
* thread #8, name = 'com.apple.audio.IOThread.client', stop reason = EXC_BAD_ACCESS (code=2, address=0x2040d4000)
    frame #0: 0x00007ff80c1f1c81 libsystem_platform.dylib`_platform_memset$VARIANT$Rosetta + 108
libsystem_platform.dylib`:
->  0x7ff80c1f1c81 <+108>: movntiq %rsi, (%rcx)
    0x7ff80c1f1c85 <+112>: movntiq %rsi, 0x8(%rcx)
    0x7ff80c1f1c8a <+117>: movntiq %rsi, 0x10(%rcx)
    0x7ff80c1f1c8f <+122>: movntiq %rsi, 0x18(%rcx)

I have no idea what went wrong, so I gave up on dr_wav

You are probably blowing up your limited stack space on this line:

float data[sample_count];

You would be better off going back to std::vector<float>, which dynamically allocates the memory. I think you are very close… don’t give up!

But I can’t understand, if I do

float data[sample_count];

It will allocate sizeof(float) * sample_count bytes of memory for me, won’t it?

Thanks

It tries to allocate it, but it does so on the stack, which is usually limited to a few kilobytes of memory. There is not enough stack space for an array that large. You are running into a stack overflow that causes a crash.

You need to allocate from heap memory, which is why you should use std::vector<float> to wrap the allocation, and to automatically free the memory via destructor when the vector goes out of scope.

2 Likes

You are right, I edited my code to use vec.data(), now it works fine! :grinning:

Thank you very much!

        int sample_count = sample_rate * 20; // sample_rate * seconds
        DEBUG("sample_count,%d", sample_count);
        std::vector<float> data;
        for (int i = 0; i < sample_count; i++)
        {
            data.push_back(0.f);
        }

        drwav_data_format format;
        format.container = drwav_container_riff;   // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
        format.format = DR_WAVE_FORMAT_IEEE_FLOAT; // <-- Any of the DR_WAVE_FORMAT_* codes.
        format.channels = 1;
        format.sampleRate = sample_rate;
        DEBUG("sample rate: %d", sample_rate);
        format.bitsPerSample = 32;

        std::string filename = "/recording.wav";
        std::string fullpath = path + filename;
        DEBUG("save path: %s", fullpath.c_str());
        drwav wav;
        drwav_init_file_write(&wav, fullpath.c_str(), &format, NULL);
        drwav_uint64 framesWritten = drwav_write_pcm_frames(&wav, sample_count, data.data());
        drwav_uninit(&wav);
        DEBUG("frame written: %d", (int)framesWritten);
4 Likes