Export a Wav File


#1

Hello there!

I’m trying to export the audiostream from my Synthesiser to a wavfile.

But an EXC_BAD_ACCESS signal is sent to me at the same moment (near startsample = 2028) during the export. It comes from AudioSource::renderNextBlock at this line :

if (numThisTime > 0) { for (int i = voices.size(); --i >= 0;) voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime); //OVER HERE }

Here is my ExportWavFile method :

[code]void SynthAudioSource::ExportWavFile(const File& file)
{
mIsExporting = true;
MidiBuffer midibuffer;
uint startsample = 0;
uint endsample = 0;
uint numSamples = mSeq.GetLengthPatternInFrames();
FileOutputStream* fos = new FileOutputStream(file);
AudioFormatWriter* wavwriter = WavAudioFormat().createWriterFor(fos, 44100, 2, 16, StringPairArray(), 0);
AudioSampleBuffer audiobuffer(2, numSamples);

if(startsample + 1024 <= numSamples)
{
endsample += 1024;
}
else
{
endsample = numSamples - startsample;
}

while (startsample < numSamples)
{
//Fill the midibuffer with NoteOn and NoteOff events raise from the Sequencer
mSeq.ExportWavFile(startsample, endsample, midibuffer);
//Synthesiser renders midibuffer’s events
mSynth.renderNextBlock(audiobuffer, midibuffer, startsample, endsample);
//Write audiobuffer into the FOS
audiobuffer.writeToAudioWriter(wavwriter, startsample, endsample);
midibuffer.clear();

startsample += 1024;

if(startsample + 1024 <= numSamples)
{
  endsample += 1024;
}
else
{
  endsample = numSamples - startsample;
}

}
[/code]

mSeq.ExportWavFile looks like mSeq.Process (without some useless stuffs in this case like asynchronous GUI events) that i’m using in the AudioSource::getNextAudioBlock callback (and it’s working well for two months) :

[code]void SynthAudioSource::getNextAudioBlock(const AudioSourceChannelInfo& bufferToFill)
{
bufferToFill.clearActiveBufferRegion();

if(!mIsExporting)
{
MidiBuffer incomingMidi;
mMidiCollector.removeNextBlockOfMessages(incomingMidi, bufferToFill.numSamples);
mSeq.Process(bufferToFill.numSamples, incomingMidi);
mSynth.renderNextBlock (*bufferToFill.buffer, incomingMidi, 0, bufferToFill.numSamples);
}
}
[/code]

I block this calback when I’m exporting the wav file, to be safer, and they have the same numSample (1024).

I really don’t understand what is happening.

Any ideas ?

Thanks.


#2

Damn it was my dummy endsample.

Here is a better code. But for now, i’ve only got the first beat (sample = 0) which seems to be exported.

[code]if(startsample + 1024 <= numSamples)
{
endsample += 1024;
}
else
{
endsample = numSamples;
}

while (startsample < numSamples)
{
//Fill the midibuffer with NoteOn and NoteOff events raise from the Sequencer
mSeq.ExportWavFile(startsample, endsample, midibuffer);

//Synthesiser renders midibuffer's events
mSynth.renderNextBlock(audiobuffer, midibuffer, startsample, endsample - startsample);

//Write audiobuffer into the FOS
audiobuffer.writeToAudioWriter(wavwriter, startsample, endsample - startsample);
midibuffer.clear();

startsample += 1024;

if(startsample + 1024 <= numSamples)
{
  endsample += 1024;
}
else
{
  endsample = numSamples;
}

}
[/code]


#3

Maybe try actually deleting your wav writer object…


#4

I missed this part when i pasted but it’s deleted.


#5

I put an assertion in writeToAudioWriter to catch it when your parameters are out-of-range, as yours seem to be. Aren’t you running in debug mode?


#6

I’m in debug mode.

Yes i know this assert but my new code is correct.

My original song is about 10 seconds, the exported file is about 10 secs but only the notes on the first beat are listenable. I think I’ll find, don’t bother. Thanks.


#7

Like I said, it just looks like you’re just passing the wrong parameters to writeToAudioWriter - it takes the offset from the start of the audio buffer, not the offset from the start of the target file.


#8

Yep. I didn’t understand how audiobuffer and writeTo work.

Here is the correct one :

[code]void SynthAudioSource::ExportWavFile(const File& file)
{
mExportLocker.enter();

MidiBuffer midibuffer;
uint numFrames = 0;
uint numSamples = mSeq.GetLengthPatternInFrames();
FileOutputStream* fos = new FileOutputStream(file);
AudioFormatWriter* wavwriter = WavAudioFormat().createWriterFor(fos, 44100, 2, 16, StringPairArray(), 0);
AudioSampleBuffer audiobuffer(2, 1024);

mSeq.PrepareToExport();

if(1024 <= numSamples)
{
numFrames = 1024;
}
else
{
numFrames = numSamples;
}

uint startsample = 0;

while (startsample + numFrames < numSamples)
{
//Fill the midibuffer with NoteOn and NoteOff events from the Sequencer
mSeq.Process(numFrames, midibuffer);
//Synthesiser renders midibuffer’s events
mSynth.renderNextBlock(audiobuffer, midibuffer, 0, numFrames);
//Write audiobuffer into the FOS
audiobuffer.writeToAudioWriter(wavwriter, 0, numFrames);
audiobuffer.clear();
midibuffer.clear();

startsample = mSeq.mCurrentFrame;

if(startsample + 1024 <= numSamples)
{
  numFrames = 1024;
}
else
{
  numFrames = numSamples - startsample;
}

}

delete wavwriter;

mSeq.Reset();

mExportLocker.exit();
}[/code]