mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 15:49:36 +02:00
Bug 1906 - Issues with dynamic Play-at-Speed (Play doesn't pop up)
Fixed issue 1, i.e. the play button does not pop up after play at speed completes.
This commit is contained in:
parent
5caa14e4f9
commit
f0637eeb85
@ -2003,7 +2003,7 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
||||
}
|
||||
else {
|
||||
playbackTime = lrint(scrubOptions.delay * sampleRate) / sampleRate;
|
||||
mPlayMode = PLAY_SCRUB;
|
||||
mPlayMode = (scrubOptions.isPlayingAtSpeed) ? PLAY_AT_SPEED : PLAY_SCRUB;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2942,7 +2942,7 @@ double AudioIO::NormalizeStreamTime(double absoluteTime) const
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
// Limit the time between t0 and t1 if not scrubbing.
|
||||
// Should the limiting be necessary in any play mode if there are no bugs?
|
||||
if (mPlayMode != PLAY_SCRUB)
|
||||
if( (mPlayMode != PLAY_SCRUB) && (mPlayMode != PLAY_AT_SPEED))
|
||||
#endif
|
||||
absoluteTime = LimitStreamTime(absoluteTime);
|
||||
|
||||
@ -3262,6 +3262,11 @@ AudioThread::ExitCode AudioThread::Entry()
|
||||
// This allows the scrubbing update interval to be made very short without
|
||||
// playback becoming intermittent.
|
||||
}
|
||||
else if (gAudioIO->mPlayMode == AudioIO::PLAY_AT_SPEED) {
|
||||
// Rely on the Wait() in ScrubQueue::Transformer()
|
||||
// This allows the scrubbing update interval to be made very short without
|
||||
// playback becoming intermittent.
|
||||
}
|
||||
else {
|
||||
// Perhaps this too could use a condition variable, for available space in the
|
||||
// ring buffer, instead of a polling loop? But no harm in doing it this way.
|
||||
@ -3850,7 +3855,7 @@ void AudioIO::FillBuffers()
|
||||
auto frames = available;
|
||||
bool progress = true;
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
if (mPlayMode == PLAY_SCRUB)
|
||||
if ((mPlayMode == PLAY_SCRUB) || (mPlayMode == PLAY_AT_SPEED))
|
||||
// scrubbing does not use warped time and length
|
||||
frames = limitSampleBufferSize(frames, mScrubDuration);
|
||||
else
|
||||
@ -3887,7 +3892,8 @@ void AudioIO::FillBuffers()
|
||||
|
||||
// don't generate either if scrubbing at zero speed.
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
const bool silent = (mPlayMode == PLAY_SCRUB) && mSilentScrub;
|
||||
const bool silent = ((mPlayMode == PLAY_SCRUB)||
|
||||
(mPlayMode == PLAY_AT_SPEED)) && mSilentScrub;
|
||||
#else
|
||||
const bool silent = false;
|
||||
#endif
|
||||
@ -3930,6 +3936,7 @@ void AudioIO::FillBuffers()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
case PLAY_SCRUB:
|
||||
case PLAY_AT_SPEED:
|
||||
{
|
||||
mScrubDuration -= frames;
|
||||
wxASSERT(mScrubDuration >= 0);
|
||||
@ -4940,6 +4947,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
||||
// While scrubbing, ignore seek requests
|
||||
if (gAudioIO->mSeek && gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB)
|
||||
gAudioIO->mSeek = 0.0;
|
||||
else if (gAudioIO->mSeek && gAudioIO->mPlayMode == AudioIO::PLAY_AT_SPEED)
|
||||
gAudioIO->mSeek = 0.0;
|
||||
else
|
||||
#endif
|
||||
if (gAudioIO->mSeek)
|
||||
@ -5118,22 +5127,37 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
||||
}
|
||||
group++;
|
||||
|
||||
// If our buffer is empty and the time indicator is past
|
||||
// the end, then we've actually finished playing the entire
|
||||
|
||||
bool bDone = true;
|
||||
|
||||
// If the time indicator is past
|
||||
// the end, then we may have finished playing the entire
|
||||
// selection.
|
||||
// msmeyer: We never finish if we are playing looped
|
||||
// PRL: or scrubbing.
|
||||
if (len == 0 &&
|
||||
gAudioIO->mPlayMode == AudioIO::PLAY_STRAIGHT) {
|
||||
if ((gAudioIO->ReversedTime()
|
||||
if (bDone)
|
||||
bDone = bDone && (gAudioIO->ReversedTime()
|
||||
? gAudioIO->mTime <= gAudioIO->mT1
|
||||
: gAudioIO->mTime >= gAudioIO->mT1))
|
||||
// PRL: singalling MIDI output complete is necessary if
|
||||
// not USE_MIDI_THREAD, otherwise it's harmlessly redundant
|
||||
: gAudioIO->mTime >= gAudioIO->mT1);
|
||||
|
||||
// We never finish if we are playing looped or or scrubbing.
|
||||
if (bDone) {
|
||||
// playing straight we must have no more audio.
|
||||
if (gAudioIO->mPlayMode == AudioIO::PLAY_STRAIGHT)
|
||||
bDone = (len == 0);
|
||||
// playing at speed, it is OK to have some audio left over.
|
||||
else if (gAudioIO->mPlayMode == AudioIO::PLAY_AT_SPEED)
|
||||
bDone = true;
|
||||
else
|
||||
bDone = false;
|
||||
}
|
||||
|
||||
|
||||
if (bDone){
|
||||
// PRL: singalling MIDI output complete is necessary if
|
||||
// not USE_MIDI_THREAD, otherwise it's harmlessly redundant
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
gAudioIO->mMidiOutputComplete = true,
|
||||
gAudioIO->mMidiOutputComplete = true,
|
||||
#endif
|
||||
callbackReturn = paComplete;
|
||||
callbackReturn = paComplete;
|
||||
}
|
||||
|
||||
if (cut) // no samples to process, they've been discarded
|
||||
@ -5208,6 +5232,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
||||
// be less than framesPerBuffer (during "stutter")
|
||||
if (gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB)
|
||||
gAudioIO->mTime = gAudioIO->mScrubQueue->Consumer(maxLen);
|
||||
else if (gAudioIO->mPlayMode == AudioIO::PLAY_AT_SPEED)
|
||||
gAudioIO->mTime = gAudioIO->mScrubQueue->Consumer(maxLen);
|
||||
#endif
|
||||
|
||||
em.RealtimeProcessEnd();
|
||||
@ -5344,7 +5370,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
||||
// Update the current time position if not scrubbing
|
||||
// (Already did it above, for scrubbing)
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
if (gAudioIO->mPlayMode != AudioIO::PLAY_SCRUB)
|
||||
if( (gAudioIO->mPlayMode != AudioIO::PLAY_SCRUB) &&
|
||||
(gAudioIO->mPlayMode != AudioIO::PLAY_AT_SPEED) )
|
||||
#endif
|
||||
{
|
||||
double delta = framesPerBuffer / gAudioIO->mRate;
|
||||
|
@ -750,6 +750,7 @@ private:
|
||||
PLAY_LOOPED,
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||
PLAY_SCRUB,
|
||||
PLAY_AT_SPEED, // a version of PLAY_SCRUB.
|
||||
#endif
|
||||
} mPlayMode;
|
||||
double mCutPreviewGapStart;
|
||||
|
@ -354,6 +354,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx)
|
||||
options.pScrubbingOptions = &mOptions;
|
||||
options.timeTrack = NULL;
|
||||
mOptions.delay = (ScrubPollInterval_ms * 0.9 / 1000.0);
|
||||
mOptions.isPlayingAtSpeed = false;
|
||||
mOptions.minSpeed = 0.0;
|
||||
#ifdef USE_TRANSCRIPTION_TOOLBAR
|
||||
if (!mAlwaysSeeking) {
|
||||
@ -472,7 +473,7 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1)
|
||||
mOptions.minStutter = lrint(std::max(0.0, MinStutter) * options.rate);
|
||||
mOptions.enqueueBySpeed = true;
|
||||
mOptions.adjustStart = false;
|
||||
|
||||
mOptions.isPlayingAtSpeed = true;
|
||||
|
||||
ControlToolBar::PlayAppearance appearance = ControlToolBar::PlayAppearance::Straight;
|
||||
|
||||
@ -486,8 +487,11 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1)
|
||||
#endif
|
||||
|
||||
mScrubSpeedDisplayCountdown = 0;
|
||||
// last buffer should not be any bigger than this.
|
||||
double lastBuffer = (2 * ScrubPollInterval_ms) / 1000.0;
|
||||
mScrubToken =
|
||||
ctb->PlayPlayRegion(SelectedRegion(time0, time1), options,
|
||||
// Reduce time by 'lastBuffer' fudge factor, so that the Play will stop.
|
||||
ctb->PlayPlayRegion(SelectedRegion(time0, time1-lastBuffer), options,
|
||||
PlayMode::normalPlay, appearance, backwards);
|
||||
|
||||
if (mScrubToken >= 0) {
|
||||
|
@ -45,6 +45,7 @@ struct ScrubbingOptions {
|
||||
sampleCount minSample {};
|
||||
|
||||
bool enqueueBySpeed {};
|
||||
bool isPlayingAtSpeed{};
|
||||
|
||||
double delay {};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user