1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-20 14:20:06 +02:00

Fix bug 182 - Crash playing/freeze removing large number of tracks

Patch by Rick Yorgason
I modified it to use linear instead of n squared ring buffer size after verifying that this yields better performance on my mac and pc.
This commit is contained in:
mchinen 2010-12-24 13:08:46 +00:00
parent 4f6c56450a
commit 0e03fe34fd
2 changed files with 139 additions and 45 deletions

View File

@ -1138,6 +1138,10 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
mPlayLooped = playLooped; mPlayLooped = playLooped;
mCutPreviewGapStart = cutPreviewGapStart; mCutPreviewGapStart = cutPreviewGapStart;
mCutPreviewGapLen = cutPreviewGapLen; mCutPreviewGapLen = cutPreviewGapLen;
mPlaybackBuffers = NULL;
mPlaybackMixers = NULL;
mCaptureBuffers = NULL;
mResample = NULL;
double factor = 1.0; double factor = 1.0;
if (mTimeTrack) if (mTimeTrack)
@ -1152,11 +1156,11 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
// killing performance. // killing performance.
// //
mPlaybackRingBufferSecs = 4.5 + (0.5 * mPlaybackTracks.GetCount()); mPlaybackRingBufferSecs = 10.0;
mMaxPlaybackSecsToCopy = 0.75 + (0.25 * mPlaybackTracks.GetCount()); mMaxPlaybackSecsToCopy = 4.0;
mCaptureRingBufferSecs = 4.5 + 0.5 * mCaptureTracks.GetCount(); mCaptureRingBufferSecs = 4.5 + 0.5 * std::min(size_t(16), mCaptureTracks.GetCount());
mMinCaptureSecsToCopy = 0.2 + (0.2 * mCaptureTracks.GetCount()); mMinCaptureSecsToCopy = 0.2 + 0.2 * std::min(size_t(16), mCaptureTracks.GetCount());
unsigned int playbackChannels = 0; unsigned int playbackChannels = 0;
unsigned int captureChannels = 0; unsigned int captureChannels = 0;
@ -1219,16 +1223,35 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
// allocate the memory structures the stream will need. // allocate the memory structures the stream will need.
// //
bool bDone;
do
{
bDone = true; // assume success
try
{
if( mNumPlaybackChannels > 0 ) { if( mNumPlaybackChannels > 0 ) {
// Allocate output buffers. For every output track we allocate // Allocate output buffers. For every output track we allocate
// a ring buffer of five seconds // a ring buffer of five seconds
sampleCount playbackBufferSize = sampleCount playbackBufferSize =
(sampleCount)(mRate * mPlaybackRingBufferSecs + 0.5); (sampleCount)(mRate * mPlaybackRingBufferSecs + 0.5f);
sampleCount playbackMixBufferSize = sampleCount playbackMixBufferSize =
(sampleCount)(mRate * mMaxPlaybackSecsToCopy + 0.5); (sampleCount)(mRate * mMaxPlaybackSecsToCopy + 0.5f);
// In the extraordinarily rare case that we can't even afford 100 samples, just give up.
if(playbackBufferSize < 100 || playbackMixBufferSize < 100)
{
StartStreamCleanup();
wxMessageBox(_("Out of memory!"));
return 0;
}
mPlaybackBuffers = new RingBuffer* [mPlaybackTracks.GetCount()]; mPlaybackBuffers = new RingBuffer* [mPlaybackTracks.GetCount()];
mPlaybackMixers = new Mixer* [mPlaybackTracks.GetCount()]; mPlaybackMixers = new Mixer* [mPlaybackTracks.GetCount()];
// Set everything to zero in case we have to delete these due to a memory exception.
memset(mPlaybackBuffers, NULL, sizeof(RingBuffer*)*mPlaybackTracks.GetCount());
memset(mPlaybackMixers, NULL, sizeof(Mixer*)*mPlaybackTracks.GetCount());
for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ ) for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
{ {
mPlaybackBuffers[i] = new RingBuffer(floatSample, playbackBufferSize); mPlaybackBuffers[i] = new RingBuffer(floatSample, playbackBufferSize);
@ -1247,10 +1270,23 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
// a ring buffer of five seconds // a ring buffer of five seconds
sampleCount captureBufferSize = sampleCount captureBufferSize =
(sampleCount)(mRate * mCaptureRingBufferSecs + 0.5); (sampleCount)(mRate * mCaptureRingBufferSecs + 0.5);
// In the extraordinarily rare case that we can't even afford 100 samples, just give up.
if(captureBufferSize < 100)
{
StartStreamCleanup();
wxMessageBox(_("Out of memory!"));
return 0;
}
mCaptureBuffers = new RingBuffer* [mCaptureTracks.GetCount()]; mCaptureBuffers = new RingBuffer* [mCaptureTracks.GetCount()];
mResample = new Resample* [mCaptureTracks.GetCount()]; mResample = new Resample* [mCaptureTracks.GetCount()];
mFactor = sampleRate / mRate; mFactor = sampleRate / mRate;
// Set everything to zero in case we have to delete these due to a memory exception.
memset(mCaptureBuffers, NULL, sizeof(RingBuffer*)*mCaptureTracks.GetCount());
memset(mResample, NULL, sizeof(Resample*)*mCaptureTracks.GetCount());
for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ ) for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
{ {
mCaptureBuffers[i] = new RingBuffer( mCaptureTracks[i]->GetSampleFormat(), mCaptureBuffers[i] = new RingBuffer( mCaptureTracks[i]->GetSampleFormat(),
@ -1258,6 +1294,19 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
mResample[i] = new Resample( true, mFactor, mFactor ); mResample[i] = new Resample( true, mFactor, mFactor );
} }
} }
}
catch(std::bad_alloc&)
{
// Oops! Ran out of memory. This is pretty rare, so we'll just
// try deleting everything, halving our buffer size, and try again.
StartStreamCleanup(true);
mPlaybackRingBufferSecs *= 0.5;
mMaxPlaybackSecsToCopy *= 0.5;
mCaptureRingBufferSecs *= 0.5;
mMinCaptureSecsToCopy *= 0.5;
bDone = false;
}
} while(!bDone);
#ifdef AUTOMATED_INPUT_LEVEL_ADJUSTMENT #ifdef AUTOMATED_INPUT_LEVEL_ADJUSTMENT
AILASetStartTime(); AILASetStartTime();
@ -1288,13 +1337,10 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
if( err != paNoError ) if( err != paNoError )
{ {
// TODO
// we'll need a more complete way to indicate error.
// AND we need to delete the ring buffers and mixers, etc.
if (mListener && mNumCaptureChannels > 0) if (mListener && mNumCaptureChannels > 0)
mListener->OnAudioIOStopRecording(); mListener->OnAudioIOStopRecording();
wxPrintf(wxT("%hs\n"), Pa_GetErrorText(err)); StartStreamCleanup();
mStreamToken = 0; wxMessageBox(LAT1CTOWX(Pa_GetErrorText(err)));
return 0; return 0;
} }
} }
@ -1318,6 +1364,49 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks,
return mStreamToken; return mStreamToken;
} }
void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
{
if(mPlaybackBuffers)
{
for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
delete mPlaybackBuffers[i];
delete [] mPlaybackBuffers;
mPlaybackBuffers = NULL;
}
if(mPlaybackMixers)
{
for( unsigned int i = 0; i < mPlaybackTracks.GetCount(); i++ )
delete mPlaybackMixers[i];
delete [] mPlaybackMixers;
mPlaybackMixers = NULL;
}
if(mCaptureBuffers)
{
delete mCaptureBuffers;
delete [] mCaptureBuffers;
mCaptureBuffers = NULL;
}
if(mResample)
{
for( unsigned int i = 0; i < mCaptureTracks.GetCount(); i++ )
delete mResample;
delete [] mResample;
mResample = NULL;
}
if(!bOnlyBuffers)
{
Pa_AbortStream( mPortStreamV19 );
Pa_CloseStream( mPortStreamV19 );
mPortStreamV19 = NULL;
mStreamToken = 0;
}
}
#ifdef EXPERIMENTAL_MIDI_OUT #ifdef EXPERIMENTAL_MIDI_OUT
PmTimestamp MidiTime(void *info) PmTimestamp MidiTime(void *info)

View File

@ -399,6 +399,11 @@ private:
double NormalizeStreamTime(double absoluteTime) const; double NormalizeStreamTime(double absoluteTime) const;
/** \brief Clean up after StartStream if it fails.
*
* If bOnlyBuffers is specified, it only cleans up the buffers. */
void StartStreamCleanup(bool bOnlyBuffers = false);
#ifdef EXPERIMENTAL_MIDI_OUT #ifdef EXPERIMENTAL_MIDI_OUT
// MIDI_PLAYBACK: // MIDI_PLAYBACK:
PmStream *mMidiStream; PmStream *mMidiStream;