Hello people!
I am really struggling writing audio to wav file. Sorry if this are basic questions, i am just starting, so please be patient
I am trying to build a bare minimum code to test it, but keep getting different errors. Searched the forum and tried for two days now but cant get it working.
What am i doing wrong?
From what i understood from the documentation, i should use the function:
writeFromAudioSampleBuffer()
from the class:
AudioFormatWriter
The class description says:
After creating one of these with the AudioFormat::createWriterFor() method you can call its write() method to store the samples, and then delete it.
So since the goal is to write wav files, i choose the WavAudioFormat
subclass and go to createWriterFor()
, which has a constructor like this:
OutputStream *streamToWriteTo*,
double *sampleRateToUse*,
unsigned int *numberOfChannels*,
int *bitsPerSample*,
const StringPairArray& *metadataValues*,
int *qualityOptionIndex*
- qualityOptionIndex “…just pass 0 in this parameter, as it’ll be ignored”
- metadataValues can also be ignored (from the AudioRecordingDemo.h) “{}”
- bitsPerSample is self explanatory (values 8,16,24,32) (saw this somewhere in the source code but cant find it anymore)
- numberOfChannels and sampleRateToUse, also self explanatory
- streamToWriteTo: we need to create an OutputStream object:
The documentation for the functions also says:
The writer object that is returned can be used to write to the stream, and should then be deleted by the caller.
but OutputStream has a more promissing subclass to use: FileOutputStream
:
Which has a constructor like this:
FileOutputStream::FileOutputStream ( const File& *fileToWriteTo*,
size_t *bufferSizeToUse* = 16384 )
write next to it the documentation gives us an example as:
FileOutputStream stream (file);
question 1)
What is this bufferSizeToUse
for? what implications does it have?
is this not set later by the writeFromAudioSampleBuffer?
writeFromAudioSampleBuffer ( const AudioBuffer< float > & source,
int startSample,
int numSamples )
but going foward, we now need a file object:
File::File ( const String & absolutePath )
So our code in compact form should be something like:
juce::File file("path/output.wav");
juce::FileOutputStream stream (file);
// test with stream.openedOk()
// now we need the WavAudioFormat to return the pointer for the writer:
juce::WavAudioFormat wavFormat;
// from other forum posts i am assuming that the returned writer object is in the form of a unique pointer
std::unique_ptr<juce::AudioFormatWriter> writer;
writer.reset(wavFormat.createWriterFor(
&stream,
44100,
2,
16,
{},
0));
//still dont understand when to use . or ->
writer->writeFromAudioSampleBuffer(buffer, 0, buffer.getNumSamples())
Question 2)
How should this be applied to a plugin, if i want to write the incoming buffers to a wav file?
just calling writeFromAudioSampleBuffer
inside processBlock should be avoided so we dont block the audiothread.
But i am confused on how to use the ThreadedWriter
Question 3)
from AudioRecordingDemo.h
:
fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it)
Why we need this?
i am really confused how this all works. We have a file, a file stream to this file, and a writer that “uses” this stream to write to the file.
I need to study pointers more.
Question 4)
What happens if the Sample rate and BitDepth from the buffer passed to writeFromAudioSampleBuffer()
are different from the ones declared inside wavFormat.createWriterFor()
?
.
.
.
My attempt, to just get it working in the simplest way, even if breaking the audiothread, was to do it like this:
// Declare stuff in ProcessPlugin.h
private:
std::unique_ptr<juce::AudioFormatWriter> writer;
// PluginProcessor.cpp
// inside prepareToPlay() (not really sure if here or at AudioProcessor() constructor)
// open/create file, initialize stream and writer
juce::File file("path/output.wav");
juce::FileOutputStream stream(file);
juce::WavAudioFormat wavFormat;
writer.reset(wavFormat.createWriterFor(
&stream,
44100,
2,
16,
{},
0));
// Inside ProcessBlock() write the buffer
if (writer != nullptr)
writer->writeFromAudioSampleBuffer(buffer, 0, buffer.getNumSamples());
Runing this i receive the Error:
//at juce_WavAudioFormat.cpp 1652:
// bool write(
// ...
// if (! output->write (tempBlock.getData(), bytes)) {...}
Exception thrown: read access violation.
this->output-> was 0x1F68.
Any thoughts or insights on how to proper use the writeFromAudioSampleBuffer and write incoming audio to Wav?
Running on Windows 11, Visual Studio 2022, AudioPluginHost.
Tried to make this the most detailed possible, sorry for the long post.