29 : lowerZone (other.lowerZone),
30 upperZone (other.upperZone)
36 lowerZone = other.lowerZone;
37 upperZone = other.upperZone;
39 sendLayoutChangeMessage();
44void MPEZoneLayout::sendLayoutChangeMessage()
46 listeners.call ([
this] (Listener& l) { l.zoneLayoutChanged (*
this); });
50void 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);
120void MPEZoneLayout::processZoneLayoutRpnMessage (MidiRPNMessage rpn)
124 if (rpn.channel == 1)
126 else if (rpn.channel == 16)
131void MPEZoneLayout::updateMasterPitchbend (Zone& zone,
int value)
133 if (zone.masterPitchbendRange != value)
135 checkAndLimitZoneParameters (0, 96, zone.masterPitchbendRange);
136 zone.masterPitchbendRange = value;
137 sendLayoutChangeMessage();
141void MPEZoneLayout::updatePerNotePitchbendRange (Zone& zone,
int value)
143 if (zone.perNotePitchbendRange != value)
145 checkAndLimitZoneParameters (0, 96, zone.perNotePitchbendRange);
146 zone.perNotePitchbendRange = value;
147 sendLayoutChangeMessage();
151void MPEZoneLayout::processPitchbendRangeRpnMessage (MidiRPNMessage rpn)
153 if (rpn.channel == 1)
155 updateMasterPitchbend (lowerZone, rpn.value);
157 else if (rpn.channel == 16)
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);
192void MPEZoneLayout::checkAndLimitZoneParameters (
int minValue,
int maxValue,
193 int& valueToCheckAndLimit)
noexcept
195 if (valueToCheckAndLimit < minValue || valueToCheckAndLimit > maxValue)
204 valueToCheckAndLimit = jlimit (minValue, maxValue, valueToCheckAndLimit);
213class MPEZoneLayoutTests :
public UnitTest
217 : UnitTest (
"MPEZoneLayout class", UnitTestCategories::midi)
220 void runTest()
override
222 beginTest (
"initialisation");
224 MPEZoneLayout layout;
225 expect (! layout.getLowerZone().isActive());
226 expect (! layout.getUpperZone().isActive());
229 beginTest (
"adding zones");
231 MPEZoneLayout layout;
233 layout.setLowerZone (7);
235 expect (layout.getLowerZone().isActive());
236 expect (! layout.getUpperZone().isActive());
237 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
238 expectEquals (layout.getLowerZone().numMemberChannels, 7);
240 layout.setUpperZone (7);
242 expect (layout.getLowerZone().isActive());
243 expect (layout.getUpperZone().isActive());
244 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
245 expectEquals (layout.getLowerZone().numMemberChannels, 7);
246 expectEquals (layout.getUpperZone().getMasterChannel(), 16);
247 expectEquals (layout.getUpperZone().numMemberChannels, 7);
249 layout.setLowerZone (3);
251 expect (layout.getLowerZone().isActive());
252 expect (layout.getUpperZone().isActive());
253 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
254 expectEquals (layout.getLowerZone().numMemberChannels, 3);
255 expectEquals (layout.getUpperZone().getMasterChannel(), 16);
256 expectEquals (layout.getUpperZone().numMemberChannels, 7);
258 layout.setUpperZone (3);
260 expect (layout.getLowerZone().isActive());
261 expect (layout.getUpperZone().isActive());
262 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
263 expectEquals (layout.getLowerZone().numMemberChannels, 3);
264 expectEquals (layout.getUpperZone().getMasterChannel(), 16);
265 expectEquals (layout.getUpperZone().numMemberChannels, 3);
267 layout.setLowerZone (15);
269 expect (layout.getLowerZone().isActive());
270 expect (! layout.getUpperZone().isActive());
271 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
272 expectEquals (layout.getLowerZone().numMemberChannels, 15);
275 beginTest (
"clear all zones");
277 MPEZoneLayout layout;
279 expect (! layout.getLowerZone().isActive());
280 expect (! layout.getUpperZone().isActive());
282 layout.setLowerZone (7);
283 layout.setUpperZone (2);
285 expect (layout.getLowerZone().isActive());
286 expect (layout.getUpperZone().isActive());
288 layout.clearAllZones();
290 expect (! layout.getLowerZone().isActive());
291 expect (! layout.getUpperZone().isActive());
294 beginTest (
"process MIDI buffers");
296 MPEZoneLayout layout;
300 layout.processNextMidiBuffer (buffer);
302 expect (layout.getLowerZone().isActive());
303 expect (! layout.getUpperZone().isActive());
304 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
305 expectEquals (layout.getLowerZone().numMemberChannels, 7);
308 layout.processNextMidiBuffer (buffer);
310 expect (layout.getLowerZone().isActive());
311 expect (layout.getUpperZone().isActive());
312 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
313 expectEquals (layout.getLowerZone().numMemberChannels, 7);
314 expectEquals (layout.getUpperZone().getMasterChannel(), 16);
315 expectEquals (layout.getUpperZone().numMemberChannels, 7);
319 layout.processNextMidiBuffer (buffer);
321 expect (layout.getLowerZone().isActive());
322 expect (layout.getUpperZone().isActive());
323 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
324 expectEquals (layout.getLowerZone().numMemberChannels, 10);
325 expectEquals (layout.getUpperZone().getMasterChannel(), 16);
326 expectEquals (layout.getUpperZone().numMemberChannels, 4);
330 layout.processNextMidiBuffer (buffer);
332 expectEquals (layout.getLowerZone().numMemberChannels, 10);
333 expectEquals (layout.getLowerZone().perNotePitchbendRange, 33);
334 expectEquals (layout.getLowerZone().masterPitchbendRange, 44);
339 layout.processNextMidiBuffer (buffer);
341 expect (layout.getLowerZone().isActive());
342 expect (layout.getUpperZone().isActive());
343 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
344 expectEquals (layout.getLowerZone().numMemberChannels, 4);
345 expectEquals (layout.getUpperZone().getMasterChannel(), 16);
346 expectEquals (layout.getUpperZone().numMemberChannels, 10);
350 layout.processNextMidiBuffer (buffer);
352 expectEquals (layout.getUpperZone().numMemberChannels, 10);
353 expectEquals (layout.getUpperZone().perNotePitchbendRange, 33);
354 expectEquals (layout.getUpperZone().masterPitchbendRange, 44);
358 layout.processNextMidiBuffer (buffer);
360 expect (! layout.getLowerZone().isActive());
361 expect (! layout.getUpperZone().isActive());
364 beginTest (
"process individual MIDI messages");
366 MPEZoneLayout layout;
368 layout.processNextMidiEvent ({ 0x80, 0x59, 0xd0 });
369 layout.processNextMidiEvent ({ 0xb0, 0x64, 0x06 });
370 layout.processNextMidiEvent ({ 0xb0, 0x65, 0x00 });
371 layout.processNextMidiEvent ({ 0xb8, 0x0b, 0x66 });
372 layout.processNextMidiEvent ({ 0xb0, 0x06, 0x03 });
373 layout.processNextMidiEvent ({ 0x90, 0x60, 0x00 });
375 expect (layout.getLowerZone().isActive());
376 expect (! layout.getUpperZone().isActive());
377 expectEquals (layout.getLowerZone().getMasterChannel(), 1);
378 expectEquals (layout.getLowerZone().numMemberChannels, 3);
379 expectEquals (layout.getLowerZone().perNotePitchbendRange, 48);
380 expectEquals (layout.getLowerZone().masterPitchbendRange, 2);
385static MPEZoneLayoutTests MPEZoneLayoutUnitTests;
static MidiBuffer setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
static MidiBuffer clearAllZones()
static MidiBuffer setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
static const int zoneLayoutMessagesRpnNumber
void processNextMidiBuffer(const MidiBuffer &buffer)
void setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
void removeListener(Listener *const listenerToRemove) noexcept
void addListener(Listener *const listenerToAdd) noexcept
MPEZoneLayout & operator=(const MPEZoneLayout &other)
void setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
void processNextMidiEvent(const MidiMessage &message)
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
int getChannel() const noexcept
bool isController() const noexcept
int getControllerNumber() const noexcept
int getControllerValue() const noexcept
bool parseControllerMessage(int midiChannel, int controllerNumber, int controllerValue, MidiRPNMessage &result) noexcept