LCOV - code coverage report
Current view: top level - src/engraving/automation/internal - scoreautomationcontroller.h Coverage Total Hit
Test: filtered_coverage.info Lines: 100.0 % 3 3
Test Date: 2026-11-05 04:07:02

            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              : }
        

Generated by: LCOV version 2.0-1