mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-24 16:20:05 +02:00
Make AudioIO::Callback() code shorter
Use subroutines, wxClip and cut out some dead code.
This commit is contained in:
parent
939b967497
commit
494ab4eafe
185
src/AudioIO.cpp
185
src/AudioIO.cpp
@ -4828,19 +4828,6 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
|
|
||||||
if( outputBuffer && (numPlaybackChannels > 0) )
|
if( outputBuffer && (numPlaybackChannels > 0) )
|
||||||
{
|
{
|
||||||
// The drop and dropQuickly booleans are for historical reasons.
|
|
||||||
// JKC: The original code attempted to be faster by doing nothing on silenced audio.
|
|
||||||
// This, IMHO, is 'premature optimisation'. Instead clearer and cleaner code would
|
|
||||||
// simply use a gain of 0.0 for silent audio and go on through to the stage of
|
|
||||||
// applying that 0.0 gain to the data mixed into the buffer.
|
|
||||||
// Then (and only then) we would have if needed fast paths for:
|
|
||||||
// - Applying a uniform gain of 0.0.
|
|
||||||
// - Applying a uniform gain of 1.0.
|
|
||||||
// - Applying some other uniform gain.
|
|
||||||
// - Applying a linearly interpolated gain.
|
|
||||||
// I would expect us not to need the fast paths, since linearly interpolated gain
|
|
||||||
// is very cheap to process.
|
|
||||||
|
|
||||||
float *outputFloats = (float *)outputBuffer;
|
float *outputFloats = (float *)outputBuffer;
|
||||||
for( unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
|
for( unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
|
||||||
outputFloats[i] = 0.0;
|
outputFloats[i] = 0.0;
|
||||||
@ -4862,16 +4849,19 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
// While scrubbing, ignore seek requests
|
// While scrubbing, ignore seek requests
|
||||||
if (mSeek && mPlaybackSchedule.Interactive())
|
if (mSeek && mPlaybackSchedule.Interactive())
|
||||||
mSeek = 0.0;
|
mSeek = 0.0;
|
||||||
else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (mSeek){
|
if (mSeek){
|
||||||
mCallbackReturn = CallbackDoSeek();
|
mCallbackReturn = CallbackDoSeek();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------ MEMORY ALLOCATION ----------------------
|
||||||
|
// These are small structures.
|
||||||
WaveTrack **chans = (WaveTrack **) alloca(numPlaybackChannels * sizeof(WaveTrack *));
|
WaveTrack **chans = (WaveTrack **) alloca(numPlaybackChannels * sizeof(WaveTrack *));
|
||||||
float **tempBufs = (float **) alloca(numPlaybackChannels * sizeof(float *));
|
float **tempBufs = (float **) alloca(numPlaybackChannels * sizeof(float *));
|
||||||
|
// ------ End of MEMORY ALLOCATION ---------------
|
||||||
|
|
||||||
for (unsigned int c = 0; c < numPlaybackChannels; c++)
|
for (unsigned int c = 0; c < numPlaybackChannels; c++)
|
||||||
{
|
{
|
||||||
tempBufs[c] = (float *) alloca(framesPerBuffer * sizeof(float));
|
tempBufs[c] = (float *) alloca(framesPerBuffer * sizeof(float));
|
||||||
@ -4888,12 +4878,24 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
const auto toGet =
|
const auto toGet =
|
||||||
std::min<size_t>(framesPerBuffer, GetCommonlyReadyPlayback());
|
std::min<size_t>(framesPerBuffer, GetCommonlyReadyPlayback());
|
||||||
|
|
||||||
bool drop = false;
|
// The drop and dropQuickly booleans are so named for historical reasons.
|
||||||
bool dropQuickly = false;
|
// JKC: The original code attempted to be faster by doing nothing on silenced audio.
|
||||||
|
// This, IMHO, is 'premature optimisation'. Instead clearer and cleaner code would
|
||||||
|
// simply use a gain of 0.0 for silent audio and go on through to the stage of
|
||||||
|
// applying that 0.0 gain to the data mixed into the buffer.
|
||||||
|
// Then (and only then) we would have if needed fast paths for:
|
||||||
|
// - Applying a uniform gain of 0.0.
|
||||||
|
// - Applying a uniform gain of 1.0.
|
||||||
|
// - Applying some other uniform gain.
|
||||||
|
// - Applying a linearly interpolated gain.
|
||||||
|
// I would expect us not to need the fast paths, since linearly interpolated gain
|
||||||
|
// is very cheap to process.
|
||||||
|
|
||||||
|
bool drop = false; // Track should become silent.
|
||||||
|
bool dropQuickly = false; // Track has already been faded to silence.
|
||||||
for (unsigned t = 0; t < numPlaybackTracks; t++)
|
for (unsigned t = 0; t < numPlaybackTracks; t++)
|
||||||
{
|
{
|
||||||
WaveTrack *vt = mPlaybackTracks[t].get();
|
WaveTrack *vt = mPlaybackTracks[t].get();
|
||||||
|
|
||||||
chans[chanCnt] = vt;
|
chans[chanCnt] = vt;
|
||||||
|
|
||||||
// TODO: more-than-two-channels
|
// TODO: more-than-two-channels
|
||||||
@ -4904,32 +4906,23 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
bool firstChannel = vt->IsLeader();
|
bool firstChannel = vt->IsLeader();
|
||||||
bool lastChannel = !nextTrack || nextTrack->IsLeader();
|
bool lastChannel = !nextTrack || nextTrack->IsLeader();
|
||||||
|
|
||||||
if ( ! firstChannel )
|
if ( firstChannel )
|
||||||
dropQuickly = dropQuickly && TrackHasBeenFadedOut( *vt );
|
{
|
||||||
else {
|
|
||||||
drop = TrackShouldBeSilent( *vt );
|
drop = TrackShouldBeSilent( *vt );
|
||||||
|
|
||||||
selected = vt->GetSelected();
|
selected = vt->GetSelected();
|
||||||
|
|
||||||
|
// IF mono THEN clear 'the other' channel.
|
||||||
if ( lastChannel ) {
|
if ( lastChannel ) {
|
||||||
// TODO: more-than-two-channels
|
// TODO: more-than-two-channels
|
||||||
#if 1
|
|
||||||
// If we have a mono track, clear the right channel
|
|
||||||
memset(tempBufs[1], 0, framesPerBuffer * sizeof(float));
|
memset(tempBufs[1], 0, framesPerBuffer * sizeof(float));
|
||||||
#else
|
|
||||||
// clear any other channels
|
|
||||||
for ( size_t c = chanCnt + 1; c < numPlaybackChannels; ++c )
|
|
||||||
memset(tempBufs[c], 0, framesPerBuffer * sizeof(float));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dropQuickly = drop && TrackHasBeenFadedOut( *vt );
|
dropQuickly = drop && TrackHasBeenFadedOut( *vt );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
#define ORIGINAL_DO_NOT_PLAY_ALL_MUTED_TRACKS_TO_END
|
dropQuickly = dropQuickly && TrackHasBeenFadedOut( *vt );
|
||||||
#ifdef ORIGINAL_DO_NOT_PLAY_ALL_MUTED_TRACKS_TO_END
|
|
||||||
decltype(framesPerBuffer) len = 0;
|
decltype(framesPerBuffer) len = 0;
|
||||||
// this is original code prior to r10680 -RBD
|
|
||||||
if (dropQuickly)
|
if (dropQuickly)
|
||||||
{
|
{
|
||||||
len = mPlaybackBuffers[t]->Discard(framesPerBuffer);
|
len = mPlaybackBuffers[t]->Discard(framesPerBuffer);
|
||||||
@ -4951,7 +4944,6 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
// zeroes and not random garbage.
|
// zeroes and not random garbage.
|
||||||
memset((void*)&tempBufs[chanCnt][len], 0,
|
memset((void*)&tempBufs[chanCnt][len], 0,
|
||||||
(framesPerBuffer - len) * sizeof(float));
|
(framesPerBuffer - len) * sizeof(float));
|
||||||
|
|
||||||
chanCnt++;
|
chanCnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4964,34 +4956,8 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
// available, so maxLen ought to increase from 0 only once
|
// available, so maxLen ought to increase from 0 only once
|
||||||
maxLen = std::max(maxLen, len);
|
maxLen = std::max(maxLen, len);
|
||||||
|
|
||||||
|
if ( !lastChannel )
|
||||||
if ( ! lastChannel )
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
#else
|
|
||||||
// This code was reorganized so that if all audio tracks
|
|
||||||
// are muted, we still return paComplete when the end of
|
|
||||||
// a selection is reached.
|
|
||||||
// Vaughan, 2011-10-20: Further comments from Roger, by off-list email:
|
|
||||||
// ...something to do with what it means to mute all audio tracks. E.g. if you
|
|
||||||
// mute all and play, does the playback terminate immediately or play
|
|
||||||
// silence? If it terminates immediately, does that terminate any MIDI
|
|
||||||
// playback that might also be going on? ...Maybe muted audio tracks + MIDI,
|
|
||||||
// the playback would NEVER terminate. ...I think the #else part is probably preferable...
|
|
||||||
size_t len;
|
|
||||||
if (dropQuickly)
|
|
||||||
{
|
|
||||||
len =
|
|
||||||
mPlaybackBuffers[t]->Discard(framesPerBuffer);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
len =
|
|
||||||
mPlaybackBuffers[t]->Get((samplePtr)tempFloats,
|
|
||||||
floatSample,
|
|
||||||
framesPerBuffer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Last channel of a track seen now
|
// Last channel of a track seen now
|
||||||
len = maxLen;
|
len = maxLen;
|
||||||
@ -5002,67 +4968,57 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
}
|
}
|
||||||
group++;
|
group++;
|
||||||
|
|
||||||
|
|
||||||
CallbackCheckCompletion(mCallbackReturn, len);
|
CallbackCheckCompletion(mCallbackReturn, len);
|
||||||
|
|
||||||
if (dropQuickly) // no samples to process, they've been discarded
|
if (dropQuickly) // no samples to process, they've been discarded
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
// Our channels aren't silent. We need to pass their data on.
|
||||||
if (len > 0) for (int c = 0; c < chanCnt; c++)
|
if (len > 0) for (int c = 0; c < chanCnt; c++)
|
||||||
{
|
{
|
||||||
vt = chans[c];
|
vt = chans[c];
|
||||||
|
|
||||||
if (vt->GetChannelIgnoringPan() == Track::LeftChannel ||
|
// A function to apply the requested gain, fading up or down from the
|
||||||
vt->GetChannelIgnoringPan() == Track::MonoChannel )
|
// most recently applied gain.
|
||||||
{
|
// Note that there are two kinds of channel count.
|
||||||
float gain = vt->GetChannelGain(0);
|
// chan (and numPlayBackChannels) is counting channels on the device.
|
||||||
|
// c and chanCnt are counting channels in the Tracks.
|
||||||
|
// chan = 0 is left channel
|
||||||
|
// chan = 1 is right channel.
|
||||||
|
auto fadeChannel = [&]( unsigned int chan){
|
||||||
|
float gain = vt->GetChannelGain(chan);
|
||||||
if (drop || !mAudioThreadFillBuffersLoopRunning || mPaused)
|
if (drop || !mAudioThreadFillBuffersLoopRunning || mPaused)
|
||||||
gain = 0.0;
|
gain = 0.0;
|
||||||
|
|
||||||
// Output volume emulation: possibly copy meter samples, then
|
// Output volume emulation: possibly copy meter samples, then
|
||||||
// apply volume, then copy to the output buffer
|
// apply volume, then copy to the output buffer
|
||||||
if (outputMeterFloats != outputFloats)
|
if (outputMeterFloats != outputFloats)
|
||||||
for (decltype(len) i = 0; i < len; ++i)
|
for ( unsigned i = 0; i < len; ++i)
|
||||||
outputMeterFloats[numPlaybackChannels*i] +=
|
outputMeterFloats[numPlaybackChannels*i+chan] +=
|
||||||
gain*tempFloats[i];
|
gain*tempFloats[i];
|
||||||
|
|
||||||
if (mEmulateMixerOutputVol)
|
if (mEmulateMixerOutputVol)
|
||||||
gain *= mMixerOutputVol;
|
gain *= mMixerOutputVol;
|
||||||
|
|
||||||
float oldGain = vt->GetOldChannelGain(0);
|
float oldGain = vt->GetOldChannelGain(chan);
|
||||||
if( gain != oldGain )
|
if( gain != oldGain )
|
||||||
vt->SetOldChannelGain(0, gain);
|
vt->SetOldChannelGain(chan, gain);
|
||||||
wxASSERT(len > 0);
|
wxASSERT(len > 0);
|
||||||
float deltaGain = (gain - oldGain) / len;
|
|
||||||
for (decltype(len) i = 0; i < len; i++)
|
|
||||||
outputFloats[numPlaybackChannels*i] += (oldGain + deltaGain * i) *tempBufs[c][i];
|
|
||||||
|
|
||||||
}
|
// Linear interpolate.
|
||||||
|
float deltaGain = (gain - oldGain) / len;
|
||||||
|
for (unsigned i = 0; i < len; i++)
|
||||||
|
outputFloats[numPlaybackChannels*i+chan] += (oldGain + deltaGain * i) *tempBufs[c][i];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (vt->GetChannelIgnoringPan() == Track::LeftChannel ||
|
||||||
|
vt->GetChannelIgnoringPan() == Track::MonoChannel )
|
||||||
|
fadeChannel( 0 );
|
||||||
|
|
||||||
if (vt->GetChannelIgnoringPan() == Track::RightChannel ||
|
if (vt->GetChannelIgnoringPan() == Track::RightChannel ||
|
||||||
vt->GetChannelIgnoringPan() == Track::MonoChannel )
|
vt->GetChannelIgnoringPan() == Track::MonoChannel )
|
||||||
{
|
fadeChannel( 1 );
|
||||||
float gain = vt->GetChannelGain(1);
|
|
||||||
if (drop || !mAudioThreadFillBuffersLoopRunning || mPaused)
|
|
||||||
gain = 0.0;
|
|
||||||
|
|
||||||
// Output volume emulation (as above)
|
|
||||||
if (outputMeterFloats != outputFloats)
|
|
||||||
for (decltype(len) i = 0; i < len; ++i)
|
|
||||||
outputMeterFloats[numPlaybackChannels*i+1] +=
|
|
||||||
gain*tempFloats[i];
|
|
||||||
|
|
||||||
if (mEmulateMixerOutputVol)
|
|
||||||
gain *= mMixerOutputVol;
|
|
||||||
|
|
||||||
float oldGain = vt->GetOldChannelGain(1);
|
|
||||||
if (gain != oldGain)
|
|
||||||
vt->SetOldChannelGain(1,gain);
|
|
||||||
wxASSERT(len > 0);
|
|
||||||
float deltaGain = (gain - oldGain) / len;
|
|
||||||
for(decltype(len) i = 0; i < len; i++)
|
|
||||||
outputFloats[numPlaybackChannels*i+1] += (oldGain + deltaGain*i) *tempBufs[c][i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chanCnt = 0;
|
chanCnt = 0;
|
||||||
@ -5077,33 +5033,17 @@ bool AudioIO::FillOutputBuffers(
|
|||||||
// wxASSERT( maxLen == toGet );
|
// wxASSERT( maxLen == toGet );
|
||||||
|
|
||||||
em.RealtimeProcessEnd();
|
em.RealtimeProcessEnd();
|
||||||
|
|
||||||
mLastPlaybackTimeMillis = ::wxGetLocalTimeMillis();
|
mLastPlaybackTimeMillis = ::wxGetLocalTimeMillis();
|
||||||
|
|
||||||
//
|
// Limit values to -1.0..+1.0
|
||||||
// Clip output to [-1.0,+1.0] range (msmeyer)
|
auto clampBuffer = [&] (float * pBuffer){
|
||||||
//
|
for(unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
|
||||||
for(unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; i++)
|
pBuffer[i] = wxClip( -1.0f, pBuffer[i], 1.0f);
|
||||||
{
|
};
|
||||||
float f = outputFloats[i];
|
|
||||||
if (f > 1.0)
|
|
||||||
outputFloats[i] = 1.0;
|
|
||||||
else if (f < -1.0)
|
|
||||||
outputFloats[i] = -1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Same for meter output
|
clampBuffer( outputFloats );
|
||||||
if (outputMeterFloats != outputFloats)
|
if (outputMeterFloats != outputFloats)
|
||||||
{
|
clampBuffer( outputMeterFloats );
|
||||||
for (unsigned i = 0; i < framesPerBuffer*numPlaybackChannels; ++i)
|
|
||||||
{
|
|
||||||
float f = outputMeterFloats[i];
|
|
||||||
if (f > 1.0)
|
|
||||||
outputMeterFloats[i] = 1.0;
|
|
||||||
else if (f < -1.0)
|
|
||||||
outputMeterFloats[i] = -1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the position seen by drawing code
|
// Update the position seen by drawing code
|
||||||
@ -5212,10 +5152,7 @@ bool AudioIO::FillInputBuffers(
|
|||||||
short *tempShorts = (short *)tempFloats;
|
short *tempShorts = (short *)tempFloats;
|
||||||
for( unsigned i = 0; i < len; i++) {
|
for( unsigned i = 0; i < len; i++) {
|
||||||
float tmp = inputShorts[numCaptureChannels*i+t];
|
float tmp = inputShorts[numCaptureChannels*i+t];
|
||||||
if (tmp > 32767)
|
tmp = wxClip( -32768, tmp, 32767 );
|
||||||
tmp = 32767;
|
|
||||||
if (tmp < -32768)
|
|
||||||
tmp = -32768;
|
|
||||||
tempShorts[i] = (short)(tmp);
|
tempShorts[i] = (short)(tmp);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user