Consume equal amounts from play ring buffers in each callback pass...

... which should be the whole framesPerBuffer normally.

Also rename another function used in producing the samples.
This commit is contained in:
Paul Licameli 2018-08-17 08:47:36 -04:00
parent 8a6351d9cd
commit 45231b8f6a
2 changed files with 35 additions and 6 deletions

View File

@ -3379,12 +3379,23 @@ MidiThread::ExitCode MidiThread::Entry()
}
#endif
size_t AudioIO::GetCommonlyAvailPlayback()
size_t AudioIO::GetCommonlyFreePlayback()
{
auto commonlyAvail = mPlaybackBuffers[0]->AvailForPut();
for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
commonlyAvail = std::min(commonlyAvail,
mPlaybackBuffers[i]->AvailForPut());
// MB: subtract a few samples because the code in FillBuffers has rounding
// errors
return commonlyAvail - std::min(size_t(10), commonlyAvail);
}
size_t AudioIO::GetCommonlyReadyPlayback()
{
auto commonlyAvail = mPlaybackBuffers[0]->AvailForGet();
for (unsigned i = 1; i < mPlaybackTracks.size(); ++i)
commonlyAvail = std::min(commonlyAvail,
mPlaybackBuffers[i]->AvailForGet());
return commonlyAvail;
}
@ -3902,8 +3913,7 @@ void AudioIO::FillBuffers()
// if we hit this code during the PortAudio callback. To keep
// things simple, we only write as much data as is vacant in
// ALL buffers, and advance the global time by that much.
// MB: subtract a few samples because the code below has rounding errors
auto nAvailable = (int)GetCommonlyAvailPlayback() - 10;
auto nAvailable = (int)GetCommonlyFreePlayback();
//
// Don't fill the buffers at all unless we can do the
@ -5089,6 +5099,11 @@ int AudioIO::AudioCallback(const void *inputBuffer, void *outputBuffer,
int group = 0;
int chanCnt = 0;
decltype(framesPerBuffer) maxLen = 0;
// Choose a common size to take from all ring buffers
const auto toGet =
std::min<size_t>(framesPerBuffer, GetCommonlyReadyPlayback());
for (unsigned t = 0; t < numPlaybackTracks; t++)
{
WaveTrack *vt = mPlaybackTracks[t].get();
@ -5147,9 +5162,15 @@ int AudioIO::AudioCallback(const void *inputBuffer, void *outputBuffer,
{
len = mPlaybackBuffers[t]->Get((samplePtr)tempBufs[chanCnt],
floatSample,
framesPerBuffer);
toGet);
// wxASSERT( len == toGet );
if (len < framesPerBuffer)
// Pad with zeroes to the end, in case of a short channel
// This used to happen normally at the end of non-looping
// plays, but it can also be an anomalous case where the
// supply from FillBuffers fails to keep up with the
// real-time demand in this thread (see bug 1932). We
// must supply something to the sound card, so pad it with
// zeroes and not random garbage.
memset((void*)&tempBufs[chanCnt][len], 0,
(framesPerBuffer - len) * sizeof(float));
@ -5278,6 +5299,7 @@ int AudioIO::AudioCallback(const void *inputBuffer, void *outputBuffer,
// Update the current time position, for scrubbing
// "Consume" only as much as the ring buffers produced, which may
// be less than framesPerBuffer (during "stutter")
// wxASSERT( maxLen == toGet );
if (mPlaybackSchedule.Interactive())
mPlaybackSchedule.SetTrackTime( mScrubQueue->Consumer( maxLen ) );
#endif

View File

@ -538,7 +538,14 @@ private:
*
* Returns the smallest of the buffer free space values in the event that
* they are different. */
size_t GetCommonlyAvailPlayback();
size_t GetCommonlyFreePlayback();
/** \brief Get the number of audio samples ready in all of the playback
* buffers.
*
* Returns the smallest of the buffer ready space values in the event that
* they are different. */
size_t GetCommonlyReadyPlayback();
/** \brief Get the number of audio samples ready in all of the recording
* buffers.