1
0
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:
James Crook 2018-07-21 21:14:30 +01:00
parent 5caa14e4f9
commit f0637eeb85
4 changed files with 52 additions and 19 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -45,6 +45,7 @@ struct ScrubbingOptions {
sampleCount minSample {};
bool enqueueBySpeed {};
bool isPlayingAtSpeed{};
double delay {};