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) 2025 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 : #pragma once
23 :
24 : #include <map>
25 : #include <optional>
26 : #include <set>
27 : #include <variant>
28 : #include <vector>
29 :
30 : #include "engraving/automation/automationdata.h"
31 : #include "engraving/automation/automationtypes.h"
32 : #include "engraving/dom/tempotimeline.h"
33 : #include "engraving/types/types.h"
34 :
35 : namespace mu::engraving {
36 : class Score;
37 : class Fraction;
38 : class EngravingItem;
39 : class Measure;
40 : class Segment;
41 : class Dynamic;
42 : class Fermata;
43 : class Hairpin;
44 : class TempoText;
45 : class GradualTempoChange;
46 : class Volta;
47 : class MeasureRepeat;
48 : class RepeatList;
49 : class RepeatSegment;
50 : struct RepeatSegmentInfo;
51 : struct ScoreChanges;
52 :
53 : class ScoreAutomationController
54 : {
55 : public:
56 : void init(Score* score);
57 : void ensureInitialized(Score* score);
58 :
59 : void insertTime(const Fraction& tick, const Fraction& len, const std::vector<RepeatSegmentInfo>& oldSegments);
60 : void update(const ScoreChanges& changes);
61 :
62 : void editPoints(const AutomationCurveKey& key, AutomationPointEdits& edits);
63 :
64 553 : AutomationDataConstPtr automationData() const { return m_automationData; }
65 1010 : void setAutomationData(AutomationDataPtr data) { m_automationData = std::move(data); }
66 :
67 : const TempoTimeline& tempoTimeline(bool expandRepeats = true) const;
68 : void setTempoMultiplier(const BeatsPerSecond& bps);
69 :
70 : void setTempoTimelineOverride(std::optional<TempoTimeline> timeline);
71 :
72 : private:
73 : struct UpdateRequest {
74 : int tickFrom = 0;
75 : staff_idx_t staffIdxFrom = muse::nidx;
76 : staff_idx_t staffIdxTo = muse::nidx;
77 : bool includeTempo = false;
78 : bool includeDynamics = false;
79 : };
80 :
81 : struct StaffRange {
82 : StaffRange(const Score* score, staff_idx_t staffIdxFrom, staff_idx_t staffIdxTo);
83 :
84 : staff_idx_t from = 0;
85 : staff_idx_t to = 0;
86 : bool isFull = true;
87 : std::set<muse::ID> staffIds; // only populated when !isFull
88 :
89 : bool contains(staff_idx_t staffIdx) const;
90 : bool contains(const muse::ID& staffId) const;
91 : };
92 :
93 : struct MirrorRange {
94 : int from = 0;
95 : int toExclusive = 0;
96 : int tickOffset = 0;
97 : };
98 :
99 : struct AnacrusisMeasureInfo {
100 : const Measure* measure = nullptr;
101 : int tickOffset = 0;
102 : std::optional<utick_t> nextMeasureUTick; // next measure in the same repeat pass, if any
103 : };
104 :
105 : using DynamicPriorities = std::map<AutomationCurveKey, std::map<utick_t, int> >;
106 : using MeasureRepeats = std::vector<std::pair<const MeasureRepeat*, int> >;
107 :
108 : struct UpdateContext {
109 : UpdateRequest request;
110 : AutomationCurveMap curves;
111 : utick_t clearFromUTick = 0;
112 : DynamicPriorities dynamicPriorities;
113 : MeasureRepeats measureRepeats;
114 : std::optional<BeatsPerSecond> tempoPrimo;
115 : PausesMap pauses;
116 : PausesMap noRepeatPauses; // repeat-agnostic twin of pauses
117 : std::vector<AnacrusisMeasureInfo> anacrusisMeasures;
118 : AutomationCurve* tempoCurve = nullptr;
119 : AutomationCurve noRepeatTempoCurve; // repeat-agnostic Tempo curve
120 : std::vector<std::pair<utick_t, int> > pendingTempoResets;
121 : BeatsPerSecond tempoMultiplier = 1.0;
122 : };
123 :
124 : struct DynamicInfo {
125 : struct Ordinary {
126 : real_t value = 0;
127 : };
128 : struct SingleNote {
129 : real_t value = 0;
130 : std::optional<utick_t> nextTick; // tick of the next segment, if any (recovery point)
131 : };
132 : struct Compound {
133 : real_t startValue = 0;
134 : real_t endValue = 0;
135 : utick_t endPointTick = 0; // tick + velocityChangeLength (arrival point)
136 : };
137 :
138 : utick_t tick = 0;
139 : EID eid = EID::invalid();
140 : int priority = 0;
141 : std::variant<Ordinary, SingleNote, Compound> kind = Ordinary {};
142 : };
143 :
144 : struct HairpinInfo {
145 : utick_t from = 0;
146 : utick_t to = 0;
147 : EID eid = EID::invalid();
148 : int priority = 0;
149 : bool isCrescendo = false;
150 : std::optional<real_t> nominalValueFrom;
151 : std::optional<real_t> nominalValueTo;
152 : };
153 :
154 : void update(const UpdateRequest& request, const AutomationCurveMap& curves);
155 : void fullRebuild(AutomationCurveMap& curves, bool includeTempo = true, bool includeDynamics = true);
156 :
157 : static void copyCurvesForRebuild(const AutomationCurveMap& curves, const StaffRange& range, utick_t clearFromUTick, bool includeTempo,
158 : bool includeDynamics, AutomationCurveMap& destCurves);
159 :
160 : static void addSegmentPoints(const Segment* segment, int tickOffset, const StaffRange& range, UpdateContext& ctx);
161 : static void addDynamicPoints(const Dynamic* dynamic, int tickOffset, const StaffRange& range, UpdateContext& ctx);
162 : static void addDynamicPoints(const DynamicInfo& info, const AutomationCurveKey& key, UpdateContext& ctx);
163 :
164 : static void addSpannerPoints(const Score* score, int repeatStartTick, int repeatEndTick, int tickOffset, const StaffRange& range,
165 : UpdateContext& ctx);
166 : static void addHairpinPoints(const Hairpin* hairpin, int tickOffset, const std::vector<AutomationCurveKey>& keys, UpdateContext& ctx);
167 : static void addHairpinPoints(const HairpinInfo& info, const AutomationCurveKey& key, UpdateContext& ctx);
168 :
169 : static void fillVoiceCurvesFromBase(UpdateContext& ctx);
170 :
171 : static void collectMeasureRepeats(const Segment* segment, int tickOffset, const StaffRange& range, MeasureRepeats& result);
172 : static void addMeasureRepeatPoints(UpdateContext& ctx);
173 :
174 : void mirrorAuthoredPointsToRepeats(UpdateContext& ctx);
175 : void fillNoRepeatTempoCurve(const AutomationCurve& tempoCurve, AutomationCurve& noRepeatTempoCurve);
176 :
177 : static void collectPauses(const Measure* measure, int tickOffset, PausesMap& pauses, PausesMap& noRepeatPauses);
178 : static void addTempoTextPoint(const TempoText* tt, int tickOffset, UpdateContext& ctx);
179 : static void addFermataStretchPoints(const Fermata* fermata, int tickOffset, double stretch, UpdateContext& ctx);
180 : static void addGradualTempoChangePoints(const GradualTempoChange* tempoChange, int tickOffset, UpdateContext& ctx);
181 : static void addVoltaTempoResetPoint(const Volta* volta, UpdateContext& ctx);
182 : static void resolvePendingTempoResets(UpdateContext& ctx);
183 : static void fixAnacrusisTempo(UpdateContext& ctx);
184 :
185 : static bool tryAddDynamicPoint(AutomationCurve& curve, std::map<utick_t, int>& tickPrioMap, utick_t tick, const AutomationPoint& point,
186 : int priority);
187 : static void addDynamicPoint(AutomationCurve& curve, std::map<utick_t, int>& tickPrioMap, utick_t tick, const AutomationPoint& point,
188 : int priority);
189 : static void setTempoPoint(utick_t tick, int tickOffset, real_t normalizedBps, UpdateContext& ctx,
190 : std::optional<EID> itemId = std::nullopt);
191 : //! NOTE: for callers that already know no point exists at tick (e.g. via lower_bound) - skips the redundant lookup
192 : static void setTempoPoint(AutomationCurve::iterator hint, utick_t tick, int tickOffset, real_t normalizedBps, UpdateContext& ctx,
193 2 : std::optional<EID> itemId = std::nullopt);
194 : static void setNoRepeatTempoPoint(utick_t rawTick, const AutomationPoint& point, UpdateContext& ctx);
195 :
196 : static std::vector<AutomationCurveKey> resolveKeys(const EngravingItem* item, AutomationType type, const StaffRange& range);
197 :
198 : void mirrorEditsToRepeats(const AutomationCurveKey& key, AutomationPointEdits& edits);
199 :
200 : static void mirrorPointIfInRange(const AutomationPointEdit& localEdit, const MirrorRange& range, AutomationPointEdits& allEdits);
201 :
202 : static void mirrorToMeasureRepeats(const RepeatSegment* targetSeg, const StaffRange& range, const AutomationPointEdit& localEdit,
203 : AutomationPointEdits& allEdits);
204 :
205 : Score* m_score = nullptr;
206 : AutomationDataPtr m_automationData;
207 : TempoTimeline m_tempoTimeline;
208 : TempoTimeline m_flattenedTempoTimeline;
209 : std::optional<TempoTimeline> m_tempoTimelineOverride;
210 : };
211 : }
|