1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-16 08:34:10 +02:00

When recording into region selection, stop it precisely

This commit is contained in:
Paul Licameli 2018-05-24 02:35:44 -04:00
parent 92d27c618b
commit 0887d6d01e
2 changed files with 54 additions and 14 deletions

View File

@ -1933,10 +1933,21 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
mTimeTrack = options.timeTrack; mTimeTrack = options.timeTrack;
} }
mListener = options.listener;
mRate = sampleRate;
mT0 = t0; mT0 = t0;
mT1 = t1; mT1 = t1;
mRecordingSchedule = {};
mRecordingSchedule.mLatencyCorrection =
(gPrefs->Read(wxT("/AudioIO/LatencyCorrection"),
DEFAULT_LATENCY_CORRECTION))
/ 1000.0;
mRecordingSchedule.mDuration = mT1 - mT0;
if (captureTracks.size() > 0 && playbackTracks.size() > 0)
// adjust mT1 so that we don't give paComplete too soon to fill up the
// desired length of recording
mT1 -= mRecordingSchedule.mLatencyCorrection;
mListener = options.listener;
mRate = sampleRate;
mTime = t0; mTime = t0;
mSeek = 0; mSeek = 0;
mLastRecordingOffset = 0; mLastRecordingOffset = 0;
@ -2150,7 +2161,12 @@ int AudioIO::StartStream(const WaveTrackConstArray &playbackTracks,
// Don't throw for read errors, just play silence: // Don't throw for read errors, just play silence:
false, false,
warpOptions, warpOptions,
mT0, mT1, 1, mT0,
// Pass t1 -- not mT1 as may have been adjusted for latency
// -- so that overdub recording stops playing back samples
// at the right time, though transport may continue to record
t1,
1,
playbackMixBufferSize, false, playbackMixBufferSize, false,
mRate, floatSample, false); mRate, floatSample, false);
mPlaybackMixers[i]->ApplyTrackGains(false); mPlaybackMixers[i]->ApplyTrackGains(false);
@ -2724,11 +2740,10 @@ void AudioIO::StopStream()
// case that we do not apply latency correction when recording the // case that we do not apply latency correction when recording the
// first track in a project. // first track in a project.
// //
double latencyCorrection = DEFAULT_LATENCY_CORRECTION;
gPrefs->Read(wxT("/AudioIO/LatencyCorrection"), &latencyCorrection);
double recordingOffset = double recordingOffset =
mLastRecordingOffset + latencyCorrection / 1000.0; mLastRecordingOffset +
mRecordingSchedule.mLatencyCorrection;
for (unsigned int i = 0; i < mCaptureTracks.size(); i++) { for (unsigned int i = 0; i < mCaptureTracks.size(); i++) {
// The calls to Flush, and (less likely) Clear and InsertSilence, // The calls to Flush, and (less likely) Clear and InsertSilence,
@ -4016,12 +4031,16 @@ void AudioIO::FillBuffers()
mCaptureTracks.size() > 0) mCaptureTracks.size() > 0)
GuardedCall( [&] { GuardedCall( [&] {
// start record buffering // start record buffering
auto commonlyAvail = GetCommonlyAvailCapture(); const auto avail = GetCommonlyAvailCapture(); // samples
const auto remainingTime =
std::max(0.0, mRecordingSchedule.Remaining());
// This may be a very big double number:
const auto remainingSamples = remainingTime * mRate;
// //
// Determine how much this will add to captured tracks // Determine how much this will add to captured tracks
// //
double deltat = commonlyAvail / mRate; double deltat = avail / mRate;
if (mAudioThreadShouldCallFillBuffersOnce || if (mAudioThreadShouldCallFillBuffersOnce ||
deltat >= mMinCaptureSecsToCopy) deltat >= mMinCaptureSecsToCopy)
@ -4033,7 +4052,6 @@ void AudioIO::FillBuffers()
for( i = 0; i < numChannels; i++ ) for( i = 0; i < numChannels; i++ )
{ {
auto avail = commonlyAvail;
sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat(); sampleFormat trackFormat = mCaptureTracks[i]->GetSampleFormat();
AutoSaveFile appendLog; AutoSaveFile appendLog;
@ -4042,12 +4060,16 @@ void AudioIO::FillBuffers()
{ {
SampleBuffer temp(avail, trackFormat); SampleBuffer temp(avail, trackFormat);
const auto got = const auto got =
mCaptureBuffers[i]->Get(temp.ptr(), trackFormat, avail); mCaptureBuffers[i]->Get(temp.ptr(), trackFormat, avail);
// wxASSERT(got == avail); // wxASSERT(got == avail);
// but we can't assert in this thread // but we can't assert in this thread
wxUnusedVar(got); wxUnusedVar(got);
// see comment in second handler about guarantee // see comment in second handler about guarantee
mCaptureTracks[i]-> Append(temp.ptr(), trackFormat, avail, 1, size_t size = avail;
if (double(size) > remainingSamples)
size = floor(remainingSamples);
mCaptureTracks[i]-> Append(temp.ptr(), trackFormat,
size, 1,
&appendLog); &appendLog);
} }
else else
@ -4056,7 +4078,7 @@ void AudioIO::FillBuffers()
SampleBuffer temp1(avail, floatSample); SampleBuffer temp1(avail, floatSample);
SampleBuffer temp2(size, floatSample); SampleBuffer temp2(size, floatSample);
const auto got = const auto got =
mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, avail); mCaptureBuffers[i]->Get(temp1.ptr(), floatSample, avail);
// wxASSERT(got == avail); // wxASSERT(got == avail);
// but we can't assert in this thread // but we can't assert in this thread
wxUnusedVar(got); wxUnusedVar(got);
@ -4070,7 +4092,10 @@ void AudioIO::FillBuffers()
!IsStreamActive(), (float *)temp2.ptr(), size); !IsStreamActive(), (float *)temp2.ptr(), size);
size = results.second; size = results.second;
// see comment in second handler about guarantee // see comment in second handler about guarantee
mCaptureTracks[i]-> Append(temp2.ptr(), floatSample, size, 1, if (double(size) > remainingSamples)
size = floor(remainingSamples);
mCaptureTracks[i]-> Append(temp2.ptr(), floatSample,
size, 1,
&appendLog); &appendLog);
} }
} }
@ -4084,7 +4109,9 @@ void AudioIO::FillBuffers()
blockFileLog.WriteSubTree(appendLog); blockFileLog.WriteSubTree(appendLog);
blockFileLog.EndTag(wxT("recordingrecovery")); blockFileLog.EndTag(wxT("recordingrecovery"));
} }
} } // end loop over capture channels
mRecordingSchedule.mPosition += avail / mRate;
if (mListener && !blockFileLog.IsEmpty()) if (mListener && !blockFileLog.IsEmpty())
mListener->OnAudioIONewBlockFiles(blockFileLog); mListener->OnAudioIONewBlockFiles(blockFileLog);

View File

@ -814,6 +814,19 @@ public:
// Whether to check the error code passed to audacityAudioCallback to // Whether to check the error code passed to audacityAudioCallback to
// detect more dropouts // detect more dropouts
bool mDetectUpstreamDropouts{ true }; bool mDetectUpstreamDropouts{ true };
private:
struct RecordingSchedule {
double mLatencyCorrection{};
double mDuration{};
// This is initialized to 0 by the main thread, then updated
// only by the thread calling FillBuffers:
double mPosition{};
double Remaining() const
{ return mDuration - mLatencyCorrection - mPosition; }
} mRecordingSchedule{};
}; };
#endif #endif