Skip to content

Commit

Permalink
Merge pull request #3789 from brdvd/fix/duplicate-tempo
Browse files Browse the repository at this point in the history
Track tempo ticks in MIDI to avoid duplicate tempo events
  • Loading branch information
lpugin authored Sep 19, 2024
2 parents 3d63219 + 3ae93e9 commit 5ff1c0b
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 1 deletion.
11 changes: 11 additions & 0 deletions include/vrv/midifunctor.h
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,13 @@ class GenerateMIDIFunctor : public ConstFunctor {
*/
bool ImplementsEndInterface() const override { return true; }

/*
* Getter for properties
*/
///@{
std::set<int> GetTempoEventTicks() const { return m_tempoEventTicks; }
///@}

/*
* Setter for various properties
*/
Expand All @@ -287,6 +294,7 @@ class GenerateMIDIFunctor : public ConstFunctor {
void SetCurrentTempo(double tempo) { m_currentTempo = tempo; }
void SetDeferredNotes(const std::map<const Note *, double> &deferredNotes) { m_deferredNotes = deferredNotes; }
void SetStaffN(int staffN) { m_staffN = staffN; }
void SetTempoEventTicks(const std::set<int> &ticks) { m_tempoEventTicks = ticks; }
void SetTrack(int track) { m_midiTrack = track; }
void SetTransSemi(int transSemi) { m_transSemi = transSemi; }
///@}
Expand Down Expand Up @@ -345,6 +353,9 @@ class GenerateMIDIFunctor : public ConstFunctor {
int m_transSemi;
// The current tempo
double m_currentTempo;
// Tempo events are always added on track 0
// This set contains the ticks of all added tempo events to avoid multiple events at the same time
std::set<int> m_tempoEventTicks;
// The last (non grace) note that was performed
const Note *m_lastNote;
// Expanded notes due to ornaments and tremolandi
Expand Down
6 changes: 6 additions & 0 deletions src/doc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,15 +406,18 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile)
}

double tempo = MIDI_TEMPO;
std::set<int> tempoEventTicks; // track the ticks of added tempo events

// set MIDI tempo
ScoreDef *scoreDef = this->GetFirstVisibleScore()->GetScoreDef();
if (scoreDef->HasMidiBpm()) {
tempo = scoreDef->GetMidiBpm();
tempoEventTicks.insert(0);
midiFile->addTempo(0, 0, tempo);
}
else if (scoreDef->HasMm()) {
tempo = Tempo::CalcTempo(scoreDef);
tempoEventTicks.insert(0);
midiFile->addTempo(0, 0, tempo);
}

Expand Down Expand Up @@ -522,13 +525,16 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile)
generateMIDI.SetChannel(midiChannel);
generateMIDI.SetTrack(midiTrack);
generateMIDI.SetStaffN(staves->first);
generateMIDI.SetTempoEventTicks(tempoEventTicks);
generateMIDI.SetTransSemi(transSemi);
generateMIDI.SetCurrentTempo(tempo);
generateMIDI.SetDeferredNotes(initMIDI.GetDeferredNotes());
generateMIDI.SetCueExclusion(this->GetOptions()->m_midiNoCue.GetValue());

// LogDebug("Exporting track %d ----------------", midiTrack);
this->Process(generateMIDI);

tempoEventTicks = generateMIDI.GetTempoEventTicks();
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/midifunctor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,11 @@ FunctorCode GenerateMIDIFunctor::VisitMeasure(const Measure *measure)

if (measure->GetCurrentTempo() != m_currentTempo) {
m_currentTempo = measure->GetCurrentTempo();
m_midiFile->addTempo(0, m_totalTime * m_midiFile->getTPQ(), m_currentTempo);
const int tick = m_totalTime * m_midiFile->getTPQ();
// Check if there was already a tempo event added for the given tick
if (m_tempoEventTicks.insert(tick).second) {
m_midiFile->addTempo(0, tick, m_currentTempo);
}
}

return FUNCTOR_CONTINUE;
Expand Down

0 comments on commit 5ff1c0b

Please sign in to comment.