mirror of
https://github.com/cookiengineer/audacity
synced 2025-05-06 14:52:34 +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;
|
mLastRecordingOffset = 0.0;
|
||||||
mNumCaptureChannels = 0;
|
mNumCaptureChannels = 0;
|
||||||
mPaused = false;
|
mPaused = false;
|
||||||
mPlaybackSchedule.ResetMode();
|
|
||||||
|
|
||||||
mListener = NULL;
|
mListener = NULL;
|
||||||
mUpdateMeters = false;
|
mUpdateMeters = false;
|
||||||
@ -1917,22 +1916,8 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
}
|
}
|
||||||
mSilenceLevel = (silenceLevelDB + dBRange)/(double)dBRange; // meter goes -dBRange dB -> 0dB
|
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
|
// Clamp pre-roll so we don't play before time 0
|
||||||
const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
|
const auto preRoll = std::max(0.0, std::min(t0, options.preRoll));
|
||||||
mPlaybackSchedule.mT0 = t0 - preRoll;
|
|
||||||
mPlaybackSchedule.mT1 = t1;
|
|
||||||
mRecordingSchedule = {};
|
mRecordingSchedule = {};
|
||||||
mRecordingSchedule.mPreRoll = preRoll;
|
mRecordingSchedule.mPreRoll = preRoll;
|
||||||
mRecordingSchedule.mLatencyCorrection =
|
mRecordingSchedule.mLatencyCorrection =
|
||||||
@ -1940,16 +1925,12 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
DEFAULT_LATENCY_CORRECTION))
|
DEFAULT_LATENCY_CORRECTION))
|
||||||
/ 1000.0;
|
/ 1000.0;
|
||||||
mRecordingSchedule.mDuration = t1 - t0;
|
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)
|
if (options.pCrossfadeData)
|
||||||
mRecordingSchedule.mCrossfadeData.swap( *options.pCrossfadeData );
|
mRecordingSchedule.mCrossfadeData.swap( *options.pCrossfadeData );
|
||||||
|
|
||||||
mListener = options.listener;
|
mListener = options.listener;
|
||||||
mRate = sampleRate;
|
mRate = sampleRate;
|
||||||
mPlaybackSchedule.mTime = mPlaybackSchedule.mT0;
|
|
||||||
mSeek = 0;
|
mSeek = 0;
|
||||||
mLastRecordingOffset = 0;
|
mLastRecordingOffset = 0;
|
||||||
mCaptureTracks = tracks.captureTracks;
|
mCaptureTracks = tracks.captureTracks;
|
||||||
@ -1967,15 +1948,12 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
mMidiPlaybackTracks.clear();
|
mMidiPlaybackTracks.clear();
|
||||||
#endif
|
#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();
|
mPlaybackBuffers.reset();
|
||||||
mPlaybackMixers.reset();
|
mPlaybackMixers.reset();
|
||||||
mCaptureBuffers.reset();
|
mCaptureBuffers.reset();
|
||||||
@ -1988,36 +1966,12 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
streamStartTime = SystemTime(mUsingAlsa);
|
streamStartTime = SystemTime(mUsingAlsa);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
mPlaybackSchedule.Init(
|
||||||
bool scrubbing = (options.pScrubbingOptions != nullptr);
|
t0, t1, options, mCaptureTracks.empty() ? nullptr : &mRecordingSchedule );
|
||||||
|
const bool scrubbing = mPlaybackSchedule.Interactive();
|
||||||
// Scrubbing is not compatible with looping or recording or a time track!
|
|
||||||
if (scrubbing)
|
if (scrubbing)
|
||||||
{
|
playbackTime =
|
||||||
const auto &scrubOptions = *options.pScrubbingOptions;
|
lrint(options.pScrubbingOptions->delay * sampleRate) / sampleRate;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// The RingBuffer sizes, and the max amount of the buffer to
|
// The RingBuffer sizes, and the max amount of the buffer to
|
||||||
@ -2099,9 +2053,6 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
mListener->OnAudioIOStopRecording();
|
mListener->OnAudioIOStopRecording();
|
||||||
mStreamToken = 0;
|
mStreamToken = 0;
|
||||||
|
|
||||||
// Don't cause a busy wait in the audio thread after stopping scrubbing
|
|
||||||
mPlaybackSchedule.ResetMode();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2396,10 +2347,6 @@ void AudioIO::StartStreamCleanup(bool bOnlyBuffers)
|
|||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
mScrubQueue.reset();
|
mScrubQueue.reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Don't cause a busy wait in the audio thread after stopping scrubbing
|
|
||||||
mPlaybackSchedule.ResetMode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
@ -2905,6 +2852,69 @@ bool AudioIO::IsMonitoring()
|
|||||||
return ( mPortStreamV19 && mStreamToken==0 );
|
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
|
double AudioIO::PlaybackSchedule::LimitStreamTime() const
|
||||||
{
|
{
|
||||||
// Allows for forward or backward play
|
// Allows for forward or backward play
|
||||||
@ -4960,7 +4970,6 @@ int AudioIO::AudioCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
mPlaybackSchedule.mTime = mPlaybackSchedule.LimitStreamTime();
|
mPlaybackSchedule.mTime = mPlaybackSchedule.LimitStreamTime();
|
||||||
mSeek = 0.0;
|
mSeek = 0.0;
|
||||||
|
|
||||||
// Reset mixer positions and flush buffers for all tracks
|
|
||||||
mPlaybackSchedule.RealTimeInit();
|
mPlaybackSchedule.RealTimeInit();
|
||||||
|
|
||||||
// Reset mixer positions and flush buffers for all tracks
|
// Reset mixer positions and flush buffers for all tracks
|
||||||
|
@ -805,6 +805,24 @@ public:
|
|||||||
// detect more dropouts
|
// detect more dropouts
|
||||||
bool mDetectUpstreamDropouts{ true };
|
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 {
|
struct PlaybackSchedule {
|
||||||
/// Playback starts at offset of mT0, which is measured in seconds.
|
/// Playback starts at offset of mT0, which is measured in seconds.
|
||||||
double mT0;
|
double mT0;
|
||||||
@ -840,10 +858,15 @@ public:
|
|||||||
PLAY_SCRUB,
|
PLAY_SCRUB,
|
||||||
PLAY_AT_SPEED, // a version of PLAY_SCRUB.
|
PLAY_AT_SPEED, // a version of PLAY_SCRUB.
|
||||||
#endif
|
#endif
|
||||||
} mPlayMode;
|
} mPlayMode { PLAY_STRAIGHT };
|
||||||
double mCutPreviewGapStart;
|
double mCutPreviewGapStart;
|
||||||
double mCutPreviewGapLen;
|
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 */
|
/** \brief True if the end time is before the start time */
|
||||||
bool ReversedTime() const
|
bool ReversedTime() const
|
||||||
{
|
{
|
||||||
@ -899,24 +922,6 @@ public:
|
|||||||
void RealTimeRestart();
|
void RealTimeRestart();
|
||||||
|
|
||||||
} mPlaybackSchedule;
|
} 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
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user