LCOV - code coverage report
Current view: top level - src/engraving/dom - instrument.h Coverage Total Hit
Test: filtered_coverage.info Lines: 87.7 % 73 64
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              : #pragma once
      24              : 
      25              : #include <vector>
      26              : 
      27              : #include "global/containers.h"
      28              : 
      29              : #include "clef.h"
      30              : #include "interval.h"
      31              : #include "notifier.h"
      32              : #include "stafflabel.h"
      33              : #include "stringdata.h"
      34              : 
      35              : #include "../compat/midi/midicoreevent.h"
      36              : 
      37              : namespace mu::engraving {
      38              : class ChannelListener;
      39              : class Drumset;
      40              : class InstrumentTemplate;
      41              : class MasterScore;
      42              : class Part;
      43              : class StringData;
      44              : class Synthesizer;
      45              : 
      46              : //---------------------------------------------------------
      47              : //   NamedEventList
      48              : //---------------------------------------------------------
      49              : 
      50              : struct NamedEventList {
      51              :     String name;
      52              :     String descr;
      53              :     std::vector<MidiCoreEvent> events;
      54              : 
      55            0 :     bool operator==(const NamedEventList& i) const { return i.name == name && i.events == events; }
      56              : };
      57              : 
      58              : //---------------------------------------------------------
      59              : //   MidiArticulation
      60              : //---------------------------------------------------------
      61              : 
      62              : struct MidiArticulation {
      63              :     String name;
      64              :     String descr;
      65              :     int velocity = 0;         // velocity change: -100% - +100%
      66              :     int gateTime = 0;         // gate time change: -100% - +100%
      67              : 
      68         7708 :     MidiArticulation() {}
      69          104 :     MidiArticulation(const String& n, const String& d, int v, int g)
      70          104 :         : name(n), descr(d), velocity(v), gateTime(g) {}
      71              : 
      72              :     bool operator==(const MidiArticulation& i) const;
      73              : };
      74              : 
      75              : //---------------------------------------------------------
      76              : //   Channel
      77              : //---------------------------------------------------------
      78              : 
      79              : class InstrChannel
      80              : {
      81              : public:
      82              :     static const char* DEFAULT_NAME;
      83              :     static const char* HARMONY_NAME;
      84              :     static const char* PALM_MUTE_NAME;
      85              :     static const int DEFAULT_COLOR = 0x3399ff;
      86              :     static constexpr char defaultVolume = 100;
      87              : 
      88              :     enum class A : char {
      89              :         HBANK, LBANK, PROGRAM, VOLUME, PAN, CHORUS, REVERB,
      90              :         INIT_COUNT
      91              :     };
      92              : 
      93              :     enum class Prop : char {
      94              :         VOLUME, PAN, CHORUS, REVERB, NAME, PROGRAM, BANK, COLOR,
      95              :         SYNTI, CHANNEL, USER_BANK_CONTROL
      96              :     };
      97              : 
      98              :     std::vector<MidiCoreEvent>& initList() const;
      99              : 
     100        26376 :     String name() const { return m_name; }
     101              :     void setName(const String& value);
     102            1 :     String synti() const { return m_synti; }
     103              :     void setSynti(const String& value);
     104         1966 :     int color() const { return m_color; }
     105              :     void setColor(int value);
     106              : 
     107         2826 :     char volume() const { return m_volume; }
     108              :     void setVolume(char value);
     109         2826 :     char pan() const { return m_pan; }
     110              :     void setPan(char value);
     111         1951 :     char chorus() const { return m_chorus; }
     112              :     void setChorus(char value);
     113         1951 :     char reverb() const { return m_reverb; }
     114              :     void setReverb(char value);
     115              : 
     116            0 :     void addToInit(const MidiCoreEvent& e) { m_init.push_back(e); }
     117        14372 :     void setMustUpdateInit(bool arg) { m_mustUpdateInit = arg; }
     118              : 
     119       588891 :     int program() const { return m_program; }
     120              :     void setProgram(int value);
     121       567145 :     int bank() const { return m_bank; }
     122              :     void setBank(int value);
     123        83985 :     int channel() const { return m_channel; }
     124              :     void setChannel(int value);
     125              : 
     126              :     // If the bank controller is set by the user or not
     127         3861 :     bool userBankController() const { return m_userBankController; }
     128              :     void setUserBankController(bool val);
     129              : 
     130            0 :     bool isHarmonyChannel() const { return m_name == String::fromUtf8(InstrChannel::HARMONY_NAME); }
     131              : 
     132              :     std::vector<NamedEventList> midiActions;
     133              :     std::vector<MidiArticulation> articulation;
     134              : 
     135              :     InstrChannel();
     136              : 
     137              :     void updateInitList() const;
     138            0 :     bool operator==(const InstrChannel& c) const { return (m_name == c.m_name) && (m_channel == c.m_channel); }
     139            0 :     bool operator!=(const InstrChannel& c) const { return !(*this == c); }
     140              : 
     141              :     void addListener(ChannelListener* l);
     142              :     void removeListener(ChannelListener* l);
     143              : 
     144              :     void switchExpressive(Synthesizer* synth, bool expressive, bool force = false);
     145              : 
     146        28744 :     void setNotifyAboutChangedEnabled(bool arg) { m_notifyAboutChangedEnabled = arg; }
     147              : 
     148              : private:
     149        49822 :     void firePropertyChanged(InstrChannel::Prop prop)
     150              :     {
     151        49822 :         if (m_notifyAboutChangedEnabled) {
     152        15842 :             m_notifier.notify(prop);
     153              :         }
     154        49822 :     }
     155              : 
     156              :     Notifier<InstrChannel::Prop> m_notifier;
     157              :     bool m_notifyAboutChangedEnabled = true;
     158              : 
     159              :     // this are the indexes of controllers which are always present in
     160              :     // Channel init EventList (maybe zero)
     161              :     String m_name;
     162              : 
     163              :     int m_color = 0;    //rgb
     164              : 
     165              :     String m_synti;
     166              : 
     167              :     char m_volume = 0;
     168              :     char m_pan = 0;
     169              : 
     170              :     char m_chorus = 0;
     171              :     char m_reverb = 0;
     172              : 
     173              :     int m_program = 0;       // current values as shown in mixer
     174              :     int m_bank = 0;          // initialized from "init"
     175              :     int m_channel = 0;       // mscore channel number, mapped to midi port/channel
     176              : 
     177              :     // MuseScore General-specific SND flags:
     178              :     //! TODO Needs porting to MU4
     179              :     bool m_userBankController = false;     // if the user has changed the bank controller as opposed to switchExpressive
     180              :     //bool _switchedToExpressive = false;   // if the patch has been automatically switched to an expr variant
     181              : 
     182              :     mutable std::vector<MidiCoreEvent> m_init;
     183              :     mutable bool m_mustUpdateInit = true;
     184              : };
     185              : 
     186              : //---------------------------------------------------------
     187              : //   ChannelListener
     188              : //---------------------------------------------------------
     189              : 
     190              : class ChannelListener : public Listener<InstrChannel::Prop>
     191              : {
     192            0 :     OBJECT_ALLOCATOR(engraving, ChannelListener)
     193              : public:
     194              :     virtual void propertyChanged(InstrChannel::Prop property) = 0;
     195              :     void setNotifier(InstrChannel* ch)
     196              :     {
     197              :         Listener::setNotifier(nullptr);
     198              :         if (ch) {
     199              :             ch->addListener(this);
     200              :         }
     201              :     }
     202              : 
     203              : private:
     204         3792 :     void receive(InstrChannel::Prop prop) override { propertyChanged(prop); }
     205              : };
     206              : 
     207              : //---------------------------------------------------------
     208              : //   PartChannelSettingsLink
     209              : //---------------------------------------------------------
     210              : 
     211              : class PartChannelSettingsLink final : private ChannelListener
     212              : {
     213              : public:
     214              :     PartChannelSettingsLink() = default;
     215              :     PartChannelSettingsLink(InstrChannel* main, InstrChannel* bound, bool excerpt);
     216              :     PartChannelSettingsLink(const PartChannelSettingsLink&) = delete;
     217              :     PartChannelSettingsLink(PartChannelSettingsLink&&);
     218              :     PartChannelSettingsLink& operator=(const PartChannelSettingsLink&) = delete;
     219              :     PartChannelSettingsLink& operator=(PartChannelSettingsLink&&);
     220        19160 :     ~PartChannelSettingsLink() {}
     221              : 
     222              :     friend void swap(PartChannelSettingsLink&, PartChannelSettingsLink&);
     223              : 
     224              : private:
     225              : 
     226              :     static void applyProperty(InstrChannel::Prop p, const InstrChannel* from, InstrChannel* to);
     227              :     void propertyChanged(InstrChannel::Prop p) override;
     228              : 
     229              :     InstrChannel* m_main = nullptr;
     230              :     InstrChannel* m_bound = nullptr;
     231              :     bool m_excerpt = false;
     232              : };
     233              : 
     234              : //---------------------------------------------------------
     235              : //   Trait
     236              : //---------------------------------------------------------
     237              : 
     238              : enum class TraitType : unsigned char
     239              : {
     240              :     Unknown,
     241              :     Tuning,
     242              :     Transposition,
     243              :     Course
     244              : };
     245              : 
     246              : struct Trait
     247              : {
     248              :     String name;
     249              : 
     250              :     TraitType type = TraitType::Unknown;
     251              : 
     252              :     bool isDefault = false;
     253              :     bool isHiddenOnScore = false;
     254              : 
     255              :     bool isValid() const { return !name.isEmpty(); }
     256              : };
     257              : 
     258              : //---------------------------------------------------------
     259              : //   Instrument
     260              : //---------------------------------------------------------
     261              : 
     262              : class Instrument
     263              : {
     264              : public:
     265              :     Instrument(String id = String());
     266              :     Instrument(const Instrument&);
     267              :     ~Instrument();
     268              : 
     269              :     NamedEventList* midiAction(const String& s, int channel) const;
     270              :     int channelIdx(const String& s) const;
     271              :     double getVelocityMultiplier(const String& name) const;
     272              :     void updateGateTime(int* gateTime, const String& name) const;
     273              : 
     274              :     String recognizeMusicXmlId() const;
     275              :     String recognizeId() const;
     276              :     int recognizeMidiProgram() const;
     277              : 
     278              :     void operator=(const Instrument&);
     279              :     bool operator==(const Instrument&) const;
     280              :     bool operator!=(const Instrument&) const;
     281              : 
     282              :     bool isDifferentInstrument(const Instrument& i) const;
     283              : 
     284        64521 :     const String& id() const { return m_id; }
     285         1808 :     const String& soundId() const { return m_soundId; }
     286          799 :     void setSoundId(const String& id) { m_soundId = id; }
     287              :     String family() const;
     288              :     String group() const;
     289         1566 :     void setId(const String& id) { m_id = id; }
     290         1357 :     void setMinPitchP(int v) { m_minPitchP = v; }
     291         1357 :     void setMaxPitchP(int v) { m_maxPitchP = v; }
     292         1357 :     void setMinPitchA(int v) { m_minPitchA = v; }
     293         1357 :     void setMaxPitchA(int v) { m_maxPitchA = v; }
     294       259518 :     Interval transpose() const { return m_transpose; }
     295         2441 :     void setTranspose(const Interval& v) { m_transpose = v; }
     296         2509 :     void setMusicXmlId(const String& musicXmlId) { m_musicXmlId = musicXmlId; }
     297              : 
     298              :     void setDrumset(const Drumset* ds);
     299         3175 :     const Drumset* drumset() const { return m_drumset; }
     300        18093 :     Drumset* drumset() { return m_drumset; }
     301       343860 :     bool useDrumset() const { return m_useDrumset; }
     302              :     void setUseDrumset(bool val);
     303          799 :     void setAmateurPitchRange(int a, int b) { m_minPitchA = a; m_maxPitchA = b; }
     304          799 :     void setProfessionalPitchRange(int a, int b) { m_minPitchP = a; m_maxPitchP = b; }
     305         6385 :     InstrChannel* channel(int idx) { return muse::value(m_channel, idx); }
     306         7484 :     const InstrChannel* channel(int idx) const { return muse::value(m_channel, idx); }
     307              :     InstrChannel* playbackChannel(int idx, MasterScore*);
     308              :     const InstrChannel* playbackChannel(int idx, const MasterScore*) const;
     309              :     size_t cleffTypeCount() const;
     310              :     ClefTypeList clefType(size_t staffIdx) const;
     311              :     void setClefType(size_t staffIdx, const ClefTypeList& c);
     312              : 
     313         1762 :     const std::vector<NamedEventList>& midiActions() const { return m_midiActions; }
     314            0 :     void addMidiAction(const NamedEventList& l) { m_midiActions.push_back(l); }
     315              : 
     316         3372 :     const std::vector<MidiArticulation>& articulation() const { return m_articulation; }
     317         7244 :     void addMidiArticulation(const MidiArticulation& a) { m_articulation.push_back(a); }
     318              : 
     319        43544 :     const std::vector<InstrChannel*>& channel() const { return m_channel; }
     320         2019 :     void appendChannel(InstrChannel* c) { m_channel.push_back(c); }
     321            3 :     void removeChannel(InstrChannel* c) { muse::remove(m_channel, c); }
     322         1627 :     void clearChannels() { m_channel.clear(); }
     323              : 
     324          799 :     void setMidiActions(const std::vector<NamedEventList>& l) { m_midiActions = l; }
     325          831 :     void setArticulation(const std::vector<MidiArticulation>& l) { m_articulation = l; }
     326         8412 :     const StringData* stringData() const { return &m_stringData; }
     327         1378 :     void setStringData(const StringData& d) { m_stringData.set(d); }
     328       121369 :     bool hasStrings() const { return m_stringData.strings() > 0; }
     329              : 
     330         3205 :     void setLongName(const String& f) { m_instrumentLabel.setLongName(f); }
     331         2912 :     void setShortName(const String& f) { m_instrumentLabel.setShortName(f); }
     332          799 :     void setInstrumentName(const InstrumentLabel& n) { m_instrumentLabel = n; }
     333       599828 :     const String& longName() const { return m_instrumentLabel.longName(); }
     334       596314 :     const String& shortName() const { return m_instrumentLabel.shortName(); }
     335        38494 :     const InstrumentLabel& instrumentLabel() const { return m_instrumentLabel; }
     336        31056 :     InstrumentLabel& instrumentLabel() { return m_instrumentLabel; }
     337              : 
     338         9725 :     int number() const { return m_instrumentLabel.number(); }
     339            0 :     void setNumber(int v) { return m_instrumentLabel.setNumber(v); }
     340              : 
     341         9174 :     const String& transposition() const { return m_instrumentLabel.transposition(); }
     342            0 :     void setTransposition(const String& s) { m_instrumentLabel.setTransposition(s); }
     343              : 
     344              :     int minPitchP() const;
     345              :     int maxPitchP() const;
     346              :     int minPitchA() const;
     347              :     int maxPitchA() const;
     348              :     String musicXmlId() const;
     349              : 
     350              :     String trackName() const;
     351              :     void setTrackName(const String& s);
     352              :     String nameAsXmlText() const;
     353              :     String nameAsPlainText() const;
     354              :     String abbreviatureAsXmlText() const;
     355              :     String abbreviatureAsPlainText() const;
     356              :     static Instrument fromTemplate(const InstrumentTemplate* t);
     357              : 
     358              :     Trait trait() const;
     359              :     void setTrait(const Trait& trait);
     360              : 
     361              :     bool isPrimary() const;
     362              :     void setIsPrimary(bool isPrimary);
     363              : 
     364              :     void updateInstrumentId();
     365              : 
     366         2940 :     bool singleNoteDynamics() const { return m_singleNoteDynamics; }
     367         2743 :     void setSingleNoteDynamics(bool val) { m_singleNoteDynamics = val; }
     368              :     void setSingleNoteDynamicsFromTemplate();
     369              :     bool getSingleNoteDynamicsFromTemplate() const;
     370              :     void switchExpressive(MasterScore* score, Synthesizer* synth, bool expressive, bool force = false);
     371              : 
     372              :     bool isVocalInstrument() const;
     373              :     bool isNormallyMultiStaveInstrument() const;
     374              : 
     375              :     GlissandoStyle glissandoStyle() const;
     376              :     void setGlissandoStyle(GlissandoStyle style);
     377              : 
     378              : private:
     379              : 
     380              :     InstrumentLabel m_instrumentLabel;
     381              : 
     382              :     String m_trackName;
     383              :     String m_id;
     384              :     String m_soundId;
     385              : 
     386              :     int m_minPitchA = 0;
     387              :     int m_maxPitchA = 0;
     388              :     int m_minPitchP = 0;
     389              :     int m_maxPitchP = 0;
     390              :     Interval m_transpose;
     391              :     String m_musicXmlId;
     392              : 
     393              :     bool m_useDrumset = false;
     394              :     Drumset* m_drumset = nullptr;
     395              :     StringData m_stringData;
     396              : 
     397              :     std::vector<NamedEventList> m_midiActions;
     398              :     std::vector<MidiArticulation> m_articulation;
     399              :     std::vector<InstrChannel*> m_channel;        // at least one entry
     400              :     std::vector<ClefTypeList> m_clefType;
     401              : 
     402              :     bool m_singleNoteDynamics = false;
     403              : 
     404              :     Trait m_trait;
     405              :     bool m_isPrimary = false;
     406              : 
     407              :     mutable String m_familyCache;
     408              :     mutable String m_groupCache;
     409              : 
     410              :     GlissandoStyle m_glissandoStyle = GlissandoStyle::CHROMATIC;
     411              : };
     412              : 
     413              : //---------------------------------------------------------
     414              : //   InstrumentList
     415              : //---------------------------------------------------------
     416              : 
     417              : class InstrumentList : public std::map<const int, Instrument*>
     418              : {
     419              :     OBJECT_ALLOCATOR(engraving, InstrumentList)
     420              : 
     421              : public:
     422         3587 :     InstrumentList() {}
     423              :     const Instrument* instrument(int tick) const;
     424              :     Instrument* instrument(int tick);
     425              :     void setInstrument(Instrument*, int tick);
     426              :     bool contains(const String& instrumentId) const;
     427              : 
     428              : private:
     429              : 
     430              :     static Instrument defaultInstrument;
     431              : };
     432              : }
        

Generated by: LCOV version 2.0-1