Re: MusicEventIterator questions
Re: MusicEventIterator questions
- Subject: Re: MusicEventIterator questions
- From: Ross Bencina <email@hidden>
- Date: Thu, 21 Mar 2013 11:16:12 +1100
On 20/03/2013 8:30 AM, Aran Mulholland wrote:
> I guess I'm most interested in how to pass the audio thread the latest
> array. I'll have a look at that article you wrote.
[forwarding what I accidentally wrote privately yesterday]
Here's the game plan:
Have two lock free FIFO queues[1]
UI -> Audio (uiToAudio)
UI <- Audio (audioToUi)
struct S {}; // our audio-thread sequence type
// queues need to be available to both UI and callback
// queues carry sequence pointers only.
LockFreeFifo<S*> uiToAudio_, audioToUi_;
// keep a pointer to your audio sequence structure somewhere
// sequence version only refered to by Audio thread (aka RT).
S *sequenceRt_ = 0;
------------------------------
at the start of every audio callback do this:
while( uiToAudio_.canPop() ){
S *newS=uiToAudio_.pop()
// send old back to ui
if( sequenceRt_ ) audioToUi_.push(sequenceRt_);
// install new
sequenceRt_ = newS;
reset/update audio thread iterators
}
------------------------------
when you want to send an updated sequence to audio thread
checkForResultsFromAudioThread(); // see below
S *newS = compileNewAudioSequenceFromUiSequence(uiSequence);
uiToAudio_.push( newS );
------------------------------
// call this on a timer in the UI thread. and also before sending
void checkForResultsFromAudioThread()
{
while( audioToUi_.canPop() ){
S *oldS=audioToUi_.pop()
delete oldS;
}
}
------------------------------
If you had multiple tracks you could send more information in the queue
so that teh callback knows where to "install" the sequence
struct AudioThreadTrack {
S *sequenceRt = 0;
};
AudioThreadTrack tracks_[16];
struct UpdateCommand {
int trackIndex;
S *newS;
UpdateCommand( i, s ) : trackIndex(i), newS(s) {}
};
LockFreeFifo<UpdateCommand > uiToAudio_;
// note that the FIFO now carrys command instances, which contain the
newS and which track to install into
while( uiToAudio_.canPop() ){
const UpdateCommand& cmd = uiToAudio.front(); // read cmd in-place
// send old back to ui
if( tracks_[cmd.i].sequenceRt )
audioToUi_.push(tracks_[cmd.i].sequenceRt);
// install new
tracks_[cmd.i].sequenceRt = cmd.newS;
uiToAudio_.pop(); advance fifo
reset/update audio thread iterators
}
------------------------------
Moving beyond that you can store a "command type" enumeration in each
command to perform different actions, or store function pointers
to execute arbitrary code in the remote thread.
The main point being that these command structures are so small (a few
bytes) that you want to copy them directly into the queue not allocate
them separately. They're kind of like stack frames on the C stack.
That's the basics anyhow.
If you want to have data structures with both full-replacement and
optional replacement of sub-parts you need to use reference counting for
the subparts. Blog post for that is yet to be written.
Ross
[1] I like the ringbuffer in PortAudio one myself :), you can find it in
src/common/pa_ringbuffer.{c,h}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden