mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-28 14:18:41 +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;
|
mMidiStreamActive = false;
|
||||||
mSendMidiState = false;
|
mSendMidiState = false;
|
||||||
mIterator = NULL;
|
mIterator = NULL;
|
||||||
mMidiPlaySpeed = 1.0;
|
|
||||||
|
|
||||||
mNumFrames = 0;
|
mNumFrames = 0;
|
||||||
mNumPauseFrames = 0;
|
mNumPauseFrames = 0;
|
||||||
@ -2388,7 +2387,6 @@ void AudioIO::StopStream()
|
|||||||
}
|
}
|
||||||
|
|
||||||
mIterator.reset(); // just in case someone tries to reference it
|
mIterator.reset(); // just in case someone tries to reference it
|
||||||
mMidiPlaySpeed = 1.0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -3021,6 +3019,9 @@ MidiThread::ExitCode MidiThread::Entry()
|
|||||||
if (gAudioIO->mNumPlaybackChannels != 0) {
|
if (gAudioIO->mNumPlaybackChannels != 0) {
|
||||||
realTime -= 1; // with audio, MidiTime() runs ahead 1s
|
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
|
// The TrackPanel::OnTimer() method updates the time position
|
||||||
// indicator every 200ms, so it tends to not advance the
|
// indicator every 200ms, so it tends to not advance the
|
||||||
// indicator to the end of the selection (mT1) but instead stop
|
// 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
|
// down and the indicator is removed, but for a brief time, the
|
||||||
// indicator is clearly stopped before reaching mT1. To avoid
|
// indicator is clearly stopped before reaching mT1. To avoid
|
||||||
// this, we do not set mMidiOutputComplete until we are actually
|
// 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
|
// gives OnTimer() time to wake up and draw the final time
|
||||||
// position at mT1 before shutting down the stream.
|
// position at mT1 before shutting down the stream.
|
||||||
double timeAtSpeed = (realTime - gAudioIO->mT0) *
|
const double loopDelay = 0.220;
|
||||||
gAudioIO->mMidiPlaySpeed + gAudioIO->mT0;
|
|
||||||
|
double timeAtSpeed;
|
||||||
|
if (gAudioIO->mTimeTrack)
|
||||||
|
timeAtSpeed = gAudioIO->mTimeTrack->SolveWarpedLength(gAudioIO->mT0, realTime);
|
||||||
|
else
|
||||||
|
timeAtSpeed = realTime;
|
||||||
|
|
||||||
gAudioIO->mMidiOutputComplete =
|
gAudioIO->mMidiOutputComplete =
|
||||||
(gAudioIO->mPlayMode == gAudioIO->PLAY_STRAIGHT && // PRL: what if scrubbing?
|
(gAudioIO->mPlayMode == gAudioIO->PLAY_STRAIGHT && // PRL: what if scrubbing?
|
||||||
timeAtSpeed >= gAudioIO->mT1 + 0.220);
|
timeAtSpeed >= gAudioIO->mT1 + loopDelay);
|
||||||
// !gAudioIO->mNextEvent);
|
// !gAudioIO->mNextEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3849,8 +3855,13 @@ void AudioIO::OutputEvent()
|
|||||||
int command = -1;
|
int command = -1;
|
||||||
int data1 = -1;
|
int data1 = -1;
|
||||||
int data2 = -1;
|
int data2 = -1;
|
||||||
|
|
||||||
|
double eventTime;
|
||||||
|
if (mTimeTrack)
|
||||||
|
eventTime = mTimeTrack->ComputeWarpedLength(mT0, mNextEventTime) + mT0;
|
||||||
|
else
|
||||||
|
eventTime = mNextEventTime;
|
||||||
// 0.0005 is for rounding
|
// 0.0005 is for rounding
|
||||||
double eventTime = (mNextEventTime - mT0) / mMidiPlaySpeed + mT0;
|
|
||||||
double time = eventTime + PauseTime() + 0.0005 -
|
double time = eventTime + PauseTime() + 0.0005 -
|
||||||
((mMidiLatency + mSynthLatency) * 0.001);
|
((mMidiLatency + mSynthLatency) * 0.001);
|
||||||
|
|
||||||
@ -4028,7 +4039,11 @@ void AudioIO::FillMidiBuffers()
|
|||||||
time = AudioTime() - PauseTime();
|
time = AudioTime() - PauseTime();
|
||||||
} else {
|
} else {
|
||||||
time = mT0 + Pt_Time() * 0.001 - PauseTime();
|
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) {
|
if (mNumCaptureChannels <= 0) {
|
||||||
// no audio callback, so move the time cursor here:
|
// no audio callback, so move the time cursor here:
|
||||||
double trackTime = timeAtSpeed - mMidiLoopOffset;
|
double trackTime = timeAtSpeed - mMidiLoopOffset;
|
||||||
@ -4054,8 +4069,8 @@ void AudioIO::FillMidiBuffers()
|
|||||||
time += MIDI_SLEEP * 0.001;
|
time += MIDI_SLEEP * 0.001;
|
||||||
}
|
}
|
||||||
while (mNextEvent &&
|
while (mNextEvent &&
|
||||||
(mNextEventTime - mT0) / mMidiPlaySpeed + mT0 < time +
|
(mTimeTrack ? (mTimeTrack->ComputeWarpedLength(mT0, mNextEventTime) + mT0) : mNextEventTime)
|
||||||
((MIDI_SLEEP + mSynthLatency) * 0.001)) {
|
< time + ((MIDI_SLEEP + mSynthLatency) * 0.001)) {
|
||||||
OutputEvent();
|
OutputEvent();
|
||||||
GetNextEvent();
|
GetNextEvent();
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,6 @@ class TimeTrack;
|
|||||||
class AudioThread;
|
class AudioThread;
|
||||||
class Meter;
|
class Meter;
|
||||||
class SelectedRegion;
|
class SelectedRegion;
|
||||||
class TimeTrack;
|
|
||||||
|
|
||||||
class AudacityProject;
|
class AudacityProject;
|
||||||
|
|
||||||
@ -227,9 +226,6 @@ class AUDACITY_DLL_API AudioIO final {
|
|||||||
public:
|
public:
|
||||||
bool SetHasSolo(bool hasSolo);
|
bool SetHasSolo(bool hasSolo);
|
||||||
bool GetHasSolo() { return mHasSolo; }
|
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
|
#endif
|
||||||
|
|
||||||
/** \brief Returns true if the stream is active, or even if audio I/O is
|
/** \brief Returns true if the stream is active, or even if audio I/O is
|
||||||
@ -527,9 +523,6 @@ private:
|
|||||||
long mMidiLatency;
|
long mMidiLatency;
|
||||||
/// Latency of MIDI synthesizer
|
/// Latency of MIDI synthesizer
|
||||||
long mSynthLatency;
|
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:
|
// These fields are used to synchronize MIDI with audio:
|
||||||
|
|
||||||
|
@ -475,9 +475,6 @@ void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
|
|||||||
// Start playing
|
// Start playing
|
||||||
if (playRegionStart >= 0) {
|
if (playRegionStart >= 0) {
|
||||||
// playRegionEnd = playRegionStart + (playRegionEnd-playRegionStart)* 100.0/mPlaySpeed;
|
// playRegionEnd = playRegionStart + (playRegionEnd-playRegionStart)* 100.0/mPlaySpeed;
|
||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
|
||||||
gAudioIO->SetMidiPlaySpeed(mPlaySpeed);
|
|
||||||
#endif
|
|
||||||
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
|
AudioIOStartStreamOptions options(p->GetDefaultPlayOptions());
|
||||||
options.playLooped = looped;
|
options.playLooped = looped;
|
||||||
options.timeTrack = mTimeTrack.get();
|
options.timeTrack = mTimeTrack.get();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user