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
23namespace juce
24{
25
26MidiBuffer 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
36MidiBuffer 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{
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
113class MPEMessagesTests : public UnitTest
114{
115public:
116 MPEMessagesTests() : UnitTest ("MPEMessages class", "MIDI/MPE") {}
117
118 void runTest() override
119 {
120 beginTest ("add zone");
121 {
122 {
123 MidiBuffer buffer = MPEMessages::setLowerZone (7);
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 {
150 MidiBuffer buffer = MPEMessages::setLowerZonePerNotePitchbendRange (96);
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 {
160 MidiBuffer buffer = MPEMessages::setUpperZoneMasterPitchbendRange (60);
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 {
169 MidiBuffer buffer = MPEMessages::clearAllZones();
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
202private:
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
234static MPEMessagesTests MPEMessagesUnitTests;
235
236#endif // JUCE_UNIT_TESTS
237
238} // namespace juce
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 setUpperZoneMasterPitchbendRange(int masterPitchbendRange=2)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the master...
static MidiBuffer clearAllZones()
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will clear the lowe...
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 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 ...
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 const int zoneLayoutMessagesRpnNumber
The RPN number used for MPE zone layout messages.
static MidiBuffer setLowerZoneMasterPitchbendRange(int masterPitchbendRange=2)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the master...
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 setUpperZonePerNotePitchbendRange(int perNotePitchbendRange=48)
Returns the sequence of MIDI messages that, if sent to an Expressive MIDI device, will set the per-no...
This class represents the current MPE zone layout of a device capable of handling MPE.
const Zone getUpperZone() const noexcept
Returns a struct representing the upper MPE zone.
const Zone getLowerZone() const noexcept
Returns a struct representing the lower MPE zone.
Holds a sequence of time-stamped midi events.
void addEvents(const MidiBuffer &otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd)
Adds some events from another buffer to this one.
static MidiBuffer generate(MidiRPNMessage message)
Generates a MIDI sequence representing the given RPN or NRPN message.
This is a base class for classes that perform a unit test.