    #include "importmidi_tempo.h"

    #include "importmidi_inner.h"
    #include "importmidi_beat.h"
    #include "libmscore/score.h"
    #include "libmscore/measure.h"
    #include "libmscore/tempo.h"
    #include "libmscore/tempotext.h"
    #include "mscore/preferences.h"

    namespace Ms {
    namespace MidiTempo {

    ReducedFraction time2Tick(double time, double ticksPerSec)
          {
          return ReducedFraction::fromTicks(int(ticksPerSec * time));
          }

    // tempo in beats per second

    double findBasicTempo(const std::multimap<int, MTrack> &tracks, bool isHumanPerformance)
          {
          for (const auto &track: tracks) {
                            // don't read tempo from tempo track for human performed files
                            // because very often the tempo in such track is completely erroneous
                if (isHumanPerformance && track.second.chords.empty())
                      continue;
                for (const auto &ie : track.second.mtrack->events()) {
                      const MidiEvent &e = ie.second;
                      if (e.type() == ME_META && e.metaType() == META_TEMPO) {
                            const uchar* data = (uchar*)e.edata();
                            const unsigned tempo = data[2] + (data[1] << 8) + (data[0] << 16);
                            return 1000000.0 / double(tempo);
                            }
                      }
                }

          return 2;   // default beats per second = 120 beats per minute
          }

    void setTempoToScore(Score *score, int tick, double beatsPerSecond)
          {
          if (score->tempomap()->find(tick) != score->tempomap()->end())
                return;
                      // don't repeat tempo, always set only tempo for tick 0
          if (tick > 0 && score->tempo(tick) == beatsPerSecond)
                return;

          score->setTempo(tick, beatsPerSecond);

          auto *data = preferences.midiImportOperations.data();
          if (data->trackOpers.showTempoText.value()) {
                const int tempoInBpm = qRound(beatsPerSecond * 60.0);

                TempoText *tempoText = new TempoText(score);
                tempoText->setTempo(beatsPerSecond);
                tempoText->setXmlText(QString("<sym>metNoteQuarterUp</sym> = %1").arg(tempoInBpm));
                tempoText->setTrack(0);

                Measure *measure = score->tick2measure(tick);
                if (!measure) {
                      qDebug("MidiTempo::setTempoToScore: no measure for tick %d", tick);
                      return;
                      }
                Segment *segment = measure->getSegment(SegmentType::ChordRest, tick);
                if (!segment) {
                      qDebug("MidiTempo::setTempoToScore: no chord/rest segment for tempo at %d", tick);
                      return;
                      }
                segment->add(tempoText);
                data->hasTempoText = true;      // to show tempo text column in the MIDI import panel
                }
          }

    double roundToBpm(double beatsPerSecond)
          {
          return qRound(beatsPerSecond * 60.0) / 60.0;
          }

    void applyAllTempoEvents(const std::multimap<int, MTrack> &tracks, Score *score)
          {
          for (const auto &track: tracks) {
                if (track.second.isDivisionInTps) {     // ticks per second
                      const double ticksPerBeat = MScore::division;
                      const double beatsPerSecond = roundToBpm(track.second.division / ticksPerBeat);
                      setTempoToScore(score, 0, beatsPerSecond);
                      }
                else {      // beats per second
                      for (const auto &ie : track.second.mtrack->events()) {
                            const MidiEvent &e = ie.second;
                            if (e.type() == ME_META && e.metaType() == META_TEMPO) {
                                  const auto tick = toMuseScoreTicks(
                                                    ie.first, track.second.division, false);
                                  const uchar* data = (uchar*)e.edata();
                                  const unsigned tempo = data[2] + (data[1] << 8) + (data[0] << 16);
                                  const double beatsPerSecond = roundToBpm(1000000.0 / tempo);
                                  setTempoToScore(score, tick.ticks(), beatsPerSecond);
                                  }
                            }
                      }
                }
          }

    void setTempo(const std::multimap<int, MTrack> &tracks, Score *score)
          {
          score->tempomap()->clear();
          auto *midiData = preferences.midiImportOperations.data();
          std::set<ReducedFraction> beats = midiData->humanBeatData.beatSet;    // copy

          if (beats.empty()) {
                            // it's most likely not a human performance;
                            // we find all tempo events and set tempo changes to score
                applyAllTempoEvents(tracks, score);
                }
          else {            // calculate and set tempo from adjusted beat locations
                if (midiData->trackOpers.measureCount2xLess.value())
                      MidiBeat::removeEvery2ndBeat(beats);

                Q_ASSERT_X(beats.size() > 1, "MidiBeat::setTempo", "Human beat count < 2");

                double averageTempoFactor = 0.0;
                int counter = 0;
                auto it = beats.begin();
                auto beatStart = *it;
                const auto newBeatLen = ReducedFraction::fromTicks(MScore::division);

                for (++it; it != beats.end(); ++it) {
                      const auto &beatEnd = *it;

                      Q_ASSERT_X(beatEnd > beatStart, "MidiBeat::detectTempoChanges",
                                 "Beat end <= beat start that is incorrect");

                      averageTempoFactor += (newBeatLen / (beatEnd - beatStart)).toDouble();
                      ++counter;
                      beatStart = beatEnd;
                      }
                averageTempoFactor /= counter;

                const double basicTempo = MidiTempo::findBasicTempo(tracks, true);
                const double tempo = roundToBpm(basicTempo * averageTempoFactor);

                score->tempomap()->clear();         // use only one tempo marking for all score
                setTempoToScore(score, 0, tempo);
                }

          if (score->tempomap()->empty())
                score->tempomap()->setTempo(0, 2.0);      // default tempo
          }

    } // namespace MidiTempo
    } // namespace Ms

↑ V773 The function was exited without releasing the 'tempoText' pointer. A memory leak is possible.