MuseScore/libmscore/instrument.h
James Thistlewood 642e79c97e Refactor SND
- move most of the logic to velo.cpp and VeloList
- allow dynamic playback of tremolos
- get velocity directly in note collection code
- allow use of poly aftertouch in the future
2020-01-26 17:17:16 +00:00

366 lines
13 KiB
C++

//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2002-2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#ifndef __INSTRUMENT_H__
#define __INSTRUMENT_H__
#include "stringdata.h"
#include "mscore.h"
#include "notifier.hpp"
#include "synthesizer/event.h"
#include "interval.h"
#include "clef.h"
#include <QtGlobal>
#include <QString>
namespace Ms {
class InstrumentTemplate;
class MasterScore;
class XmlWriter;
class XmlReader;
class Drumset;
class StringData;
class ChannelListener;
class Synthesizer;
//---------------------------------------------------------
// StaffName
//---------------------------------------------------------
class StaffName {
QString _name; // html string
int _pos; // even number -> between staves
public:
StaffName() {}
StaffName(const QString& s, int p=0);
bool operator==(const StaffName&) const;
void read(XmlReader&);
void write(XmlWriter& xml, const char* name) const;
int pos() const { return _pos; }
QString name() const { return _name; }
};
//---------------------------------------------------------
// StaffNameList
//---------------------------------------------------------
class StaffNameList : public QList<StaffName> {
public:
void write(XmlWriter& xml, const char* name) const;
};
//---------------------------------------------------------
// NamedEventList
//---------------------------------------------------------
struct NamedEventList {
QString name;
QString descr;
std::vector<MidiCoreEvent> events;
void write(XmlWriter&, const QString& name) const;
void read(XmlReader&);
bool operator==(const NamedEventList& i) const { return i.name == name && i.events == events; }
};
//---------------------------------------------------------
// MidiArticulation
//---------------------------------------------------------
struct MidiArticulation {
QString name;
QString descr;
int velocity; // velocity change: -100% - +100%
int gateTime; // gate time change: -100% - +100%
void write(XmlWriter&) const;
void read(XmlReader&);
MidiArticulation() {}
MidiArticulation(const QString& n, const QString& d, int v, int g) : name(n), descr(d), velocity(v), gateTime(g) {}
bool operator==(const MidiArticulation& i) const;
};
//---------------------------------------------------------
// Channel
//---------------------------------------------------------
class Channel {
// this are the indexes of controllers which are always present in
// Channel init EventList (maybe zero)
QString _name;
QString _descr;
static const int DEFAULT_COLOR = 0x3399ff;
int _color; //rgb
QString _synti;
char _volume;
char _pan;
char _chorus;
char _reverb;
int _program; // current values as shown in mixer
int _bank; // initialized from "init"
int _channel { 0 }; // mscore channel number, mapped to midi port/channel
bool _soloMute;
bool _mute;
bool _solo;
// MuseScore General-specific SND flags:
bool _userBankController = false; // if the user has changed the bank controller as opposed to switchExpressive
bool _switchedToExpressive = false; // if the patch has been automatically switched to and expr variant
mutable std::vector<MidiCoreEvent> _init;
mutable bool _mustUpdateInit = true;
public:
static const char* DEFAULT_NAME;
static constexpr char defaultVolume = 100;
enum class A : char {
HBANK, LBANK, PROGRAM, VOLUME, PAN, CHORUS, REVERB,
INIT_COUNT
};
enum class Prop : char {
VOLUME, PAN, CHORUS, REVERB, NAME, DESCR, PROGRAM, BANK, COLOR,
SOLOMUTE, SOLO, MUTE, SYNTI, CHANNEL, USER_BANK_CONTROL
};
private:
Notifier<Channel::Prop> _notifier;
void firePropertyChanged(Channel::Prop prop) { _notifier.notify(prop); }
public:
std::vector<MidiCoreEvent>& initList() const;
QString name() const { return _name; }
void setName(const QString& value);
QString descr() const { return _descr; }
void setDescr(const QString& value);
QString synti() const { return _synti; }
void setSynti(const QString& value);
int color() const { return _color; }
void setColor(int value);
char volume() const { return _volume; }
void setVolume(char value);
char pan() const { return _pan; }
void setPan(char value);
char chorus() const { return _chorus; }
void setChorus(char value);
char reverb() const { return _reverb; }
void setReverb(char value);
int program() const { return _program; }
void setProgram(int value);
int bank() const { return _bank; }
void setBank(int value);
int channel() const { return _channel; }
void setChannel(int value);
bool soloMute() const { return _soloMute; }
void setSoloMute(bool value);
bool mute() const { return _mute; }
void setMute(bool value);
bool solo() const { return _solo; }
void setSolo(bool value);
// If the bank controller is set by the user or not
bool userBankController() const { return _userBankController; }
void setUserBankController(bool val);
QList<NamedEventList> midiActions;
QList<MidiArticulation> articulation;
Channel();
void write(XmlWriter&, const Part* part) const;
void read(XmlReader&, Part *part);
void updateInitList() const;
bool operator==(const Channel& c) { return (_name == c._name) && (_channel == c._channel); }
void addListener(ChannelListener* l);
void removeListener(ChannelListener* l);
void switchExpressive(Synthesizer* synth, bool expressive, bool force = false);
};
//---------------------------------------------------------
// ChannelListener
//---------------------------------------------------------
class ChannelListener : public Listener<Channel::Prop> {
public:
virtual void propertyChanged(Channel::Prop property) = 0;
void setNotifier(Channel* ch) { Listener::setNotifier(nullptr); if (ch) ch->addListener(this); }
private:
void receive(Channel::Prop prop) override { propertyChanged(prop); }
};
//---------------------------------------------------------
// PartChannelSettingsLink
//---------------------------------------------------------
class PartChannelSettingsLink final : private ChannelListener {
// A list of properties which may vary for different excerpts.
static const std::initializer_list<Channel::Prop> excerptProperties;
private:
Channel* _main;
Channel* _bound;
bool _excerpt;
static bool isExcerptProperty(Channel::Prop p) { return std::find(excerptProperties.begin(), excerptProperties.end(), p) != excerptProperties.end(); }
static void applyProperty(Channel::Prop p, const Channel* from, Channel* to);
void propertyChanged(Channel::Prop p) override;
public:
PartChannelSettingsLink() : _main(nullptr), _bound(nullptr), _excerpt(false) {}
PartChannelSettingsLink(Channel* main, Channel* bound, bool excerpt);
PartChannelSettingsLink(const PartChannelSettingsLink&) = delete;
PartChannelSettingsLink(PartChannelSettingsLink&&);
PartChannelSettingsLink& operator=(const PartChannelSettingsLink&) = delete;
PartChannelSettingsLink& operator=(PartChannelSettingsLink&&);
~PartChannelSettingsLink() {};
friend void swap(PartChannelSettingsLink&, PartChannelSettingsLink&);
};
//---------------------------------------------------------
// Instrument
//---------------------------------------------------------
class Instrument {
StaffNameList _longNames;
StaffNameList _shortNames;
QString _trackName;
char _minPitchA, _maxPitchA, _minPitchP, _maxPitchP;
Interval _transpose;
QString _instrumentId;
bool _useDrumset;
Drumset* _drumset;
StringData _stringData;
QList<NamedEventList> _midiActions;
QList<MidiArticulation> _articulation;
QList<Channel*> _channel; // at least one entry
QList<ClefTypeList> _clefType;
bool _singleNoteDynamics;
public:
Instrument();
Instrument(const Instrument&);
void operator=(const Instrument&);
~Instrument();
void read(XmlReader&, Part *part);
bool readProperties(XmlReader&, Part* , bool* customDrumset);
void write(XmlWriter& xml, const Part* part) const;
NamedEventList* midiAction(const QString& s, int channel) const;
int channelIdx(const QString& s) const;
void updateVelocity(int* velocity, int channel, const QString& name);
qreal getVelocityMultiplier(const QString& name);
void updateGateTime(int* gateTime, int channelIdx, const QString& name);
bool operator==(const Instrument&) const;
void setMinPitchP(int v) { _minPitchP = v; }
void setMaxPitchP(int v) { _maxPitchP = v; }
void setMinPitchA(int v) { _minPitchA = v; }
void setMaxPitchA(int v) { _maxPitchA = v; }
Interval transpose() const { return _transpose; }
void setTranspose(const Interval& v) { _transpose = v; }
QString instrumentId() { return _instrumentId; }
void setInstrumentId(const QString& instrumentId) { _instrumentId = instrumentId; }
void setDrumset(const Drumset* ds);
const Drumset* drumset() const { return _drumset; }
Drumset* drumset() { return _drumset; }
bool useDrumset() const { return _useDrumset; }
void setUseDrumset(bool val);
void setAmateurPitchRange(int a, int b) { _minPitchA = a; _maxPitchA = b; }
void setProfessionalPitchRange(int a, int b) { _minPitchP = a; _maxPitchP = b; }
Channel* channel(int idx) { return _channel[idx]; }
const Channel* channel(int idx) const { return _channel[idx]; }
Channel* playbackChannel(int idx, MasterScore*);
const Channel* playbackChannel(int idx, const MasterScore*) const;
ClefTypeList clefType(int staffIdx) const;
void setClefType(int staffIdx, const ClefTypeList& c);
const QList<NamedEventList>& midiActions() const { return _midiActions; }
const QList<MidiArticulation>& articulation() const { return _articulation; }
const QList<Channel*>& channel() const { return _channel; }
void appendChannel(Channel* c) { _channel.append(c); }
void clearChannels() { _channel.clear(); }
void setMidiActions(const QList<NamedEventList>& l) { _midiActions = l; }
void setArticulation(const QList<MidiArticulation>& l) { _articulation = l; }
const StringData* stringData() const { return &_stringData; }
void setStringData(const StringData& d) { _stringData = d; }
void setLongName(const QString& f);
void setShortName(const QString& f);
void addLongName(const StaffName& f);
void addShortName(const StaffName& f);
int minPitchP() const;
int maxPitchP() const;
int minPitchA() const;
int maxPitchA() const;
QString instrumentId() const;
const QList<StaffName>& longNames() const;
const QList<StaffName>& shortNames() const;
QList<StaffName>& longNames();
QList<StaffName>& shortNames();
QString trackName() const;
void setTrackName(const QString& s);
static Instrument fromTemplate(const InstrumentTemplate* t);
bool singleNoteDynamics() const { return _singleNoteDynamics; }
void setSingleNoteDynamics(bool val) { _singleNoteDynamics = val; }
void setSingleNoteDynamicsFromTemplate();
bool getSingleNoteDynamicsFromTemplate() const;
void switchExpressive(MasterScore* score, Synthesizer* synth, bool expressive, bool force = false);
};
//---------------------------------------------------------
// InstrumentList
//---------------------------------------------------------
class InstrumentList : public std::map<const int, Instrument*> {
static Instrument defaultInstrument;
public:
InstrumentList() {}
const Instrument* instrument(int tick) const;
Instrument* instrument(int tick);
void setInstrument(Instrument*, int tick);
};
} // namespace Ms
#endif