I’ve had a go at making a basic class that will save data to a .WAV on a background thread.
Alas it is giving an error during a memcpy
.
Can anyone see what I’m doing wrong?
(I’m on OSX fwiw).
// WavDump.hh
#include "../JuceLibraryCode/JuceHeader.h"
class WavDump
{
public:
TimeSliceThread backgroundThread; // the thread that will write our audio data to disk
ScopedPointer<AudioFormatWriter::ThreadedWriter> threadedWriter; // the FIFO used to buffer the incoming data
double sampleRate;
//int64 nextSampleNum;
//int numInputChannels;
CriticalSection writerLock;
AudioFormatWriter::ThreadedWriter* volatile activeWriter;
WavDump(File& file, int numInputChannels) : backgroundThread("RecThread"), sampleRate (44100),
/*numInputChannels(_numInputChannels), nextSampleNum (0),*/ activeWriter (nullptr)
{
backgroundThread.startThread();
// Create an OutputStream to write to our destination file...
file.deleteFile();
ScopedPointer<FileOutputStream> fileStream (file.createOutputStream());
assert(fileStream != nullptr);
// Now create a WAV writer object that writes to our output stream...
WavAudioFormat wavFormat;
AudioFormatWriter* writer = wavFormat.createWriterFor (fileStream, sampleRate, numInputChannels, 16, StringPairArray(), 0);
assert(writer != nullptr);
fileStream.release(); // (passes responsibility for deleting the stream to the writer object that is now using it)
// Now we'll create one of these helper objects which will act as a FIFO buffer, and will
// write the data to disk on our background thread.
threadedWriter = new AudioFormatWriter::ThreadedWriter (writer, backgroundThread, 32768);
assert(threadedWriter != nullptr);
// Reset our recording thumbnail
//thumbnail.reset (writer->getNumChannels(), writer->getSampleRate());
//nextSampleNum = 0;
// And now, swap over our active writer pointer so that the audio callback will start using it..
{
const ScopedLock sl (writerLock);
activeWriter = threadedWriter;
}
}
void stop()
{
// First, clear this pointer to stop the audio callback from using our writer object..
{
const ScopedLock sl (writerLock);
activeWriter = nullptr;
}
// Now we can delete the writer object. It's done in this order because the deletion could
// take a little time while remaining data gets flushed to disk, so it's best to avoid blocking
// the audio callback while this happens.
threadedWriter = nullptr;
}
void feed (const float** inputChannelData, int numSamples)
{
const ScopedLock sl (writerLock);
if (activeWriter != nullptr)
activeWriter->write (inputChannelData, numSamples);
}
};
class TestWavDump
{
public:
TestWavDump() {
File file("/Users/pi/Desktop/dump.wav");
int numChans = 1;
float data[6] = {.1f,.2f,.4f,.3f,.5f,.6f};
WavDump dumper(file, numChans);
dumper.feed( (const float**)&data, 5 );
dumper.stop();
}
};
I call it with:
TestWavDump td = TestWavDump();