From 752d145e8e0cba579dff2f5f1e9a3c7e9141dc09 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Wed, 18 Sep 2024 22:05:13 +0200 Subject: [PATCH 1/2] Check against duplicate tempo events in MIDI functor --- include/vrv/midifunctor.h | 11 +++++++++++ src/midifunctor.cpp | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/vrv/midifunctor.h b/include/vrv/midifunctor.h index 9900ea45f6a..2e7ade355fa 100644 --- a/include/vrv/midifunctor.h +++ b/include/vrv/midifunctor.h @@ -278,6 +278,13 @@ class GenerateMIDIFunctor : public ConstFunctor { */ bool ImplementsEndInterface() const override { return true; } + /* + * Getter for properties + */ + ///@{ + std::set GetTempoEventTicks() const { return m_tempoEventTicks; } + ///@} + /* * Setter for various properties */ @@ -287,6 +294,7 @@ class GenerateMIDIFunctor : public ConstFunctor { void SetCurrentTempo(double tempo) { m_currentTempo = tempo; } void SetDeferredNotes(const std::map &deferredNotes) { m_deferredNotes = deferredNotes; } void SetStaffN(int staffN) { m_staffN = staffN; } + void SetTempoEventTicks(const std::set &ticks) { m_tempoEventTicks = ticks; } void SetTrack(int track) { m_midiTrack = track; } void SetTransSemi(int transSemi) { m_transSemi = transSemi; } ///@} @@ -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 m_tempoEventTicks; // The last (non grace) note that was performed const Note *m_lastNote; // Expanded notes due to ornaments and tremolandi diff --git a/src/midifunctor.cpp b/src/midifunctor.cpp index 8e19d336ed8..f9c705c6204 100644 --- a/src/midifunctor.cpp +++ b/src/midifunctor.cpp @@ -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; From 3ae93e906fb1fc52ccb774850e33a0548d8d0e4a Mon Sep 17 00:00:00 2001 From: David Bauer Date: Wed, 18 Sep 2024 22:13:43 +0200 Subject: [PATCH 2/2] Use tick set outside functor to track tempo events across multiple staves and layers --- src/doc.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/doc.cpp b/src/doc.cpp index 3bc43359905..b123741b1cf 100644 --- a/src/doc.cpp +++ b/src/doc.cpp @@ -406,15 +406,18 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) } double tempo = MIDI_TEMPO; + std::set 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); } @@ -522,6 +525,7 @@ 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()); @@ -529,6 +533,8 @@ void Doc::ExportMIDI(smf::MidiFile *midiFile) // LogDebug("Exporting track %d ----------------", midiTrack); this->Process(generateMIDI); + + tempoEventTicks = generateMIDI.GetTempoEventTicks(); } } }