mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-28 06:08:40 +02:00
Time track properly warps the MIDI event times (but not pitches)
mMidiPlaySpeed doesn't handle all of the options provided by time tracks, and in fact doesn't even use time tracks. Using the time track instead allows note tracks to remain synchronized with the rest of the audio. mMidiPlaySpeed _did_ work where it was used in the transcription tool bar, but that already updates a time track so no special handling is needed.
This commit is contained in:
parent
8b37ac5c39
commit
c50567e1db
@ -997,7 +997,6 @@ AudioIO::AudioIO()
|
||||
mMidiStreamActive = false;
|
||||
mSendMidiState = false;
|
||||
mIterator = NULL;
|
||||
mMidiPlaySpeed = 1.0;
|
||||
|
||||
mNumFrames = 0;
|
||||
mNumPauseFrames = 0;
|
||||
@ -2388,7 +2387,6 @@ void AudioIO::StopStream()
|
||||
}
|
||||
|
||||
mIterator.reset(); // just in case someone tries to reference it
|
||||
mMidiPlaySpeed = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -3021,6 +3019,9 @@ MidiThread::ExitCode MidiThread::Entry()
|
||||
if (gAudioIO->mNumPlaybackChannels != 0) {
|
||||
realTime -= 1; // with audio, MidiTime() runs ahead 1s
|
||||
}
|
||||
|
||||
// XXX Is this still true now? It seems to break looping --Poke
|
||||
//
|
||||
// The TrackPanel::OnTimer() method updates the time position
|
||||
// indicator every 200ms, so it tends to not advance the
|
||||
// indicator to the end of the selection (mT1) but instead stop
|
||||
@ -3028,15 +3029,20 @@ MidiThread::ExitCode MidiThread::Entry()
|
||||
// down and the indicator is removed, but for a brief time, the
|
||||
// indicator is clearly stopped before reaching mT1. To avoid
|
||||
// this, we do not set mMidiOutputComplete until we are actually
|
||||
// 0.22s beyond mT1 (even though we stop playing at mT1. This
|
||||
// 0.22s beyond mT1 (even though we stop playing at mT1). This
|
||||
// gives OnTimer() time to wake up and draw the final time
|
||||
// position at mT1 before shutting down the stream.
|
||||
double timeAtSpeed = (realTime - gAudioIO->mT0) *
|
||||
gAudioIO->mMidiPlaySpeed + gAudioIO->mT0;
|
||||
const double loopDelay = 0.220;
|
||||
|
||||
double timeAtSpeed;
|
||||
if (gAudioIO->mTimeTrack)
|
||||
timeAtSpeed = gAudioIO->mTimeTrack->SolveWarpedLength(gAudioIO->mT0, realTime);
|
||||
else
|
||||
timeAtSpeed = realTime;
|
||||
|
||||
gAudioIO->mMidiOutputComplete =
|
||||
(gAudioIO->mPlayMode == gAudioIO->PLAY_STRAIGHT && // PRL: what if scrubbing?
|
||||
timeAtSpeed >= gAudioIO->mT1 + 0.220);
|
||||
timeAtSpeed >= gAudioIO->mT1 + loopDelay);
|
||||
// !gAudioIO->mNextEvent);
|
||||
}
|
||||
}
|
||||
@ -3849,8 +3855,13 @@ void AudioIO::OutputEvent()
|
||||
int command = -1;
|
||||
int data1 = -1;
|
||||
int data2 = -1;
|
||||
|
||||
double eventTime;
|
||||
if (mTimeTrack)
|
||||
eventTime = mTimeTrack->ComputeWarpedLength(mT0, mNextEventTime) + mT0;
|
||||
else
|
||||
eventTime = mNextEventTime;
|
||||
// 0.0005 is for rounding
|
||||
double eventTime = (mNextEventTime - mT0) / mMidiPlaySpeed + mT0;
|
||||
double time = eventTime + PauseTime() + 0.0005 -
|
||||
((mMidiLatency + mSynthLatency) * 0.001);
|
||||
|
||||
@ -4028,7 +4039,11 @@ void AudioIO::FillMidiBuffers()
|
||||
time = AudioTime() - PauseTime();
|
||||
} else {
|
||||
time = mT0 + Pt_Time() * 0.001 - PauseTime();
|
||||
double timeAtSpeed = (time - mT0) * mMidiPlaySpeed + mT0;
|
||||
double timeAtSpeed;
|
||||
if (mTimeTrack)
|
||||
timeAtSpeed = mTimeTrack->SolveWarpedLength(mT0, time);
|
||||
else
|
||||
timeAtSpeed = time;
|
||||
if (mNumCaptureChannels <= 0) {
|
||||
// no audio callback, so move the time cursor here:
|
||||
double trackTime = timeAtSpeed - mMidiLoopOffset;
|
||||
@ -4054,8 +4069,8 @@ void AudioIO::FillMidiBuffers()
|
||||
time += MIDI_SLEEP * 0.001;
|
||||
}
|
||||
while (mNextEvent &&
|
||||
(mNextEventTime - mT0) / mMidiPlaySpeed + mT0 < time +
|
||||
((MIDI_SLEEP + mSynthLatency) * 0.001)) {
|
||||
(mTimeTrack ? (mTimeTrack->ComputeWarpedLength(mT0, mNextEventTime) + mT0) : mNextEventTime)
|
||||
< time + ((MIDI_SLEEP + mSynthLatency) * 0.001)) {
|
||||
OutputEvent();
|
||||
GetNextEvent();
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ class TimeTrack;
|
||||
class AudioThread;
|
||||
class Meter;
|
||||
class SelectedRegion;
|
||||
class TimeTrack;
|
||||
|
||||
class AudacityProject;
|
||||
|
||||
@ -227,9 +226,6 @@ class AUDACITY_DLL_API AudioIO final {
|
||||
public:
|
||||
bool SetHasSolo(bool hasSolo);
|
||||
bool GetHasSolo() { return mHasSolo; }
|
||||
/// Sets the speed for midi playback, based off of the transcription speed.
|
||||
/// This takes a percentage, so passing 100 will play at normal speed.
|
||||
void SetMidiPlaySpeed(double s) { mMidiPlaySpeed = s * 0.01; }
|
||||
#endif
|
||||
|
||||
/** \brief Returns true if the stream is active, or even if audio I/O is
|
||||
@ -527,9 +523,6 @@ private:
|
||||
long mMidiLatency;
|
||||
/// Latency of MIDI synthesizer
|
||||
long mSynthLatency;
|
||||
/// A copy of TranscriptionToolBar::mPlaySpeed - a linear speed offset.
|
||||
/// Should be replaced with use of mTimeTrack
|
||||
double mMidiPlaySpeed;
|
||||
|
||||
// These fields are used to synchronize MIDI with audio:
|
||||
|
||||
|
@ -475,9 +475,6 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
|
||||
// Start playing
|
||||
if (playRegionStart >= 0) {
|
||||
// playRegionEnd = playRegionStart + (playRegionEnd-playRegionStart)* 100.0/mPlaySpeed;
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
gAudioIO->SetMidiPlaySpeed(mPlaySpeed);
|
||||
#endif
|
||||
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
|
||||
options.playLooped = looped;
|
||||
options.timeTrack = mTimeTrack.get();
|
||||
|
Loading…
x
Reference in New Issue
Block a user