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.

MidiMessage.cpp 31KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /*
  2. ==============================================================================
  3. This file is part of the Water library.
  4. Copyright (c) 2016 ROLI Ltd.
  5. Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
  6. Permission is granted to use this software under the terms of the ISC license
  7. http://www.isc.org/downloads/software-support-policy/isc-license/
  8. Permission to use, copy, modify, and/or distribute this software for any
  9. purpose with or without fee is hereby granted, provided that the above
  10. copyright notice and this permission notice appear in all copies.
  11. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
  12. TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  13. FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
  14. OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  15. USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  16. TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  17. OF THIS SOFTWARE.
  18. ==============================================================================
  19. */
  20. #include "MidiMessage.h"
  21. #include "../maths/MathsFunctions.h"
  22. #include "../memory/HeapBlock.h"
  23. namespace water {
  24. namespace MidiHelpers
  25. {
  26. inline uint8 initialByte (const int type, const int channel) noexcept
  27. {
  28. return (uint8) (type | jlimit (0, 15, channel - 1));
  29. }
  30. inline uint8 validVelocity (const int v) noexcept
  31. {
  32. return (uint8) jlimit (0, 127, v);
  33. }
  34. }
  35. //==============================================================================
  36. uint8 MidiMessage::floatValueToMidiByte (const float v) noexcept
  37. {
  38. return MidiHelpers::validVelocity (roundToInt (v * 127.0f));
  39. }
  40. uint16 MidiMessage::pitchbendToPitchwheelPos (const float pitchbend,
  41. const float pitchbendRange) noexcept
  42. {
  43. // can't translate a pitchbend value that is outside of the given range!
  44. jassert (std::abs (pitchbend) <= pitchbendRange);
  45. return static_cast<uint16> (pitchbend > 0.0f
  46. ? jmap (pitchbend, 0.0f, pitchbendRange, 8192.0f, 16383.0f)
  47. : jmap (pitchbend, -pitchbendRange, 0.0f, 0.0f, 8192.0f));
  48. }
  49. //==============================================================================
  50. int MidiMessage::readVariableLengthVal (const uint8* data, int& numBytesUsed) noexcept
  51. {
  52. numBytesUsed = 0;
  53. int v = 0, i;
  54. do
  55. {
  56. i = (int) *data++;
  57. if (++numBytesUsed > 6)
  58. break;
  59. v = (v << 7) + (i & 0x7f);
  60. } while (i & 0x80);
  61. return v;
  62. }
  63. int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) noexcept
  64. {
  65. // this method only works for valid starting bytes of a short midi message
  66. jassert (firstByte >= 0x80 && firstByte != 0xf0 && firstByte != 0xf7);
  67. static const char messageLengths[] =
  68. {
  69. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  70. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  71. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  72. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  73. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  74. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
  75. 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  76. 1, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  77. };
  78. return messageLengths [firstByte & 0x7f];
  79. }
  80. //==============================================================================
  81. MidiMessage::MidiMessage() noexcept
  82. : timeStamp (0), size (2)
  83. {
  84. packedData.asBytes[0] = 0xf0;
  85. packedData.asBytes[1] = 0xf7;
  86. }
  87. MidiMessage::MidiMessage (const void* const d, const int dataSize, const double t)
  88. : timeStamp (t), size (dataSize)
  89. {
  90. jassert (dataSize > 0);
  91. // this checks that the length matches the data..
  92. jassert (dataSize > 3 || *(uint8*)d >= 0xf0 || getMessageLengthFromFirstByte (*(uint8*)d) == size);
  93. memcpy (allocateSpace (dataSize), d, (size_t) dataSize);
  94. }
  95. MidiMessage::MidiMessage (const int byte1, const double t) noexcept
  96. : timeStamp (t), size (1)
  97. {
  98. packedData.asBytes[0] = (uint8) byte1;
  99. // check that the length matches the data..
  100. jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 1);
  101. }
  102. MidiMessage::MidiMessage (const int byte1, const int byte2, const double t) noexcept
  103. : timeStamp (t), size (2)
  104. {
  105. packedData.asBytes[0] = (uint8) byte1;
  106. packedData.asBytes[1] = (uint8) byte2;
  107. // check that the length matches the data..
  108. jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 2);
  109. }
  110. MidiMessage::MidiMessage (const int byte1, const int byte2, const int byte3, const double t) noexcept
  111. : timeStamp (t), size (3)
  112. {
  113. packedData.asBytes[0] = (uint8) byte1;
  114. packedData.asBytes[1] = (uint8) byte2;
  115. packedData.asBytes[2] = (uint8) byte3;
  116. // check that the length matches the data..
  117. jassert (byte1 >= 0xf0 || getMessageLengthFromFirstByte ((uint8) byte1) == 3);
  118. }
  119. MidiMessage::MidiMessage (const MidiMessage& other)
  120. : timeStamp (other.timeStamp), size (other.size)
  121. {
  122. if (isHeapAllocated())
  123. memcpy (allocateSpace (size), other.getData(), (size_t) size);
  124. else
  125. packedData.allocatedData = other.packedData.allocatedData;
  126. }
  127. MidiMessage::MidiMessage (const MidiMessage& other, const double newTimeStamp)
  128. : timeStamp (newTimeStamp), size (other.size)
  129. {
  130. if (isHeapAllocated())
  131. memcpy (allocateSpace (size), other.getData(), (size_t) size);
  132. else
  133. packedData.allocatedData = other.packedData.allocatedData;
  134. }
  135. MidiMessage::MidiMessage (const void* srcData, int sz, int& numBytesUsed, const uint8 lastStatusByte,
  136. double t, bool sysexHasEmbeddedLength)
  137. : timeStamp (t)
  138. {
  139. const uint8* src = static_cast<const uint8*> (srcData);
  140. unsigned int byte = (unsigned int) *src;
  141. if (byte < 0x80)
  142. {
  143. byte = (unsigned int) (uint8) lastStatusByte;
  144. numBytesUsed = -1;
  145. }
  146. else
  147. {
  148. numBytesUsed = 0;
  149. --sz;
  150. ++src;
  151. }
  152. if (byte >= 0x80)
  153. {
  154. if (byte == 0xf0)
  155. {
  156. const uint8* d = src;
  157. bool haveReadAllLengthBytes = ! sysexHasEmbeddedLength;
  158. int numVariableLengthSysexBytes = 0;
  159. while (d < src + sz)
  160. {
  161. if (*d >= 0x80)
  162. {
  163. if (*d == 0xf7)
  164. {
  165. ++d; // include the trailing 0xf7 when we hit it
  166. break;
  167. }
  168. if (haveReadAllLengthBytes) // if we see a 0x80 bit set after the initial data length
  169. break; // bytes, assume it's the end of the sysex
  170. ++numVariableLengthSysexBytes;
  171. }
  172. else if (! haveReadAllLengthBytes)
  173. {
  174. haveReadAllLengthBytes = true;
  175. ++numVariableLengthSysexBytes;
  176. }
  177. ++d;
  178. }
  179. src += numVariableLengthSysexBytes;
  180. size = 1 + (int) (d - src);
  181. uint8* dest = allocateSpace (size);
  182. *dest = (uint8) byte;
  183. memcpy (dest + 1, src, (size_t) (size - 1));
  184. numBytesUsed += numVariableLengthSysexBytes; // (these aren't counted in the size)
  185. }
  186. else if (byte == 0xff)
  187. {
  188. int n;
  189. const int bytesLeft = readVariableLengthVal (src + 1, n);
  190. size = jmin (sz + 1, n + 2 + bytesLeft);
  191. uint8* dest = allocateSpace (size);
  192. *dest = (uint8) byte;
  193. memcpy (dest + 1, src, (size_t) size - 1);
  194. }
  195. else
  196. {
  197. size = getMessageLengthFromFirstByte ((uint8) byte);
  198. packedData.asBytes[0] = (uint8) byte;
  199. if (size > 1)
  200. {
  201. packedData.asBytes[1] = src[0];
  202. if (size > 2)
  203. packedData.asBytes[2] = src[1];
  204. }
  205. }
  206. numBytesUsed += size;
  207. }
  208. else
  209. {
  210. packedData.allocatedData = nullptr;
  211. size = 0;
  212. }
  213. }
  214. MidiMessage& MidiMessage::operator= (const MidiMessage& other)
  215. {
  216. if (this != &other)
  217. {
  218. if (other.isHeapAllocated())
  219. {
  220. if (isHeapAllocated())
  221. packedData.allocatedData = static_cast<uint8*> (std::realloc (packedData.allocatedData, (size_t) other.size));
  222. else
  223. packedData.allocatedData = static_cast<uint8*> (std::malloc ((size_t) other.size));
  224. memcpy (packedData.allocatedData, other.packedData.allocatedData, (size_t) other.size);
  225. }
  226. else
  227. {
  228. if (isHeapAllocated())
  229. std::free (packedData.allocatedData);
  230. packedData.allocatedData = other.packedData.allocatedData;
  231. }
  232. timeStamp = other.timeStamp;
  233. size = other.size;
  234. }
  235. return *this;
  236. }
  237. #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
  238. MidiMessage::MidiMessage (MidiMessage&& other) noexcept
  239. : timeStamp (other.timeStamp), size (other.size)
  240. {
  241. packedData.allocatedData = other.packedData.allocatedData;
  242. other.size = 0;
  243. }
  244. MidiMessage& MidiMessage::operator= (MidiMessage&& other) noexcept
  245. {
  246. packedData.allocatedData = other.packedData.allocatedData;
  247. timeStamp = other.timeStamp;
  248. size = other.size;
  249. other.size = 0;
  250. return *this;
  251. }
  252. #endif
  253. MidiMessage::~MidiMessage() noexcept
  254. {
  255. if (isHeapAllocated())
  256. std::free (packedData.allocatedData);
  257. }
  258. uint8* MidiMessage::allocateSpace (int bytes)
  259. {
  260. if (bytes > (int) sizeof (packedData))
  261. {
  262. uint8* d = static_cast<uint8*> (std::malloc ((size_t) bytes));
  263. packedData.allocatedData = d;
  264. return d;
  265. }
  266. return packedData.asBytes;
  267. }
  268. int MidiMessage::getChannel() const noexcept
  269. {
  270. const uint8* const data = getRawData();
  271. if ((data[0] & 0xf0) != 0xf0)
  272. return (data[0] & 0xf) + 1;
  273. return 0;
  274. }
  275. bool MidiMessage::isForChannel (const int channel) const noexcept
  276. {
  277. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  278. const uint8* const data = getRawData();
  279. return ((data[0] & 0xf) == channel - 1)
  280. && ((data[0] & 0xf0) != 0xf0);
  281. }
  282. void MidiMessage::setChannel (const int channel) noexcept
  283. {
  284. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  285. uint8* const data = getData();
  286. if ((data[0] & 0xf0) != (uint8) 0xf0)
  287. data[0] = (uint8) ((data[0] & (uint8) 0xf0)
  288. | (uint8)(channel - 1));
  289. }
  290. bool MidiMessage::isNoteOn (const bool returnTrueForVelocity0) const noexcept
  291. {
  292. const uint8* const data = getRawData();
  293. return ((data[0] & 0xf0) == 0x90)
  294. && (returnTrueForVelocity0 || data[2] != 0);
  295. }
  296. bool MidiMessage::isNoteOff (const bool returnTrueForNoteOnVelocity0) const noexcept
  297. {
  298. const uint8* const data = getRawData();
  299. return ((data[0] & 0xf0) == 0x80)
  300. || (returnTrueForNoteOnVelocity0 && (data[2] == 0) && ((data[0] & 0xf0) == 0x90));
  301. }
  302. bool MidiMessage::isNoteOnOrOff() const noexcept
  303. {
  304. const uint8* const data = getRawData();
  305. const int d = data[0] & 0xf0;
  306. return (d == 0x90) || (d == 0x80);
  307. }
  308. int MidiMessage::getNoteNumber() const noexcept
  309. {
  310. return getRawData()[1];
  311. }
  312. void MidiMessage::setNoteNumber (const int newNoteNumber) noexcept
  313. {
  314. if (isNoteOnOrOff() || isAftertouch())
  315. getData()[1] = (uint8) (newNoteNumber & 127);
  316. }
  317. uint8 MidiMessage::getVelocity() const noexcept
  318. {
  319. if (isNoteOnOrOff())
  320. return getRawData()[2];
  321. return 0;
  322. }
  323. float MidiMessage::getFloatVelocity() const noexcept
  324. {
  325. return getVelocity() * (1.0f / 127.0f);
  326. }
  327. void MidiMessage::setVelocity (const float newVelocity) noexcept
  328. {
  329. if (isNoteOnOrOff())
  330. getData()[2] = floatValueToMidiByte (newVelocity);
  331. }
  332. void MidiMessage::multiplyVelocity (const float scaleFactor) noexcept
  333. {
  334. if (isNoteOnOrOff())
  335. {
  336. uint8* const data = getData();
  337. data[2] = MidiHelpers::validVelocity (roundToInt (scaleFactor * data[2]));
  338. }
  339. }
  340. bool MidiMessage::isAftertouch() const noexcept
  341. {
  342. return (getRawData()[0] & 0xf0) == 0xa0;
  343. }
  344. int MidiMessage::getAfterTouchValue() const noexcept
  345. {
  346. jassert (isAftertouch());
  347. return getRawData()[2];
  348. }
  349. MidiMessage MidiMessage::aftertouchChange (const int channel,
  350. const int noteNum,
  351. const int aftertouchValue) noexcept
  352. {
  353. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  354. jassert (isPositiveAndBelow (noteNum, (int) 128));
  355. jassert (isPositiveAndBelow (aftertouchValue, (int) 128));
  356. return MidiMessage (MidiHelpers::initialByte (0xa0, channel),
  357. noteNum & 0x7f,
  358. aftertouchValue & 0x7f);
  359. }
  360. bool MidiMessage::isChannelPressure() const noexcept
  361. {
  362. return (getRawData()[0] & 0xf0) == 0xd0;
  363. }
  364. int MidiMessage::getChannelPressureValue() const noexcept
  365. {
  366. jassert (isChannelPressure());
  367. return getRawData()[1];
  368. }
  369. MidiMessage MidiMessage::channelPressureChange (const int channel, const int pressure) noexcept
  370. {
  371. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  372. jassert (isPositiveAndBelow (pressure, (int) 128));
  373. return MidiMessage (MidiHelpers::initialByte (0xd0, channel), pressure & 0x7f);
  374. }
  375. bool MidiMessage::isSustainPedalOn() const noexcept { return isControllerOfType (0x40) && getRawData()[2] >= 64; }
  376. bool MidiMessage::isSustainPedalOff() const noexcept { return isControllerOfType (0x40) && getRawData()[2] < 64; }
  377. bool MidiMessage::isSostenutoPedalOn() const noexcept { return isControllerOfType (0x42) && getRawData()[2] >= 64; }
  378. bool MidiMessage::isSostenutoPedalOff() const noexcept { return isControllerOfType (0x42) && getRawData()[2] < 64; }
  379. bool MidiMessage::isSoftPedalOn() const noexcept { return isControllerOfType (0x43) && getRawData()[2] >= 64; }
  380. bool MidiMessage::isSoftPedalOff() const noexcept { return isControllerOfType (0x43) && getRawData()[2] < 64; }
  381. bool MidiMessage::isProgramChange() const noexcept
  382. {
  383. return (getRawData()[0] & 0xf0) == 0xc0;
  384. }
  385. int MidiMessage::getProgramChangeNumber() const noexcept
  386. {
  387. jassert (isProgramChange());
  388. return getRawData()[1];
  389. }
  390. MidiMessage MidiMessage::programChange (const int channel, const int programNumber) noexcept
  391. {
  392. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  393. return MidiMessage (MidiHelpers::initialByte (0xc0, channel), programNumber & 0x7f);
  394. }
  395. bool MidiMessage::isPitchWheel() const noexcept
  396. {
  397. return (getRawData()[0] & 0xf0) == 0xe0;
  398. }
  399. int MidiMessage::getPitchWheelValue() const noexcept
  400. {
  401. jassert (isPitchWheel());
  402. const uint8* const data = getRawData();
  403. return data[1] | (data[2] << 7);
  404. }
  405. MidiMessage MidiMessage::pitchWheel (const int channel, const int position) noexcept
  406. {
  407. jassert (channel > 0 && channel <= 16); // valid channels are numbered 1 to 16
  408. jassert (isPositiveAndBelow (position, (int) 0x4000));
  409. return MidiMessage (MidiHelpers::initialByte (0xe0, channel),
  410. position & 127, (position >> 7) & 127);
  411. }
  412. bool MidiMessage::isController() const noexcept
  413. {
  414. return (getRawData()[0] & 0xf0) == 0xb0;
  415. }
  416. bool MidiMessage::isControllerOfType (const int controllerType) const noexcept
  417. {
  418. const uint8* const data = getRawData();
  419. return (data[0] & 0xf0) == 0xb0 && data[1] == controllerType;
  420. }
  421. int MidiMessage::getControllerNumber() const noexcept
  422. {
  423. jassert (isController());
  424. return getRawData()[1];
  425. }
  426. int MidiMessage::getControllerValue() const noexcept
  427. {
  428. jassert (isController());
  429. return getRawData()[2];
  430. }
  431. MidiMessage MidiMessage::controllerEvent (const int channel, const int controllerType, const int value) noexcept
  432. {
  433. // the channel must be between 1 and 16 inclusive
  434. jassert (channel > 0 && channel <= 16);
  435. return MidiMessage (MidiHelpers::initialByte (0xb0, channel),
  436. controllerType & 127, value & 127);
  437. }
  438. MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const uint8 velocity) noexcept
  439. {
  440. jassert (channel > 0 && channel <= 16);
  441. jassert (isPositiveAndBelow (noteNumber, (int) 128));
  442. return MidiMessage (MidiHelpers::initialByte (0x90, channel),
  443. noteNumber & 127, MidiHelpers::validVelocity (velocity));
  444. }
  445. MidiMessage MidiMessage::noteOn (const int channel, const int noteNumber, const float velocity) noexcept
  446. {
  447. return noteOn (channel, noteNumber, floatValueToMidiByte (velocity));
  448. }
  449. MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, uint8 velocity) noexcept
  450. {
  451. jassert (channel > 0 && channel <= 16);
  452. jassert (isPositiveAndBelow (noteNumber, (int) 128));
  453. return MidiMessage (MidiHelpers::initialByte (0x80, channel),
  454. noteNumber & 127, MidiHelpers::validVelocity (velocity));
  455. }
  456. MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber, float velocity) noexcept
  457. {
  458. return noteOff (channel, noteNumber, floatValueToMidiByte (velocity));
  459. }
  460. MidiMessage MidiMessage::noteOff (const int channel, const int noteNumber) noexcept
  461. {
  462. jassert (channel > 0 && channel <= 16);
  463. jassert (isPositiveAndBelow (noteNumber, (int) 128));
  464. return MidiMessage (MidiHelpers::initialByte (0x80, channel), noteNumber & 127, 0);
  465. }
  466. MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
  467. {
  468. return controllerEvent (channel, 123, 0);
  469. }
  470. bool MidiMessage::isAllNotesOff() const noexcept
  471. {
  472. const uint8* const data = getRawData();
  473. return (data[0] & 0xf0) == 0xb0 && data[1] == 123;
  474. }
  475. MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
  476. {
  477. return controllerEvent (channel, 120, 0);
  478. }
  479. bool MidiMessage::isAllSoundOff() const noexcept
  480. {
  481. const uint8* const data = getRawData();
  482. return (data[0] & 0xf0) == 0xb0 && data[1] == 120;
  483. }
  484. MidiMessage MidiMessage::allControllersOff (const int channel) noexcept
  485. {
  486. return controllerEvent (channel, 121, 0);
  487. }
  488. MidiMessage MidiMessage::masterVolume (const float volume)
  489. {
  490. const int vol = jlimit (0, 0x3fff, roundToInt (volume * 0x4000));
  491. const uint8 buf[] = { 0xf0, 0x7f, 0x7f, 0x04, 0x01,
  492. (uint8) (vol & 0x7f),
  493. (uint8) (vol >> 7),
  494. 0xf7 };
  495. return MidiMessage (buf, 8);
  496. }
  497. //==============================================================================
  498. bool MidiMessage::isSysEx() const noexcept
  499. {
  500. return *getRawData() == 0xf0;
  501. }
  502. MidiMessage MidiMessage::createSysExMessage (const void* sysexData, const int dataSize)
  503. {
  504. HeapBlock<uint8> m;
  505. CARLA_SAFE_ASSERT_RETURN(m.malloc((size_t) dataSize + 2U), MidiMessage());
  506. m[0] = 0xf0;
  507. memcpy (m + 1, sysexData, (size_t) dataSize);
  508. m[dataSize + 1] = 0xf7;
  509. return MidiMessage (m, dataSize + 2);
  510. }
  511. const uint8* MidiMessage::getSysExData() const noexcept
  512. {
  513. return isSysEx() ? getRawData() + 1 : nullptr;
  514. }
  515. int MidiMessage::getSysExDataSize() const noexcept
  516. {
  517. return isSysEx() ? size - 2 : 0;
  518. }
  519. //==============================================================================
  520. bool MidiMessage::isMetaEvent() const noexcept { return *getRawData() == 0xff; }
  521. bool MidiMessage::isActiveSense() const noexcept { return *getRawData() == 0xfe; }
  522. int MidiMessage::getMetaEventType() const noexcept
  523. {
  524. const uint8* const data = getRawData();
  525. return *data != 0xff ? -1 : data[1];
  526. }
  527. int MidiMessage::getMetaEventLength() const noexcept
  528. {
  529. const uint8* const data = getRawData();
  530. if (*data == 0xff)
  531. {
  532. int n;
  533. return jmin (size - 2, readVariableLengthVal (data + 2, n));
  534. }
  535. return 0;
  536. }
  537. const uint8* MidiMessage::getMetaEventData() const noexcept
  538. {
  539. jassert (isMetaEvent());
  540. int n;
  541. const uint8* d = getRawData() + 2;
  542. readVariableLengthVal (d, n);
  543. return d + n;
  544. }
  545. bool MidiMessage::isTrackMetaEvent() const noexcept { return getMetaEventType() == 0; }
  546. bool MidiMessage::isEndOfTrackMetaEvent() const noexcept { return getMetaEventType() == 47; }
  547. bool MidiMessage::isTextMetaEvent() const noexcept
  548. {
  549. const int t = getMetaEventType();
  550. return t > 0 && t < 16;
  551. }
  552. String MidiMessage::getTextFromTextMetaEvent() const
  553. {
  554. const char* const textData = reinterpret_cast<const char*> (getMetaEventData());
  555. return String (CharPointer_UTF8 (textData),
  556. CharPointer_UTF8 (textData + getMetaEventLength()));
  557. }
  558. MidiMessage MidiMessage::textMetaEvent (int type, StringRef text)
  559. {
  560. jassert (type > 0 && type < 16);
  561. MidiMessage result;
  562. const size_t textSize = text.text.sizeInBytes() - 1;
  563. uint8 header[8];
  564. size_t n = sizeof (header);
  565. header[--n] = (uint8) (textSize & 0x7f);
  566. for (size_t i = textSize; (i >>= 7) != 0;)
  567. header[--n] = (uint8) ((i & 0x7f) | 0x80);
  568. header[--n] = (uint8) type;
  569. header[--n] = 0xff;
  570. const size_t headerLen = sizeof (header) - n;
  571. const int totalSize = (int) (headerLen + textSize);
  572. uint8* const dest = result.allocateSpace (totalSize);
  573. result.size = totalSize;
  574. memcpy (dest, header + n, headerLen);
  575. memcpy (dest + headerLen, text.text.getAddress(), textSize);
  576. return result;
  577. }
  578. bool MidiMessage::isTrackNameEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 3) && (*data == 0xff); }
  579. bool MidiMessage::isTempoMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 81) && (*data == 0xff); }
  580. bool MidiMessage::isMidiChannelMetaEvent() const noexcept { const uint8* data = getRawData(); return (data[1] == 0x20) && (*data == 0xff) && (data[2] == 1); }
  581. int MidiMessage::getMidiChannelMetaEventChannel() const noexcept
  582. {
  583. jassert (isMidiChannelMetaEvent());
  584. return getRawData()[3] + 1;
  585. }
  586. double MidiMessage::getTempoSecondsPerQuarterNote() const noexcept
  587. {
  588. if (! isTempoMetaEvent())
  589. return 0.0;
  590. const uint8* const d = getMetaEventData();
  591. return (((unsigned int) d[0] << 16)
  592. | ((unsigned int) d[1] << 8)
  593. | d[2])
  594. / 1000000.0;
  595. }
  596. double MidiMessage::getTempoMetaEventTickLength (const short timeFormat) const noexcept
  597. {
  598. if (timeFormat > 0)
  599. {
  600. if (! isTempoMetaEvent())
  601. return 0.5 / timeFormat;
  602. return getTempoSecondsPerQuarterNote() / timeFormat;
  603. }
  604. else
  605. {
  606. const int frameCode = (-timeFormat) >> 8;
  607. double framesPerSecond;
  608. switch (frameCode)
  609. {
  610. case 24: framesPerSecond = 24.0; break;
  611. case 25: framesPerSecond = 25.0; break;
  612. case 29: framesPerSecond = 29.97; break;
  613. case 30: framesPerSecond = 30.0; break;
  614. default: framesPerSecond = 30.0; break;
  615. }
  616. return (1.0 / framesPerSecond) / (timeFormat & 0xff);
  617. }
  618. }
  619. MidiMessage MidiMessage::tempoMetaEvent (int microsecondsPerQuarterNote) noexcept
  620. {
  621. const uint8 d[] = { 0xff, 81, 3,
  622. (uint8) (microsecondsPerQuarterNote >> 16),
  623. (uint8) (microsecondsPerQuarterNote >> 8),
  624. (uint8) microsecondsPerQuarterNote };
  625. return MidiMessage (d, 6, 0.0);
  626. }
  627. bool MidiMessage::isTimeSignatureMetaEvent() const noexcept
  628. {
  629. const uint8* const data = getRawData();
  630. return (data[1] == 0x58) && (*data == (uint8) 0xff);
  631. }
  632. void MidiMessage::getTimeSignatureInfo (int& numerator, int& denominator) const noexcept
  633. {
  634. if (isTimeSignatureMetaEvent())
  635. {
  636. const uint8* const d = getMetaEventData();
  637. numerator = d[0];
  638. denominator = 1 << d[1];
  639. }
  640. else
  641. {
  642. numerator = 4;
  643. denominator = 4;
  644. }
  645. }
  646. MidiMessage MidiMessage::timeSignatureMetaEvent (const int numerator, const int denominator)
  647. {
  648. int n = 1;
  649. int powerOfTwo = 0;
  650. while (n < denominator)
  651. {
  652. n <<= 1;
  653. ++powerOfTwo;
  654. }
  655. const uint8 d[] = { 0xff, 0x58, 0x04, (uint8) numerator, (uint8) powerOfTwo, 1, 96 };
  656. return MidiMessage (d, 7, 0.0);
  657. }
  658. MidiMessage MidiMessage::midiChannelMetaEvent (const int channel) noexcept
  659. {
  660. const uint8 d[] = { 0xff, 0x20, 0x01, (uint8) jlimit (0, 0xff, channel - 1) };
  661. return MidiMessage (d, 4, 0.0);
  662. }
  663. bool MidiMessage::isKeySignatureMetaEvent() const noexcept
  664. {
  665. return getMetaEventType() == 0x59;
  666. }
  667. int MidiMessage::getKeySignatureNumberOfSharpsOrFlats() const noexcept
  668. {
  669. return (int) (int8) getMetaEventData()[0];
  670. }
  671. bool MidiMessage::isKeySignatureMajorKey() const noexcept
  672. {
  673. return getMetaEventData()[1] == 0;
  674. }
  675. MidiMessage MidiMessage::keySignatureMetaEvent (int numberOfSharpsOrFlats, bool isMinorKey)
  676. {
  677. jassert (numberOfSharpsOrFlats >= -7 && numberOfSharpsOrFlats <= 7);
  678. const uint8 d[] = { 0xff, 0x59, 0x02, (uint8) numberOfSharpsOrFlats, isMinorKey ? (uint8) 1 : (uint8) 0 };
  679. return MidiMessage (d, 5, 0.0);
  680. }
  681. MidiMessage MidiMessage::endOfTrack() noexcept
  682. {
  683. return MidiMessage (0xff, 0x2f, 0, 0.0);
  684. }
  685. //==============================================================================
  686. bool MidiMessage::isSongPositionPointer() const noexcept { return *getRawData() == 0xf2; }
  687. int MidiMessage::getSongPositionPointerMidiBeat() const noexcept { const uint8* data = getRawData(); return data[1] | (data[2] << 7); }
  688. MidiMessage MidiMessage::songPositionPointer (const int positionInMidiBeats) noexcept
  689. {
  690. return MidiMessage (0xf2,
  691. positionInMidiBeats & 127,
  692. (positionInMidiBeats >> 7) & 127);
  693. }
  694. bool MidiMessage::isMidiStart() const noexcept { return *getRawData() == 0xfa; }
  695. MidiMessage MidiMessage::midiStart() noexcept { return MidiMessage (0xfa); }
  696. bool MidiMessage::isMidiContinue() const noexcept { return *getRawData() == 0xfb; }
  697. MidiMessage MidiMessage::midiContinue() noexcept { return MidiMessage (0xfb); }
  698. bool MidiMessage::isMidiStop() const noexcept { return *getRawData() == 0xfc; }
  699. MidiMessage MidiMessage::midiStop() noexcept { return MidiMessage (0xfc); }
  700. bool MidiMessage::isMidiClock() const noexcept { return *getRawData() == 0xf8; }
  701. MidiMessage MidiMessage::midiClock() noexcept { return MidiMessage (0xf8); }
  702. bool MidiMessage::isQuarterFrame() const noexcept { return *getRawData() == 0xf1; }
  703. int MidiMessage::getQuarterFrameSequenceNumber() const noexcept { return ((int) getRawData()[1]) >> 4; }
  704. int MidiMessage::getQuarterFrameValue() const noexcept { return ((int) getRawData()[1]) & 0x0f; }
  705. MidiMessage MidiMessage::quarterFrame (const int sequenceNumber, const int value) noexcept
  706. {
  707. return MidiMessage (0xf1, (sequenceNumber << 4) | value);
  708. }
  709. bool MidiMessage::isFullFrame() const noexcept
  710. {
  711. const uint8* const data = getRawData();
  712. return data[0] == 0xf0
  713. && data[1] == 0x7f
  714. && size >= 10
  715. && data[3] == 0x01
  716. && data[4] == 0x01;
  717. }
  718. void MidiMessage::getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames,
  719. MidiMessage::SmpteTimecodeType& timecodeType) const noexcept
  720. {
  721. jassert (isFullFrame());
  722. const uint8* const data = getRawData();
  723. timecodeType = (SmpteTimecodeType) (data[5] >> 5);
  724. hours = data[5] & 0x1f;
  725. minutes = data[6];
  726. seconds = data[7];
  727. frames = data[8];
  728. }
  729. MidiMessage MidiMessage::fullFrame (const int hours, const int minutes,
  730. const int seconds, const int frames,
  731. MidiMessage::SmpteTimecodeType timecodeType)
  732. {
  733. const uint8 d[] = { 0xf0, 0x7f, 0x7f, 0x01, 0x01,
  734. (uint8) ((hours & 0x01f) | (timecodeType << 5)),
  735. (uint8) minutes,
  736. (uint8) seconds,
  737. (uint8) frames,
  738. 0xf7 };
  739. return MidiMessage (d, 10, 0.0);
  740. }
  741. bool MidiMessage::isMidiMachineControlMessage() const noexcept
  742. {
  743. const uint8* const data = getRawData();
  744. return data[0] == 0xf0
  745. && data[1] == 0x7f
  746. && data[3] == 0x06
  747. && size > 5;
  748. }
  749. MidiMessage::MidiMachineControlCommand MidiMessage::getMidiMachineControlCommand() const noexcept
  750. {
  751. jassert (isMidiMachineControlMessage());
  752. return (MidiMachineControlCommand) getRawData()[4];
  753. }
  754. MidiMessage MidiMessage::midiMachineControlCommand (MidiMessage::MidiMachineControlCommand command)
  755. {
  756. const uint8 d[] = { 0xf0, 0x7f, 0, 6, (uint8) command, 0xf7 };
  757. return MidiMessage (d, 6, 0.0);
  758. }
  759. //==============================================================================
  760. bool MidiMessage::isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const noexcept
  761. {
  762. const uint8* const data = getRawData();
  763. if (size >= 12
  764. && data[0] == 0xf0
  765. && data[1] == 0x7f
  766. && data[3] == 0x06
  767. && data[4] == 0x44
  768. && data[5] == 0x06
  769. && data[6] == 0x01)
  770. {
  771. hours = data[7] % 24; // (that some machines send out hours > 24)
  772. minutes = data[8];
  773. seconds = data[9];
  774. frames = data[10];
  775. return true;
  776. }
  777. return false;
  778. }
  779. MidiMessage MidiMessage::midiMachineControlGoto (int hours, int minutes, int seconds, int frames)
  780. {
  781. const uint8 d[] = { 0xf0, 0x7f, 0, 6, 0x44, 6, 1,
  782. (uint8) hours,
  783. (uint8) minutes,
  784. (uint8) seconds,
  785. (uint8) frames,
  786. 0xf7 };
  787. return MidiMessage (d, 12, 0.0);
  788. }
  789. //==============================================================================
  790. String MidiMessage::getMidiNoteName (int note, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC)
  791. {
  792. static const char* const sharpNoteNames[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
  793. static const char* const flatNoteNames[] = { "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B" };
  794. if (isPositiveAndBelow (note, (int) 128))
  795. {
  796. String s (useSharps ? sharpNoteNames [note % 12]
  797. : flatNoteNames [note % 12]);
  798. if (includeOctaveNumber)
  799. s << (note / 12 + (octaveNumForMiddleC - 5));
  800. return s;
  801. }
  802. return String();
  803. }
  804. double MidiMessage::getMidiNoteInHertz (const int noteNumber, const double frequencyOfA) noexcept
  805. {
  806. return frequencyOfA * pow (2.0, (noteNumber - 69) / 12.0);
  807. }
  808. bool MidiMessage::isMidiNoteBlack (int noteNumber) noexcept
  809. {
  810. return ((1 << (noteNumber % 12)) & 0x054a) != 0;
  811. }
  812. }