LCOV - code coverage report
Current view: top level - src/engraving/dom - part.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 68.7 % 454 312
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              : 
      23              : #include "part.h"
      24              : 
      25              : #include "containers.h"
      26              : 
      27              : #include "iengravingconfiguration.h"
      28              : 
      29              : #include "style/style.h"
      30              : #include "rw/xmlwriter.h"
      31              : 
      32              : #include "chordrest.h"
      33              : #include "factory.h"
      34              : #include "fret.h"
      35              : #include "harppedaldiagram.h"
      36              : #include "instrtemplate.h"
      37              : #include "instrchange.h"
      38              : #include "linkedobjects.h"
      39              : #include "masterscore.h"
      40              : #include "measure.h"
      41              : #include "score.h"
      42              : #include "sharedpart.h"
      43              : #include "staff.h"
      44              : #include "system.h"
      45              : #include "stringtunings.h"
      46              : 
      47              : #include "log.h"
      48              : 
      49              : using namespace mu;
      50              : using namespace mu::engraving;
      51              : 
      52              : namespace mu::engraving {
      53              : const Fraction Part::MAIN_INSTRUMENT_TICK = Fraction(-1, 1);
      54              : //---------------------------------------------------------
      55              : //   Part
      56              : //---------------------------------------------------------
      57              : 
      58         3054 : Part::Part(Score* s, ElementType type)
      59         3054 :     : EngravingObject(type, s)
      60              : {
      61         3054 :     m_show    = true;
      62         3054 :     m_soloist = false;
      63         3054 :     m_instruments.setInstrument(new Instrument, -1);     // default instrument
      64         3054 :     m_preferSharpFlat = PreferSharpFlat::AUTO;
      65         3054 : }
      66              : 
      67              : //---------------------------------------------------------
      68              : //   initFromInstrTemplate
      69              : //---------------------------------------------------------
      70              : 
      71          326 : void Part::initFromInstrTemplate(const InstrumentTemplate* t)
      72              : {
      73          326 :     setInstrument(Instrument::fromTemplate(t));
      74          326 : }
      75              : 
      76        27766 : const ID& Part::id() const
      77              : {
      78        27766 :     return m_id;
      79              : }
      80              : 
      81         3940 : void Part::setId(const ID& id)
      82              : {
      83         3940 :     m_id = id;
      84         3940 : }
      85              : 
      86            0 : Part* Part::clone() const
      87              : {
      88            0 :     return new Part(*this);
      89              : }
      90              : 
      91              : //---------------------------------------------------------
      92              : //   staff
      93              : //---------------------------------------------------------
      94              : 
      95         4056 : Staff* Part::staff(staff_idx_t idx) const
      96              : {
      97         4056 :     if (idx >= m_staves.size()) {
      98            0 :         return nullptr;
      99              :     }
     100              : 
     101         4056 :     return m_staves[idx];
     102              : }
     103              : 
     104              : //---------------------------------------------------------
     105              : //   family
     106              : //---------------------------------------------------------
     107              : 
     108            0 : String Part::familyId() const
     109              : {
     110            0 :     if (m_instruments.empty()) {
     111            0 :         return String();
     112              :     }
     113              : 
     114            0 :     InstrumentIndex ii = searchTemplateIndexForId(instrumentId());
     115            0 :     return ii.instrTemplate && ii.instrTemplate->family ? ii.instrTemplate->family->id : String();
     116              : }
     117              : 
     118              : //---------------------------------------------------------
     119              : //   Part::masterPart
     120              : //---------------------------------------------------------
     121              : 
     122          335 : const Part* Part::masterPart() const
     123              : {
     124          335 :     if (score()->isMaster()) {
     125           16 :         return this;
     126              :     }
     127          319 :     if (m_staves.empty()) {
     128            0 :         return this;
     129              :     }
     130              : 
     131          319 :     Staff* st = m_staves[0];
     132          319 :     LinkedObjects* links = st->links();
     133          319 :     if (!links) {
     134            0 :         return this;
     135              :     }
     136              : 
     137          319 :     for (EngravingObject* le : *links) {
     138          319 :         if (le->isStaff() && toStaff(le)->score()->isMaster()) {
     139          319 :             if (Part* p = toStaff(le)->part()) {
     140          319 :                 return p;
     141              :             }
     142              :         }
     143              :     }
     144            0 :     return this;
     145              : }
     146              : 
     147              : //---------------------------------------------------------
     148              : //   Part::masterPart
     149              : //---------------------------------------------------------
     150              : 
     151          335 : Part* Part::masterPart()
     152              : {
     153          335 :     return const_cast<Part*>(const_cast<const Part*>(this)->masterPart());
     154              : }
     155              : 
     156       300538 : const Part* Part::originPart(track_idx_t, const Fraction&) const
     157              : {
     158       300538 :     return this;
     159              : }
     160              : 
     161       303133 : Part* Part::originPart(track_idx_t track, const Fraction& tick)
     162              : {
     163       303133 :     return const_cast<Part*>(const_cast<const Part*>(this)->originPart(track, tick));
     164              : }
     165              : 
     166       398138 : size_t Part::nstaves() const
     167              : {
     168       398138 :     return m_staves.size();
     169              : }
     170              : 
     171        59727 : size_t Part::visibleStavesCount() const
     172              : {
     173        59727 :     size_t result = 0;
     174       130473 :     for (const Staff* staff : m_staves) {
     175        70746 :         if (staff->show()) {
     176        70423 :             ++result;
     177              :         }
     178              :     }
     179              : 
     180        59727 :     return result;
     181              : }
     182              : 
     183       117257 : const std::vector<Staff*>& Part::staves() const
     184              : {
     185       117257 :     return m_staves;
     186              : }
     187              : 
     188         7093 : std::set<staff_idx_t> Part::staveIdxList() const
     189              : {
     190         7093 :     std::set<staff_idx_t> result;
     191              : 
     192        14499 :     for (const Staff* stave : m_staves) {
     193         7406 :         if (!stave) {
     194            0 :             continue;
     195              :         }
     196              : 
     197         7406 :         result.insert(stave->idx());
     198              :     }
     199              : 
     200         7093 :     return result;
     201            0 : }
     202              : 
     203         3238 : void Part::appendStaff(Staff* staff)
     204              : {
     205         3238 :     m_staves.push_back(staff);
     206         3238 : }
     207              : 
     208           10 : void Part::clearStaves()
     209              : {
     210           10 :     m_staves.clear();
     211           10 : }
     212              : 
     213              : //---------------------------------------------------------
     214              : //   setStaves
     215              : //---------------------------------------------------------
     216              : 
     217          253 : void Part::setStaves(int n)
     218              : {
     219          253 :     int ns = static_cast<int>(m_staves.size());
     220          253 :     if (n < ns) {
     221            0 :         LOGD("Part::setStaves(): remove staves not implemented!");
     222            0 :         return;
     223              :     }
     224              : 
     225          253 :     int staffIdx = static_cast<int>(score()->staffIdx(this)) + ns;
     226          527 :     for (int i = ns; i < n; ++i) {
     227          274 :         Staff* staff = Factory::createStaff(this);
     228          274 :         score()->insertStaff(staff, i);
     229              : 
     230          438 :         for (Measure* m = score()->firstMeasure(); m; m = m->nextMeasure()) {
     231          164 :             m->insertStaff(staff, staffIdx);
     232          164 :             if (m->hasMMRest()) {
     233            0 :                 m->mmRest()->insertStaff(staff, staffIdx);
     234              :             }
     235              :         }
     236          274 :         ++staffIdx;
     237              :     }
     238              : }
     239              : 
     240              : //---------------------------------------------------------
     241              : //   insertStaff
     242              : //---------------------------------------------------------
     243              : 
     244          343 : void Part::insertStaff(Staff* staff, staff_idx_t idx)
     245              : {
     246          343 :     if (idx >= m_staves.size()) {
     247          338 :         idx = m_staves.size();
     248              :     }
     249          343 :     m_staves.insert(m_staves.begin() + idx, staff);
     250          343 :     staff->setPart(this);
     251          343 : }
     252              : 
     253              : //---------------------------------------------------------
     254              : //   removeStaff
     255              : //---------------------------------------------------------
     256              : 
     257           37 : void Part::removeStaff(Staff* staff)
     258              : {
     259           37 :     if (!muse::remove(m_staves, staff)) {
     260            0 :         LOGD("Part::removeStaff: not found %p", staff);
     261            0 :         return;
     262              :     }
     263              : }
     264              : 
     265      3551601 : bool Part::show() const
     266              : {
     267      3551601 :     if (score()->configuration()->debuggingOptions().showOriginAndCombinedStaves) {
     268            0 :         return m_show;
     269              :     }
     270              : 
     271      3551601 :     bool sharedPartEnabled = sharedPart() && sharedPart()->enabled();
     272      3551601 :     return m_show && !sharedPartEnabled;
     273              : }
     274              : 
     275              : //---------------------------------------------------------
     276              : //   setMidiProgram
     277              : //---------------------------------------------------------
     278              : 
     279          994 : void Part::setMidiProgram(int program, int bank)
     280              : {
     281          994 :     InstrChannel* c = instrument()->channel(0);
     282          994 :     c->setProgram(program);
     283          994 :     c->setBank(bank);
     284          994 : }
     285              : 
     286              : //---------------------------------------------------------
     287              : //   midiProgram
     288              : //---------------------------------------------------------
     289              : 
     290          103 : int Part::midiProgram() const
     291              : {
     292          103 :     return instrument()->playbackChannel(0, masterScore())->program();
     293              : }
     294              : 
     295              : //---------------------------------------------------------
     296              : //   midiChannel
     297              : //---------------------------------------------------------
     298              : 
     299         1006 : int Part::midiChannel() const
     300              : {
     301         1006 :     return masterScore()->midiChannel(instrument()->channel(0)->channel());
     302              : }
     303              : 
     304              : //---------------------------------------------------------
     305              : //   midiPort
     306              : //---------------------------------------------------------
     307              : 
     308          592 : int Part::midiPort() const
     309              : {
     310          592 :     return masterScore()->midiPort(instrument()->channel(0)->channel());
     311              : }
     312              : 
     313              : //---------------------------------------------------------
     314              : //   setMidiChannel
     315              : //   Called from importmusicxml, importMidi and importGtp*.
     316              : //   Specify tick to set MIDI channel to an InstrumentChange element.
     317              : //   Usage:
     318              : //   setMidiChannel(channel)       to set channel
     319              : //   setMidiChannel(-1, port)      to set port
     320              : //   setMidiChannel(channel, port) to set both
     321              : //---------------------------------------------------------
     322              : 
     323          958 : void Part::setMidiChannel(int ch, int port, const Fraction& tick)
     324              : {
     325          958 :     InstrChannel* channel = instrument(tick)->channel(0);
     326          958 :     if (channel->channel() == -1) {
     327          942 :         masterScore()->addMidiMapping(channel, this, port, ch);
     328              :     } else {
     329           16 :         masterScore()->updateMidiMapping(channel, this, port, ch);
     330              :     }
     331          958 : }
     332              : 
     333              : //---------------------------------------------------------
     334              : //   setInstrument
     335              : //---------------------------------------------------------
     336              : 
     337         1594 : void Part::setInstrument(Instrument* i, Fraction tick)
     338              : {
     339         1594 :     m_instruments.setInstrument(i, tick.ticks());
     340         1594 : }
     341              : 
     342            0 : void Part::setInstrument(Instrument* i, int tick)
     343              : {
     344            0 :     m_instruments.setInstrument(i, tick);
     345            0 : }
     346              : 
     347          326 : void Part::setInstrument(const Instrument&& i, Fraction tick)
     348              : {
     349          326 :     m_instruments.setInstrument(new Instrument(i), tick.ticks());
     350          326 : }
     351              : 
     352          539 : void Part::setInstrument(const Instrument& i, Fraction tick)
     353              : {
     354          539 :     m_instruments.setInstrument(new Instrument(i), tick.ticks());
     355          539 : }
     356              : 
     357            0 : void Part::setInstruments(const InstrumentList& instruments)
     358              : {
     359            0 :     m_instruments.clear();
     360              : 
     361            0 :     for (auto it = instruments.begin(); it != instruments.end(); ++it) {
     362            0 :         m_instruments.setInstrument(it->second, it->first);
     363              :     }
     364            0 : }
     365              : 
     366              : //---------------------------------------------------------
     367              : //   removeInstrument
     368              : //---------------------------------------------------------
     369              : 
     370            1 : void Part::removeInstrument(Instrument* instr, const Fraction& tick)
     371              : {
     372            1 :     auto i = m_instruments.find(tick.ticks());
     373            1 :     if (i == m_instruments.end()) {
     374            0 :         LOGD("Part::removeInstrument: not found at tick %d", tick.ticks());
     375            0 :         return;
     376              :     }
     377            1 :     if (i->second != instr) {
     378            0 :         LOGD("Part::removeInstrument: item at tick %d (%p) != instr (%p)", tick.ticks(), i->second, instr);
     379            0 :         return;
     380              :     }
     381            1 :     m_instruments.erase(i);
     382              : }
     383              : 
     384              : //---------------------------------------------------------
     385              : //   removeNonPrimaryInstruments
     386              : //---------------------------------------------------------
     387              : 
     388            0 : void Part::removeNonPrimaryInstruments()
     389              : {
     390            0 :     auto it = m_instruments.begin();
     391            0 :     while (it != m_instruments.end()) {
     392            0 :         if (it->first != -1) {
     393            0 :             it = m_instruments.erase(it);
     394            0 :             continue;
     395              :         }
     396            0 :         ++it;
     397              :     }
     398            0 : }
     399              : 
     400              : //---------------------------------------------------------
     401              : //   instrument
     402              : //---------------------------------------------------------
     403              : 
     404       795362 : Instrument* Part::instrument(Fraction tick)
     405              : {
     406       795362 :     return m_instruments.instrument(tick.ticks());
     407              : }
     408              : 
     409              : //---------------------------------------------------------
     410              : //   instrument
     411              : //---------------------------------------------------------
     412              : 
     413        39611 : const Instrument* Part::instrument(Fraction tick) const
     414              : {
     415        39611 :     return m_instruments.instrument(tick.ticks());
     416              : }
     417              : 
     418            0 : const Instrument* Part::instrumentById(const String& id) const
     419              : {
     420            0 :     for (const auto& pair: m_instruments) {
     421            0 :         if (pair.second->id() == id) {
     422            0 :             return pair.second;
     423              :         }
     424              :     }
     425              : 
     426            0 :     return nullptr;
     427              : }
     428              : 
     429              : //---------------------------------------------------------
     430              : //   instruments
     431              : //---------------------------------------------------------
     432              : 
     433        22729 : const InstrumentList& Part::instruments() const
     434              : {
     435        22729 :     return m_instruments;
     436              : }
     437              : 
     438         1844 : const StringData* Part::stringData(const Fraction& tick, staff_idx_t staffIdx) const
     439              : {
     440         1844 :     if (!score()) {
     441            0 :         return nullptr;
     442              :     }
     443              : 
     444         1844 :     const Instrument* instrument = this->instrument(tick);
     445         1844 :     if (!instrument) {
     446            0 :         return nullptr;
     447              :     }
     448              : 
     449         1844 :     bool reflectTranspositionInLinkedTab = true;
     450              : 
     451         1844 :     const Staff* staff = staffIdx != muse::nidx ? score()->staff(staffIdx) : nullptr;
     452         1844 :     if (staff && staff->isTabStaff(tick)) {
     453         1452 :         if (const Staff* primaryStaff = staff->primaryStaff()) {
     454         1126 :             reflectTranspositionInLinkedTab = primaryStaff->reflectTranspositionInLinkedTab();
     455              :         }
     456              :     }
     457              : 
     458         1844 :     StringTunings* stringTunings = nullptr;
     459              : 
     460         1844 :     if (reflectTranspositionInLinkedTab) {
     461         1844 :         auto it = muse::findLessOrEqual(m_stringTunings, tick.ticks());
     462         1844 :         if (it != m_stringTunings.end()) {
     463            3 :             stringTunings = it->second;
     464              :         }
     465              :     }
     466              : 
     467         1844 :     if (stringTunings) {
     468              :         //!NOTE: if there is string tunings element between current instrument and current tick,
     469              :         //! then return string data from string tunings element
     470            3 :         const Instrument* stringTuningsInstrument = this->instrument(stringTunings->tick());
     471            3 :         if (instrument == stringTuningsInstrument) {
     472            3 :             return stringTunings->stringData();
     473              :         }
     474              :     }
     475              : 
     476         1841 :     return instrument->stringData();
     477              : }
     478              : 
     479           19 : void Part::addStringTunings(StringTunings* stringTunings)
     480              : {
     481           19 :     DO_ASSERT(!isSharedPart());
     482           19 :     m_stringTunings[stringTunings->segment()->tick().ticks()] = stringTunings;
     483           19 : }
     484              : 
     485            0 : void Part::removeStringTunings(StringTunings* stringTunings)
     486              : {
     487            0 :     int tick = stringTunings->segment()->tick().ticks();
     488            0 :     auto it = m_stringTunings.find(tick);
     489              : 
     490            0 :     if (it != m_stringTunings.end() && it->second == stringTunings) {
     491            0 :         m_stringTunings.erase(it);
     492              :     }
     493            0 : }
     494              : 
     495           19 : StringTunings* Part::nextStringTuning(const Fraction& tick) const
     496              : {
     497           19 :     auto i = m_stringTunings.upper_bound(tick.ticks());
     498           19 :     return (i == m_stringTunings.end()) ? nullptr : i->second;
     499              : }
     500              : 
     501              : //---------------------------------------------------------
     502              : //   instrumentId
     503              : //---------------------------------------------------------
     504              : 
     505         1630 : String Part::instrumentId(const Fraction& tick) const
     506              : {
     507         1630 :     return instrument(tick)->id();
     508              : }
     509              : 
     510              : //---------------------------------------------------------
     511              : //   longName
     512              : //---------------------------------------------------------
     513              : 
     514          749 : String Part::longName(const Fraction& tick) const
     515              : {
     516          749 :     return instrument(tick)->longName();
     517              : }
     518              : 
     519              : //---------------------------------------------------------
     520              : //   instrumentName
     521              : //---------------------------------------------------------
     522              : 
     523           58 : String Part::instrumentName(const Fraction& tick) const
     524              : {
     525           58 :     return instrument(tick)->trackName();
     526              : }
     527              : 
     528              : //---------------------------------------------------------
     529              : //   shortName
     530              : //---------------------------------------------------------
     531              : 
     532         1390 : String Part::shortName(const Fraction& tick) const
     533              : {
     534         1390 :     return instrument(tick)->shortName();
     535              : }
     536              : 
     537              : //---------------------------------------------------------
     538              : //   setLongName
     539              : //---------------------------------------------------------
     540              : 
     541          848 : void Part::setLongName(const String& s, const Fraction& tick)
     542              : {
     543          848 :     instrument(tick)->setLongName(s);
     544          848 : }
     545              : 
     546              : //---------------------------------------------------------
     547              : //   setShortName
     548              : //---------------------------------------------------------
     549              : 
     550          584 : void Part::setShortName(const String& s, const Fraction& tick)
     551              : {
     552          584 :     instrument(tick)->setShortName(s);
     553          584 : }
     554              : 
     555              : //---------------------------------------------------------
     556              : //   setLongNameAll
     557              : //---------------------------------------------------------
     558              : 
     559          472 : void Part::setLongNameAll(const String& s)
     560              : {
     561          949 :     for (auto instrument : m_instruments) {
     562          477 :         instrument.second->setLongName(s);
     563              :     }
     564          472 : }
     565              : 
     566              : //---------------------------------------------------------
     567              : //   setShortNameAll
     568              : //---------------------------------------------------------
     569              : 
     570          471 : void Part::setShortNameAll(const String& s)
     571              : {
     572          947 :     for (auto instrument : m_instruments) {
     573          476 :         instrument.second->setShortName(s);
     574              :     }
     575          471 : }
     576              : 
     577          765 : int Part::number(const Fraction& tick) const
     578              : {
     579          765 :     return instrument(tick)->number();
     580              : }
     581              : 
     582            0 : void Part::setNumber(int v, const Fraction& tick)
     583              : {
     584            0 :     instrument(tick)->setNumber(v);
     585            0 : }
     586              : 
     587            0 : String Part::transposition(const Fraction& tick) const
     588              : {
     589            0 :     return instrument(tick)->transposition();
     590              : }
     591              : 
     592            0 : void Part::setTransposition(const String& s, const Fraction& tick)
     593              : {
     594            0 :     instrument(tick)->setTransposition(s);
     595            0 : }
     596              : 
     597              : //---------------------------------------------------------
     598              : //   setPlainLongName
     599              : //---------------------------------------------------------
     600              : 
     601          429 : void Part::setPlainLongName(const String& s)
     602              : {
     603          429 :     setLongName(XmlWriter::xmlString(s));
     604          429 : }
     605              : 
     606              : //---------------------------------------------------------
     607              : //   setPlainShortName
     608              : //---------------------------------------------------------
     609              : 
     610          273 : void Part::setPlainShortName(const String& s)
     611              : {
     612          273 :     setShortName(XmlWriter::xmlString(s));
     613          273 : }
     614              : 
     615              : //---------------------------------------------------------
     616              : //   setPlainLongNameAll
     617              : //---------------------------------------------------------
     618              : 
     619            0 : void Part::setPlainLongNameAll(const String& s)
     620              : {
     621            0 :     setLongNameAll(XmlWriter::xmlString(s));
     622            0 : }
     623              : 
     624              : //---------------------------------------------------------
     625              : //   setPlainShortNameAll
     626              : //---------------------------------------------------------
     627              : 
     628          471 : void Part::setPlainShortNameAll(const String& s)
     629              : {
     630          471 :     setShortNameAll(XmlWriter::xmlString(s));
     631          471 : }
     632              : 
     633              : //---------------------------------------------------------
     634              : //   getProperty
     635              : //---------------------------------------------------------
     636              : 
     637         1786 : PropertyValue Part::getProperty(Pid id) const
     638              : {
     639         1786 :     switch (id) {
     640         1762 :     case Pid::VISIBLE:
     641         1762 :         return PropertyValue(m_show);
     642            0 :     case Pid::HIDE_WHEN_EMPTY:
     643            0 :         return PropertyValue(m_hideWhenEmpty);
     644            0 :     case Pid::HIDE_STAVES_WHEN_INDIVIDUALLY_EMPTY:
     645            0 :         return PropertyValue(m_hideStavesWhenIndividuallyEmpty);
     646            0 :     case Pid::USE_DRUMSET:
     647            0 :         return instrument()->useDrumset();
     648            6 :     case Pid::PREFER_SHARP_FLAT:
     649            6 :         return int(preferSharpFlat());
     650           18 :     default:
     651           18 :         return PropertyValue();
     652              :     }
     653              : }
     654              : 
     655              : //---------------------------------------------------------
     656              : //   setProperty
     657              : //---------------------------------------------------------
     658              : 
     659           20 : bool Part::setProperty(Pid id, const PropertyValue& property)
     660              : {
     661           20 :     switch (id) {
     662            8 :     case Pid::VISIBLE:
     663            8 :         setShow(property.toBool());
     664            8 :         break;
     665            0 :     case Pid::HIDE_WHEN_EMPTY:
     666            0 :         setHideWhenEmpty(property.value<AutoOnOff>());
     667            0 :         break;
     668            0 :     case Pid::HIDE_STAVES_WHEN_INDIVIDUALLY_EMPTY:
     669            0 :         setHideStavesWhenIndividuallyEmpty(property.toBool());
     670            0 :         break;
     671            0 :     case Pid::USE_DRUMSET:
     672            0 :         instrument()->setUseDrumset(property.toBool());
     673            0 :         break;
     674            2 :     case Pid::PREFER_SHARP_FLAT:
     675            2 :         setPreferSharpFlat(PreferSharpFlat(property.toInt()));
     676            2 :         break;
     677           10 :     default:
     678           10 :         LOGD("Part::setProperty: unknown id %d", int(id));
     679           10 :         break;
     680              :     }
     681           20 :     score()->setLayoutAll();
     682           20 :     return true;
     683              : }
     684              : 
     685       154412 : TrackRange Part::trackRange() const
     686              : {
     687       154412 :     IF_ASSERT_FAILED(!m_staves.empty()) {
     688            0 :         return {};
     689              :     }
     690              : 
     691       154412 :     const track_idx_t startTrack = m_staves.front()->idx() * VOICES;
     692       154412 :     return { startTrack, startTrack + m_staves.size() * VOICES };
     693              : }
     694              : 
     695            0 : InstrumentTrackIdList Part::instrumentTrackIdList() const
     696              : {
     697            0 :     InstrumentTrackIdList result;
     698            0 :     std::set<String> seen;
     699              : 
     700            0 :     for (const auto& pair : m_instruments) {
     701            0 :         String instrId = pair.second->id();
     702            0 :         if (seen.insert(instrId).second) {
     703            0 :             result.push_back({ m_id, instrId });
     704              :         }
     705            0 :     }
     706              : 
     707            0 :     return result;
     708            0 : }
     709              : 
     710          109 : InstrumentTrackIdSet Part::instrumentTrackIdSet() const
     711              : {
     712          109 :     InstrumentTrackIdSet result;
     713              : 
     714          218 :     for (const auto& pair : m_instruments) {
     715          218 :         result.insert({ m_id, pair.second->id() });
     716              :     }
     717              : 
     718          109 :     return result;
     719          218 : }
     720              : 
     721              : //---------------------------------------------------------
     722              : //   insertTime
     723              : //---------------------------------------------------------
     724              : 
     725          542 : void Part::insertTime(const Fraction& tick, const Fraction& len)
     726              : {
     727          542 :     if (len.isZero()) {
     728            9 :         return;
     729              :     }
     730              : 
     731              :     // move all instruments
     732              : 
     733          533 :     if (len < Fraction(0, 1)) {
     734              :         // remove instruments between tickpos >= tick and tickpos < (tick+len)
     735              :         // ownership goes back to class InstrumentChange()
     736              : 
     737          141 :         auto si = m_instruments.lower_bound(tick.ticks());
     738          141 :         auto ei = m_instruments.lower_bound((tick - len).ticks());
     739          141 :         m_instruments.erase(si, ei);
     740              : 
     741              :         // remove harp pedal diagrams between tickpo >= tick
     742          141 :         m_harpDiagrams.erase(m_harpDiagrams.lower_bound(tick.ticks()), m_harpDiagrams.lower_bound((tick - len).ticks()));
     743              :     }
     744              : 
     745          533 :     InstrumentList il;
     746              : 
     747          533 :     for (auto i = m_instruments.lower_bound(tick.ticks()); i != m_instruments.end();) {
     748            0 :         Instrument* instrument = i->second;
     749            0 :         int t = i->first;
     750            0 :         m_instruments.erase(i++);
     751            0 :         il[t + len.ticks()] = instrument;
     752              :     }
     753          533 :     m_instruments.insert(il.begin(), il.end());
     754              : 
     755          533 :     std::map<int, HarpPedalDiagram*> hd2;
     756          533 :     for (auto h = m_harpDiagrams.lower_bound(tick.ticks()); h != m_harpDiagrams.end();) {
     757            0 :         HarpPedalDiagram* diagram = h->second;
     758            0 :         int t = h->first;
     759            0 :         m_harpDiagrams.erase(h++);
     760            0 :         hd2[t + len.ticks()] = diagram;
     761              :     }
     762          533 :     m_harpDiagrams.insert(hd2.begin(), hd2.end());
     763          533 : }
     764              : 
     765              : //---------------------------------------------------------
     766              : //   addHarpDiagram
     767              : //---------------------------------------------------------
     768              : 
     769           18 : void Part::addHarpDiagram(HarpPedalDiagram* harpDiagram)
     770              : {
     771           18 :     DO_ASSERT(!isSharedPart());
     772           18 :     m_harpDiagrams[harpDiagram->segment()->tick().ticks()] = harpDiagram;
     773           18 : }
     774              : 
     775              : //---------------------------------------------------------
     776              : //   removeHarpDiagram
     777              : //---------------------------------------------------------
     778              : 
     779            1 : void Part::removeHarpDiagram(HarpPedalDiagram* harpDiagram)
     780              : {
     781            1 :     int tick = harpDiagram->segment()->tick().ticks();
     782            1 :     auto it = m_harpDiagrams.find(tick);
     783              : 
     784            1 :     if (it != m_harpDiagrams.end() && it->second == harpDiagram) {
     785            1 :         m_harpDiagrams.erase(it);
     786              :     }
     787            1 : }
     788              : 
     789              : //---------------------------------------------------------
     790              : //   clearHarpDiagrams
     791              : //---------------------------------------------------------
     792              : 
     793            0 : void Part::clearHarpDiagrams()
     794              : {
     795            0 :     m_harpDiagrams.clear();
     796            0 : }
     797              : 
     798              : //---------------------------------------------------------
     799              : //   currentHarpDiagram
     800              : //---------------------------------------------------------
     801              : 
     802            3 : HarpPedalDiagram* Part::currentHarpDiagram(const Fraction& tick) const
     803              : {
     804            3 :     auto i = m_harpDiagrams.upper_bound(tick.ticks());
     805            3 :     if (i != m_harpDiagrams.begin()) {
     806            3 :         --i;
     807              :     }
     808            3 :     if (i == m_harpDiagrams.end()) {
     809            0 :         return nullptr;
     810            3 :     } else if (tick < Fraction::fromTicks(i->first)) {
     811            0 :         return nullptr;
     812              :     }
     813            3 :     return i->second;
     814              : }
     815              : 
     816              : //---------------------------------------------------------
     817              : //   nextHarpDiagram
     818              : //---------------------------------------------------------
     819              : 
     820            8 : HarpPedalDiagram* Part::nextHarpDiagram(const Fraction& tick) const
     821              : {
     822            8 :     auto i = m_harpDiagrams.upper_bound(tick.ticks());
     823            8 :     return (i == m_harpDiagrams.end()) ? nullptr : i->second;
     824              : }
     825              : 
     826              : //---------------------------------------------------------
     827              : //   prevHarpDiagram
     828              : //---------------------------------------------------------
     829              : 
     830           31 : HarpPedalDiagram* Part::prevHarpDiagram(const Fraction& tick) const
     831              : {
     832           31 :     auto i = m_harpDiagrams.lower_bound(tick.ticks());
     833           31 :     if (i == m_harpDiagrams.begin()) {
     834           10 :         return nullptr;
     835              :     }
     836           21 :     i--;
     837           21 :     return i->second;
     838              : }
     839              : 
     840              : //---------------------------------------------------------
     841              : //   currentHarpDiagramTick
     842              : //---------------------------------------------------------
     843              : 
     844            0 : Fraction Part::currentHarpDiagramTick(const Fraction& tick) const
     845              : {
     846            0 :     if (m_harpDiagrams.empty()) {
     847            0 :         return Fraction(0, 1);
     848              :     }
     849            0 :     auto i = m_harpDiagrams.upper_bound(tick.ticks());
     850            0 :     if (i == m_harpDiagrams.begin()) {
     851            0 :         return Fraction(0, 1);
     852              :     }
     853            0 :     --i;
     854            0 :     return Fraction::fromTicks(i->first);
     855              : }
     856              : 
     857          475 : String Part::partName() const
     858              : {
     859          475 :     const Instrument* i = instrument();
     860          475 :     String fullName = i->longName();
     861              : 
     862          475 :     const String& transp = i->transposition();
     863          475 :     if (!transp.empty()) {
     864              :         //: For instrument transposition, e.g. Horn in F
     865            0 :         fullName += u" " + muse::mtrc("notation", "in") + u" " + transp;
     866              :     }
     867              : 
     868          475 :     int n = number();
     869          475 :     if (n != 0) {
     870            0 :         fullName += u" " + String::number(n);
     871              :     }
     872              : 
     873          475 :     return fullName;
     874            0 : }
     875              : 
     876            0 : bool Part::isVisible() const
     877              : {
     878            0 :     return m_show;
     879              : }
     880              : 
     881              : //---------------------------------------------------------
     882              : //   lyricCount
     883              : //---------------------------------------------------------
     884              : 
     885            0 : int Part::lyricCount() const
     886              : {
     887            0 :     if (!score()) {
     888            0 :         return 0;
     889              :     }
     890              : 
     891            0 :     if (!score()->firstMeasure()) {
     892            0 :         return 0;
     893              :     }
     894              : 
     895            0 :     size_t count = 0;
     896            0 :     SegmentType st = SegmentType::ChordRest;
     897            0 :     const TrackRange range = trackRange();
     898            0 :     for (Segment* seg = score()->firstMeasure()->first(st); seg; seg = seg->next1(st)) {
     899            0 :         for (track_idx_t i = range.startTrack; i < range.endTrack; ++i) {
     900            0 :             ChordRest* cr = toChordRest(seg->element(i));
     901            0 :             if (cr) {
     902            0 :                 count += cr->lyrics().size();
     903              :             }
     904              :         }
     905              :     }
     906            0 :     return int(count);
     907              : }
     908              : 
     909              : //---------------------------------------------------------
     910              : //   harmonyCount
     911              : //---------------------------------------------------------
     912              : 
     913         1915 : int Part::harmonyCount() const
     914              : {
     915         1915 :     if (!score()) {
     916            0 :         return 0;
     917              :     }
     918              : 
     919         1915 :     Measure* firstM = score()->firstMeasure();
     920         1915 :     if (!firstM) {
     921            8 :         return 0;
     922              :     }
     923              : 
     924         1907 :     SegmentType st = SegmentType::ChordRest;
     925         1907 :     int count = 0;
     926         1907 :     const TrackRange range = trackRange();
     927        32916 :     for (const Segment* seg = firstM->first(st); seg; seg = seg->next1(st)) {
     928        34512 :         for (const EngravingItem* e : seg->annotations()) {
     929         7006 :             if ((e->isHarmony() || (e->isFretDiagram() && toFretDiagram(e)->harmony())) && e->track() >= range.startTrack
     930         7006 :                 && e->track() < range.endTrack) {
     931          601 :                 count++;
     932              :             }
     933              :         }
     934              :     }
     935         1907 :     return count;
     936              : }
     937              : 
     938              : //---------------------------------------------------------
     939              : //   updateHarmonyChannels
     940              : ///   update the harmony channel by creating a new channel
     941              : ///   when appropriate or using the existing one
     942              : ///
     943              : ///   checkRemoval can be set to true to check to see if we
     944              : ///   can remove the harmony channel
     945              : //---------------------------------------------------------
     946         1983 : void Part::updateHarmonyChannels(bool isDoOnInstrumentChanged, bool checkRemoval)
     947              : {
     948           61 :     auto onInstrumentChanged = [this]() {
     949           61 :         masterScore()->rebuildMidiMapping();
     950           61 :         masterScore()->updateChannel();
     951           61 :         score()->setInstrumentsChanged(true);
     952           61 :         score()->setLayoutAll();     //do we need this?
     953         2044 :     };
     954              : 
     955              :     // usage of harmony count is okay even if expensive since checking harmony channel will shortcircuit if existent
     956              :     // harmonyCount will only be called on loading of a score (where it will need to be scanned for harmony anyway)
     957              :     // or when the first harmony of a score is just added
     958         1983 :     if (checkRemoval) {
     959              :         //may be a bit expensive since it gets called after every single delete or undo, but it should be okay for now
     960              :         //~OPTIM~
     961           13 :         if (harmonyCount() == 0) {
     962            4 :             Instrument* instr = instrument();
     963            4 :             int hChIdx = instr->channelIdx(String::fromUtf8(InstrChannel::HARMONY_NAME));
     964            4 :             if (hChIdx != -1) {
     965            3 :                 InstrChannel* hChan = instr->channel(hChIdx);
     966            3 :                 instr->removeChannel(hChan);
     967            3 :                 delete hChan;
     968            3 :                 if (isDoOnInstrumentChanged) {
     969            3 :                     onInstrumentChanged();
     970              :                 }
     971            3 :                 return;
     972              :             }
     973              :         }
     974              :     }
     975              : 
     976         1980 :     if (!harmonyChannel() && harmonyCount() > 0) {
     977           58 :         Instrument* instr = instrument();
     978           58 :         InstrChannel* c = new InstrChannel(*instr->channel(0));
     979              :         // default to program 0, which is piano in General MIDI
     980           58 :         c->setProgram(0);
     981           58 :         if (c->bank() == 128) { // drumset?
     982            0 :             c->setBank(0);
     983              :         }
     984           58 :         c->setName(String::fromUtf8(InstrChannel::HARMONY_NAME));
     985           58 :         instr->appendChannel(c);
     986           58 :         onInstrumentChanged();
     987              :     }
     988              : }
     989              : 
     990              : //---------------------------------------------------------
     991              : //   harmonyChannel
     992              : //---------------------------------------------------------
     993              : 
     994         2143 : const InstrChannel* Part::harmonyChannel() const
     995              : {
     996         2143 :     const Instrument* instr = instrument();
     997         2143 :     if (!instr) {
     998            0 :         return nullptr;
     999              :     }
    1000              : 
    1001         2143 :     int chanIdx = instr->channelIdx(String::fromUtf8(InstrChannel::HARMONY_NAME));
    1002         2143 :     if (chanIdx == -1) {
    1003         2065 :         return nullptr;
    1004              :     }
    1005              : 
    1006           78 :     const InstrChannel* chan = instr->channel(chanIdx);
    1007           78 :     assert(chan);
    1008           78 :     return chan;
    1009              : }
    1010              : 
    1011          163 : bool Part::hasChordSymbol() const
    1012              : {
    1013          163 :     return harmonyChannel() != nullptr;
    1014              : }
    1015              : 
    1016              : //---------------------------------------------------------
    1017              : //   hasPitchedStaff
    1018              : //---------------------------------------------------------
    1019              : 
    1020            0 : bool Part::hasPitchedStaff() const
    1021              : {
    1022            0 :     for (Staff* s : staves()) {
    1023            0 :         if (s && s->isPitchedStaff(Fraction(0, 1))) {
    1024            0 :             return true;
    1025              :         }
    1026              :     }
    1027            0 :     return false;
    1028              : }
    1029              : 
    1030              : //---------------------------------------------------------
    1031              : //   hasTabStaff
    1032              : //---------------------------------------------------------
    1033              : 
    1034            0 : bool Part::hasTabStaff() const
    1035              : {
    1036            0 :     for (Staff* s : staves()) {
    1037            0 :         if (s && s->isTabStaff(Fraction(0, 1))) {
    1038            0 :             return true;
    1039              :         }
    1040              :     }
    1041            0 :     return false;
    1042              : }
    1043              : 
    1044              : //---------------------------------------------------------
    1045              : //   hasDrumStaff
    1046              : //---------------------------------------------------------
    1047              : 
    1048         2030 : bool Part::hasDrumStaff() const
    1049              : {
    1050         4015 :     for (Staff* s : staves()) {
    1051         2049 :         if (s && s->isDrumStaff(Fraction(0, 1))) {
    1052           64 :             return true;
    1053              :         }
    1054              :     }
    1055         1966 :     return false;
    1056              : }
    1057              : }
        

Generated by: LCOV version 2.0-1