If I set readerSource->setLooping(false) and the audio file has already looped the audio play back stops. Is this a bug or am I misunderstanding how setLooping works? If it is a bug is there a workaround?
There was discussion about this around seven years ago but I don’t see anything more recent.
I believe I’m using the latest version of JUCE.
It’s a bug. The problem is that the value of nextPlayPos gets higher and higher on each play-repeat, whereas it should reset to zero when starting again.
The getNextReadPosition() and getNextAudioBlock() methods get away with it because of their use of the modulo operator (the % symbol). But as soon as looping is switched off, the modulo operator is no longer applied, and you end up with a crazy high value for nextPlayPos.
A few ways to go, imo:-
fix in AudioFormatReaderSource and submit a PR
raise an issue on GitHub and ask the core team to fix
write your own version of AudioFormatReaderSource with the fix, and use that instead.
I wrote my own version of AudioFormatReaderSource in order to better control looping between user-set start/end loop points, and in doing so found and fixed this bug in my version. The code looks like this:-
juce::int64 RomplerAudioReaderSource::getNextReadPosition() const
{
#if false
// original
return looping ? nextPlayPos % reader->lengthInSamples
: nextPlayPos;
#else
// new code, to stop 'nextPlayPos' advancing higher and higher forever
if (!looping)
{
return nextPlayPos;
}
else
{
if (nextPlayPos < reader->lengthInSamples)
{
return nextPlayPos;
}
nextPlayPos = nextPlayPos % reader->lengthInSamples;
return nextPlayPos;
}
#endif
}
Two extra things to do:-
Mark field nextPlayPos as mutable in the header file, otherwise getNextReadPosition() won’t be able to update it.
Change getNextAudioBlock() to set readFrom by calling the now-correct getNextReadPosition() method, instead of repeating the computation.
--
I’m not saying that the above is the best solution. But it’s a hacky fix that works in my private version of AudioFormatReaderSource. Perhaps a better way is to wrap-around nextPlayPos just after incrementing it.