OpenShot Library | libopenshot-audio  0.2.0
juce_MPEMessages.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 MidiBuffer MPEMessages::setLowerZone (int numMemberChannels, int perNotePitchbendRange, int masterPitchbendRange)
27 {
28  auto buffer = MidiRPNGenerator::generate (1, zoneLayoutMessagesRpnNumber, numMemberChannels, false, false);
29 
30  buffer.addEvents (setLowerZonePerNotePitchbendRange (perNotePitchbendRange), 0, -1, 0);
31  buffer.addEvents (setLowerZoneMasterPitchbendRange (masterPitchbendRange), 0, -1, 0);
32 
33  return buffer;
34 }
35 
36 MidiBuffer MPEMessages::setUpperZone (int numMemberChannels, int perNotePitchbendRange, int masterPitchbendRange)
37 {
38  auto buffer = MidiRPNGenerator::generate (16, zoneLayoutMessagesRpnNumber, numMemberChannels, false, false);
39 
40  buffer.addEvents (setUpperZonePerNotePitchbendRange (perNotePitchbendRange), 0, -1, 0);
41  buffer.addEvents (setUpperZoneMasterPitchbendRange (masterPitchbendRange), 0, -1, 0);
42 
43  return buffer;
44 }
45 
47 {
48  return MidiRPNGenerator::generate (2, 0, perNotePitchbendRange, false, false);
49 }
50 
52 {
53  return MidiRPNGenerator::generate (15, 0, perNotePitchbendRange, false, false);
54 }
55 
57 {
58  return MidiRPNGenerator::generate (1, 0, masterPitchbendRange, false, false);
59 }
60 
62 {
63  return MidiRPNGenerator::generate (16, 0, masterPitchbendRange, false, false);
64 }
65 
67 {
68  return MidiRPNGenerator::generate (1, zoneLayoutMessagesRpnNumber, 0, false, false);
69 }
70 
72 {
73  return MidiRPNGenerator::generate (16, zoneLayoutMessagesRpnNumber, 0, false, false);
74 }
75 
77 {
78  MidiBuffer buffer;
79 
80  buffer.addEvents (clearLowerZone(), 0, -1, 0);
81  buffer.addEvents (clearUpperZone(), 0, -1, 0);
82 
83  return buffer;
84 }
85 
87 {
88  MidiBuffer buffer;
89 
90  buffer.addEvents (clearAllZones(), 0, -1, 0);
91 
92  auto lowerZone = layout.getLowerZone();
93  if (lowerZone.isActive())
94  buffer.addEvents (setLowerZone (lowerZone.numMemberChannels,
95  lowerZone.perNotePitchbendRange,
96  lowerZone.masterPitchbendRange),
97  0, -1, 0);
98 
99  auto upperZone = layout.getUpperZone();
100  if (upperZone.isActive())
101  buffer.addEvents (setUpperZone (upperZone.numMemberChannels,
102  upperZone.perNotePitchbendRange,
103  upperZone.masterPitchbendRange),
104  0, -1, 0);
105 
106  return buffer;
107 }
108 
109 //==============================================================================
110 //==============================================================================
111 #if JUCE_UNIT_TESTS
112 
113 class MPEMessagesTests : public UnitTest
114 {
115 public:
116  MPEMessagesTests() : UnitTest ("MPEMessages class", "MIDI/MPE") {}
117 
118  void runTest() override
119  {
120  beginTest ("add zone");
121  {
122  {
124 
125  const uint8 expectedBytes[] =
126  {
127  0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x07, // set up zone
128  0xb1, 0x64, 0x00, 0xb1, 0x65, 0x00, 0xb1, 0x06, 0x30, // per-note pbrange (default = 48)
129  0xb0, 0x64, 0x00, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x02 // master pbrange (default = 2)
130  };
131 
132  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
133  }
134  {
135  MidiBuffer buffer = MPEMessages::setUpperZone (5, 96, 0);
136 
137  const uint8 expectedBytes[] =
138  {
139  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x05, // set up zone
140  0xbe, 0x64, 0x00, 0xbe, 0x65, 0x00, 0xbe, 0x06, 0x60, // per-note pbrange (custom)
141  0xbf, 0x64, 0x00, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x00 // master pbrange (custom)
142  };
143 
144  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
145  }
146  }
147 
148  beginTest ("set per-note pitchbend range");
149  {
151 
152  const uint8 expectedBytes[] = { 0xb1, 0x64, 0x00, 0xb1, 0x65, 0x00, 0xb1, 0x06, 0x60 };
153 
154  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
155  }
156 
157 
158  beginTest ("set master pitchbend range");
159  {
161 
162  const uint8 expectedBytes[] = { 0xbf, 0x64, 0x00, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x3c };
163 
164  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
165  }
166 
167  beginTest ("clear all zones");
168  {
170 
171  const uint8 expectedBytes[] = { 0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x00, // clear lower zone
172  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x00 // clear upper zone
173  };
174 
175  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
176  }
177 
178  beginTest ("set complete state");
179  {
180  MPEZoneLayout layout;
181 
182  layout.setLowerZone (7, 96, 0);
183  layout.setUpperZone (7);
184 
185  MidiBuffer buffer = MPEMessages::setZoneLayout (layout);
186 
187  const uint8 expectedBytes[] = {
188  0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x00, // clear lower zone
189  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x00, // clear upper zone
190  0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x07, // set lower zone
191  0xb1, 0x64, 0x00, 0xb1, 0x65, 0x00, 0xb1, 0x06, 0x60, // per-note pbrange (custom)
192  0xb0, 0x64, 0x00, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x00, // master pbrange (custom)
193  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x07, // set upper zone
194  0xbe, 0x64, 0x00, 0xbe, 0x65, 0x00, 0xbe, 0x06, 0x30, // per-note pbrange (default = 48)
195  0xbf, 0x64, 0x00, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x02 // master pbrange (default = 2)
196  };
197 
198  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
199  }
200  }
201 
202 private:
203  //==============================================================================
204  void testMidiBuffer (MidiBuffer& buffer, const uint8* expectedBytes, int expectedBytesSize)
205  {
206  uint8 actualBytes[128] = { 0 };
207  extractRawBinaryData (buffer, actualBytes, sizeof (actualBytes));
208 
209  expectEquals (std::memcmp (actualBytes, expectedBytes, (std::size_t) expectedBytesSize), 0);
210  }
211 
212  //==============================================================================
213  void extractRawBinaryData (const MidiBuffer& midiBuffer, const uint8* bufferToCopyTo, std::size_t maxBytes)
214  {
215  std::size_t pos = 0;
216  MidiBuffer::Iterator iter (midiBuffer);
217  MidiMessage midiMessage;
218  int samplePosition; // Note: Not actually used, so no need to initialise.
219 
220  while (iter.getNextEvent (midiMessage, samplePosition))
221  {
222  const uint8* data = midiMessage.getRawData();
223  std::size_t dataSize = (std::size_t) midiMessage.getRawDataSize();
224 
225  if (pos + dataSize > maxBytes)
226  return;
227 
228  std::memcpy ((void*) (bufferToCopyTo + pos), data, dataSize);
229  pos += dataSize;
230  }
231  }
232 };
233 
234 static MPEMessagesTests MPEMessagesUnitTests;
235 
236 #endif // JUCE_UNIT_TESTS
237 
238 } // namespace juce
This class represents the current MPE zone layout of a device capable of handling MPE...
Encapsulates a MIDI message.
static MidiBuffer generate(MidiRPNMessage message)
Generates a MIDI sequence representing the given RPN or NRPN message.
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
Retrieves a copy of the next event from the buffer.
static MidiBuffer setUpperZonePerNotePitchbendRange(int perNotePitchbendRange=48)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the per-no...
int getRawDataSize() const noexcept
Returns the number of bytes of data in the message.
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 ...
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.
Definition: juce_UnitTest.h:73
const Zone getLowerZone() const noexcept
Returns a struct representing the lower MPE zone.
static MidiBuffer setLowerZonePerNotePitchbendRange(int perNotePitchbendRange=48)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the per-no...
static MidiBuffer clearUpperZone()
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will clear the uppe...
static MidiBuffer clearLowerZone()
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will clear the lowe...
static MidiBuffer setLowerZoneMasterPitchbendRange(int masterPitchbendRange=2)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the master...
Holds a sequence of time-stamped midi events.
const uint8 * getRawData() const noexcept
Returns a pointer to the raw midi data.
static MidiBuffer setZoneLayout(MPEZoneLayout layout)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will reset the whol...
static MidiBuffer setUpperZoneMasterPitchbendRange(int masterPitchbendRange=2)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the master...
Used to iterate through the events in a MidiBuffer.
void addEvents(const MidiBuffer &otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd)
Adds some events from another buffer to this one.
static const int zoneLayoutMessagesRpnNumber
The RPN number used for MPE zone layout messages.
void setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
Sets the lower zone of this layout.