OpenShot Audio Library | OpenShotAudio 0.4.0
Loading...
Searching...
No Matches
juce_UMPConversion.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
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#ifndef DOXYGEN
24
25namespace juce::universal_midi_packets
26{
27
33{
34 constexpr BytestreamMidiView (Span<const std::byte> bytesIn, double timestampIn)
35 : bytes (bytesIn), timestamp (timestampIn) {}
36
42 explicit BytestreamMidiView (const MidiMessage* msg)
43 : bytes (unalignedPointerCast<const std::byte*> (msg->getRawData()),
44 static_cast<size_t> (msg->getRawDataSize())),
45 timestamp (msg->getTimeStamp()) {}
46
47 explicit BytestreamMidiView (const MidiMessageMetadata msg)
48 : bytes (unalignedPointerCast<const std::byte*> (msg.data),
49 static_cast<size_t> (msg.numBytes)),
50 timestamp (msg.samplePosition) {}
51
52 MidiMessage getMessage() const
53 {
54 return MidiMessage (bytes.data(), (int) bytes.size(), timestamp);
55 }
56
57 bool isSysEx() const
58 {
59 return ! bytes.empty() && bytes.front() == std::byte { 0xf0 };
60 }
61
62 Span<const std::byte> bytes;
63 double timestamp = 0.0;
64};
65
73{
78 template <typename PacketCallbackFunction>
79 static void toMidi1 (const BytestreamMidiView& m, PacketCallbackFunction&& callback)
80 {
81 const auto size = m.bytes.size();
82
83 if (size <= 0)
84 return;
85
86 const auto* data = m.bytes.data();
87 const auto firstByte = data[0];
88
89 if (firstByte != std::byte { 0xf0 })
90 {
91 const auto mask = [size]() -> uint32_t
92 {
93 switch (size)
94 {
95 case 0: return 0xff000000;
96 case 1: return 0xffff0000;
97 case 2: return 0xffffff00;
98 case 3: return 0xffffffff;
99 }
100
101 return 0x00000000;
102 }();
103
104 const auto extraByte = ((((firstByte & std::byte { 0xf0 }) == std::byte { 0xf0 }) ? std::byte { 0x1 } : std::byte { 0x2 }) << 0x4);
105 const PacketX1 packet { mask & Utils::bytesToWord (extraByte, data[0], data[1], data[2]) };
106 callback (View (packet.data()));
107 return;
108 }
109
110 const auto numSysExBytes = (ssize_t) (size - 2);
111 const auto numMessages = SysEx7::getNumPacketsRequiredForDataSize ((uint32_t) numSysExBytes);
112 auto* dataOffset = data + 1;
113
114 if (numMessages <= 1)
115 {
116 const auto packet = Factory::makeSysExIn1Packet (0, (uint8_t) numSysExBytes, dataOffset);
117 callback (View (packet.data()));
118 return;
119 }
120
121 constexpr ssize_t byteIncrement = 6;
122
123 for (auto i = static_cast<ssize_t> (numSysExBytes); i > 0; i -= byteIncrement, dataOffset += byteIncrement)
124 {
125 const auto func = [&]
126 {
127 if (i == numSysExBytes)
128 return Factory::makeSysExStart;
129
130 if (i <= byteIncrement)
131 return Factory::makeSysExEnd;
132
133 return Factory::makeSysExContinue;
134 }();
135
136 const auto bytesNow = std::min (byteIncrement, i);
137 const auto packet = func (0, (uint8_t) bytesNow, dataOffset);
138 callback (View (packet.data()));
139 }
140 }
141
143 static uint8_t scaleTo8 (uint8_t word7Bit)
144 {
145 const auto shifted = (uint8_t) (word7Bit << 0x1);
146 const auto repeat = (uint8_t) (word7Bit & 0x3f);
147 const auto mask = (uint8_t) (word7Bit <= 0x40 ? 0x0 : 0xff);
148 return (uint8_t) (shifted | ((repeat >> 5) & mask));
149 }
150
152 static uint16_t scaleTo16 (uint8_t word7Bit)
153 {
154 const auto shifted = (uint16_t) (word7Bit << 0x9);
155 const auto repeat = (uint16_t) (word7Bit & 0x3f);
156 const auto mask = (uint16_t) (word7Bit <= 0x40 ? 0x0 : 0xffff);
157 return (uint16_t) (shifted | (((repeat << 3) | (repeat >> 3)) & mask));
158 }
159
161 static uint16_t scaleTo16 (uint16_t word14Bit)
162 {
163 const auto shifted = (uint16_t) (word14Bit << 0x2);
164 const auto repeat = (uint16_t) (word14Bit & 0x1fff);
165 const auto mask = (uint16_t) (word14Bit <= 0x2000 ? 0x0 : 0xffff);
166 return (uint16_t) (shifted | ((repeat >> 11) & mask));
167 }
168
170 static uint32_t scaleTo32 (uint8_t word7Bit)
171 {
172 const auto shifted = (uint32_t) (word7Bit << 0x19);
173 const auto repeat = (uint32_t) (word7Bit & 0x3f);
174 const auto mask = (uint32_t) (word7Bit <= 0x40 ? 0x0 : 0xffffffff);
175 return (uint32_t) (shifted | (((repeat << 19)
176 | (repeat << 13)
177 | (repeat << 7)
178 | (repeat << 1)
179 | (repeat >> 5)) & mask));
180 }
181
183 static uint32_t scaleTo32 (uint16_t word14Bit)
184 {
185 const auto shifted = (uint32_t) (word14Bit << 0x12);
186 const auto repeat = (uint32_t) (word14Bit & 0x1fff);
187 const auto mask = (uint32_t) (word14Bit <= 0x2000 ? 0x0 : 0xffffffff);
188 return (uint32_t) (shifted | (((repeat << 5) | (repeat >> 8)) & mask));
189 }
190
192 static uint8_t scaleTo7 (uint8_t word8Bit) { return (uint8_t) (word8Bit >> 1); }
193
195 static uint8_t scaleTo7 (uint16_t word16Bit) { return (uint8_t) (word16Bit >> 9); }
196
198 static uint8_t scaleTo7 (uint32_t word32Bit) { return (uint8_t) (word32Bit >> 25); }
199
201 static uint16_t scaleTo14 (uint16_t word16Bit) { return (uint16_t) (word16Bit >> 2); }
202
204 static uint16_t scaleTo14 (uint32_t word32Bit) { return (uint16_t) (word32Bit >> 18); }
205
215 template <typename Callback>
216 static void midi2ToMidi1DefaultTranslation (const View& v, Callback&& callback)
217 {
218 const auto firstWord = v[0];
219
220 if (Utils::getMessageType (firstWord) != 0x4)
221 {
222 callback (v);
223 return;
224 }
225
226 const auto status = Utils::getStatus (firstWord);
227 const auto typeAndGroup = ((std::byte { 0x2 } << 0x4) | std::byte { Utils::getGroup (firstWord) });
228
229 switch (status)
230 {
231 case 0x8: // note off
232 case 0x9: // note on
233 case 0xa: // poly pressure
234 case 0xb: // control change
235 {
236 const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff);
237 const auto byte2 = std::byte ((firstWord >> 0x08) & 0xff);
238 const auto byte3 = std::byte { scaleTo7 (v[1]) };
239
240 // If this is a note-on, and the scaled byte is 0,
241 // the scaled velocity should be 1 instead of 0
242 const auto needsCorrection = status == 0x9 && byte3 == std::byte { 0 };
243 const auto correctedByte = needsCorrection ? std::byte { 1 } : byte3;
244
245 const auto shouldIgnore = status == 0xb && [&]
246 {
247 switch (uint8_t (byte2))
248 {
249 case 0:
250 case 6:
251 case 32:
252 case 38:
253 case 98:
254 case 99:
255 case 100:
256 case 101:
257 return true;
258 }
259
260 return false;
261 }();
262
263 if (shouldIgnore)
264 return;
265
266 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
267 statusAndChannel,
268 byte2,
269 correctedByte) };
270 callback (View (packet.data()));
271 return;
272 }
273
274 case 0xd: // channel pressure
275 {
276 const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff);
277 const auto byte2 = std::byte { scaleTo7 (v[1]) };
278
279 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
280 statusAndChannel,
281 byte2,
282 std::byte { 0 }) };
283 callback (View (packet.data()));
284 return;
285 }
286
287 case 0x2: // rpn
288 case 0x3: // nrpn
289 {
290 const auto ccX = status == 0x2 ? std::byte { 101 } : std::byte { 99 };
291 const auto ccY = status == 0x2 ? std::byte { 100 } : std::byte { 98 };
292 const auto statusAndChannel = std::byte ((0xb << 0x4) | Utils::getChannel (firstWord));
293 const auto data = scaleTo14 (v[1]);
294
295 const PacketX1 packets[]
296 {
297 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccX, std::byte ((firstWord >> 0x8) & 0x7f)) },
298 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, ccY, std::byte ((firstWord >> 0x0) & 0x7f)) },
299 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 6 }, std::byte ((data >> 0x7) & 0x7f)) },
300 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 38 }, std::byte ((data >> 0x0) & 0x7f)) },
301 };
302
303 for (const auto& packet : packets)
304 callback (View (packet.data()));
305
306 return;
307 }
308
309 case 0xc: // program change / bank select
310 {
311 if (firstWord & 1)
312 {
313 const auto statusAndChannel = std::byte ((0xb << 0x4) | Utils::getChannel (firstWord));
314 const auto secondWord = v[1];
315
316 const PacketX1 packets[]
317 {
318 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 0 }, std::byte ((secondWord >> 0x8) & 0x7f)) },
319 PacketX1 { Utils::bytesToWord (typeAndGroup, statusAndChannel, std::byte { 32 }, std::byte ((secondWord >> 0x0) & 0x7f)) },
320 };
321
322 for (const auto& packet : packets)
323 callback (View (packet.data()));
324 }
325
326 const auto statusAndChannel = std::byte ((0xc << 0x4) | Utils::getChannel (firstWord));
327 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
328 statusAndChannel,
329 std::byte ((v[1] >> 0x18) & 0x7f),
330 std::byte { 0 }) };
331 callback (View (packet.data()));
332 return;
333 }
334
335 case 0xe: // pitch bend
336 {
337 const auto data = scaleTo14 (v[1]);
338 const auto statusAndChannel = std::byte ((firstWord >> 0x10) & 0xff);
339 const PacketX1 packet { Utils::bytesToWord (typeAndGroup,
340 statusAndChannel,
341 std::byte (data & 0x7f),
342 std::byte ((data >> 7) & 0x7f)) };
343 callback (View (packet.data()));
344 return;
345 }
346
347 default: // other message types do not translate
348 return;
349 }
350 }
351};
352
353} // namespace juce::universal_midi_packets
354
355#endif
static uint16_t scaleTo14(uint32_t word32Bit)
static uint16_t scaleTo16(uint16_t word14Bit)
static uint16_t scaleTo14(uint16_t word16Bit)
static void midi2ToMidi1DefaultTranslation(const View &v, Callback &&callback)
static uint32_t scaleTo32(uint8_t word7Bit)
static uint32_t scaleTo32(uint16_t word14Bit)
static uint16_t scaleTo16(uint8_t word7Bit)
static uint8_t scaleTo7(uint16_t word16Bit)
static void toMidi1(const BytestreamMidiView &m, PacketCallbackFunction &&callback)
static uint8_t scaleTo8(uint8_t word7Bit)
static uint8_t scaleTo7(uint8_t word8Bit)
static uint8_t scaleTo7(uint32_t word32Bit)
static uint32_t getNumPacketsRequiredForDataSize(uint32_t)
static constexpr uint32_t bytesToWord(std::byte a, std::byte b, std::byte c, std::byte d)