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.

juce_MidiRPN.cpp 14KB

8 years ago
8 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. MidiRPNDetector::MidiRPNDetector() noexcept
  18. {
  19. }
  20. MidiRPNDetector::~MidiRPNDetector() noexcept
  21. {
  22. }
  23. bool MidiRPNDetector::parseControllerMessage (int midiChannel,
  24. int controllerNumber,
  25. int controllerValue,
  26. MidiRPNMessage& result) noexcept
  27. {
  28. jassert (midiChannel >= 1 && midiChannel <= 16);
  29. jassert (controllerNumber >= 0 && controllerNumber < 128);
  30. jassert (controllerValue >= 0 && controllerValue < 128);
  31. return states[midiChannel - 1].handleController (midiChannel, controllerNumber, controllerValue, result);
  32. }
  33. void MidiRPNDetector::reset() noexcept
  34. {
  35. for (int i = 0; i < 16; ++i)
  36. {
  37. states[i].parameterMSB = 0xff;
  38. states[i].parameterLSB = 0xff;
  39. states[i].resetValue();
  40. states[i].isNRPN = false;
  41. }
  42. }
  43. //==============================================================================
  44. MidiRPNDetector::ChannelState::ChannelState () noexcept
  45. : parameterMSB (0xff), parameterLSB (0xff), valueMSB (0xff), valueLSB (0xff), isNRPN (false)
  46. {
  47. }
  48. bool MidiRPNDetector::ChannelState::handleController (int channel,
  49. int controllerNumber,
  50. int value,
  51. MidiRPNMessage& result) noexcept
  52. {
  53. switch (controllerNumber)
  54. {
  55. case 0x62: parameterLSB = uint8 (value); resetValue(); isNRPN = true; break;
  56. case 0x63: parameterMSB = uint8 (value); resetValue(); isNRPN = true; break;
  57. case 0x64: parameterLSB = uint8 (value); resetValue(); isNRPN = false; break;
  58. case 0x65: parameterMSB = uint8 (value); resetValue(); isNRPN = false; break;
  59. case 0x06: valueMSB = uint8 (value); return sendIfReady (channel, result);
  60. case 0x26: valueLSB = uint8 (value); break;
  61. default: break;
  62. }
  63. return false;
  64. }
  65. void MidiRPNDetector::ChannelState::resetValue() noexcept
  66. {
  67. valueMSB = 0xff;
  68. valueLSB = 0xff;
  69. }
  70. //==============================================================================
  71. bool MidiRPNDetector::ChannelState::sendIfReady (int channel, MidiRPNMessage& result) noexcept
  72. {
  73. if (parameterMSB < 0x80 && parameterLSB < 0x80)
  74. {
  75. if (valueMSB < 0x80)
  76. {
  77. result.channel = channel;
  78. result.parameterNumber = (parameterMSB << 7) + parameterLSB;
  79. result.isNRPN = isNRPN;
  80. if (valueLSB < 0x80)
  81. {
  82. result.value = (valueMSB << 7) + valueLSB;
  83. result.is14BitValue = true;
  84. }
  85. else
  86. {
  87. result.value = valueMSB;
  88. result.is14BitValue = false;
  89. }
  90. return true;
  91. }
  92. }
  93. return false;
  94. }
  95. //==============================================================================
  96. MidiBuffer MidiRPNGenerator::generate (MidiRPNMessage message)
  97. {
  98. return generate (message.channel,
  99. message.parameterNumber,
  100. message.value,
  101. message.isNRPN,
  102. message.is14BitValue);
  103. }
  104. MidiBuffer MidiRPNGenerator::generate (int midiChannel,
  105. int parameterNumber,
  106. int value,
  107. bool isNRPN,
  108. bool use14BitValue)
  109. {
  110. jassert (midiChannel > 0 && midiChannel <= 16);
  111. jassert (parameterNumber >= 0 && parameterNumber < 16384);
  112. jassert (value >= 0 && value < (use14BitValue ? 16384 : 128));
  113. uint8 parameterLSB = uint8 (parameterNumber & 0x0000007f);
  114. uint8 parameterMSB = uint8 (parameterNumber >> 7);
  115. uint8 valueLSB = use14BitValue ? uint8 (value & 0x0000007f) : 0x00;
  116. uint8 valueMSB = use14BitValue ? uint8 (value >> 7) : uint8 (value);
  117. uint8 channelByte = uint8 (0xb0 + midiChannel - 1);
  118. MidiBuffer buffer;
  119. buffer.addEvent (MidiMessage (channelByte, isNRPN ? 0x62 : 0x64, parameterLSB), 0);
  120. buffer.addEvent (MidiMessage (channelByte, isNRPN ? 0x63 : 0x65, parameterMSB), 0);
  121. // sending the value LSB is optional, but must come before sending the value MSB:
  122. if (use14BitValue)
  123. buffer.addEvent (MidiMessage (channelByte, 0x26, valueLSB), 0);
  124. buffer.addEvent (MidiMessage (channelByte, 0x06, valueMSB), 0);
  125. return buffer;
  126. }
  127. //==============================================================================
  128. //==============================================================================
  129. #if JUCE_UNIT_TESTS
  130. class MidiRPNDetectorTests : public UnitTest
  131. {
  132. public:
  133. MidiRPNDetectorTests() : UnitTest ("MidiRPNDetector class") {}
  134. void runTest() override
  135. {
  136. beginTest ("7-bit RPN");
  137. {
  138. MidiRPNDetector detector;
  139. MidiRPNMessage rpn;
  140. expect (! detector.parseControllerMessage (2, 101, 0, rpn));
  141. expect (! detector.parseControllerMessage (2, 100, 7, rpn));
  142. expect (detector.parseControllerMessage (2, 6, 42, rpn));
  143. expectEquals (rpn.channel, 2);
  144. expectEquals (rpn.parameterNumber, 7);
  145. expectEquals (rpn.value, 42);
  146. expect (! rpn.isNRPN);
  147. expect (! rpn.is14BitValue);
  148. }
  149. beginTest ("14-bit RPN");
  150. {
  151. MidiRPNDetector detector;
  152. MidiRPNMessage rpn;
  153. expect (! detector.parseControllerMessage (1, 100, 44, rpn));
  154. expect (! detector.parseControllerMessage (1, 101, 2, rpn));
  155. expect (! detector.parseControllerMessage (1, 38, 94, rpn));
  156. expect (detector.parseControllerMessage (1, 6, 1, rpn));
  157. expectEquals (rpn.channel, 1);
  158. expectEquals (rpn.parameterNumber, 300);
  159. expectEquals (rpn.value, 222);
  160. expect (! rpn.isNRPN);
  161. expect (rpn.is14BitValue);
  162. }
  163. beginTest ("RPNs on multiple channels simultaneously");
  164. {
  165. MidiRPNDetector detector;
  166. MidiRPNMessage rpn;
  167. expect (! detector.parseControllerMessage (1, 100, 44, rpn));
  168. expect (! detector.parseControllerMessage (2, 101, 0, rpn));
  169. expect (! detector.parseControllerMessage (1, 101, 2, rpn));
  170. expect (! detector.parseControllerMessage (2, 100, 7, rpn));
  171. expect (! detector.parseControllerMessage (1, 38, 94, rpn));
  172. expect (detector.parseControllerMessage (2, 6, 42, rpn));
  173. expectEquals (rpn.channel, 2);
  174. expectEquals (rpn.parameterNumber, 7);
  175. expectEquals (rpn.value, 42);
  176. expect (! rpn.isNRPN);
  177. expect (! rpn.is14BitValue);
  178. expect (detector.parseControllerMessage (1, 6, 1, rpn));
  179. expectEquals (rpn.channel, 1);
  180. expectEquals (rpn.parameterNumber, 300);
  181. expectEquals (rpn.value, 222);
  182. expect (! rpn.isNRPN);
  183. expect (rpn.is14BitValue);
  184. }
  185. beginTest ("14-bit RPN with value within 7-bit range");
  186. {
  187. MidiRPNDetector detector;
  188. MidiRPNMessage rpn;
  189. expect (! detector.parseControllerMessage (16, 100, 0 , rpn));
  190. expect (! detector.parseControllerMessage (16, 101, 0, rpn));
  191. expect (! detector.parseControllerMessage (16, 38, 3, rpn));
  192. expect (detector.parseControllerMessage (16, 6, 0, rpn));
  193. expectEquals (rpn.channel, 16);
  194. expectEquals (rpn.parameterNumber, 0);
  195. expectEquals (rpn.value, 3);
  196. expect (! rpn.isNRPN);
  197. expect (rpn.is14BitValue);
  198. }
  199. beginTest ("invalid RPN (wrong order)");
  200. {
  201. MidiRPNDetector detector;
  202. MidiRPNMessage rpn;
  203. expect (! detector.parseControllerMessage (2, 6, 42, rpn));
  204. expect (! detector.parseControllerMessage (2, 101, 0, rpn));
  205. expect (! detector.parseControllerMessage (2, 100, 7, rpn));
  206. }
  207. beginTest ("14-bit RPN interspersed with unrelated CC messages");
  208. {
  209. MidiRPNDetector detector;
  210. MidiRPNMessage rpn;
  211. expect (! detector.parseControllerMessage (16, 3, 80, rpn));
  212. expect (! detector.parseControllerMessage (16, 100, 0 , rpn));
  213. expect (! detector.parseControllerMessage (16, 4, 81, rpn));
  214. expect (! detector.parseControllerMessage (16, 101, 0, rpn));
  215. expect (! detector.parseControllerMessage (16, 5, 82, rpn));
  216. expect (! detector.parseControllerMessage (16, 5, 83, rpn));
  217. expect (! detector.parseControllerMessage (16, 38, 3, rpn));
  218. expect (! detector.parseControllerMessage (16, 4, 84, rpn));
  219. expect (! detector.parseControllerMessage (16, 3, 85, rpn));
  220. expect (detector.parseControllerMessage (16, 6, 0, rpn));
  221. expectEquals (rpn.channel, 16);
  222. expectEquals (rpn.parameterNumber, 0);
  223. expectEquals (rpn.value, 3);
  224. expect (! rpn.isNRPN);
  225. expect (rpn.is14BitValue);
  226. }
  227. beginTest ("14-bit NRPN");
  228. {
  229. MidiRPNDetector detector;
  230. MidiRPNMessage rpn;
  231. expect (! detector.parseControllerMessage (1, 98, 44, rpn));
  232. expect (! detector.parseControllerMessage (1, 99 , 2, rpn));
  233. expect (! detector.parseControllerMessage (1, 38, 94, rpn));
  234. expect (detector.parseControllerMessage (1, 6, 1, rpn));
  235. expectEquals (rpn.channel, 1);
  236. expectEquals (rpn.parameterNumber, 300);
  237. expectEquals (rpn.value, 222);
  238. expect (rpn.isNRPN);
  239. expect (rpn.is14BitValue);
  240. }
  241. beginTest ("reset");
  242. {
  243. MidiRPNDetector detector;
  244. MidiRPNMessage rpn;
  245. expect (! detector.parseControllerMessage (2, 101, 0, rpn));
  246. detector.reset();
  247. expect (! detector.parseControllerMessage (2, 100, 7, rpn));
  248. expect (! detector.parseControllerMessage (2, 6, 42, rpn));
  249. }
  250. }
  251. };
  252. static MidiRPNDetectorTests MidiRPNDetectorUnitTests;
  253. //==============================================================================
  254. class MidiRPNGeneratorTests : public UnitTest
  255. {
  256. public:
  257. MidiRPNGeneratorTests() : UnitTest ("MidiRPNGenerator class") {}
  258. void runTest() override
  259. {
  260. beginTest ("generating RPN/NRPN");
  261. {
  262. {
  263. MidiBuffer buffer = MidiRPNGenerator::generate (1, 23, 1337, true, true);
  264. expectContainsRPN (buffer, 1, 23, 1337, true, true);
  265. }
  266. {
  267. MidiBuffer buffer = MidiRPNGenerator::generate (16, 101, 34, false, false);
  268. expectContainsRPN (buffer, 16, 101, 34, false, false);
  269. }
  270. {
  271. MidiRPNMessage message = { 16, 101, 34, false, false };
  272. MidiBuffer buffer = MidiRPNGenerator::generate (message);
  273. expectContainsRPN (buffer, message);
  274. }
  275. }
  276. }
  277. private:
  278. //==============================================================================
  279. void expectContainsRPN (const MidiBuffer& midiBuffer,
  280. int channel,
  281. int parameterNumber,
  282. int value,
  283. bool isNRPN,
  284. bool is14BitValue)
  285. {
  286. MidiRPNMessage expected = { channel, parameterNumber, value, isNRPN, is14BitValue };
  287. expectContainsRPN (midiBuffer, expected);
  288. }
  289. //==============================================================================
  290. void expectContainsRPN (const MidiBuffer& midiBuffer, MidiRPNMessage expected)
  291. {
  292. MidiBuffer::Iterator iter (midiBuffer);
  293. MidiMessage midiMessage;
  294. MidiRPNMessage result = MidiRPNMessage();
  295. MidiRPNDetector detector;
  296. int samplePosition; // not actually used, so no need to initialise.
  297. while (iter.getNextEvent (midiMessage, samplePosition))
  298. {
  299. if (detector.parseControllerMessage (midiMessage.getChannel(),
  300. midiMessage.getControllerNumber(),
  301. midiMessage.getControllerValue(),
  302. result))
  303. break;
  304. }
  305. expectEquals (result.channel, expected.channel);
  306. expectEquals (result.parameterNumber, expected.parameterNumber);
  307. expectEquals (result.value, expected.value);
  308. expect (result.isNRPN == expected.isNRPN),
  309. expect (result.is14BitValue == expected.is14BitValue);
  310. }
  311. };
  312. static MidiRPNGeneratorTests MidiRPNGeneratorUnitTests;
  313. #endif // JUCE_UNIT_TESTS