1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2020 MuseScore BVBA
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //=============================================================================
19 
20 #ifndef __PLUGIN_API_INSTRUMENT_H__
21 #define __PLUGIN_API_INSTRUMENT_H__
22 
23 #include "scoreelement.h"
24 #include "libmscore/instrument.h"
25 
26 namespace Ms {
27 
28 class Instrument;
29 
30 namespace PluginAPI {
31 
32 class Instrument;
33 
34 //---------------------------------------------------------
35 //   Channel
36 ///   Provides an access to channel properties. Similar to
37 ///   Mixer, changes to some of the playback-related
38 ///   properties are not recorded to undo stack and are not
39 ///   revertable with standard user-visible "undo" action.
40 ///   Changing MIDI patch though is undoable in normal way
41 ///   ("dock" type plugins may need to call
42 ///   \ref Score.startCmd / \ref Score.endCmd for that to
43 ///   work properly).
44 ///
45 ///   Iterating over all channels in the current score can
46 ///   be done as follows:
47 ///   \code
48 ///   var parts = curScore.parts;
49 ///   for (var i = 0; i < parts.length; ++i) {
50 ///       var part = parts[i];
51 ///       var instrs = part.instruments;
52 ///       for (var j = 0; j < instrs.length; ++j) {
53 ///           var instr = instrs[j];
54 ///           var channels = instr.channels;
55 ///           for (var k = 0; k < channels.length; ++k) {
56 ///               var channel = channels[k];
57 ///               channel.volume = 64; // just for example, changing the channel's volume
58 ///           }
59 ///       }
60 ///   }
61 ///   \endcode
62 ///   \since MuseScore 3.5
63 //---------------------------------------------------------
64 
65 class Channel : public QObject {
66       Q_OBJECT
67 
68       Ms::Channel* _channel;
69       Ms::Part* _part;
70 
71       /** Name of this channel */
72       Q_PROPERTY(QString name READ name)
73 
74       /**
75        * Channel volume, from 0 to 127.
76        * \note Changing this property is **not** revertable with a standard "undo"
77        * action. Plugins may need to handle reverting this property change if
78        * necessary.
79        */
80       Q_PROPERTY(int volume READ volume WRITE setVolume)
81       /**
82        * Channel pan, from 0 to 127.
83        * \note Changing this property is **not** revertable with a standard "undo"
84        * action. Plugins may need to handle reverting this property change if
85        * necessary.
86        */
87       Q_PROPERTY(int pan READ pan WRITE setPan)
88       /**
89        * Channel chorus, from 0 to 127.
90        * \note Changing this property is **not** revertable with a standard "undo"
91        * action. Plugins may need to handle reverting this property change if
92        * necessary.
93        */
94       Q_PROPERTY(int chorus READ chorus WRITE setChorus)
95       /**
96        * Channel reverb, from 0 to 127.
97        * \note Changing this property is **not** revertable with a standard "undo"
98        * action. Plugins may need to handle reverting this property change if
99        * necessary.
100        */
101       Q_PROPERTY(int reverb READ reverb WRITE setReverb)
102       /**
103        * Whether this channel is muted.
104        * \note Changing this property is **not** revertable with a standard "undo"
105        * action. Plugins may need to handle reverting this property change if
106        * necessary.
107        */
108       Q_PROPERTY(bool mute READ mute WRITE setMute)
109 
110       /**
111        * MIDI program number, from 0 to 127. Changing this property is recorded
112        * to the program's undo stack and can be reverted with a standard "undo"
113        * action.
114        */
115       Q_PROPERTY(int midiProgram READ midiProgram WRITE setMidiProgram)
116       /**
117        * MIDI patch bank number. Changing this property is recorded
118        * to the program's undo stack and can be reverted with a standard "undo"
119        * action.
120        */
121       Q_PROPERTY(int midiBank READ midiBank WRITE setMidiBank)
122 
123       Ms::Channel* activeChannel();
124 
125       void setMidiBankAndProgram(int bank, int program, bool setUserBankController);
126 
127    public:
128       /// \cond MS_INTERNAL
129       Channel(Ms::Channel* ch, Ms::Part* p, QObject* parent = nullptr)
QObject(parent)130          : QObject(parent), _channel(ch), _part(p) {}
131 
name()132       QString name() const { return _channel->name(); }
133 
volume()134       int volume() const { return _channel->volume(); }
setVolume(int val)135       void setVolume(int val) { activeChannel()->setVolume(qBound(0, val, 127)); }
pan()136       int pan() const { return _channel->pan(); }
setPan(int val)137       void setPan(int val) { activeChannel()->setPan(qBound(0, val, 127)); }
chorus()138       int chorus() const { return _channel->chorus(); }
setChorus(int val)139       void setChorus(int val) { activeChannel()->setChorus(qBound(0, val, 127)); }
reverb()140       int reverb() const { return _channel->reverb(); }
setReverb(int val)141       void setReverb(int val) { activeChannel()->setReverb(qBound(0, val, 127)); }
142 
mute()143       bool mute() const { return _channel->mute(); }
setMute(bool val)144       void setMute(bool val) { activeChannel()->setMute(val); }
145 
midiProgram()146       int midiProgram() const { return _channel->program(); }
147       void setMidiProgram(int prog);
midiBank()148       int midiBank() const { return _channel->bank(); }
149       void setMidiBank(int bank);
150       /// \endcond
151       };
152 
153 //---------------------------------------------------------
154 //   StringData
155 ///   \since MuseScore 3.5
156 //---------------------------------------------------------
157 
158 class StringData : public QObject {
159       Q_OBJECT
160 
161       /**
162        * List of strings in this instrument.
163        * \returns A list of objects representing strings. Each
164        * object has the following fields:
165        * - \p pitch - pitch of this string on fret 0 (integer).
166        * - \p open - if \p true, this string is not fretted and
167        *             always open. If \p false, the string **is**
168        *             fretted. For example, for classical guitar
169        *             all strings are fretted, and for them
170        *             \p open value will always be \p false.
171        */
172       Q_PROPERTY(QVariantList strings READ stringList)
173 
174       /** Number of frets in this instrument */
175       Q_PROPERTY(int frets READ frets)
176 
177       Ms::StringData _data;
178 
179    public:
180       /// \cond MS_INTERNAL
181       StringData(const Ms::StringData* d, QObject* parent = nullptr)
QObject(parent)182          : QObject(parent), _data(*d) {}
183 
184       QVariantList stringList() const;
frets()185       int frets() const { return _data.frets(); }
186       /// \endcond
187       };
188 
189 //---------------------------------------------------------
190 //   ChannelListProperty
191 ///   \cond PLUGIN_API \private \endcond
192 //---------------------------------------------------------
193 
194 class ChannelListProperty : public QQmlListProperty<Channel> {
195 public:
196       ChannelListProperty(Instrument* i);
197 
198       static int count(QQmlListProperty<Channel>* l);
199       static Channel* at(QQmlListProperty<Channel>* l, int i);
200       };
201 
202 //---------------------------------------------------------
203 //   Instrument
204 ///   \since MuseScore 3.5
205 //---------------------------------------------------------
206 
207 class Instrument : public QObject {
208       Q_OBJECT
209 
210       /**
211        * The string identifier
212        * ([MusicXML Sound ID](https://www.musicxml.com/for-developers/standard-sounds/))
213        * for this instrument.
214        * \see \ref Ms::PluginAPI::Part::instrumentId "Part.instrumentId"
215        */
216       Q_PROPERTY(QString                        instrumentId         READ instrumentId)
217       // Ms::Instrument supports multiple short/long names (for aeolus instruments?)
218       // but in practice only one is actually used. If this gets changed this API could
219       // be expanded.
220       /** The long name for this instrument. */
221       Q_PROPERTY(QString                        longName             READ longName)
222       /** The short name for this instrument. */
223       Q_PROPERTY(QString                        shortName            READ shortName)
224 
225       /**
226        * For fretted instruments, an information about this
227        * instrument's strings.
228        */
229       Q_PROPERTY(Ms::PluginAPI::StringData* stringData READ stringData)
230 
231       // TODO: a property for drumset?
232 
233       Q_PROPERTY(QQmlListProperty<Ms::PluginAPI::Channel> channels READ channels)
234 
235       Ms::Instrument* _instrument;
236       Ms::Part* _part;
237 
238    public:
239       /// \cond MS_INTERNAL
Instrument(Ms::Instrument * i,Ms::Part * p)240       Instrument(Ms::Instrument* i, Ms::Part* p)
241          : QObject(), _instrument(i), _part(p) {}
242 
instrument()243       Ms::Instrument* instrument() { return _instrument; }
instrument()244       const Ms::Instrument* instrument() const { return _instrument; }
245 
part()246       Ms::Part* part() { return _part; }
247 
instrumentId()248       QString instrumentId() const { return instrument()->instrumentId(); }
249       QString longName() const;
250       QString shortName() const;
251 
stringData()252       StringData* stringData() { return customWrap<StringData>(instrument()->stringData()); }
253 
254       ChannelListProperty channels();
255       /// \endcond
256 
257       /** Checks whether two variables represent the same object. */
is(Ms::PluginAPI::Instrument * other)258       Q_INVOKABLE bool is(Ms::PluginAPI::Instrument* other) { return other && instrument() == other->instrument(); }
259       };
260 
261 } // namespace PluginAPI
262 } // namespace Ms
263 
264 #endif
265