jordanh wrote:*These are all referring to the same buffer right? So I just create one (ref counted) AudioSample buffer (in my RecOut class) when the class is instantiated, and each audio callback I clear the buffer, copy in the new data and then pass it to an AudioFormatWriter* (lets call it myWriter) via writeFromAudioSampleBuffer using the ThreadQueue call:
e.g. m_queue.call (bond (&AudioFormatWriter::writeFromAudioSampleBuffer, myWriter, AudioSampleBuffer &source, int startSample, int numSamples));
* Next I call m_queue.process()
They refer to the same buffer but you need to create a new reference counted buffer each time the audio I/O callback executes. The old one might still be getting written out (this would be the situation if the I/O cannot keep up with the stream of generated buffers).
AudioSampleBuffer cannot be passed as a reference through the thread queue. It needs to be passed by value. You want something like this:
- Code: Select all
struct ReferenceCountedBuffer : public ReferenceCountedObject
{
typedef ReferenceCountedObjectPtr <ReferenceCountedBuffer> Ptr;
AudioSampleBuffer buffer;
};
You would need to do new ReferenceCountedBuffer in the audio I/O callback and assign it to a variable of type ReferenceCountedBuffer::Ptr. The argument passed to the function used in bind (or bond) needs to be of type ReferenceCountedBuffer::Ptr. Since writeFromAudioSampleBuffer() does not take the Ptr as a parameter, you would have to write a wrapper function.
I didn't realize this was just a school project. Getting a thread queue implementation up and running is a non-trivial task, and definitely has a higher "start up" cost than a straight critical section, although the benefits definitely pay off as the system grows in size (although this might not be your use-case).
You might be misunderstanding how the queue works. m_queue.process() has to be called from the destination thread, not the thread that is doing the m_queue.call(). There are two players at work here:
1) Audio I/O Callback.
- Acts as the "Producer"
- Puts a sequence of reference counted sample buffers into each thread queue
2) Writer thread
- Acts as the "Consumer"
- Blocks until there is work in it's associated thread queue
- Calls m_queue.process() when there is work
- Receives reference counted sample buffers as an argument to a callback function
What is missing from the DspFilters demo is the "signaling" mechanism that tells the consuming thread when to wake up and call process(). In my demo, process() is simply called once at the beginning of every audio I/O callback. However, the ThreadQueue implementation provided in the demo contains overridable virtual methods (signal and reset) which allow you to implement your own signaling.
In your case, you would need to create a subclass of ThreadQueue and override the signal() and/or reset() functions. You could use the juce::Thread::notify() and juce::Thread::wait() functions - the implementation of these is done using a juce::WaitableEvent which is perfectly suited.