29 : lowerZone (other.lowerZone),
30 upperZone (other.upperZone)
36 lowerZone = other.lowerZone;
37 upperZone = other.upperZone;
39 sendLayoutChangeMessage();
44 void MPEZoneLayout::sendLayoutChangeMessage()
50 void MPEZoneLayout::setZone (
bool isLower,
int numMemberChannels,
int perNotePitchbendRange,
int masterPitchbendRange) noexcept
52 checkAndLimitZoneParameters (0, 15, numMemberChannels);
53 checkAndLimitZoneParameters (0, 96, perNotePitchbendRange);
54 checkAndLimitZoneParameters (0, 96, masterPitchbendRange);
57 lowerZone = {
true, numMemberChannels, perNotePitchbendRange, masterPitchbendRange };
59 upperZone = {
false, numMemberChannels, perNotePitchbendRange, masterPitchbendRange };
61 if (numMemberChannels > 0)
63 auto totalChannels = lowerZone.numMemberChannels + upperZone.numMemberChannels;
65 if (totalChannels >= 15)
68 upperZone.numMemberChannels = 14 - numMemberChannels;
70 lowerZone.numMemberChannels = 14 - numMemberChannels;
74 sendLayoutChangeMessage();
79 setZone (
true, numMemberChannels, perNotePitchbendRange, masterPitchbendRange);
84 setZone (
false, numMemberChannels, perNotePitchbendRange, masterPitchbendRange);
89 lowerZone = {
true, 0 };
90 upperZone = {
false, 0 };
92 sendLayoutChangeMessage();
108 processRpnMessage (rpn);
115 processZoneLayoutRpnMessage (rpn);
117 processPitchbendRangeRpnMessage (rpn);
120 void MPEZoneLayout::processZoneLayoutRpnMessage (
MidiRPNMessage rpn)
131 void MPEZoneLayout::updateMasterPitchbend (
Zone& zone,
int value)
133 if (zone.masterPitchbendRange != value)
135 checkAndLimitZoneParameters (0, 96, zone.masterPitchbendRange);
136 zone.masterPitchbendRange = value;
137 sendLayoutChangeMessage();
141 void MPEZoneLayout::updatePerNotePitchbendRange (
Zone& zone,
int value)
143 if (zone.perNotePitchbendRange != value)
145 checkAndLimitZoneParameters (0, 96, zone.perNotePitchbendRange);
146 zone.perNotePitchbendRange = value;
147 sendLayoutChangeMessage();
151 void MPEZoneLayout::processPitchbendRangeRpnMessage (
MidiRPNMessage rpn)
155 updateMasterPitchbend (lowerZone, rpn.
value);
159 updateMasterPitchbend (upperZone, rpn.
value);
163 if (lowerZone.isUsingChannelAsMemberChannel (rpn.
channel))
164 updatePerNotePitchbendRange (lowerZone, rpn.
value);
165 else if (upperZone.isUsingChannelAsMemberChannel (rpn.
channel))
166 updatePerNotePitchbendRange (upperZone, rpn.
value);
183 listeners.add (listenerToAdd);
188 listeners.remove (listenerToRemove);
192 void MPEZoneLayout::checkAndLimitZoneParameters (
int minValue,
int maxValue,
193 int& valueToCheckAndLimit) noexcept
195 if (valueToCheckAndLimit < minValue || valueToCheckAndLimit > maxValue)
204 valueToCheckAndLimit = jlimit (minValue, maxValue, valueToCheckAndLimit);
213 class MPEZoneLayoutTests :
public UnitTest 217 :
UnitTest (
"MPEZoneLayout class", UnitTestCategories::midi)
220 void runTest()
override 222 beginTest (
"initialisation");
229 beginTest (
"adding zones");
237 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
238 expectEquals (layout.
getLowerZone().numMemberChannels, 7);
244 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
245 expectEquals (layout.
getLowerZone().numMemberChannels, 7);
246 expectEquals (layout.
getUpperZone().getMasterChannel(), 16);
247 expectEquals (layout.
getUpperZone().numMemberChannels, 7);
253 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
254 expectEquals (layout.
getLowerZone().numMemberChannels, 3);
255 expectEquals (layout.
getUpperZone().getMasterChannel(), 16);
256 expectEquals (layout.
getUpperZone().numMemberChannels, 7);
262 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
263 expectEquals (layout.
getLowerZone().numMemberChannels, 3);
264 expectEquals (layout.
getUpperZone().getMasterChannel(), 16);
265 expectEquals (layout.
getUpperZone().numMemberChannels, 3);
271 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
272 expectEquals (layout.
getLowerZone().numMemberChannels, 15);
275 beginTest (
"clear all zones");
294 beginTest (
"process MIDI buffers");
304 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
305 expectEquals (layout.
getLowerZone().numMemberChannels, 7);
312 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
313 expectEquals (layout.
getLowerZone().numMemberChannels, 7);
314 expectEquals (layout.
getUpperZone().getMasterChannel(), 16);
315 expectEquals (layout.
getUpperZone().numMemberChannels, 7);
323 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
324 expectEquals (layout.
getLowerZone().numMemberChannels, 10);
325 expectEquals (layout.
getUpperZone().getMasterChannel(), 16);
326 expectEquals (layout.
getUpperZone().numMemberChannels, 4);
332 expectEquals (layout.
getLowerZone().numMemberChannels, 10);
333 expectEquals (layout.
getLowerZone().perNotePitchbendRange, 33);
334 expectEquals (layout.
getLowerZone().masterPitchbendRange, 44);
343 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
344 expectEquals (layout.
getLowerZone().numMemberChannels, 4);
345 expectEquals (layout.
getUpperZone().getMasterChannel(), 16);
346 expectEquals (layout.
getUpperZone().numMemberChannels, 10);
352 expectEquals (layout.
getUpperZone().numMemberChannels, 10);
353 expectEquals (layout.
getUpperZone().perNotePitchbendRange, 33);
354 expectEquals (layout.
getUpperZone().masterPitchbendRange, 44);
364 beginTest (
"process individual MIDI messages");
377 expectEquals (layout.
getLowerZone().getMasterChannel(), 1);
378 expectEquals (layout.
getLowerZone().numMemberChannels, 3);
379 expectEquals (layout.
getLowerZone().perNotePitchbendRange, 48);
380 expectEquals (layout.
getLowerZone().masterPitchbendRange, 2);
385 static MPEZoneLayoutTests MPEZoneLayoutUnitTests;
This class represents the current MPE zone layout of a device capable of handling MPE...
Encapsulates a MIDI message.
This struct represents an MPE zone.
void processNextMidiBuffer(const MidiBuffer &buffer)
Pass incoming MIDI buffers to an object of this class if you want the zone layout to properly react t...
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
Retrieves a copy of the next event from the buffer.
void processNextMidiEvent(const MidiMessage &message)
Pass incoming MIDI messages to an object of this class if you want the zone layout to properly react ...
virtual void zoneLayoutChanged(const MPEZoneLayout &layout)=0
Implement this callback to be notified about any changes to this MPEZoneLayout.
int channel
Midi channel of the message, in the range 1 to 16.
void setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
Sets the upper zone of this layout.
static MidiBuffer setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the upper ...
int value
The parameter value, in the range 0 to 16383 (0x3fff).
static MidiBuffer setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the lower ...
const Zone getUpperZone() const noexcept
Returns a struct representing the upper MPE zone.
static MidiBuffer clearAllZones()
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will clear the lowe...
This is a base class for classes that perform a unit test.
void addListener(Listener *const listenerToAdd) noexcept
Adds a listener.
int getControllerNumber() const noexcept
Returns the controller number of a controller message.
int getChannel() const noexcept
Returns the midi channel associated with the message.
MPEZoneLayout() noexcept
Default constructor.
bool isController() const noexcept
Returns true if this is a midi controller message.
const Zone getLowerZone() const noexcept
Returns a struct representing the lower MPE zone.
Represents a MIDI RPN (registered parameter number) or NRPN (non-registered parameter number) message...
int parameterNumber
The 14-bit parameter index, in the range 0 to 16383 (0x3fff).
Holds a sequence of time-stamped midi events.
void clearAllZones()
Clears the lower and upper zones of this layout, making them both inactive and disabling MPE mode...
int getControllerValue() const noexcept
Returns the controller value from a controller message.
Used to iterate through the events in a MidiBuffer.
MPEZoneLayout & operator=(const MPEZoneLayout &other)
Copy assignment operator.
static const int zoneLayoutMessagesRpnNumber
The RPN number used for MPE zone layout messages.
bool parseControllerMessage(int midiChannel, int controllerNumber, int controllerValue, MidiRPNMessage &result) noexcept
Takes the next in a stream of incoming MIDI CC messages and returns true if it forms the last of a se...
void removeListener(Listener *const listenerToRemove) noexcept
Removes a listener.
void setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
Sets the lower zone of this layout.