Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : /**
24 : \file
25 : Implementation of class PauseMap.
26 : */
27 :
28 : #include "pausemap.h"
29 :
30 : #include "dom/repeatlist.h"
31 : #include "dom/score.h"
32 : #include "dom/sig.h"
33 : #include "dom/tempotimeline.h"
34 :
35 : #include "log.h"
36 :
37 : using namespace mu;
38 : using namespace muse;
39 :
40 : namespace mu::engraving {
41 : //---------------------------------------------------------
42 : // calculate
43 : // MIDI files cannot contain pauses so insert extra ticks and tempo changes instead.
44 : // The PauseMap and tempo events are fully unwound to account for pauses on repeats.
45 : //---------------------------------------------------------
46 :
47 13 : void PauseMap::calculate(const Score* s)
48 : {
49 13 : IF_ASSERT_FAILED(s) {
50 0 : LOGE() << "failed to calculate pause map";
51 : }
52 :
53 13 : insert(std::pair<const int, int>(0, 0)); // can't start with a pause
54 :
55 13 : const TimeSigMap* sigmap = s->sigmap();
56 13 : const RepeatList& repeatList = s->repeatList();
57 :
58 35 : for (const TempoTimePoint& point : s->tempoTimeline().points()) {
59 22 : const int utick = point.utick;
60 :
61 22 : if (point.pause <= 0.0) {
62 : // We have a regular tempo change.
63 21 : m_tempoEvents[tickWithPauses(utick)] = point.bps;
64 21 : continue;
65 : }
66 :
67 : // We have a pause event.
68 1 : const int tick = repeatList.utick2tick(utick);
69 1 : Fraction timeSig(sigmap->timesig(tick).timesig());
70 1 : double quarterNotesPerMeasure = (4.0 * timeSig.numerator()) / timeSig.denominator();
71 1 : int ticksPerMeasure = quarterNotesPerMeasure * Constants::DIVISION; // store a full measure of ticks to keep barlines in same places
72 1 : m_tempoEvents[tickWithPauses(utick)] = quarterNotesPerMeasure / point.pause; // new tempo for pause
73 1 : insert(std::pair<const int, int>(utick, ticksPerMeasure + offsetAtUTick(utick))); // store running total of extra ticks
74 1 : m_tempoEvents[tickWithPauses(utick)] = point.bps; // restore previous tempo
75 : }
76 13 : }
77 :
78 : //---------------------------------------------------------
79 : // offsetAtUTick
80 : // In total, how many extra ticks have been inserted prior to this utick.
81 : //---------------------------------------------------------
82 :
83 567 : int PauseMap::offsetAtUTick(int utick) const
84 : {
85 : // make sure calculate was called
86 567 : IF_ASSERT_FAILED(!empty()) {
87 0 : LOGE() << "accessing empty container";
88 : }
89 :
90 567 : auto i = upper_bound(utick);
91 567 : if (i != begin()) {
92 567 : --i;
93 : }
94 1134 : return i->second;
95 : }
96 : }
|