LCOV - code coverage report
Current view: top level - src/engraving/dom - masterscore.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 67.7 % 430 291
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) 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              : #include "masterscore.h"
      23              : 
      24              : #include "io/buffer.h"
      25              : 
      26              : #include "compat/writescorehook.h"
      27              : #include "editing/editautomationpoints.h"
      28              : #include "editing/editkeysig.h"
      29              : #include "editing/editmeasures.h"
      30              : #include "editing/transaction/transaction.h"
      31              : #include "editing/transaction/undostack.h"
      32              : #include "rw/mscloader.h"
      33              : #include "rw/xmlreader.h"
      34              : #include "rw/rwregister.h"
      35              : 
      36              : #include "style/defaultstyle.h"
      37              : 
      38              : #include "engravingproject.h"
      39              : 
      40              : #include "automation/internal/scoreautomationcontroller.h"
      41              : 
      42              : #include "barline.h"
      43              : #include "excerpt.h"
      44              : #include "factory.h"
      45              : #include "clef.h"
      46              : #include "key.h"
      47              : #include "keysig.h"
      48              : #include "part.h"
      49              : #include "repeatlist.h"
      50              : #include "rest.h"
      51              : #include "sig.h"
      52              : #include "staff.h"
      53              : #include "timesig.h"
      54              : #include "linkedobjects.h"
      55              : 
      56              : #include "log.h"
      57              : 
      58              : using namespace mu;
      59              : using namespace muse::io;
      60              : using namespace mu::engraving;
      61              : 
      62              : //---------------------------------------------------------
      63              : //   MasterScore
      64              : //---------------------------------------------------------
      65              : 
      66         2169 : MasterScore::MasterScore(const muse::modularity::ContextPtr& iocCtx, std::weak_ptr<engraving::EngravingProject> project)
      67         4338 :     : Score(iocCtx)
      68              : {
      69         2169 :     m_project = project;
      70         2169 :     m_transactionManager = std::make_unique<TransactionManager>(this);
      71         2169 :     m_undoStack   = new UndoStack();
      72         2169 :     m_sigmap      = new TimeSigMap();
      73         2169 :     m_automationController = new ScoreAutomationController();
      74         2169 :     m_expandedRepeatList  = new RepeatList(this);
      75         2169 :     m_nonExpandedRepeatList = new RepeatList(this);
      76         2169 :     setMasterScore(this);
      77              : 
      78              : #if defined(Q_OS_WIN)
      79              :     metaTags().insert({ u"platform", u"Microsoft Windows" });
      80              : #elif defined(Q_OS_MAC)
      81              :     metaTags().insert({ u"platform", u"Apple Macintosh" });
      82              : #elif defined(Q_OS_LINUX)
      83         2169 :     metaTags().insert({ u"platform", u"Linux" });
      84              : #else
      85              :     metaTags().insert({ u"platform", u"Unknown" });
      86              : #endif
      87         2169 :     metaTags().insert({ u"movementNumber", u"" });
      88         2169 :     metaTags().insert({ u"movementTitle", u"" });
      89         2169 :     metaTags().insert({ u"workNumber", u"" });
      90         2169 :     metaTags().insert({ u"workTitle", u"" });
      91         2169 :     metaTags().insert({ u"arranger", u"" });
      92         2169 :     metaTags().insert({ u"composer", u"" });
      93         2169 :     metaTags().insert({ u"lyricist", u"" });
      94         2169 :     metaTags().insert({ u"translator", u"" });
      95         2169 :     metaTags().insert({ u"source", u"" });
      96         2169 :     metaTags().insert({ u"copyright", u"" });
      97         2169 :     metaTags().insert({ u"creationDate", muse::Date::currentDate().toString(muse::DateFormat::ISODate) });
      98         4338 : }
      99              : 
     100         2061 : MasterScore::MasterScore(const muse::modularity::ContextPtr& iocCtx, const MStyle& s, std::weak_ptr<engraving::EngravingProject> project)
     101         2061 :     : MasterScore{iocCtx, project}
     102              : {
     103         2061 :     setStyle(s);
     104         2061 : }
     105              : 
     106         3888 : MasterScore::~MasterScore()
     107              : {
     108         1944 :     if (m_project.lock()) {
     109            0 :         m_project.lock()->m_masterScore = nullptr;
     110              :     }
     111              : 
     112         1944 :     delete m_expandedRepeatList;
     113         1944 :     delete m_nonExpandedRepeatList;
     114         1944 :     delete m_sigmap;
     115         1944 :     delete m_undoStack;
     116         1944 :     delete m_automationController;
     117         1944 :     muse::DeleteAll(m_excerpts);
     118         3888 : }
     119              : 
     120              : //---------------------------------------------------------
     121              : //   fileInfo
     122              : //---------------------------------------------------------
     123              : 
     124         1095 : IFileInfoProviderPtr MasterScore::fileInfo() const
     125              : {
     126         1095 :     return m_fileInfoProvider;
     127              : }
     128              : 
     129         3039 : void MasterScore::setFileInfoProvider(IFileInfoProviderPtr fileInfoProvider)
     130              : {
     131         3039 :     m_fileInfoProvider = fileInfoProvider;
     132         3039 : }
     133              : 
     134            1 : String MasterScore::name() const
     135              : {
     136            1 :     return fileInfo()->displayName();
     137              : }
     138              : 
     139          505 : AutomationDataConstPtr MasterScore::automationData() const
     140              : {
     141          505 :     return m_automationController->automationData();
     142              : }
     143              : 
     144         1008 : void MasterScore::setAutomationData(AutomationDataPtr data)
     145              : {
     146         1008 :     m_automationController->setAutomationData(std::move(data));
     147         1008 : }
     148              : 
     149            1 : void MasterScore::editAutomationPoints(const AutomationCurveKey& key, AutomationPointEdits& edits, bool undoable)
     150              : {
     151            1 :     IF_ASSERT_FAILED(key.isValid() && !edits.empty()) {
     152            0 :         return;
     153              :     }
     154              : 
     155            1 :     if (undoable) {
     156            1 :         undo(new EditAutomationPoints(this, m_automationController, key, edits));
     157              :     } else {
     158            0 :         m_automationController->editPoints(key, edits);
     159              :     }
     160              : }
     161              : 
     162          451 : void MasterScore::onTimeInserted(const Fraction& tick, const Fraction& len, const std::vector<RepeatSegmentInfo>& oldSegments)
     163              : {
     164          451 :     m_automationController->insertTime(tick, len, oldSegments);
     165          451 : }
     166              : 
     167              : //---------------------------------------------------------
     168              : //   invalidateRepeatLists
     169              : //---------------------------------------------------------
     170              : 
     171         8592 : void MasterScore::invalidateRepeatList()
     172              : {
     173         8592 :     m_expandedRepeatList->setScoreChanged();
     174         8592 :     m_nonExpandedRepeatList->setScoreChanged();
     175         8592 : }
     176              : 
     177              : //---------------------------------------------------------
     178              : //   setExpandRepeats
     179              : //---------------------------------------------------------
     180              : 
     181          216 : void MasterScore::setExpandRepeats(bool expand)
     182              : {
     183          216 :     if (m_expandRepeats == expand) {
     184          216 :         return;
     185              :     }
     186            0 :     m_expandRepeats = expand;
     187            0 :     invalidateRepeatList();
     188              : }
     189              : 
     190              : //---------------------------------------------------------
     191              : //   updateRepeatListTempo
     192              : ///   needed for usage in Seq::processMessages
     193              : //---------------------------------------------------------
     194              : 
     195            0 : void MasterScore::updateRepeatListTempo()
     196              : {
     197            0 :     m_expandedRepeatList->updateUticks();
     198            0 :     m_nonExpandedRepeatList->updateUticks();
     199            0 : }
     200              : 
     201            0 : void MasterScore::updateRepeatList()
     202              : {
     203            0 :     m_expandedRepeatList->update(true);
     204            0 :     m_nonExpandedRepeatList->update(false);
     205            0 : }
     206              : 
     207              : //---------------------------------------------------------
     208              : //   repeatList
     209              : //---------------------------------------------------------
     210              : 
     211         1316 : const RepeatList& MasterScore::repeatList() const
     212              : {
     213         1316 :     if (m_expandRepeats) {
     214         1316 :         m_expandedRepeatList->update(true);
     215         1316 :         return *m_expandedRepeatList;
     216              :     }
     217              : 
     218            0 :     m_nonExpandedRepeatList->update(false);
     219            0 :     return *m_nonExpandedRepeatList;
     220              : }
     221              : 
     222        36570 : const RepeatList& MasterScore::repeatList(bool expandRepeats, bool updateTies) const
     223              : {
     224        36570 :     if (expandRepeats) {
     225        36570 :         m_expandedRepeatList->update(true, updateTies);
     226        36570 :         return *m_expandedRepeatList;
     227              :     }
     228              : 
     229            0 :     m_nonExpandedRepeatList->update(false, updateTies);
     230            0 :     return *m_nonExpandedRepeatList;
     231              : }
     232              : 
     233         8644 : const TempoTimeline& MasterScore::tempoTimeline() const
     234              : {
     235         8644 :     return tempoTimeline(masterScore()->expandRepeats());
     236              : }
     237              : 
     238         9531 : const TempoTimeline& MasterScore::tempoTimeline(bool expandRepeats) const
     239              : {
     240         9531 :     m_automationController->ensureInitialized(const_cast<MasterScore*>(this));
     241         9531 :     return m_automationController->tempoTimeline(expandRepeats);
     242              : }
     243              : 
     244           26 : bool MasterScore::setTempoMultiplier(BeatsPerSecond val)
     245              : {
     246           26 :     IF_ASSERT_FAILED(val > BeatsPerSecond(0.0)) {
     247            0 :         return false;
     248              :     }
     249              : 
     250           26 :     if (m_automationController->tempoTimeline().tempoMultiplier() == val) {
     251            0 :         return false;
     252              :     }
     253              : 
     254           26 :     m_automationController->setTempoMultiplier(val);
     255           26 :     return true;
     256              : }
     257              : 
     258            0 : void MasterScore::setTempoTimelineOverride(std::optional<TempoTimeline> timeline)
     259              : {
     260            0 :     m_automationController->setTempoTimelineOverride(std::move(timeline));
     261            0 : }
     262              : 
     263              : //---------------------------------------------------------
     264              : //   addExcerpt
     265              : //---------------------------------------------------------
     266              : 
     267          110 : void MasterScore::addExcerpt(Excerpt* ex, size_t index)
     268              : {
     269          110 :     if (!ex->inited()) {
     270          110 :         initParts(ex);
     271              :     }
     272              : 
     273          110 :     excerpts().insert(excerpts().begin() + (index == muse::nidx ? excerpts().size() : index), ex);
     274          110 :     setExcerptsChanged(true);
     275          110 : }
     276              : 
     277              : //---------------------------------------------------------
     278              : //   removeExcerpt
     279              : //---------------------------------------------------------
     280              : 
     281            2 : void MasterScore::removeExcerpt(Excerpt* ex)
     282              : {
     283            2 :     if (muse::remove(excerpts(), ex)) {
     284            1 :         setExcerptsChanged(true);
     285              :         // delete ex;
     286              :     } else {
     287            1 :         LOGD("removeExcerpt:: ex not found");
     288              :     }
     289            2 : }
     290              : 
     291              : //---------------------------------------------------------
     292              : //   clone
     293              : //---------------------------------------------------------
     294              : 
     295            0 : MasterScore* MasterScore::clone()
     296              : {
     297            0 :     auto buffer = Buffer::opened(IODevice::WriteOnly);
     298              : 
     299            0 :     rw::RWRegister::writer()->writeScore(this, &buffer);
     300              : 
     301            0 :     buffer.close();
     302              : 
     303            0 :     muse::ByteArray scoreData = buffer.data();
     304            0 :     MasterScore* score = new MasterScore(iocContext(), style(), m_project);
     305              : 
     306            0 :     XmlReader r(scoreData);
     307            0 :     MscLoader().readMasterScore(score, r, true);
     308              : 
     309            0 :     score->doLayout();
     310            0 :     return score;
     311            0 : }
     312              : 
     313          165 : Score* MasterScore::createScore()
     314              : {
     315          165 :     return new Score(this, DefaultStyle::baseStyle());
     316              : }
     317              : 
     318            0 : Score* MasterScore::createScore(const MStyle& s)
     319              : {
     320            0 :     return new Score(this, s);
     321              : }
     322              : 
     323              : //---------------------------------------------------------
     324              : //   setPos
     325              : //---------------------------------------------------------
     326              : 
     327            0 : Fraction MasterScore::loopBoundaryTick(LoopBoundaryType type) const
     328              : {
     329            0 :     IF_ASSERT_FAILED(type != LoopBoundaryType::Unknown) {
     330            0 :         return Fraction();
     331              :     }
     332            0 :     return m_loopBoundaries[size_t(type)];
     333              : }
     334              : 
     335            0 : void MasterScore::setLoopBoundaryTick(LoopBoundaryType type, Fraction tick)
     336              : {
     337            0 :     IF_ASSERT_FAILED(type != LoopBoundaryType::Unknown) {
     338            0 :         return;
     339              :     }
     340            0 :     if (tick < Fraction(0, 1)) {
     341            0 :         tick = Fraction(0, 1);
     342              :     }
     343            0 :     if (tick > lastMeasure()->endTick()) {
     344              :         // End Reverb may last longer than written notation, but cursor position should not
     345            0 :         tick = lastMeasure()->endTick();
     346              :     }
     347              : 
     348            0 :     m_loopBoundaries[size_t(type)] = tick;
     349              :     // even though tick position might not have changed, layout might have
     350              :     // so we should update cursor here
     351              :     // however, we must be careful not to call setLoopBoundaryTick() again while handling posChanged, or recursion results
     352            0 :     for (Score* s : scoreList()) {
     353            0 :         s->notifyLoopBoundaryTickChanged(type, unsigned(tick.ticks()));
     354            0 :     }
     355              : }
     356              : 
     357              : //---------------------------------------------------------
     358              : //   setUpdateAll
     359              : //---------------------------------------------------------
     360              : 
     361          404 : void MasterScore::setUpdateAll()
     362              : {
     363          404 :     m_cmdState.setUpdateMode(UpdateMode::UpdateAll);
     364          404 : }
     365              : 
     366              : //---------------------------------------------------------
     367              : //   setLayoutAll
     368              : //---------------------------------------------------------
     369              : 
     370         9097 : void MasterScore::setLayoutAll(staff_idx_t staff, const EngravingItem* e)
     371              : {
     372         9097 :     m_cmdState.setTick(Fraction(0, 1));
     373         9097 :     m_cmdState.setTick(Fraction::max());
     374              : 
     375         9097 :     if (e && e->score() == this) {
     376              :         // TODO: map staff number properly
     377         2352 :         const staff_idx_t startStaff = staff == muse::nidx ? 0 : staff;
     378         2352 :         const staff_idx_t endStaff = staff == muse::nidx ? (nstaves() - 1) : staff;
     379         2352 :         m_cmdState.setStaff(startStaff);
     380         2352 :         m_cmdState.setStaff(endStaff);
     381              : 
     382         2352 :         m_cmdState.setElement(e);
     383              :     }
     384         9097 : }
     385              : 
     386              : //---------------------------------------------------------
     387              : //   setLayout
     388              : //---------------------------------------------------------
     389              : 
     390       919228 : void MasterScore::setLayout(const Fraction& t, staff_idx_t staff, const EngravingItem* e)
     391              : {
     392       919228 :     if (t >= Fraction(0, 1)) {
     393       919228 :         m_cmdState.setTick(t);
     394              :     }
     395              : 
     396       919228 :     if (e && e->score() == this) {
     397              :         // TODO: map staff number properly
     398       868675 :         m_cmdState.setStaff(staff);
     399       868675 :         m_cmdState.setElement(e);
     400              :     }
     401       919228 : }
     402              : 
     403        15454 : void MasterScore::setLayout(const Fraction& tick1, const Fraction& tick2, staff_idx_t staff1, staff_idx_t staff2, const EngravingItem* e)
     404              : {
     405        15454 :     if (tick1 >= Fraction(0, 1)) {
     406        15454 :         m_cmdState.setTick(tick1);
     407              :     }
     408        15454 :     if (tick2 >= Fraction(0, 1)) {
     409        15454 :         m_cmdState.setTick(tick2);
     410              :     }
     411              : 
     412        15454 :     if (e && e->score() == this) {
     413              :         // TODO: map staff number properly
     414        14082 :         m_cmdState.setStaff(staff1);
     415        14082 :         m_cmdState.setStaff(staff2);
     416              : 
     417        14082 :         m_cmdState.setElement(e);
     418              :     }
     419        15454 : }
     420              : 
     421            9 : void MasterScore::initAutomation()
     422              : {
     423            9 :     IF_ASSERT_FAILED(m_automationController) {
     424            0 :         return;
     425              :     }
     426            9 :     m_automationController->init(this);
     427              : }
     428              : 
     429          967 : void MasterScore::updateAutomation(const ScoreChanges& changes)
     430              : {
     431          967 :     m_automationController->update(changes);
     432          967 : }
     433              : 
     434              : //---------------------------------------------------------
     435              : //   setPlaybackScore
     436              : //---------------------------------------------------------
     437              : 
     438         6044 : void MasterScore::setPlaybackScore(Score* score)
     439              : {
     440         6044 :     if (m_playbackScore == score) {
     441         2035 :         return;
     442              :     }
     443              : 
     444         4009 :     m_playbackScore = score;
     445         4009 :     m_playbackSettingsLinks.clear();
     446              : 
     447         4009 :     if (!m_playbackScore) {
     448          987 :         return;
     449              :     }
     450              : 
     451         7432 :     for (Part* part : score->parts()) {
     452         8911 :         for (const auto& pair : part->instruments()) {
     453         4501 :             Instrument* instr = pair.second;
     454         9843 :             for (InstrChannel* ch : instr->channel()) {
     455         5342 :                 InstrChannel* pChannel = playbackChannel(ch);
     456         5342 :                 IF_ASSERT_FAILED(pChannel) {
     457            0 :                     continue;
     458              :                 }
     459         5342 :                 m_playbackSettingsLinks.emplace_back(pChannel, ch, /* excerpt */ true);
     460              :             }
     461              :         }
     462              :     }
     463              : }
     464              : 
     465              : //---------------------------------------------------------
     466              : //   updateExpressive
     467              : //    change patches to their expressive equivalent or vica versa, if possible
     468              : //    This works only with MuseScore general soundfont
     469              : //
     470              : //    The first version of the function decides whether to make patches expressive
     471              : //    or not, based on the synth settings. The second will switch patches based on
     472              : //    the value of the expressive parameter.
     473              : //---------------------------------------------------------
     474              : 
     475            0 : void MasterScore::updateExpressive(Synthesizer* synth)
     476              : {
     477            0 :     SynthesizerState s = synthesizerState();
     478            0 :     SynthesizerGroup g = s.group(u"master");
     479              : 
     480            0 :     int method = 1;
     481            0 :     for (const IdValue& idVal : g) {
     482            0 :         if (idVal.id == 4) {
     483            0 :             method = idVal.data.toInt();
     484            0 :             break;
     485              :         }
     486              :     }
     487              : 
     488            0 :     updateExpressive(synth, (method != 0));
     489            0 : }
     490              : 
     491            0 : void MasterScore::updateExpressive(Synthesizer* synth, bool expressive, bool force /* = false */)
     492              : {
     493            0 :     if (!synth) {
     494            0 :         return;
     495              :     }
     496              : 
     497            0 :     if (!force) {
     498            0 :         SynthesizerState s = synthesizerState();
     499            0 :         SynthesizerGroup g = s.group(u"master");
     500              : 
     501            0 :         for (const IdValue& idVal : g) {
     502            0 :             if (idVal.id == 4) {
     503            0 :                 int method = idVal.data.toInt();
     504            0 :                 if (expressive == (method == 0)) {
     505            0 :                     return; // method and expression change don't match, so don't switch
     506              :                 }
     507              :             }
     508              :         }
     509            0 :     }
     510              : 
     511            0 :     for (Part* p : parts()) {
     512            0 :         for (const auto& pair : p->instruments()) {
     513            0 :             pair.second->switchExpressive(this, synth, expressive, force);
     514              :         }
     515              :     }
     516              : }
     517              : 
     518              : //---------------------------------------------------------
     519              : //   rebuildAndUpdateExpressive
     520              : //    implicitly rebuild midi mappings as well. Should be preferred over
     521              : //    just updateExpressive, in most cases.
     522              : //---------------------------------------------------------
     523              : 
     524            0 : void MasterScore::rebuildAndUpdateExpressive(Synthesizer* synth)
     525              : {
     526              :     // Rebuild midi mappings to make sure we have playback channels
     527            0 :     rebuildMidiMapping();
     528              : 
     529            0 :     updateExpressive(synth);
     530              : 
     531              :     // Rebuild midi mappings again to be safe
     532            0 :     rebuildMidiMapping();
     533            0 : }
     534              : 
     535              : //---------------------------------------------------------
     536              : //   insertMeasure
     537              : //    Create a new MeasureBase of Measure type and insert
     538              : //    before measure.
     539              : //    If measure is zero, append new MeasureBase.
     540              : //---------------------------------------------------------
     541              : 
     542          274 : MeasureBase* MasterScore::insertMeasure(MeasureBase* beforeMeasure, const InsertMeasureOptions& options)
     543              : {
     544          274 :     Fraction tick;
     545          274 :     if (beforeMeasure) {
     546           51 :         if (beforeMeasure->isMeasure()) {
     547           51 :             if (toMeasure(beforeMeasure)->isMMRest()) {
     548            0 :                 beforeMeasure = toMeasure(beforeMeasure)->prev();
     549            0 :                 beforeMeasure = beforeMeasure ? beforeMeasure->next() : firstMeasure();
     550            0 :                 deselectAll();
     551              :             }
     552          111 :             for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
     553           60 :                 if (toMeasure(beforeMeasure)->isMeasureRepeatGroupWithPrevM(staffIdx)) {
     554            0 :                     MScore::setError(MsError::CANNOT_SPLIT_MEASURE_REPEAT);
     555            0 :                     return nullptr;
     556              :                 }
     557              :             }
     558              :         }
     559           51 :         tick = beforeMeasure->tick();
     560              :     } else {
     561          223 :         tick = last() ? last()->endTick() : Fraction(0, 1);
     562              :     }
     563              : 
     564          274 :     const bool isBeginning = tick.isZero();
     565              : 
     566              :     // Use nominal time signature of current or previous measure, depending on whether
     567              :     // the time sig from `beforeMeasure` will be moved to the newly created measure
     568              :     const Fraction currentTimeSig
     569          603 :         = sigmap()->timesig(!options.moveSignaturesClef && !isBeginning && beforeMeasure && beforeMeasure->prevMeasure()
     570          329 :                             ? beforeMeasure->prevMeasure()->tick()
     571              :                             : tick)
     572          274 :           .nominal();
     573              : 
     574          274 :     Measure* masterMeasure = nullptr;
     575          274 :     Fraction ticks = { 0, 1 };
     576              : 
     577          562 :     for (Score* score : scoreList()) {
     578          288 :         MeasureBase* actualBeforeMeasure = nullptr;
     579              : 
     580          288 :         if (beforeMeasure) {
     581           61 :             if (beforeMeasure->score() == score) {
     582           51 :                 actualBeforeMeasure = beforeMeasure;
     583           10 :             } else if (!beforeMeasure->isMeasure() && beforeMeasure->links()) {
     584            0 :                 for (EngravingObject* m : *beforeMeasure->links()) {
     585            0 :                     if (m && m->isMeasureBase() && m->score() == score) {
     586            0 :                         actualBeforeMeasure = toMeasureBase(m);
     587            0 :                         break;
     588              :                     }
     589              :                 }
     590              :             }
     591              :             // if beforeMeasure is measure; or if din't find linked frame, use measure
     592           61 :             if (!actualBeforeMeasure) {
     593           10 :                 actualBeforeMeasure = score->tick2measure(tick);
     594              :             }
     595              : 
     596           61 :             if (!actualBeforeMeasure) {
     597            0 :                 LOGD("measure not found");
     598              :             }
     599              :         }
     600              : 
     601          288 :         Measure* newMeasure = Factory::createMeasure(score);
     602          288 :         newMeasure->setTick(tick);
     603              : 
     604          288 :         if (actualBeforeMeasure) {
     605           61 :             actualBeforeMeasure = actualBeforeMeasure->top(); // don't try to insert in front of nested frame
     606              :         }
     607          288 :         newMeasure->setNext(actualBeforeMeasure);
     608          288 :         newMeasure->setPrev(actualBeforeMeasure ? actualBeforeMeasure->prev() : score->last());
     609              : 
     610          288 :         newMeasure->setTimesig(currentTimeSig);
     611          288 :         newMeasure->setTicks(currentTimeSig);
     612              : 
     613          288 :         undo(new InsertMeasures(newMeasure, newMeasure, options.moveStaffTypeChanges));
     614              : 
     615          288 :         ticks = newMeasure->ticks();
     616          288 :         Measure* measureInsert = nullptr; // insert before
     617          288 :         if (actualBeforeMeasure) {
     618           61 :             if (actualBeforeMeasure->isMeasure()) {
     619           61 :                 measureInsert = toMeasure(actualBeforeMeasure);
     620              :             } else {
     621            0 :                 measureInsert = score->tick2measure(actualBeforeMeasure->tick());
     622              :             }
     623              :         }
     624              : 
     625          288 :         if (score->isMaster()) {
     626          274 :             masterMeasure = newMeasure;
     627              :         }
     628              : 
     629          288 :         std::vector<TimeSig*> timeSigList;
     630          288 :         std::vector<KeySig*> keySigList;
     631          288 :         std::vector<Clef*> initClefList;
     632          288 :         std::vector<Clef*> previousClefList;
     633          288 :         std::vector<Clef*> specialCaseClefs;
     634          288 :         std::vector<Clef*> afterBarlineClefs;
     635          288 :         std::vector<BarLine*> previousBarLinesList;
     636              : 
     637          288 :         Measure* pm = newMeasure->prevMeasure();
     638              : 
     639              :         //
     640              :         // remove clefs, barlines, time and key signatures
     641              :         //
     642          288 :         bool headerKeySig = false;
     643          288 :         if (measureInsert) {
     644              :             // if inserting before first measure, always preserve clefs and signatures
     645              :             // at the begining of the score (move them back)
     646              : 
     647           61 :             if (measureInsert->hasMMRest() && score->style().value(Sid::createMultiMeasureRests).toBool()) {
     648            1 :                 measureInsert = measureInsert->mmRest();
     649              :             }
     650              : 
     651           61 :             if (pm && !options.moveSignaturesClef && !isBeginning) {
     652           40 :                 Segment* ps = pm->findSegment(SegmentType::Clef, tick);
     653           40 :                 if (ps && ps->enabled()) {
     654            0 :                     for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     655            0 :                         EngravingItem* pc = ps->element(staffIdx * VOICES);
     656            0 :                         if (pc) {
     657            0 :                             previousClefList.push_back(toClef(pc));
     658            0 :                             doUndoRemoveElement(pc);
     659            0 :                             pc->undoUnlink();
     660            0 :                             if (ps->empty()) {
     661            0 :                                 undoRemoveElement(ps);
     662              :                             }
     663              :                         }
     664              :                     }
     665              :                 }
     666              :             }
     667              : 
     668           61 :             if (options.moveSignaturesClef || isBeginning) {
     669           49 :                 for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     670          112 :                     for (Segment* s = measureInsert->first(); s && s->rtick().isZero(); s = s->next()) {
     671           84 :                         if (!s->enabled()) {
     672            0 :                             continue;
     673              :                         }
     674           84 :                         EngravingItem* e = s->element(staffIdx * VOICES);
     675           84 :                         bool specialCase = false;
     676           84 :                         bool initClef = false;
     677           84 :                         bool moveClef = false;
     678           84 :                         bool moveOther = false;
     679           84 :                         if (e && e->isClef()) {
     680           14 :                             if (s->isHeaderClefType()) {
     681              :                                 // if it's a header clef, we only add if it's an init clef
     682              :                                 // (other header clefs are handled by undo(new InsertMeasures())
     683           13 :                                 initClef = isBeginning && !toClef(e)->forInstrumentChange();
     684           13 :                                 moveClef = initClef;
     685              :                             } else {
     686            1 :                                 ClefToBarlinePosition clefPos = toClef(e)->clefToBarlinePosition();
     687            1 :                                 if (isBeginning) {
     688              :                                     // special case:
     689              :                                     // there is a non-header clef at global tick 0, and we are inserting at the beginning of the score.
     690              :                                     // this clef will be moved with the measure it accompanies, but it will be moved before the barline.
     691            1 :                                     specialCase = true;
     692            1 :                                     moveClef = true;
     693            0 :                                 } else if (clefPos == ClefToBarlinePosition::AFTER) {
     694              :                                     // non header clef at the begining of the measure
     695            0 :                                     moveClef = true;
     696              :                                 }
     697              :                             }
     698              :                         } else {
     699              :                             // otherwise, we only add if e is not generated
     700           70 :                             moveOther = e && (!e->generated() || tick.isZero());
     701              :                         }
     702           84 :                         if (!moveClef && !moveOther) {
     703            0 :                             continue; // this item will remain with the old measure
     704              :                         }
     705              :                         // otherwise, this item is moved back to the new measure
     706           84 :                         EngravingItem* ee = 0;
     707           84 :                         if (e->isKeySig()) {
     708           18 :                             KeySig* ks = toKeySig(e);
     709           18 :                             if (ks->forInstrumentChange()) {
     710            0 :                                 continue;
     711              :                             }
     712           18 :                             keySigList.push_back(ks);
     713              :                             // if instrument change on that place, set correct key signature for instrument change
     714           18 :                             const TrackRange trackRange = e->part()->trackRange();
     715           18 :                             bool ic = s->next(SegmentType::ChordRest)->findAnnotation(ElementType::INSTRUMENT_CHANGE,
     716           18 :                                                                                       trackRange.startTrack,
     717           18 :                                                                                       trackRange.endTrack - 1);
     718           18 :                             if (ic) {
     719            0 :                                 KeySigEvent ke = ks->keySigEvent();
     720            0 :                                 ke.setForInstrumentChange(true);
     721            0 :                                 EditKeySig::undoChangeKeySig(transactionManager()->currentOrDummyTransaction(), this, ks->staff(),
     722            0 :                                                              e->tick(), ke);
     723            0 :                             } else {
     724           18 :                                 ee = e;
     725              :                             }
     726           18 :                             if (s->header()) {
     727           13 :                                 headerKeySig = true;
     728              :                             }
     729           66 :                         } else if (e->isTimeSig()) {
     730           17 :                             TimeSig* ts = toTimeSig(e);
     731           17 :                             timeSigList.push_back(ts);
     732           17 :                             ee = e;
     733           49 :                         } else if (e->isClef()) {
     734           14 :                             Clef* clef = toClef(e);
     735           14 :                             if (specialCase) {
     736            1 :                                 specialCaseClefs.push_back(clef);
     737           13 :                             } else if (initClef) {
     738           13 :                                 initClefList.push_back(clef);
     739              :                             } else {
     740            0 :                                 afterBarlineClefs.push_back(toClef(e));
     741              :                             }
     742           14 :                             ee = e;
     743              :                         }
     744           84 :                         if (ee) {
     745           49 :                             doUndoRemoveElement(ee);
     746           49 :                             ee->undoUnlink();
     747           49 :                             if (s->empty() && s->isTimeSigType()) {
     748           13 :                                 undoRemoveElement(s);
     749              :                             }
     750              :                         }
     751              :                     }
     752              :                 }
     753              : 
     754           21 :                 if (masterMeasure && measureInsert->repeatStart()) {
     755            0 :                     masterMeasure->undoChangeProperty(Pid::REPEAT_START, true);
     756            0 :                     measureInsert->undoChangeProperty(Pid::REPEAT_START, false);
     757              :                 }
     758              :             }
     759          227 :         } else if (!measureInsert && tick == Fraction(0, 1)) {
     760              :             // If inserting measure into an empty score, restore default C key signature
     761              :             // and 4/4 time signature
     762           38 :             score->restoreInitialKeySigAndTimeSig();
     763              :         }
     764              : 
     765          288 :         if (pm && !options.moveSignaturesClef && !options.ignoreBarLines) {
     766            0 :             Segment* pbs = pm->findSegment(SegmentType::EndBarLine, tick);
     767            0 :             if (pbs && pbs->enabled()) {
     768            0 :                 for (size_t staffIdx = 0; staffIdx < score->nstaves(); ++staffIdx) {
     769            0 :                     EngravingItem* pb = pbs->element(staffIdx * VOICES);
     770            0 :                     if (pb && !pb->generated()) {
     771            0 :                         previousBarLinesList.push_back(toBarLine(pb));
     772            0 :                         doUndoRemoveElement(pb);
     773            0 :                         if (pbs->empty()) {
     774            0 :                             pbs->setEnabled(false);
     775              :                         }
     776              :                     }
     777              :                 }
     778              :             }
     779            0 :             if (masterMeasure && pm->repeatEnd()) {
     780            0 :                 masterMeasure->undoChangeProperty(Pid::REPEAT_END, true);
     781            0 :                 pm->undoChangeProperty(Pid::REPEAT_END, false);
     782              :             }
     783              :         }
     784              : 
     785              :         //
     786              :         // move clef, barline, time, key signatures
     787              :         //
     788          305 :         for (TimeSig* ts : timeSigList) {
     789           17 :             TimeSig* nts = Factory::copyTimeSig(*ts);
     790           17 :             Segment* s   = newMeasure->undoGetSegmentR(SegmentType::TimeSig, Fraction(0, 1));
     791           17 :             nts->setOwnershipParent(s);
     792           17 :             doUndoAddElement(nts);
     793              :         }
     794          306 :         for (KeySig* ks : keySigList) {
     795           18 :             KeySig* nks = Factory::copyKeySig(*ks);
     796           18 :             Segment* s  = newMeasure->undoGetSegmentR(SegmentType::KeySig, Fraction(0, 1));
     797           18 :             if (headerKeySig || newMeasure->tick().isZero()) {
     798           17 :                 s->setHeader(true);
     799              :             }
     800           18 :             nks->setOwnershipParent(s);
     801           18 :             if (!nks->isAtonal()) {
     802           18 :                 nks->setKey(nks->concertKey());  // to set correct (transposing) key
     803              :             }
     804           18 :             doUndoAddElement(nks);
     805              :         }
     806          301 :         for (Clef* clef : initClefList) {
     807           13 :             Clef* nClef = Factory::copyClef(*clef);
     808           13 :             Segment* s  = newMeasure->undoGetSegmentR(SegmentType::HeaderClef, Fraction(0, 1));
     809           13 :             s->setHeader(true);
     810           13 :             nClef->setOwnershipParent(s);
     811           13 :             doUndoAddElement(nClef);
     812              :         }
     813          288 :         for (Clef* clef : afterBarlineClefs) {
     814            0 :             Clef* nClef = Factory::copyClef(*clef);
     815            0 :             Segment* s  = newMeasure->undoGetSegmentR(SegmentType::Clef, Fraction(0, 1));
     816            0 :             s->setHeader(true);
     817            0 :             nClef->setOwnershipParent(s);
     818            0 :             doUndoAddElement(nClef);
     819              :         }
     820          288 :         for (Clef* clef : previousClefList) {
     821            0 :             Clef* nClef = Factory::copyClef(*clef);
     822            0 :             Segment* s  = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks());
     823            0 :             nClef->setOwnershipParent(s);
     824            0 :             doUndoAddElement(nClef);
     825              :         }
     826          289 :         for (Clef* clef : specialCaseClefs) {
     827            1 :             Clef* nClef = Factory::copyClef(*clef);
     828            1 :             Segment* s  = newMeasure->undoGetSegmentR(SegmentType::Clef, newMeasure->ticks());
     829            1 :             nClef->setOwnershipParent(s);
     830            1 :             doUndoAddElement(nClef);
     831              :         }
     832          288 :         for (BarLine* barLine : previousBarLinesList) {
     833            0 :             BarLine* nBarLine = Factory::copyBarLine(*barLine);
     834            0 :             Segment* s = newMeasure->undoGetSegmentR(SegmentType::EndBarLine, newMeasure->ticks());
     835            0 :             nBarLine->setOwnershipParent(s);
     836            0 :             doUndoAddElement(nBarLine);
     837              :         }
     838          562 :     }
     839              : 
     840          274 :     undoInsertTime(tick, ticks);
     841              : 
     842          274 :     if (masterMeasure && !options.createMeasureRests) {
     843              :         //
     844              :         // fill measure with rest
     845              :         // undoAddCR adds rest to linked staves as well
     846          490 :         for (size_t staffIdx = 0; staffIdx < nstaves(); ++staffIdx) {
     847          271 :             size_t track = staffIdx * VOICES;
     848          271 :             Rest* rest = Factory::createRest(dummy(), TDuration(DurationType::V_MEASURE));
     849          271 :             Fraction timeStretch(staff(staffIdx)->timeStretch(masterMeasure->tick()));
     850          271 :             rest->setTicks(masterMeasure->ticks() * timeStretch);
     851          271 :             rest->setTrack(track);
     852          271 :             undoAddCR(rest, masterMeasure, tick);
     853              :         }
     854              :     }
     855              : 
     856          274 :     if (options.needDeselectAll) {
     857          274 :         deselectAll();
     858              :     }
     859              : 
     860          274 :     return masterMeasure;
     861              : }
        

Generated by: LCOV version 2.0-1