mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-04 22:29:27 +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 {
|
else {
|
||||||
playbackTime = lrint(scrubOptions.delay * sampleRate) / sampleRate;
|
playbackTime = lrint(scrubOptions.delay * sampleRate) / sampleRate;
|
||||||
mPlayMode = PLAY_SCRUB;
|
mPlayMode = (scrubOptions.isPlayingAtSpeed) ? PLAY_AT_SPEED : PLAY_SCRUB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -2942,7 +2942,7 @@ double AudioIO::NormalizeStreamTime(double absoluteTime) const
|
|||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
// Limit the time between t0 and t1 if not scrubbing.
|
// Limit the time between t0 and t1 if not scrubbing.
|
||||||
// Should the limiting be necessary in any play mode if there are no bugs?
|
// 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
|
#endif
|
||||||
absoluteTime = LimitStreamTime(absoluteTime);
|
absoluteTime = LimitStreamTime(absoluteTime);
|
||||||
|
|
||||||
@ -3262,6 +3262,11 @@ AudioThread::ExitCode AudioThread::Entry()
|
|||||||
// This allows the scrubbing update interval to be made very short without
|
// This allows the scrubbing update interval to be made very short without
|
||||||
// playback becoming intermittent.
|
// 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 {
|
else {
|
||||||
// Perhaps this too could use a condition variable, for available space in the
|
// 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.
|
// 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;
|
auto frames = available;
|
||||||
bool progress = true;
|
bool progress = true;
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
if (mPlayMode == PLAY_SCRUB)
|
if ((mPlayMode == PLAY_SCRUB) || (mPlayMode == PLAY_AT_SPEED))
|
||||||
// scrubbing does not use warped time and length
|
// scrubbing does not use warped time and length
|
||||||
frames = limitSampleBufferSize(frames, mScrubDuration);
|
frames = limitSampleBufferSize(frames, mScrubDuration);
|
||||||
else
|
else
|
||||||
@ -3887,7 +3892,8 @@ void AudioIO::FillBuffers()
|
|||||||
|
|
||||||
// don't generate either if scrubbing at zero speed.
|
// don't generate either if scrubbing at zero speed.
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
const bool silent = (mPlayMode == PLAY_SCRUB) && mSilentScrub;
|
const bool silent = ((mPlayMode == PLAY_SCRUB)||
|
||||||
|
(mPlayMode == PLAY_AT_SPEED)) && mSilentScrub;
|
||||||
#else
|
#else
|
||||||
const bool silent = false;
|
const bool silent = false;
|
||||||
#endif
|
#endif
|
||||||
@ -3930,6 +3936,7 @@ void AudioIO::FillBuffers()
|
|||||||
{
|
{
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
case PLAY_SCRUB:
|
case PLAY_SCRUB:
|
||||||
|
case PLAY_AT_SPEED:
|
||||||
{
|
{
|
||||||
mScrubDuration -= frames;
|
mScrubDuration -= frames;
|
||||||
wxASSERT(mScrubDuration >= 0);
|
wxASSERT(mScrubDuration >= 0);
|
||||||
@ -4940,6 +4947,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
// While scrubbing, ignore seek requests
|
// While scrubbing, ignore seek requests
|
||||||
if (gAudioIO->mSeek && gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB)
|
if (gAudioIO->mSeek && gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB)
|
||||||
gAudioIO->mSeek = 0.0;
|
gAudioIO->mSeek = 0.0;
|
||||||
|
else if (gAudioIO->mSeek && gAudioIO->mPlayMode == AudioIO::PLAY_AT_SPEED)
|
||||||
|
gAudioIO->mSeek = 0.0;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if (gAudioIO->mSeek)
|
if (gAudioIO->mSeek)
|
||||||
@ -5118,22 +5127,37 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
}
|
}
|
||||||
group++;
|
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.
|
// selection.
|
||||||
// msmeyer: We never finish if we are playing looped
|
if (bDone)
|
||||||
// PRL: or scrubbing.
|
bDone = bDone && (gAudioIO->ReversedTime()
|
||||||
if (len == 0 &&
|
|
||||||
gAudioIO->mPlayMode == AudioIO::PLAY_STRAIGHT) {
|
|
||||||
if ((gAudioIO->ReversedTime()
|
|
||||||
? gAudioIO->mTime <= gAudioIO->mT1
|
? gAudioIO->mTime <= gAudioIO->mT1
|
||||||
: 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
|
// 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
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
gAudioIO->mMidiOutputComplete = true,
|
gAudioIO->mMidiOutputComplete = true,
|
||||||
#endif
|
#endif
|
||||||
callbackReturn = paComplete;
|
callbackReturn = paComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cut) // no samples to process, they've been discarded
|
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")
|
// be less than framesPerBuffer (during "stutter")
|
||||||
if (gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB)
|
if (gAudioIO->mPlayMode == AudioIO::PLAY_SCRUB)
|
||||||
gAudioIO->mTime = gAudioIO->mScrubQueue->Consumer(maxLen);
|
gAudioIO->mTime = gAudioIO->mScrubQueue->Consumer(maxLen);
|
||||||
|
else if (gAudioIO->mPlayMode == AudioIO::PLAY_AT_SPEED)
|
||||||
|
gAudioIO->mTime = gAudioIO->mScrubQueue->Consumer(maxLen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
em.RealtimeProcessEnd();
|
em.RealtimeProcessEnd();
|
||||||
@ -5344,7 +5370,8 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
|
|||||||
// Update the current time position if not scrubbing
|
// Update the current time position if not scrubbing
|
||||||
// (Already did it above, for scrubbing)
|
// (Already did it above, for scrubbing)
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
if (gAudioIO->mPlayMode != AudioIO::PLAY_SCRUB)
|
if( (gAudioIO->mPlayMode != AudioIO::PLAY_SCRUB) &&
|
||||||
|
(gAudioIO->mPlayMode != AudioIO::PLAY_AT_SPEED) )
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
double delta = framesPerBuffer / gAudioIO->mRate;
|
double delta = framesPerBuffer / gAudioIO->mRate;
|
||||||
|
@ -750,6 +750,7 @@ private:
|
|||||||
PLAY_LOOPED,
|
PLAY_LOOPED,
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
PLAY_SCRUB,
|
PLAY_SCRUB,
|
||||||
|
PLAY_AT_SPEED, // a version of PLAY_SCRUB.
|
||||||
#endif
|
#endif
|
||||||
} mPlayMode;
|
} mPlayMode;
|
||||||
double mCutPreviewGapStart;
|
double mCutPreviewGapStart;
|
||||||
|
@ -354,6 +354,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx)
|
|||||||
options.pScrubbingOptions = &mOptions;
|
options.pScrubbingOptions = &mOptions;
|
||||||
options.timeTrack = NULL;
|
options.timeTrack = NULL;
|
||||||
mOptions.delay = (ScrubPollInterval_ms * 0.9 / 1000.0);
|
mOptions.delay = (ScrubPollInterval_ms * 0.9 / 1000.0);
|
||||||
|
mOptions.isPlayingAtSpeed = false;
|
||||||
mOptions.minSpeed = 0.0;
|
mOptions.minSpeed = 0.0;
|
||||||
#ifdef USE_TRANSCRIPTION_TOOLBAR
|
#ifdef USE_TRANSCRIPTION_TOOLBAR
|
||||||
if (!mAlwaysSeeking) {
|
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.minStutter = lrint(std::max(0.0, MinStutter) * options.rate);
|
||||||
mOptions.enqueueBySpeed = true;
|
mOptions.enqueueBySpeed = true;
|
||||||
mOptions.adjustStart = false;
|
mOptions.adjustStart = false;
|
||||||
|
mOptions.isPlayingAtSpeed = true;
|
||||||
|
|
||||||
ControlToolBar::PlayAppearance appearance = ControlToolBar::PlayAppearance::Straight;
|
ControlToolBar::PlayAppearance appearance = ControlToolBar::PlayAppearance::Straight;
|
||||||
|
|
||||||
@ -486,8 +487,11 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
mScrubSpeedDisplayCountdown = 0;
|
mScrubSpeedDisplayCountdown = 0;
|
||||||
|
// last buffer should not be any bigger than this.
|
||||||
|
double lastBuffer = (2 * ScrubPollInterval_ms) / 1000.0;
|
||||||
mScrubToken =
|
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);
|
PlayMode::normalPlay, appearance, backwards);
|
||||||
|
|
||||||
if (mScrubToken >= 0) {
|
if (mScrubToken >= 0) {
|
||||||
|
@ -45,6 +45,7 @@ struct ScrubbingOptions {
|
|||||||
sampleCount minSample {};
|
sampleCount minSample {};
|
||||||
|
|
||||||
bool enqueueBySpeed {};
|
bool enqueueBySpeed {};
|
||||||
|
bool isPlayingAtSpeed{};
|
||||||
|
|
||||||
double delay {};
|
double delay {};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user