Hi, is there a simple way to save a say, std::vector<float>
to disk as a WAV file? Thanks.
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);
I second that. It does not use std::vector, is uses constant float * I think.
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/
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.
You are right, I edited my code to use vec.data()
, now it works fine!
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);