Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1159 lines
44KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2016 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of the ISC license
  6. http://www.isc.org/downloads/software-support-policy/isc-license/
  7. Permission to use, copy, modify, and/or distribute this software for any
  8. purpose with or without fee is hereby granted, provided that the above
  9. copyright notice and this permission notice appear in all copies.
  10. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  11. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  12. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  13. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  14. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  16. OF THIS SOFTWARE.
  17. -----------------------------------------------------------------------------
  18. To release a closed-source product which uses other parts of JUCE not
  19. licensed under the ISC terms, commercial licenses are available: visit
  20. www.juce.com for more information.
  21. ==============================================================================
  22. */
  23. #include "juce_MidiMessage.h"
  24. #include "../maths/juce_MathsFunctions.h"
  25. #include "../memory/juce_HeapBlock.h"
  26. namespace water {
  27. namespace MidiHelpers
  28. {
  29. inline uint8 initialByte (const int type, const int channel) noexcept
  30. {
  31. return (uint8) (type | jlimit (0, 15, channel - 1));
  32. }
  33. inline uint8 validVelocity (const int v) noexcept
  34. {
  35. return (uint8) jlimit (0, 127, v);
  36. }
  37. }
  38. //==============================================================================
  39. uint8 MidiMessage::floatValueToMidiByte (const float v) noexcept
  40. {
  41. return MidiHelpers::validVelocity (roundToInt (v * 127.0f));
  42. }
  43. uint16 MidiMessage::pitchbendToPitchwheelPos (const float pitchbend,
  44. const float pitchbendRange) noexcept
  45. {
  46. // can't translate a pitchbend value that is outside of the given range!
  47. jassert (std::abs (pitchbend) <= pitchbendRange);
  48. return static_cast<uint16> (pitchbend > 0.0f
  49. ? jmap (pitchbend, 0.0f, pitchbendRange, 8192.0f, 16383.0f)
  50. : jmap (pitchbend, -pitchbendRange, 0.0f, 0.0f, 8192.0f));
  51. }
  52. //==============================================================================
  53. int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept
  54. {
  55. numBytesUsed = 0;
  56. int v = 0, i;
  57. do
  58. {
  59. i = (int) *data++;
  60. if (++numBytesUsed > 6)
  61. break;
  62. v = (v << 7) + (i & 0x7f);
  63. } while (i & 0x80);
  64. return v;
  65. }
  66. int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) noexcept
  67. {
  68. // this method only works for valid starting bytes of a short midi message
  69. jassert (firstByte >= 0x80 && firstByte != 0xf0 && firstByte != 0xf7);
  70. static const char messageLengths[] =
  71. {
  72. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  73. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  74. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  75. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  76. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  77. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  78. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  79. 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  80. };
  81. return messageLengths [firstByte & 0x7f];
  82. }
  83. //==============================================================================
  84. MidiMessage::MidiMessage() noexcept
  85. : timeStamp (0), size (2)
  86. {
  87. packedData.asBytes[0] = 0xf0;
  88. packedData.asBytes[1] = 0xf7;
  89. }
  90. MidiMessage::MidiMessage (const void* const d, const int dataSize, const double t)
  91. : timeStamp (t), size (dataSize)
  92. {
  93. jassert (dataSize > 0);
  94. // this checks that the length matches the data..
  95. jassert (dataSize > 3 || *(uint8*)d >= 0xf0 || getMessageLengthFromFirstByte (*(uint8*)d) == size);
  96. memcpy (allocateSpace (dataSize), d, (size_t) dataSize);
  97. }
  98. MidiMessage::MidiMessage (const int byte1, const double t) noexcept
  99. : timeStamp (t), size (1)
  100. {
  101. packedData.asBytes[0] = (uint8) byte1;
  102. // check that the length matches the data..
  103. jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 1);
  104. }
  105. MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noexcept
  106. : timeStamp (t), size (2)
  107. {
  108. packedData.asBytes[0] = (uint8) byte1;
  109. packedData.asBytes[1] = (uint8) byte2;
  110. // check that the length matches the data..
  111. jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 2);
  112. }
  113. MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, const double t) noexcept
  114. : timeStamp (t), size (3)
  115. {
  116. packedData.asBytes[0] = (uint8) byte1;
  117. packedData.asBytes[1] = (uint8) byte2;
  118. packedData.asBytes[2] = (uint8) byte3;
  119. // check that the length matches the data..
  120. jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 3);
  121. }
  122. MidiMessage::MidiMessage (const MidiMessage& other)
  123. : timeStamp (other.timeStamp), size (other.size)
  124. {
  125. if (isHeapAllocated())
  126. memcpy (allocateSpace (size), other.getData(), (size_t) size);
  127. else
  128. packedData.allocatedData = other.packedData.allocatedData;
  129. }
  130. MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
  131. : timeStamp (newTimeStamp), size (other.size)
  132. {
  133. if (isHeapAllocated())
  134. memcpy (allocateSpace (size), other.getData(), (size_t) size);
  135. else
  136. packedData.allocatedData = other.packedData.allocatedData;
  137. }
  138. MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte,
  139. double t, bool sysexHasEmbeddedLength)
  140. : timeStamp (t)
  141. {
  142. const uint8* src = static_cast<const uint8*> (srcData);
  143. unsigned int byte = (unsigned int) *src;
  144. if (byte < 0x80)
  145. {
  146. byte = (unsigned int) (uint8) lastStatusByte;
  147. numBytesUsed = -1;
  148. }
  149. else
  150. {
  151. numBytesUsed = 0;
  152. --sz;
  153. ++src;
  154. }
  155. if (byte >= 0x80)
  156. {
  157. if (byte == 0xf0)
  158. {
  159. const uint8* d = src;
  160. bool haveReadAllLengthBytes = ! sysexHasEmbeddedLength;
  161. int numVariableLengthSysexBytes = 0;
  162. while (d < src + sz)
  163. {
  164. if (*d >= 0x80)
  165. {
  166. if (*d == 0xf7)
  167. {
  168. ++d; // include the trailing 0xf7 when we hit it
  169. break;
  170. }
  171. if (haveReadAllLengthBytes) // if we see a 0x80 bit set after the initial data length
  172. break; // bytes, assume it's the end of the sysex
  173. ++numVariableLengthSysexBytes;
  174. }
  175. else if (! haveReadAllLengthBytes)
  176. {
  177. haveReadAllLengthBytes = true;
  178. ++numVariableLengthSysexBytes;
  179. }
  180. ++d;
  181. }
  182. src += numVariableLengthSysexBytes;
  183. size = 1 + (int) (d - src);
  184. uint8* dest = allocateSpace (size);
  185. *dest = (uint8) byte;
  186. memcpy (dest + 1, src, (size_t) (size - 1));
  187. numBytesUsed += numVariableLengthSysexBytes; // (these aren't counted in the size)
  188. }
  189. else if (byte == 0xff)
  190. {
  191. int n;
  192. const int bytesLeft = readVariableLengthVal (src + 1, n);
  193. size = jmin (sz + 1, n + 2 + bytesLeft);
  194. uint8* dest = allocateSpace (size);
  195. *dest = (uint8) byte;
  196. memcpy (dest + 1, src, (size_t) size - 1);
  197. }
  198. else
  199. {
  200. size = getMessageLengthFromFirstByte ((uint8) byte);
  201. packedData.asBytes[0] = (uint8) byte;
  202. if (size > 1)
  203. {
  204. packedData.asBytes[1] = src[0];
  205. if (size > 2)
  206. packedData.asBytes[2] = src[1];
  207. }
  208. }
  209. numBytesUsed += size;
  210. }
  211. else
  212. {
  213. packedData.allocatedData = nullptr;
  214. size = 0;
  215. }
  216. }
  217. MidiMessage& MidiMessage::operator= (const MidiMessage& other)
  218. {
  219. if (this != &other)
  220. {
  221. if (other.isHeapAllocated())
  222. {
  223. if (isHeapAllocated())
  224. packedData.allocatedData = static_cast<uint8*> (std::realloc (packedData.allocatedData, (size_t) other.size));
  225. else
  226. packedData.allocatedData = static_cast<uint8*> (std::malloc ((size_t) other.size));
  227. memcpy (packedData.allocatedData, other.packedData.allocatedData, (size_t) other.size);
  228. }
  229. else
  230. {
  231. if (isHeapAllocated())
  232. std::free (packedData.allocatedData);
  233. packedData.allocatedData = other.packedData.allocatedData;
  234. }
  235. timeStamp = other.timeStamp;
  236. size = other.size;
  237. }
  238. return *this;
  239. }
  240. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  241. MidiMessage::MidiMessage (MidiMessage&& other) noexcept
  242. : timeStamp (other.timeStamp), size (other.size)
  243. {
  244. packedData.allocatedData = other.packedData.allocatedData;
  245. other.size = 0;
  246. }
  247. MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
  248. {
  249. packedData.allocatedData = other.packedData.allocatedData;
  250. timeStamp = other.timeStamp;
  251. size = other.size;
  252. other.size = 0;
  253. return *this;
  254. }
  255. #endif
  256. MidiMessage::~MidiMessage() noexcept
  257. {
  258. if (isHeapAllocated())
  259. std::free (packedData.allocatedData);
  260. }
  261. uint8* MidiMessage::allocateSpace (int bytes)
  262. {
  263. if (bytes > (int) sizeof (packedData))
  264. {
  265. uint8* d = static_cast<uint8*> (std::malloc ((size_t) bytes));
  266. packedData.allocatedData = d;
  267. return d;
  268. }
  269. return packedData.asBytes;
  270. }
  271. String MidiMessage::getDescription() const
  272. {
  273. if (isNoteOn()) return "Note on " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + " Velocity " + String (getVelocity()) + " Channel " + String (getChannel());
  274. if (isNoteOff()) return "Note off " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + " Velocity " + String (getVelocity()) + " Channel " + String (getChannel());
  275. if (isProgramChange()) return "Program change " + String (getProgramChangeNumber()) + " Channel " + String (getChannel());
  276. if (isPitchWheel()) return "Pitch wheel " + String (getPitchWheelValue()) + " Channel " + String (getChannel());
  277. if (isAftertouch()) return "Aftertouch " + MidiMessage::getMidiNoteName (getNoteNumber(), true, true, 3) + ": " + String (getAfterTouchValue()) + " Channel " + String (getChannel());
  278. if (isChannelPressure()) return "Channel pressure " + String (getChannelPressureValue()) + " Channel " + String (getChannel());
  279. if (isAllNotesOff()) return "All notes off Channel " + String (getChannel());
  280. if (isAllSoundOff()) return "All sound off Channel " + String (getChannel());
  281. if (isMetaEvent()) return "Meta event";
  282. if (isController())
  283. {
  284. String name (MidiMessage::getControllerName (getControllerNumber()));
  285. if (name.isEmpty())
  286. name = String (getControllerNumber());
  287. return "Controller " + name + ": " + String (getControllerValue()) + " Channel " + String (getChannel());
  288. }
  289. return String::toHexString (getRawData(), getRawDataSize());
  290. }
  291. int MidiMessage::getChannel() const noexcept
  292. {
  293. const uint8* const data = getRawData();
  294. if ((data[0] & 0xf0) != 0xf0)
  295. return (data[0] & 0xf) + 1;
  296. return 0;
  297. }
  298. bool MidiMessage::isForChannel (const int channel) const noexcept
  299. {
  300. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  301. const uint8* const data = getRawData();
  302. return ((data[0] & 0xf) == channel - 1)
  303. && ((data[0] & 0xf0) != 0xf0);
  304. }
  305. void MidiMessage::setChannel (const int channel) noexcept
  306. {
  307. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  308. uint8* const data = getData();
  309. if ((data[0] & 0xf0) != (uint8) 0xf0)
  310. data[0] = (uint8) ((data[0] & (uint8) 0xf0)
  311. | (uint8)(channel - 1));
  312. }
  313. bool MidiMessage::isNoteOn (const bool returnTrueForVelocity0) const noexcept
  314. {
  315. const uint8* const data = getRawData();
  316. return ((data[0] & 0xf0) == 0x90)
  317. && (returnTrueForVelocity0 || data[2] != 0);
  318. }
  319. bool MidiMessage::isNoteOff (const bool returnTrueForNoteOnVelocity0) const noexcept
  320. {
  321. const uint8* const data = getRawData();
  322. return ((data[0] & 0xf0) == 0x80)
  323. || (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
  324. }
  325. bool MidiMessage::isNoteOnOrOff() const noexcept
  326. {
  327. const uint8* const data = getRawData();
  328. const int d = data[0] & 0xf0;
  329. return (d == 0x90) || (d == 0x80);
  330. }
  331. int MidiMessage::getNoteNumber() const noexcept
  332. {
  333. return getRawData()[1];
  334. }
  335. void MidiMessage::setNoteNumber (const int newNoteNumber) noexcept
  336. {
  337. if (isNoteOnOrOff() || isAftertouch())
  338. getData()[1] = (uint8) (newNoteNumber & 127);
  339. }
  340. uint8 MidiMessage::getVelocity() const noexcept
  341. {
  342. if (isNoteOnOrOff())
  343. return getRawData()[2];
  344. return 0;
  345. }
  346. float MidiMessage::getFloatVelocity() const noexcept
  347. {
  348. return getVelocity() * (1.0f / 127.0f);
  349. }
  350. void MidiMessage::setVelocity (const float newVelocity) noexcept
  351. {
  352. if (isNoteOnOrOff())
  353. getData()[2] = floatValueToMidiByte (newVelocity);
  354. }
  355. void MidiMessage::multiplyVelocity (const float scaleFactor) noexcept
  356. {
  357. if (isNoteOnOrOff())
  358. {
  359. uint8* const data = getData();
  360. data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
  361. }
  362. }
  363. bool MidiMessage::isAftertouch() const noexcept
  364. {
  365. return (getRawData()[0] & 0xf0) == 0xa0;
  366. }
  367. int MidiMessage::getAfterTouchValue() const noexcept
  368. {
  369. jassert (isAftertouch());
  370. return getRawData()[2];
  371. }
  372. MidiMessage MidiMessage::aftertouchChange (const int channel,
  373. const int noteNum,
  374. const int aftertouchValue) noexcept
  375. {
  376. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  377. jassert (isPositiveAndBelow (noteNum, (int) 128));
  378. jassert (isPositiveAndBelow (aftertouchValue, (int) 128));
  379. return MidiMessage (MidiHelpers::initialByte (0xa0, channel),
  380. noteNum & 0x7f,
  381. aftertouchValue & 0x7f);
  382. }
  383. bool MidiMessage::isChannelPressure() const noexcept
  384. {
  385. return (getRawData()[0] & 0xf0) == 0xd0;
  386. }
  387. int MidiMessage::getChannelPressureValue() const noexcept
  388. {
  389. jassert (isChannelPressure());
  390. return getRawData()[1];
  391. }
  392. MidiMessage MidiMessage::channelPressureChange (const int channel, const int pressure) noexcept
  393. {
  394. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  395. jassert (isPositiveAndBelow (pressure, (int) 128));
  396. return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
  397. }
  398. bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && getRawData()[2] >= 64; }
  399. bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && getRawData()[2] < 64; }
  400. bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && getRawData()[2] >= 64; }
  401. bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && getRawData()[2] < 64; }
  402. bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && getRawData()[2] >= 64; }
  403. bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && getRawData()[2] < 64; }
  404. bool MidiMessage::isProgramChange() const noexcept
  405. {
  406. return (getRawData()[0] & 0xf0) == 0xc0;
  407. }
  408. int MidiMessage::getProgramChangeNumber() const noexcept
  409. {
  410. jassert (isProgramChange());
  411. return getRawData()[1];
  412. }
  413. MidiMessage MidiMessage::programChange (const int channel, const int programNumber) noexcept
  414. {
  415. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  416. return MidiMessage (MidiHelpers::initialByte (0xc0, channel), programNumber & 0x7f);
  417. }
  418. bool MidiMessage::isPitchWheel() const noexcept
  419. {
  420. return (getRawData()[0] & 0xf0) == 0xe0;
  421. }
  422. int MidiMessage::getPitchWheelValue() const noexcept
  423. {
  424. jassert (isPitchWheel());
  425. const uint8* const data = getRawData();
  426. return data[1] | (data[2] << 7);
  427. }
  428. MidiMessage MidiMessage::pitchWheel (const int channel, const int position) noexcept
  429. {
  430. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  431. jassert (isPositiveAndBelow (position, (int) 0x4000));
  432. return MidiMessage (MidiHelpers::initialByte (0xe0, channel),
  433. position & 127, (position >> 7) & 127);
  434. }
  435. bool MidiMessage::isController() const noexcept
  436. {
  437. return (getRawData()[0] & 0xf0) == 0xb0;
  438. }
  439. bool MidiMessage::isControllerOfType (const int controllerType) const noexcept
  440. {
  441. const uint8* const data = getRawData();
  442. return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
  443. }
  444. int MidiMessage::getControllerNumber() const noexcept
  445. {
  446. jassert (isController());
  447. return getRawData()[1];
  448. }
  449. int MidiMessage::getControllerValue() const noexcept
  450. {
  451. jassert (isController());
  452. return getRawData()[2];
  453. }
  454. MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) noexcept
  455. {
  456. // the channel must be between 1 and 16 inclusive
  457. jassert (channel > 0 && channel <= 16);
  458. return MidiMessage (MidiHelpers::initialByte (0xb0, channel),
  459. controllerType & 127, value & 127);
  460. }
  461. MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept
  462. {
  463. jassert (channel > 0 && channel <= 16);
  464. jassert (isPositiveAndBelow (noteNumber, (int) 128));
  465. return MidiMessage (MidiHelpers::initialByte (0x90, channel),
  466. noteNumber & 127, MidiHelpers::validVelocity (velocity));
  467. }
  468. MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept
  469. {
  470. return noteOn (channel, noteNumber, floatValueToMidiByte (velocity));
  471. }
  472. MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept
  473. {
  474. jassert (channel > 0 && channel <= 16);
  475. jassert (isPositiveAndBelow (noteNumber, (int) 128));
  476. return MidiMessage (MidiHelpers::initialByte (0x80, channel),
  477. noteNumber & 127, MidiHelpers::validVelocity (velocity));
  478. }
  479. MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, float velocity) noexcept
  480. {
  481. return noteOff (channel, noteNumber, floatValueToMidiByte (velocity));
  482. }
  483. MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber) noexcept
  484. {
  485. jassert (channel > 0 && channel <= 16);
  486. jassert (isPositiveAndBelow (noteNumber, (int) 128));
  487. return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, 0);
  488. }
  489. MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
  490. {
  491. return controllerEvent (channel, 123, 0);
  492. }
  493. bool MidiMessage::isAllNotesOff() const noexcept
  494. {
  495. const uint8* const data = getRawData();
  496. return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
  497. }
  498. MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
  499. {
  500. return controllerEvent (channel, 120, 0);
  501. }
  502. bool MidiMessage::isAllSoundOff() const noexcept
  503. {
  504. const uint8* const data = getRawData();
  505. return (data[0] & 0xf0) == 0xb0 && data[1] == 120;
  506. }
  507. MidiMessage MidiMessage::allControllersOff (const int channel) noexcept
  508. {
  509. return controllerEvent (channel, 121, 0);
  510. }
  511. MidiMessage MidiMessage::masterVolume (const float volume)
  512. {
  513. const int vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000));
  514. const uint8 buf[] = { 0xf0, 0x7f, 0x7f, 0x04, 0x01,
  515. (uint8) (vol & 0x7f),
  516. (uint8) (vol >> 7),
  517. 0xf7 };
  518. return MidiMessage (buf, 8);
  519. }
  520. //==============================================================================
  521. bool MidiMessage::isSysEx() const noexcept
  522. {
  523. return *getRawData() == 0xf0;
  524. }
  525. MidiMessage MidiMessage::createSysExMessage (const void* sysexData, const int dataSize)
  526. {
  527. HeapBlock<uint8> m ((size_t) dataSize + 2);
  528. m[0] = 0xf0;
  529. memcpy (m + 1, sysexData, (size_t) dataSize);
  530. m[dataSize + 1] = 0xf7;
  531. return MidiMessage (m, dataSize + 2);
  532. }
  533. const uint8* MidiMessage::getSysExData() const noexcept
  534. {
  535. return isSysEx() ? getRawData() + 1 : nullptr;
  536. }
  537. int MidiMessage::getSysExDataSize() const noexcept
  538. {
  539. return isSysEx() ? size - 2 : 0;
  540. }
  541. //==============================================================================
  542. bool MidiMessage::isMetaEvent() const noexcept { return *getRawData() == 0xff; }
  543. bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0xfe; }
  544. int MidiMessage::getMetaEventType() const noexcept
  545. {
  546. const uint8* const data = getRawData();
  547. return *data != 0xff ? -1 : data[1];
  548. }
  549. int MidiMessage::getMetaEventLength() const noexcept
  550. {
  551. const uint8* const data = getRawData();
  552. if (*data == 0xff)
  553. {
  554. int n;
  555. return jmin (size - 2, readVariableLengthVal (data + 2, n));
  556. }
  557. return 0;
  558. }
  559. const uint8* MidiMessage::getMetaEventData() const noexcept
  560. {
  561. jassert (isMetaEvent());
  562. int n;
  563. const uint8* d = getRawData() + 2;
  564. readVariableLengthVal (d, n);
  565. return d + n;
  566. }
  567. bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; }
  568. bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; }
  569. bool MidiMessage::isTextMetaEvent() const noexcept
  570. {
  571. const int t = getMetaEventType();
  572. return t > 0 && t < 16;
  573. }
  574. String MidiMessage::getTextFromTextMetaEvent() const
  575. {
  576. const char* const textData = reinterpret_cast<const char*> (getMetaEventData());
  577. return String (CharPointer_UTF8 (textData),
  578. CharPointer_UTF8 (textData + getMetaEventLength()));
  579. }
  580. MidiMessage MidiMessage::textMetaEvent (int type, StringRef text)
  581. {
  582. jassert (type > 0 && type < 16);
  583. MidiMessage result;
  584. const size_t textSize = text.text.sizeInBytes() - 1;
  585. uint8 header[8];
  586. size_t n = sizeof (header);
  587. header[--n] = (uint8) (textSize & 0x7f);
  588. for (size_t i = textSize; (i >>= 7) != 0;)
  589. header[--n] = (uint8) ((i & 0x7f) | 0x80);
  590. header[--n] = (uint8) type;
  591. header[--n] = 0xff;
  592. const size_t headerLen = sizeof (header) - n;
  593. const int totalSize = (int) (headerLen + textSize);
  594. uint8* const dest = result.allocateSpace (totalSize);
  595. result.size = totalSize;
  596. memcpy (dest, header + n, headerLen);
  597. memcpy (dest + headerLen, text.text.getAddress(), textSize);
  598. return result;
  599. }
  600. bool MidiMessage::isTrackNameEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
  601. bool MidiMessage::isTempoMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
  602. bool MidiMessage::isMidiChannelMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
  603. int MidiMessage::getMidiChannelMetaEventChannel() const noexcept
  604. {
  605. jassert (isMidiChannelMetaEvent());
  606. return getRawData()[3] + 1;
  607. }
  608. double MidiMessage::getTempoSecondsPerQuarterNote() const noexcept
  609. {
  610. if (! isTempoMetaEvent())
  611. return 0.0;
  612. const uint8* const d = getMetaEventData();
  613. return (((unsigned int) d[0] << 16)
  614. | ((unsigned int) d[1] << 8)
  615. | d[2])
  616. / 1000000.0;
  617. }
  618. double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const noexcept
  619. {
  620. if (timeFormat > 0)
  621. {
  622. if (! isTempoMetaEvent())
  623. return 0.5 / timeFormat;
  624. return getTempoSecondsPerQuarterNote() / timeFormat;
  625. }
  626. else
  627. {
  628. const int frameCode = (-timeFormat) >> 8;
  629. double framesPerSecond;
  630. switch (frameCode)
  631. {
  632. case 24: framesPerSecond = 24.0; break;
  633. case 25: framesPerSecond = 25.0; break;
  634. case 29: framesPerSecond = 29.97; break;
  635. case 30: framesPerSecond = 30.0; break;
  636. default: framesPerSecond = 30.0; break;
  637. }
  638. return (1.0 / framesPerSecond) / (timeFormat & 0xff);
  639. }
  640. }
  641. MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept
  642. {
  643. const uint8 d[] = { 0xff, 81, 3,
  644. (uint8) (microsecondsPerQuarterNote >> 16),
  645. (uint8) (microsecondsPerQuarterNote >> 8),
  646. (uint8) microsecondsPerQuarterNote };
  647. return MidiMessage (d, 6, 0.0);
  648. }
  649. bool MidiMessage::isTimeSignatureMetaEvent() const noexcept
  650. {
  651. const uint8* const data = getRawData();
  652. return (data[1] == 0x58) && (*data == (uint8) 0xff);
  653. }
  654. void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const noexcept
  655. {
  656. if (isTimeSignatureMetaEvent())
  657. {
  658. const uint8* const d = getMetaEventData();
  659. numerator = d[0];
  660. denominator = 1 << d[1];
  661. }
  662. else
  663. {
  664. numerator = 4;
  665. denominator = 4;
  666. }
  667. }
  668. MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator)
  669. {
  670. int n = 1;
  671. int powerOfTwo = 0;
  672. while (n < denominator)
  673. {
  674. n <<= 1;
  675. ++powerOfTwo;
  676. }
  677. const uint8 d[] = { 0xff, 0x58, 0x04, (uint8) numerator, (uint8) powerOfTwo, 1, 96 };
  678. return MidiMessage (d, 7, 0.0);
  679. }
  680. MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept
  681. {
  682. const uint8 d[] = { 0xff, 0x20, 0x01, (uint8) jlimit (0, 0xff, channel - 1) };
  683. return MidiMessage (d, 4, 0.0);
  684. }
  685. bool MidiMessage::isKeySignatureMetaEvent() const noexcept
  686. {
  687. return getMetaEventType() == 0x59;
  688. }
  689. int MidiMessage::getKeySignatureNumberOfSharpsOrFlats() const noexcept
  690. {
  691. return (int) (int8) getMetaEventData()[0];
  692. }
  693. bool MidiMessage::isKeySignatureMajorKey() const noexcept
  694. {
  695. return getMetaEventData()[1] == 0;
  696. }
  697. MidiMessage MidiMessage::keySignatureMetaEvent (int numberOfSharpsOrFlats, bool isMinorKey)
  698. {
  699. jassert (numberOfSharpsOrFlats >= -7 && numberOfSharpsOrFlats <= 7);
  700. const uint8 d[] = { 0xff, 0x59, 0x02, (uint8) numberOfSharpsOrFlats, isMinorKey ? (uint8) 1 : (uint8) 0 };
  701. return MidiMessage (d, 5, 0.0);
  702. }
  703. MidiMessage MidiMessage::endOfTrack() noexcept
  704. {
  705. return MidiMessage (0xff, 0x2f, 0, 0.0);
  706. }
  707. //==============================================================================
  708. bool MidiMessage::isSongPositionPointer() const noexcept { return *getRawData() == 0xf2; }
  709. int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { const uint8* data = getRawData(); return data[1] | (data[2] << 7); }
  710. MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept
  711. {
  712. return MidiMessage (0xf2,
  713. positionInMidiBeats & 127,
  714. (positionInMidiBeats >> 7) & 127);
  715. }
  716. bool MidiMessage::isMidiStart() const noexcept { return *getRawData() == 0xfa; }
  717. MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); }
  718. bool MidiMessage::isMidiContinue() const noexcept { return *getRawData() == 0xfb; }
  719. MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); }
  720. bool MidiMessage::isMidiStop() const noexcept { return *getRawData() == 0xfc; }
  721. MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); }
  722. bool MidiMessage::isMidiClock() const noexcept { return *getRawData() == 0xf8; }
  723. MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); }
  724. bool MidiMessage::isQuarterFrame() const noexcept { return *getRawData() == 0xf1; }
  725. int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) getRawData()[1]) >> 4; }
  726. int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
  727. MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
  728. {
  729. return MidiMessage (0xf1, (sequenceNumber << 4) | value);
  730. }
  731. bool MidiMessage::isFullFrame() const noexcept
  732. {
  733. const uint8* const data = getRawData();
  734. return data[0] == 0xf0
  735. && data[1] == 0x7f
  736. && size >= 10
  737. && data[3] == 0x01
  738. && data[4] == 0x01;
  739. }
  740. void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames,
  741. MidiMessage::SmpteTimecodeType& timecodeType) const noexcept
  742. {
  743. jassert (isFullFrame());
  744. const uint8* const data = getRawData();
  745. timecodeType = (SmpteTimecodeType) (data[5] >> 5);
  746. hours = data[5] & 0x1f;
  747. minutes = data[6];
  748. seconds = data[7];
  749. frames = data[8];
  750. }
  751. MidiMessage MidiMessage::fullFrame (const int hours, const int minutes,
  752. const int seconds, const int frames,
  753. MidiMessage::SmpteTimecodeType timecodeType)
  754. {
  755. const uint8 d[] = { 0xf0, 0x7f, 0x7f, 0x01, 0x01,
  756. (uint8) ((hours & 0x01f) | (timecodeType << 5)),
  757. (uint8) minutes,
  758. (uint8) seconds,
  759. (uint8) frames,
  760. 0xf7 };
  761. return MidiMessage (d, 10, 0.0);
  762. }
  763. bool MidiMessage::isMidiMachineControlMessage() const noexcept
  764. {
  765. const uint8* const data = getRawData();
  766. return data[0] == 0xf0
  767. && data[1] == 0x7f
  768. && data[3] == 0x06
  769. && size > 5;
  770. }
  771. MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand() const noexcept
  772. {
  773. jassert (isMidiMachineControlMessage());
  774. return (MidiMachineControlCommand) getRawData()[4];
  775. }
  776. MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command)
  777. {
  778. const uint8 d[] = { 0xf0, 0x7f, 0, 6, (uint8) command, 0xf7 };
  779. return MidiMessage (d, 6, 0.0);
  780. }
  781. //==============================================================================
  782. bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept
  783. {
  784. const uint8* const data = getRawData();
  785. if (size >= 12
  786. && data[0] == 0xf0
  787. && data[1] == 0x7f
  788. && data[3] == 0x06
  789. && data[4] == 0x44
  790. && data[5] == 0x06
  791. && data[6] == 0x01)
  792. {
  793. hours = data[7] % 24; // (that some machines send out hours > 24)
  794. minutes = data[8];
  795. seconds = data[9];
  796. frames = data[10];
  797. return true;
  798. }
  799. return false;
  800. }
  801. MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int seconds, int frames)
  802. {
  803. const uint8 d[] = { 0xf0, 0x7f, 0, 6, 0x44, 6, 1,
  804. (uint8) hours,
  805. (uint8) minutes,
  806. (uint8) seconds,
  807. (uint8) frames,
  808. 0xf7 };
  809. return MidiMessage (d, 12, 0.0);
  810. }
  811. //==============================================================================
  812. String MidiMessage::getMidiNoteName (int note, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
  813. {
  814. static const char* const sharpNoteNames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
  815. static const char* const flatNoteNames[] = { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
  816. if (isPositiveAndBelow (note, (int) 128))
  817. {
  818. String s (useSharps ? sharpNoteNames [note % 12]
  819. : flatNoteNames [note % 12]);
  820. if (includeOctaveNumber)
  821. s << (note / 12 + (octaveNumForMiddleC - 5));
  822. return s;
  823. }
  824. return String();
  825. }
  826. double MidiMessage::getMidiNoteInHertz (const int noteNumber, const double frequencyOfA) noexcept
  827. {
  828. return frequencyOfA * pow (2.0, (noteNumber - 69) / 12.0);
  829. }
  830. bool MidiMessage::isMidiNoteBlack (int noteNumber) noexcept
  831. {
  832. return ((1 << (noteNumber % 12)) & 0x054a) != 0;
  833. }
  834. const char* MidiMessage::getGMInstrumentName (const int n)
  835. {
  836. static const char* names[] =
  837. {
  838. NEEDS_TRANS("Acoustic Grand Piano"), NEEDS_TRANS("Bright Acoustic Piano"), NEEDS_TRANS("Electric Grand Piano"), NEEDS_TRANS("Honky-tonk Piano"),
  839. NEEDS_TRANS("Electric Piano 1"), NEEDS_TRANS("Electric Piano 2"), NEEDS_TRANS("Harpsichord"), NEEDS_TRANS("Clavinet"),
  840. NEEDS_TRANS("Celesta"), NEEDS_TRANS("Glockenspiel"), NEEDS_TRANS("Music Box"), NEEDS_TRANS("Vibraphone"),
  841. NEEDS_TRANS("Marimba"), NEEDS_TRANS("Xylophone"), NEEDS_TRANS("Tubular Bells"), NEEDS_TRANS("Dulcimer"),
  842. NEEDS_TRANS("Drawbar Organ"), NEEDS_TRANS("Percussive Organ"), NEEDS_TRANS("Rock Organ"), NEEDS_TRANS("Church Organ"),
  843. NEEDS_TRANS("Reed Organ"), NEEDS_TRANS("Accordion"), NEEDS_TRANS("Harmonica"), NEEDS_TRANS("Tango Accordion"),
  844. NEEDS_TRANS("Acoustic Guitar (nylon)"), NEEDS_TRANS("Acoustic Guitar (steel)"), NEEDS_TRANS("Electric Guitar (jazz)"), NEEDS_TRANS("Electric Guitar (clean)"),
  845. NEEDS_TRANS("Electric Guitar (mute)"), NEEDS_TRANS("Overdriven Guitar"), NEEDS_TRANS("Distortion Guitar"), NEEDS_TRANS("Guitar Harmonics"),
  846. NEEDS_TRANS("Acoustic Bass"), NEEDS_TRANS("Electric Bass (finger)"), NEEDS_TRANS("Electric Bass (pick)"), NEEDS_TRANS("Fretless Bass"),
  847. NEEDS_TRANS("Slap Bass 1"), NEEDS_TRANS("Slap Bass 2"), NEEDS_TRANS("Synth Bass 1"), NEEDS_TRANS("Synth Bass 2"),
  848. NEEDS_TRANS("Violin"), NEEDS_TRANS("Viola"), NEEDS_TRANS("Cello"), NEEDS_TRANS("Contrabass"),
  849. NEEDS_TRANS("Tremolo Strings"), NEEDS_TRANS("Pizzicato Strings"), NEEDS_TRANS("Orchestral Harp"), NEEDS_TRANS("Timpani"),
  850. NEEDS_TRANS("String Ensemble 1"), NEEDS_TRANS("String Ensemble 2"), NEEDS_TRANS("SynthStrings 1"), NEEDS_TRANS("SynthStrings 2"),
  851. NEEDS_TRANS("Choir Aahs"), NEEDS_TRANS("Voice Oohs"), NEEDS_TRANS("Synth Voice"), NEEDS_TRANS("Orchestra Hit"),
  852. NEEDS_TRANS("Trumpet"), NEEDS_TRANS("Trombone"), NEEDS_TRANS("Tuba"), NEEDS_TRANS("Muted Trumpet"),
  853. NEEDS_TRANS("French Horn"), NEEDS_TRANS("Brass Section"), NEEDS_TRANS("SynthBrass 1"), NEEDS_TRANS("SynthBrass 2"),
  854. NEEDS_TRANS("Soprano Sax"), NEEDS_TRANS("Alto Sax"), NEEDS_TRANS("Tenor Sax"), NEEDS_TRANS("Baritone Sax"),
  855. NEEDS_TRANS("Oboe"), NEEDS_TRANS("English Horn"), NEEDS_TRANS("Bassoon"), NEEDS_TRANS("Clarinet"),
  856. NEEDS_TRANS("Piccolo"), NEEDS_TRANS("Flute"), NEEDS_TRANS("Recorder"), NEEDS_TRANS("Pan Flute"),
  857. NEEDS_TRANS("Blown Bottle"), NEEDS_TRANS("Shakuhachi"), NEEDS_TRANS("Whistle"), NEEDS_TRANS("Ocarina"),
  858. NEEDS_TRANS("Lead 1 (square)"), NEEDS_TRANS("Lead 2 (sawtooth)"), NEEDS_TRANS("Lead 3 (calliope)"), NEEDS_TRANS("Lead 4 (chiff)"),
  859. NEEDS_TRANS("Lead 5 (charang)"), NEEDS_TRANS("Lead 6 (voice)"), NEEDS_TRANS("Lead 7 (fifths)"), NEEDS_TRANS("Lead 8 (bass+lead)"),
  860. NEEDS_TRANS("Pad 1 (new age)"), NEEDS_TRANS("Pad 2 (warm)"), NEEDS_TRANS("Pad 3 (polysynth)"), NEEDS_TRANS("Pad 4 (choir)"),
  861. NEEDS_TRANS("Pad 5 (bowed)"), NEEDS_TRANS("Pad 6 (metallic)"), NEEDS_TRANS("Pad 7 (halo)"), NEEDS_TRANS("Pad 8 (sweep)"),
  862. NEEDS_TRANS("FX 1 (rain)"), NEEDS_TRANS("FX 2 (soundtrack)"), NEEDS_TRANS("FX 3 (crystal)"), NEEDS_TRANS("FX 4 (atmosphere)"),
  863. NEEDS_TRANS("FX 5 (brightness)"), NEEDS_TRANS("FX 6 (goblins)"), NEEDS_TRANS("FX 7 (echoes)"), NEEDS_TRANS("FX 8 (sci-fi)"),
  864. NEEDS_TRANS("Sitar"), NEEDS_TRANS("Banjo"), NEEDS_TRANS("Shamisen"), NEEDS_TRANS("Koto"),
  865. NEEDS_TRANS("Kalimba"), NEEDS_TRANS("Bag pipe"), NEEDS_TRANS("Fiddle"), NEEDS_TRANS("Shanai"),
  866. NEEDS_TRANS("Tinkle Bell"), NEEDS_TRANS("Agogo"), NEEDS_TRANS("Steel Drums"), NEEDS_TRANS("Woodblock"),
  867. NEEDS_TRANS("Taiko Drum"), NEEDS_TRANS("Melodic Tom"), NEEDS_TRANS("Synth Drum"), NEEDS_TRANS("Reverse Cymbal"),
  868. NEEDS_TRANS("Guitar Fret Noise"), NEEDS_TRANS("Breath Noise"), NEEDS_TRANS("Seashore"), NEEDS_TRANS("Bird Tweet"),
  869. NEEDS_TRANS("Telephone Ring"), NEEDS_TRANS("Helicopter"), NEEDS_TRANS("Applause"), NEEDS_TRANS("Gunshot")
  870. };
  871. return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
  872. }
  873. const char* MidiMessage::getGMInstrumentBankName (const int n)
  874. {
  875. static const char* names[] =
  876. {
  877. NEEDS_TRANS("Piano"), NEEDS_TRANS("Chromatic Percussion"), NEEDS_TRANS("Organ"), NEEDS_TRANS("Guitar"),
  878. NEEDS_TRANS("Bass"), NEEDS_TRANS("Strings"), NEEDS_TRANS("Ensemble"), NEEDS_TRANS("Brass"),
  879. NEEDS_TRANS("Reed"), NEEDS_TRANS("Pipe"), NEEDS_TRANS("Synth Lead"), NEEDS_TRANS("Synth Pad"),
  880. NEEDS_TRANS("Synth Effects"), NEEDS_TRANS("Ethnic"), NEEDS_TRANS("Percussive"), NEEDS_TRANS("Sound Effects")
  881. };
  882. return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
  883. }
  884. const char* MidiMessage::getRhythmInstrumentName (const int n)
  885. {
  886. static const char* names[] =
  887. {
  888. NEEDS_TRANS("Acoustic Bass Drum"), NEEDS_TRANS("Bass Drum 1"), NEEDS_TRANS("Side Stick"), NEEDS_TRANS("Acoustic Snare"),
  889. NEEDS_TRANS("Hand Clap"), NEEDS_TRANS("Electric Snare"), NEEDS_TRANS("Low Floor Tom"), NEEDS_TRANS("Closed Hi-Hat"),
  890. NEEDS_TRANS("High Floor Tom"), NEEDS_TRANS("Pedal Hi-Hat"), NEEDS_TRANS("Low Tom"), NEEDS_TRANS("Open Hi-Hat"),
  891. NEEDS_TRANS("Low-Mid Tom"), NEEDS_TRANS("Hi-Mid Tom"), NEEDS_TRANS("Crash Cymbal 1"), NEEDS_TRANS("High Tom"),
  892. NEEDS_TRANS("Ride Cymbal 1"), NEEDS_TRANS("Chinese Cymbal"), NEEDS_TRANS("Ride Bell"), NEEDS_TRANS("Tambourine"),
  893. NEEDS_TRANS("Splash Cymbal"), NEEDS_TRANS("Cowbell"), NEEDS_TRANS("Crash Cymbal 2"), NEEDS_TRANS("Vibraslap"),
  894. NEEDS_TRANS("Ride Cymbal 2"), NEEDS_TRANS("Hi Bongo"), NEEDS_TRANS("Low Bongo"), NEEDS_TRANS("Mute Hi Conga"),
  895. NEEDS_TRANS("Open Hi Conga"), NEEDS_TRANS("Low Conga"), NEEDS_TRANS("High Timbale"), NEEDS_TRANS("Low Timbale"),
  896. NEEDS_TRANS("High Agogo"), NEEDS_TRANS("Low Agogo"), NEEDS_TRANS("Cabasa"), NEEDS_TRANS("Maracas"),
  897. NEEDS_TRANS("Short Whistle"), NEEDS_TRANS("Long Whistle"), NEEDS_TRANS("Short Guiro"), NEEDS_TRANS("Long Guiro"),
  898. NEEDS_TRANS("Claves"), NEEDS_TRANS("Hi Wood Block"), NEEDS_TRANS("Low Wood Block"), NEEDS_TRANS("Mute Cuica"),
  899. NEEDS_TRANS("Open Cuica"), NEEDS_TRANS("Mute Triangle"), NEEDS_TRANS("Open Triangle")
  900. };
  901. return (n >= 35 && n <= 81) ? names [n - 35] : nullptr;
  902. }
  903. const char* MidiMessage::getControllerName (const int n)
  904. {
  905. static const char* names[] =
  906. {
  907. NEEDS_TRANS("Bank Select"), NEEDS_TRANS("Modulation Wheel (coarse)"), NEEDS_TRANS("Breath controller (coarse)"),
  908. nullptr,
  909. NEEDS_TRANS("Foot Pedal (coarse)"), NEEDS_TRANS("Portamento Time (coarse)"), NEEDS_TRANS("Data Entry (coarse)"),
  910. NEEDS_TRANS("Volume (coarse)"), NEEDS_TRANS("Balance (coarse)"),
  911. nullptr,
  912. NEEDS_TRANS("Pan position (coarse)"), NEEDS_TRANS("Expression (coarse)"), NEEDS_TRANS("Effect Control 1 (coarse)"),
  913. NEEDS_TRANS("Effect Control 2 (coarse)"),
  914. nullptr, nullptr,
  915. NEEDS_TRANS("General Purpose Slider 1"), NEEDS_TRANS("General Purpose Slider 2"),
  916. NEEDS_TRANS("General Purpose Slider 3"), NEEDS_TRANS("General Purpose Slider 4"),
  917. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  918. NEEDS_TRANS("Bank Select (fine)"), NEEDS_TRANS("Modulation Wheel (fine)"), NEEDS_TRANS("Breath controller (fine)"),
  919. nullptr,
  920. NEEDS_TRANS("Foot Pedal (fine)"), NEEDS_TRANS("Portamento Time (fine)"), NEEDS_TRANS("Data Entry (fine)"), NEEDS_TRANS("Volume (fine)"),
  921. NEEDS_TRANS("Balance (fine)"), nullptr, NEEDS_TRANS("Pan position (fine)"), NEEDS_TRANS("Expression (fine)"),
  922. NEEDS_TRANS("Effect Control 1 (fine)"), NEEDS_TRANS("Effect Control 2 (fine)"),
  923. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  924. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  925. NEEDS_TRANS("Hold Pedal (on/off)"), NEEDS_TRANS("Portamento (on/off)"), NEEDS_TRANS("Sustenuto Pedal (on/off)"), NEEDS_TRANS("Soft Pedal (on/off)"),
  926. NEEDS_TRANS("Legato Pedal (on/off)"), NEEDS_TRANS("Hold 2 Pedal (on/off)"), NEEDS_TRANS("Sound Variation"), NEEDS_TRANS("Sound Timbre"),
  927. NEEDS_TRANS("Sound Release Time"), NEEDS_TRANS("Sound Attack Time"), NEEDS_TRANS("Sound Brightness"), NEEDS_TRANS("Sound Control 6"),
  928. NEEDS_TRANS("Sound Control 7"), NEEDS_TRANS("Sound Control 8"), NEEDS_TRANS("Sound Control 9"), NEEDS_TRANS("Sound Control 10"),
  929. NEEDS_TRANS("General Purpose Button 1 (on/off)"), NEEDS_TRANS("General Purpose Button 2 (on/off)"),
  930. NEEDS_TRANS("General Purpose Button 3 (on/off)"), NEEDS_TRANS("General Purpose Button 4 (on/off)"),
  931. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  932. NEEDS_TRANS("Reverb Level"), NEEDS_TRANS("Tremolo Level"), NEEDS_TRANS("Chorus Level"), NEEDS_TRANS("Celeste Level"),
  933. NEEDS_TRANS("Phaser Level"), NEEDS_TRANS("Data Button increment"), NEEDS_TRANS("Data Button decrement"), NEEDS_TRANS("Non-registered Parameter (fine)"),
  934. NEEDS_TRANS("Non-registered Parameter (coarse)"), NEEDS_TRANS("Registered Parameter (fine)"), NEEDS_TRANS("Registered Parameter (coarse)"),
  935. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  936. nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
  937. NEEDS_TRANS("All Sound Off"), NEEDS_TRANS("All Controllers Off"), NEEDS_TRANS("Local Keyboard (on/off)"), NEEDS_TRANS("All Notes Off"),
  938. NEEDS_TRANS("Omni Mode Off"), NEEDS_TRANS("Omni Mode On"), NEEDS_TRANS("Mono Operation"), NEEDS_TRANS("Poly Operation")
  939. };
  940. return isPositiveAndBelow (n, numElementsInArray (names)) ? names[n] : nullptr;
  941. }
  942. }