Multiple Audio File Writing


#1

Hi everybody.
I’m writing an app that’s supposed to write all active audio outputs to mono wav-files. I tried the followingto create my files

[code]outputFiles[128];
int outputChannel=0;
int i=0;
while ( outputChannel != -1 )
{
// find next active output
outputChannel = audioDeviceManager->getOutputChannels().findNextSetBit(outputChannel);

if ( outputChannel != -1 )	// we have an active output at this index
{
	String fileName = String("c:\\test\\channel");
	fileName += String(outputChannel+1);	// add channel-number
	fileName += String(".wav");

	outputFiles[i] = File(fileName);
	outputChannel++;
	i++;
}

}[/code]
and in the thread that’s doing the actual writing

for (int i=0; i<buffer->getNumChannels(); i++) // loop over all available channels { // more code... outputTo = outputFiles[i].createOutputStream(); writer = wavFormat->createWriterFor(outputTo, 44100, 1, 16, NULL, 0); oneChannelBuffer.writeToAudioWriter( writer, 0, OneChannelBuffer.getNumSamples()); delete writer; oneChannelBuffer.clear(); }
Problem is that I can’t open the files in Audacity. I can only import them as raw data and there is a crackle in the files (about 20-22 Samples) at the positions I guess, where the writer continued to write to the file.
any suggestions what I’m doing wrong? Thanks for your help :slight_smile:


#2

Looks to me you are creating a raw binary file(no wave header) which explains why Audacity needs to read it in as raw.

Take a look at juce_WavAudioFormat.h there is a createWriterFor function that “Tries to create an object that can write to a stream with this audio format.”

I haven’t used it myself(yet!) but in the constructor/deconstructor(for updating after writing audio samples) of WavAudioFormatWriter you can it creating the proper header. The writer also seems to take care of converting from float to little/big endian ints as well…

Hope that helps…


#3

hm, I am actually using the createWriterFor function, as you can see. In first tests, when writing only one file, I created the outputStream and writer in the constructor and then repeatedly wrote to the file and there was no problem. The errors occured when I started to create and delete stream and writer during the loop. So I guess, I’m wrong there.


#4

Whoops, sorry, my mistake, that’s what I get for posting before breakfast!


#5

Most likely you’re re-using a deleted writer or deleting an input stream twice, or something like that. Or if you’re using threads, there could be more than one trying to write the same file.


#6

I use only one thread for file writing, which repeatedly should create and destroy a writer to the destination file. I record the output of processed audio, so i append audio data to the files when it’s available.
At this point the crackle appears (so it’s the first 22 samples, too). I had a closer look at the waveforms and saw that they are all the same. I mean the crackle, in all files.
So using only one thread to write, I don’t think it’s a thread problem. The data is read from audioDeviceOutput and buffered to a multichannel AudioSampleBuffer, copied to a single Channel AudioSampleBuffer and sent to the audioWriter, so I don’t have or delete any input streams.
Thought about re-using a deleted writer, but I think I’m creating a new one, ain’t I?
Thanks for your help,
Ingo


#7

Oh, well you can’t use these classes to append to a file - not sure how you imagined that would work! Effectively, you’re sticking one wave file on the end of another, so obviously you’ll get a “crackle” - that’s the second file’s header bytes!


#8

ohh, thanks… a bit too fast perhaps :oops:
I read this thread http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=2272 and modified mrblasto’s code. But isn’t he doing the same thing?
So I have to use FileOutputStream::write for my issue?


#9

??? Only if you’re going to manually write the file yourself.

You can’t just stuff extra bytes on the end of a file and expect it to work - the header needs to contain info about the file size. If you’re streaming to a file, just keep the writer open and keep writing to it until you’re finished.


#10

ok, understood. can I create the writers in an array like I did it with the files then. At the moment I’ve got 128 outputChannels and this number will possibly even increase. That’s the reason why I came to the stupid idea of creating the write in loop when i actually want to write some audio. I hoped to have it working with one writer instead of 128…
Any other suggestions to solve this problem more elegantly?


#11

http://code.google.com/p/thor-v2/source/browse/trunk/ThorWorkerThread.cpp

this is how i did it, check the bool ThorWorkerThread::ogg2wav (InputStream *in, OutputStream *out) method, it works for me and my little kitty:
http://code.google.com/p/thor-v2/