mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-06 23:02:42 +02:00
Collect initialization of playback schedule into a function
This commit is contained in:
parent
6e4d11e5af
commit
197122c7d5
135
src/AudioIO.cpp
135
src/AudioIO.cpp
@ -1206,7 +1206,6 @@ AudioIO::AudioIO()
|
||||
mLastRecordingOffset = 0.0;
|
||||
mNumCaptureChannels = 0;
|
||||
mPaused = false;
|
||||
mPlaybackSchedule.ResetMode();
|
||||
|
||||
mListener = NULL;
|
||||
mUpdateMeters = false;
|
||||
@ -1917,22 +1916,8 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
}
|
||||
mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange; // meter goes -dBRange dB -> 0dB
|
||||
|
||||
if ( !tracks.captureTracks.empty() ) {
|
||||
// It does not make sense to apply the time warp during overdub recording,
|
||||
// which defeats the purpose of making the recording synchronized with
|
||||
// the existing audio. (Unless we figured out the inverse warp of the
|
||||
// captured samples in real time.)
|
||||
// So just quietly ignore the time track.
|
||||
mPlaybackSchedule.mTimeTrack = nullptr;
|
||||
}
|
||||
else {
|
||||
mPlaybackSchedule.mTimeTrack = options.timeTrack;
|
||||
}
|
||||
|
||||
// Clamp pre-roll so we don't play before time 0
|
||||
const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
|
||||
mPlaybackSchedule.mT0 = t0 - preRoll;
|
||||
mPlaybackSchedule.mT1 = t1;
|
||||
mRecordingSchedule = {};
|
||||
mRecordingSchedule.mPreRoll = preRoll;
|
||||
mRecordingSchedule.mLatencyCorrection =
|
||||
@ -1940,16 +1925,12 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
DEFAULT_LATENCY_CORRECTION))
|
||||
/ 1000.0;
|
||||
mRecordingSchedule.mDuration = t1 - t0;
|
||||
if (tracks.captureTracks.size() > 0)
|
||||
// adjust mT1 so that we don't give paComplete too soon to fill up the
|
||||
// desired length of recording
|
||||
mPlaybackSchedule.mT1 -= mRecordingSchedule.mLatencyCorrection;
|
||||
if (options.pCrossfadeData)
|
||||
mRecordingSchedule.mCrossfadeData.swap( *options.pCrossfadeData );
|
||||
|
||||
mListener = options.listener;
|
||||
mRate = sampleRate;
|
||||
mPlaybackSchedule.mTime = mPlaybackSchedule.mT0;
|
||||
|
||||
mSeek = 0;
|
||||
mLastRecordingOffset = 0;
|
||||
mCaptureTracks = tracks.captureTracks;
|
||||
@ -1967,15 +1948,12 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mMidiPlaybackTracks.clear();
|
||||
#endif
|
||||
|
||||
// Don't cause a busy wait in the audio thread after stopping scrubbing
|
||||
mPlaybackSchedule.ResetMode();
|
||||
}
|
||||
});
|
||||
|
||||
mPlaybackSchedule.mPlayMode = options.playLooped
|
||||
? PlaybackSchedule::PLAY_LOOPED
|
||||
: PlaybackSchedule::PLAY_STRAIGHT;
|
||||
mPlaybackSchedule.mCutPreviewGapStart = options.cutPreviewGapStart;
|
||||
mPlaybackSchedule.mCutPreviewGapLen = options.cutPreviewGapLen;
|
||||
|
||||
mPlaybackBuffers.reset();
|
||||
mPlaybackMixers.reset();
|
||||
mCaptureBuffers.reset();
|
||||
@ -1988,36 +1966,12 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
streamStartTime = SystemTime(mUsingAlsa);
|
||||
#endif
|
||||
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
bool scrubbing = (options.pScrubbingOptions != nullptr);
|
||||
|
||||
// Scrubbing is not compatible with looping or recording or a time track!
|
||||
mPlaybackSchedule.Init(
|
||||
t0, t1, options, mCaptureTracks.empty() ? nullptr : &mRecordingSchedule );
|
||||
const bool scrubbing = mPlaybackSchedule.Interactive();
|
||||
if (scrubbing)
|
||||
{
|
||||
const auto &scrubOptions = *options.pScrubbingOptions;
|
||||
|
||||
if (mCaptureTracks.size() > 0 ||
|
||||
mPlaybackSchedule.Looping() ||
|
||||
mPlaybackSchedule.mTimeTrack != NULL ||
|
||||
scrubOptions.maxSpeed < ScrubbingOptions::MinAllowedScrubSpeed()) {
|
||||
wxASSERT(false);
|
||||
scrubbing = false;
|
||||
}
|
||||
else {
|
||||
playbackTime = lrint(scrubOptions.delay * sampleRate) / sampleRate;
|
||||
mPlaybackSchedule.mPlayMode = (scrubOptions.isPlayingAtSpeed) ? PlaybackSchedule::PLAY_AT_SPEED : PlaybackSchedule::PLAY_SCRUB;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
mPlaybackSchedule.mWarpedTime = 0.0;
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
if (mPlaybackSchedule.Scrubbing())
|
||||
mPlaybackSchedule.mWarpedLength = 0.0f;
|
||||
else
|
||||
#endif
|
||||
mPlaybackSchedule.mWarpedLength =
|
||||
mPlaybackSchedule.RealDuration(mPlaybackSchedule.mT1);
|
||||
playbackTime =
|
||||
lrint(options.pScrubbingOptions->delay * sampleRate) / sampleRate;
|
||||
|
||||
//
|
||||
// The RingBuffer sizes, and the max amount of the buffer to
|
||||
@ -2099,9 +2053,6 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
mListener->OnAudioIOStopRecording();
|
||||
mStreamToken = 0;
|
||||
|
||||
// Don't cause a busy wait in the audio thread after stopping scrubbing
|
||||
mPlaybackSchedule.ResetMode();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2396,10 +2347,6 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
mScrubQueue.reset();
|
||||
#endif
|
||||
|
||||
|
||||
// Don't cause a busy wait in the audio thread after stopping scrubbing
|
||||
mPlaybackSchedule.ResetMode();
|
||||
}
|
||||
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
@ -2905,6 +2852,69 @@ bool AudioIO::IsMonitoring()
|
||||
return ( mPortStreamV19 && mStreamToken==0 );
|
||||
}
|
||||
|
||||
void AudioIO::PlaybackSchedule::Init(
|
||||
const double t0, const double t1,
|
||||
const AudioIOStartStreamOptions &options,
|
||||
const RecordingSchedule *pRecordingSchedule )
|
||||
{
|
||||
if ( pRecordingSchedule )
|
||||
// It does not make sense to apply the time warp during overdub recording,
|
||||
// which defeats the purpose of making the recording synchronized with
|
||||
// the existing audio. (Unless we figured out the inverse warp of the
|
||||
// captured samples in real time.)
|
||||
// So just quietly ignore the time track.
|
||||
mTimeTrack = nullptr;
|
||||
else
|
||||
mTimeTrack = options.timeTrack;
|
||||
|
||||
mT0 = t0;
|
||||
if (pRecordingSchedule)
|
||||
mT0 -= pRecordingSchedule->mPreRoll;
|
||||
|
||||
mT1 = t1;
|
||||
if (pRecordingSchedule)
|
||||
// adjust mT1 so that we don't give paComplete too soon to fill up the
|
||||
// desired length of recording
|
||||
mT1 -= pRecordingSchedule->mLatencyCorrection;
|
||||
|
||||
mTime = mT0;
|
||||
|
||||
mPlayMode = options.playLooped
|
||||
? PlaybackSchedule::PLAY_LOOPED
|
||||
: PlaybackSchedule::PLAY_STRAIGHT;
|
||||
mCutPreviewGapStart = options.cutPreviewGapStart;
|
||||
mCutPreviewGapLen = options.cutPreviewGapLen;
|
||||
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
bool scrubbing = (options.pScrubbingOptions != nullptr);
|
||||
|
||||
// Scrubbing is not compatible with looping or recording or a time track!
|
||||
if (scrubbing)
|
||||
{
|
||||
const auto &scrubOptions = *options.pScrubbingOptions;
|
||||
if (pRecordingSchedule ||
|
||||
Looping() ||
|
||||
mTimeTrack != NULL ||
|
||||
scrubOptions.maxSpeed < ScrubbingOptions::MinAllowedScrubSpeed()) {
|
||||
wxASSERT(false);
|
||||
scrubbing = false;
|
||||
}
|
||||
else
|
||||
mPlayMode = (scrubOptions.isPlayingAtSpeed)
|
||||
? PlaybackSchedule::PLAY_AT_SPEED
|
||||
: PlaybackSchedule::PLAY_SCRUB;
|
||||
}
|
||||
#endif
|
||||
|
||||
mWarpedTime = 0.0;
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
if (Scrubbing())
|
||||
mWarpedLength = 0.0f;
|
||||
else
|
||||
#endif
|
||||
mWarpedLength = RealDuration(mT1);
|
||||
}
|
||||
|
||||
double AudioIO::PlaybackSchedule::LimitStreamTime() const
|
||||
{
|
||||
// Allows for forward or backward play
|
||||
@ -4960,7 +4970,6 @@ int AudioIO::AudioCallback(const void *inputBuffer, void *outputBuffer,
|
||||
mPlaybackSchedule.mTime = mPlaybackSchedule.LimitStreamTime();
|
||||
mSeek = 0.0;
|
||||
|
||||
// Reset mixer positions and flush buffers for all tracks
|
||||
mPlaybackSchedule.RealTimeInit();
|
||||
|
||||
// Reset mixer positions and flush buffers for all tracks
|
||||
|
@ -805,6 +805,24 @@ public:
|
||||
// detect more dropouts
|
||||
bool mDetectUpstreamDropouts{ true };
|
||||
|
||||
private:
|
||||
struct RecordingSchedule {
|
||||
double mPreRoll{};
|
||||
double mLatencyCorrection{}; // negative value usually
|
||||
double mDuration{};
|
||||
PRCrossfadeData mCrossfadeData;
|
||||
|
||||
// These are initialized by the main thread, then updated
|
||||
// only by the thread calling FillBuffers:
|
||||
double mPosition{};
|
||||
bool mLatencyCorrected{};
|
||||
|
||||
double TotalCorrection() const { return mLatencyCorrection - mPreRoll; }
|
||||
double ToConsume() const;
|
||||
double Consumed() const;
|
||||
double ToDiscard() const;
|
||||
} mRecordingSchedule{};
|
||||
|
||||
struct PlaybackSchedule {
|
||||
/// Playback starts at offset of mT0, which is measured in seconds.
|
||||
double mT0;
|
||||
@ -840,10 +858,15 @@ public:
|
||||
PLAY_SCRUB,
|
||||
PLAY_AT_SPEED, // a version of PLAY_SCRUB.
|
||||
#endif
|
||||
} mPlayMode;
|
||||
} mPlayMode { PLAY_STRAIGHT };
|
||||
double mCutPreviewGapStart;
|
||||
double mCutPreviewGapLen;
|
||||
|
||||
|
||||
void Init(
|
||||
double t0, double t1,
|
||||
const AudioIOStartStreamOptions &options,
|
||||
const RecordingSchedule *pRecordingSchedule );
|
||||
|
||||
/** \brief True if the end time is before the start time */
|
||||
bool ReversedTime() const
|
||||
{
|
||||
@ -899,24 +922,6 @@ public:
|
||||
void RealTimeRestart();
|
||||
|
||||
} mPlaybackSchedule;
|
||||
|
||||
private:
|
||||
struct RecordingSchedule {
|
||||
double mPreRoll{};
|
||||
double mLatencyCorrection{}; // negative value usually
|
||||
double mDuration{};
|
||||
PRCrossfadeData mCrossfadeData;
|
||||
|
||||
// These are initialized by the main thread, then updated
|
||||
// only by the thread calling FillBuffers:
|
||||
double mPosition{};
|
||||
bool mLatencyCorrected{};
|
||||
|
||||
double TotalCorrection() const { return mLatencyCorrection - mPreRoll; }
|
||||
double ToConsume() const;
|
||||
double Consumed() const;
|
||||
double ToDiscard() const;
|
||||
} mRecordingSchedule{};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user