OpenShot Audio Library | OpenShotAudio  0.6.0
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 
25 namespace 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 
72 struct Conversion
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)
Definition: juce_UMPUtils.h:36