43 enum class Type { lower, upper };
47 MPEZone (Type type,
int memberChannels = 0,
int perNotePitchbend = 48,
int masterPitchbend = 2)
49 numMemberChannels (memberChannels),
50 perNotePitchbendRange (perNotePitchbend),
51 masterPitchbendRange (masterPitchbend)
54 bool isLowerZone()
const noexcept {
return zoneType == Type::lower; }
55 bool isUpperZone()
const noexcept {
return zoneType == Type::upper; }
57 bool isActive()
const noexcept {
return numMemberChannels > 0; }
59 int getMasterChannel()
const noexcept {
return isLowerZone() ? lowerZoneMasterChannel : upperZoneMasterChannel; }
60 int getFirstMemberChannel()
const noexcept {
return isLowerZone() ? lowerZoneMasterChannel + 1 : upperZoneMasterChannel - 1; }
61 int getLastMemberChannel()
const noexcept {
return isLowerZone() ? (lowerZoneMasterChannel + numMemberChannels)
62 : (upperZoneMasterChannel - numMemberChannels); }
64 bool isUsingChannelAsMemberChannel (
int channel)
const noexcept
66 return isLowerZone() ? (lowerZoneMasterChannel < channel && channel <= getLastMemberChannel())
67 : (channel < upperZoneMasterChannel && getLastMemberChannel() <= channel);
70 bool isUsing (
int channel)
const noexcept
72 return isUsingChannelAsMemberChannel (channel) || channel == getMasterChannel();
75 static auto tie (
const MPEZone& z)
77 return std::tie (z.zoneType,
79 z.perNotePitchbendRange,
80 z.masterPitchbendRange);
83 bool operator== (
const MPEZone& other)
const
85 return tie (*
this) == tie (other);
88 bool operator!= (
const MPEZone& other)
const
90 return tie (*
this) != tie (other);
94 static constexpr int lowerZoneMasterChannel = 1,
95 upperZoneMasterChannel = 16;
97 Type zoneType = Type::lower;
99 int numMemberChannels = 0;
100 int perNotePitchbendRange = 48;
101 int masterPitchbendRange = 2;
138 bool operator== (
const MPEZoneLayout& other)
const {
return lowerZone == other.lowerZone && upperZone == other.upperZone; }
139 bool operator!= (
const MPEZoneLayout& other)
const {
return ! operator== (other); }
149 void setLowerZone (
int numMemberChannels = 0,
150 int perNotePitchbendRange = 48,
151 int masterPitchbendRange = 2) noexcept;
154 void setUpperZone (
int numMemberChannels = 0,
155 int perNotePitchbendRange = 48,
156 int masterPitchbendRange = 2) noexcept;
161 void clearAllZones();
164 bool isActive()
const {
return lowerZone.isActive() || upperZone.isActive(); }
178 void processNextMidiEvent (
const MidiMessage& message);
191 void processNextMidiBuffer (
const MidiBuffer& buffer);
212 void addListener (
Listener*
const listenerToAdd)
noexcept;
215 void removeListener (
Listener*
const listenerToRemove)
noexcept;
223 MPEZone lowerZone { MPEZone::Type::lower, 0 };
224 MPEZone upperZone { MPEZone::Type::upper, 0 };
226 MidiRPNDetector rpnDetector;
227 ListenerList<Listener> listeners;
230 void setZone (
bool,
int,
int,
int)
noexcept;
232 void processRpnMessage (MidiRPNMessage);
233 void processZoneLayoutRpnMessage (MidiRPNMessage);
234 void processPitchbendRangeRpnMessage (MidiRPNMessage);
236 void updateMasterPitchbend (MPEZone&,
int);
237 void updatePerNotePitchbendRange (MPEZone&,
int);
239 void sendLayoutChangeMessage();
240 void checkAndLimitZoneParameters (
int,
int,
int&)
noexcept;