OpenShot Audio Library | OpenShotAudio  0.3.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 //==============================================================================
112 #if JUCE_UNIT_TESTS
113 
114 class MPEMessagesTests : public UnitTest
115 {
116 public:
117  MPEMessagesTests()
118  : UnitTest ("MPEMessages class", UnitTestCategories::midi)
119  {}
120 
121  void runTest() override
122  {
123  beginTest ("add zone");
124  {
125  {
127 
128  const uint8 expectedBytes[] =
129  {
130  0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x07, // set up zone
131  0xb1, 0x64, 0x00, 0xb1, 0x65, 0x00, 0xb1, 0x06, 0x30, // per-note pbrange (default = 48)
132  0xb0, 0x64, 0x00, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x02 // master pbrange (default = 2)
133  };
134 
135  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
136  }
137  {
138  MidiBuffer buffer = MPEMessages::setUpperZone (5, 96, 0);
139 
140  const uint8 expectedBytes[] =
141  {
142  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x05, // set up zone
143  0xbe, 0x64, 0x00, 0xbe, 0x65, 0x00, 0xbe, 0x06, 0x60, // per-note pbrange (custom)
144  0xbf, 0x64, 0x00, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x00 // master pbrange (custom)
145  };
146 
147  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
148  }
149  }
150 
151  beginTest ("set per-note pitchbend range");
152  {
154 
155  const uint8 expectedBytes[] = { 0xb1, 0x64, 0x00, 0xb1, 0x65, 0x00, 0xb1, 0x06, 0x60 };
156 
157  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
158  }
159 
160 
161  beginTest ("set master pitchbend range");
162  {
164 
165  const uint8 expectedBytes[] = { 0xbf, 0x64, 0x00, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x3c };
166 
167  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
168  }
169 
170  beginTest ("clear all zones");
171  {
173 
174  const uint8 expectedBytes[] = { 0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x00, // clear lower zone
175  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x00 // clear upper zone
176  };
177 
178  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
179  }
180 
181  beginTest ("set complete state");
182  {
183  MPEZoneLayout layout;
184 
185  layout.setLowerZone (7, 96, 0);
186  layout.setUpperZone (7);
187 
188  MidiBuffer buffer = MPEMessages::setZoneLayout (layout);
189 
190  const uint8 expectedBytes[] = {
191  0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x00, // clear lower zone
192  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x00, // clear upper zone
193  0xb0, 0x64, 0x06, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x07, // set lower zone
194  0xb1, 0x64, 0x00, 0xb1, 0x65, 0x00, 0xb1, 0x06, 0x60, // per-note pbrange (custom)
195  0xb0, 0x64, 0x00, 0xb0, 0x65, 0x00, 0xb0, 0x06, 0x00, // master pbrange (custom)
196  0xbf, 0x64, 0x06, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x07, // set upper zone
197  0xbe, 0x64, 0x00, 0xbe, 0x65, 0x00, 0xbe, 0x06, 0x30, // per-note pbrange (default = 48)
198  0xbf, 0x64, 0x00, 0xbf, 0x65, 0x00, 0xbf, 0x06, 0x02 // master pbrange (default = 2)
199  };
200 
201  testMidiBuffer (buffer, expectedBytes, sizeof (expectedBytes));
202  }
203  }
204 
205 private:
206  //==============================================================================
207  void testMidiBuffer (MidiBuffer& buffer, const uint8* expectedBytes, int expectedBytesSize)
208  {
209  uint8 actualBytes[128] = { 0 };
210  extractRawBinaryData (buffer, actualBytes, sizeof (actualBytes));
211 
212  expectEquals (std::memcmp (actualBytes, expectedBytes, (std::size_t) expectedBytesSize), 0);
213  }
214 
215  //==============================================================================
216  void extractRawBinaryData (const MidiBuffer& midiBuffer, const uint8* bufferToCopyTo, std::size_t maxBytes)
217  {
218  std::size_t pos = 0;
219  MidiBuffer::Iterator iter (midiBuffer);
220  MidiMessage midiMessage;
221  int samplePosition; // Note: Not actually used, so no need to initialise.
222 
223  while (iter.getNextEvent (midiMessage, samplePosition))
224  {
225  const uint8* data = midiMessage.getRawData();
226  std::size_t dataSize = (std::size_t) midiMessage.getRawDataSize();
227 
228  if (pos + dataSize > maxBytes)
229  return;
230 
231  std::memcpy ((void*) (bufferToCopyTo + pos), data, dataSize);
232  pos += dataSize;
233  }
234  }
235 };
236 
237 static MPEMessagesTests MPEMessagesUnitTests;
238 
239 #endif
240 
241 } // namespace juce
static MidiBuffer generate(MidiRPNMessage message)
bool getNextEvent(MidiMessage &result, int &samplePosition) noexcept
static MidiBuffer setUpperZonePerNotePitchbendRange(int perNotePitchbendRange=48)
int getRawDataSize() const noexcept
void setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept
static MidiBuffer setUpperZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
static MidiBuffer setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2)
const Zone getUpperZone() const noexcept
static MidiBuffer clearAllZones()
const Zone getLowerZone() const noexcept
static MidiBuffer setLowerZonePerNotePitchbendRange(int perNotePitchbendRange=48)
static MidiBuffer clearUpperZone()
static MidiBuffer clearLowerZone()
static MidiBuffer setLowerZoneMasterPitchbendRange(int masterPitchbendRange=2)
const uint8 * getRawData() const noexcept
static MidiBuffer setZoneLayout(MPEZoneLayout layout)
static MidiBuffer setUpperZoneMasterPitchbendRange(int masterPitchbendRange=2)
void addEvents(const MidiBuffer &otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd)
static const int zoneLayoutMessagesRpnNumber
void setLowerZone(int numMemberChannels=0, int perNotePitchbendRange=48, int masterPitchbendRange=2) noexcept