Playback multiple audio files in sync


#1

Hi,

I need to be able to playback 24 audio files in sync. Due to wav size limits I am unable to create a multichannel file (the audio files may be an hour long). So my question is:

What is the correct way to playback multiple files in sync?

Should I create a MixerAudioSource with 24 input channels?

Note: I made a very quick mockup using a vector of audio players (a custom class),  looped through them and called start() on the AudioTransportSource and it seemed to playback in sync anyway - does this mean I don't need to do anything in particular or was I just lucky?

Thanks!

 


#2

I doubt you were just lucky.  If the files are all at the same sample rate and you are getting the same sized blocks each time it'll just stay in synchronization.


#3

It looks lucky to me.  When calling start, each transport takes it's own lock on the audio thread so the audio thread could very well start some transports before others.  I believe you'd need to lock the audio thread for the duration of your start loop to ensure proper synchronization.


#4

Thanks for the replies.

 

Just found this:

'If you mean two AudioTransportSources, then they should be syncronised as long as you start them both before the same audio callback.'

from here: http://www.juce.com/forum/topic/synchronising-audio-tracks

 

So I guess I do not need to do anything special, just lock the audio thread?


#5

Or I guess just start them from the audio thread at the same time .. ?  Or possibly even just start the audio callbacks after you've started the audio sources.  What are you using to mix / play them?  


#6

I'm simply using AudioSourcePlayer and AudioTransportSource to playback the files.


#7

So lots of AudioSourcePlayer instances? I"m siding with Graeme now - there's a definitely possibility of out-of-sync. 

CriticalSection& AudioDeviceManager::getAudioCallbackLock() noexcept

Returns the a lock that can be used to synchronise access to the audio callback.

Obviously while this is locked, you're blocking the audio thread from running, so it must only be used for very brief periods when absolutely necessary.

Or just don't start the audio device until after you've set up the callbacks.  Once the callbacks have started okay though everything will keep in step.


#8

Thanks for the replies.

So, to preform the lock do I need to do something along the lines of this:

 

//lock

for (int i = 0; i < numSamples; ++i){

    ScopedLock lock(audioPlayers[i]->audioDeviceManager.getAudioCallbackLock());

}

 

//play

for (int i = 0; i < numSamples; ++i){

    audioPlayers[i]->playSample();

}

 

//unlock

for (int i = 0; i < numSamples; ++i){

    ScopedLock unlock(audioPlayers[i]->audioDeviceManager.getAudioCallbackLock());

}


#9

A ScopedLock only exists within the block it is defined so any locks aquired in the first for loop will be aquired and destroyed with each iteration of the loop.  Also the "unlock" loop doesn't make sense as all it's doing is aquiring the locks again.  A ScopedLock is automatically "unlocked" when the scope it's defined in is exited.  You'll just need to do something like this:

...

ScopedLock lock(audioPlayers[0]->audioDeviceManager.getAudioCallbackLock());

for (int i = 0; i < numSamples; ++i){

    audioPlayers[i]->playSample();

}

...


#10

Ah I see,  that is a big help. thanks!