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.

271 lines
7.9KB

  1. // Copyright 2013 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. //
  25. // -----------------------------------------------------------------------------
  26. //
  27. // MIDI event handler.
  28. #include "yarns/midi_handler.h"
  29. #include <algorithm>
  30. #include "yarns/multi.h"
  31. #ifndef TEST
  32. #include "yarns/storage_manager.h"
  33. #endif // TEST
  34. namespace yarns {
  35. using namespace std;
  36. /* static */
  37. MidiHandler::MidiBuffer MidiHandler::input_buffer_;
  38. /* static */
  39. MidiHandler::MidiBuffer MidiHandler::output_buffer_;
  40. /* static */
  41. MidiHandler::SmallMidiBuffer MidiHandler::high_priority_output_buffer_;
  42. /* static */
  43. stmlib_midi::MidiStreamParser<MidiHandler> MidiHandler::parser_;
  44. /* static */
  45. const MidiHandler::SysExDescription MidiHandler::accepted_sysex_[] = {
  46. { { 0xf0, 0x00, 0x21, 0x02, 0x00, 0x0b }, 6, 0xff,
  47. &MidiHandler::HandleYarnsSpecificMessage },
  48. { { 0xf0, 0x7f, 0xff, 0x08, 0x08 }, 5, 21,
  49. &MidiHandler::HandleScaleOctaveTuning1ByteForm },
  50. { { 0xf0, 0x7e, 0xff, 0x08, 0x08 }, 5, 21,
  51. &MidiHandler::HandleScaleOctaveTuning1ByteForm },
  52. { { 0xf0, 0x7f, 0xff, 0x08, 0x09 }, 5, 33,
  53. &MidiHandler::HandleScaleOctaveTuning2ByteForm },
  54. { { 0xf0, 0x7e, 0xff, 0x08, 0x09 }, 5, 33,
  55. &MidiHandler::HandleScaleOctaveTuning2ByteForm }
  56. };
  57. /* static */
  58. uint8_t MidiHandler::sysex_rx_write_ptr_;
  59. /* static */
  60. uint8_t MidiHandler::previous_packet_index_;
  61. /* static */
  62. uint8_t MidiHandler::sysex_rx_buffer_[kSysexRxBufferSize];
  63. /* static */
  64. uint8_t MidiHandler::calibration_voice_;
  65. /* static */
  66. uint8_t MidiHandler::calibration_note_;
  67. /* static */
  68. bool MidiHandler::factory_testing_requested_;
  69. /* static */
  70. void MidiHandler::Init() {
  71. input_buffer_.Init();
  72. output_buffer_.Init();
  73. high_priority_output_buffer_.Init();
  74. sysex_rx_write_ptr_ = 0;
  75. previous_packet_index_ = 0;
  76. calibration_voice_ = 0xff;
  77. calibration_note_ = 0xff;
  78. factory_testing_requested_ = false;
  79. }
  80. /* static */
  81. void MidiHandler::DecodeSysExMessage() {
  82. uint8_t length = sysex_rx_write_ptr_;
  83. if (sysex_rx_buffer_[length - 1] != 0xf7) {
  84. // Discard long messages that have been truncated.
  85. return;
  86. }
  87. for (uint8_t i = 0;
  88. i < sizeof(accepted_sysex_) / sizeof(SysExDescription);
  89. ++i) {
  90. const SysExDescription& description = accepted_sysex_[i];
  91. if (description.expected_size == length ||
  92. description.expected_size == 0xff) {
  93. bool match = true;
  94. for (uint8_t j = 0; j < description.prefix_length; ++j) {
  95. if (description.prefix[j] != sysex_rx_buffer_[j] &&
  96. description.prefix[j] != 0xff) {
  97. match = false;
  98. break;
  99. }
  100. }
  101. if (match) {
  102. (*description.handler)();
  103. break;
  104. }
  105. }
  106. }
  107. }
  108. /* static */
  109. void MidiHandler::HandleScaleOctaveTuning1ByteForm() {
  110. for (uint8_t pitch_class = 0; pitch_class < 12; ++pitch_class) {
  111. int16_t correction = sysex_rx_buffer_[8 + pitch_class];
  112. correction -= 64;
  113. correction = (correction * 128 + (correction > 0 ? 64 : -64)) / 100;
  114. multi.set_custom_pitch(pitch_class, correction);
  115. }
  116. }
  117. /* static */
  118. void MidiHandler::HandleScaleOctaveTuning2ByteForm() {
  119. for (uint8_t pitch_class = 0; pitch_class < 12; ++pitch_class) {
  120. int16_t correction = sysex_rx_buffer_[8 + pitch_class * 2] << 7;
  121. correction += sysex_rx_buffer_[9 + pitch_class * 2];
  122. correction -= 8192;
  123. correction >>= 6;
  124. multi.set_custom_pitch(pitch_class, correction);
  125. }
  126. }
  127. enum SysExCommand {
  128. SYSEX_COMMAND_DUMP_PACKET = 1,
  129. SYSEX_COMMAND_REQUEST_PACKETS = 17,
  130. SYSEX_COMMAND_FACTORY_TESTING_MODE = 32,
  131. SYSEX_COMMAND_CALIBRATE = 33,
  132. };
  133. /* static */
  134. void MidiHandler::HandleYarnsSpecificMessage() {
  135. #ifndef TEST
  136. uint8_t command = sysex_rx_buffer_[6];
  137. if (command == SYSEX_COMMAND_DUMP_PACKET) {
  138. uint8_t packet_index = sysex_rx_buffer_[7];
  139. // Handle packet reception.
  140. if (packet_index != 0 && packet_index != previous_packet_index_ + 1) {
  141. // Packet not in sequence!
  142. return;
  143. }
  144. previous_packet_index_ = packet_index;
  145. // Denibblize.
  146. uint8_t* data = &sysex_rx_buffer_[8];
  147. uint8_t* byte_ptr = data;
  148. uint8_t* nibble_ptr = data;
  149. uint8_t checksum = 0;
  150. while (*nibble_ptr != 0xf7 &&
  151. static_cast<size_t>(byte_ptr - data) <= kSysexMaxChunkSize + 1) {
  152. *byte_ptr = (*nibble_ptr++) << 4;
  153. *byte_ptr |= (*nibble_ptr++);
  154. // Warning! The last byte of the block, which is the checksum
  155. // is summed here!
  156. checksum += *byte_ptr++;
  157. }
  158. size_t size = byte_ptr - data - 1;
  159. checksum -= data[size];
  160. if (checksum != data[size]) {
  161. previous_packet_index_ = 0xff;
  162. return;
  163. }
  164. if (size != 0) {
  165. storage_manager.AppendData(data, size, packet_index == 0);
  166. } else if (packet_index) {
  167. storage_manager.DeserializeMulti();
  168. }
  169. } else if (command == SYSEX_COMMAND_REQUEST_PACKETS) {
  170. if (sysex_rx_buffer_[7] == 0 &&
  171. sysex_rx_buffer_[8] == 0 &&
  172. sysex_rx_buffer_[9] == 0 &&
  173. sysex_rx_buffer_[10] == 0xf7) {
  174. storage_manager.SysExSendMulti();
  175. }
  176. } else if (command == SYSEX_COMMAND_FACTORY_TESTING_MODE) {
  177. if (sysex_rx_buffer_[7] == 0 &&
  178. sysex_rx_buffer_[8] == 0 &&
  179. sysex_rx_buffer_[9] == 0 &&
  180. sysex_rx_buffer_[10] == 0xf7) {
  181. factory_testing_requested_ = true;
  182. }
  183. } else if (command == SYSEX_COMMAND_CALIBRATE) {
  184. calibration_voice_ = sysex_rx_buffer_[7] >> 4;
  185. calibration_note_ = sysex_rx_buffer_[7] & 0xf;
  186. if (calibrating()) {
  187. uint16_t dac_code = (sysex_rx_buffer_[8] << 12) | (sysex_rx_buffer_[9] << 8) |
  188. (sysex_rx_buffer_[10] << 4) | (sysex_rx_buffer_[11] << 0);
  189. Voice* voice = multi.mutable_voice(calibration_voice_);
  190. voice->set_calibration_dac_code(calibration_note_, dac_code);
  191. } else {
  192. storage_manager.SaveCalibration();
  193. }
  194. }
  195. #endif // TEST
  196. }
  197. /* static */
  198. void MidiHandler::SysExSendPacket(
  199. uint8_t packet_index,
  200. const uint8_t* data,
  201. size_t size) {
  202. Flush();
  203. for (uint8_t i = 0; i < 6; ++i) {
  204. SendBlocking(accepted_sysex_[0].prefix[i]);
  205. }
  206. SendBlocking(SYSEX_COMMAND_DUMP_PACKET);
  207. SendBlocking(packet_index);
  208. // Outputs the data.
  209. uint8_t checksum = 0;
  210. for (uint8_t i = 0; i < size; ++i) {
  211. checksum += data[i];
  212. SendBlocking(data[i] >> 4);
  213. SendBlocking(data[i] & 0x0f);
  214. }
  215. // Outputs a checksum.
  216. SendBlocking(checksum >> 4);
  217. SendBlocking(checksum & 0x0f);
  218. // End of SysEx block.
  219. SendBlocking(0xf7);
  220. Flush();
  221. }
  222. /* static */
  223. void MidiHandler::SysExSendPackets(const uint8_t* data, size_t size) {
  224. uint8_t block_index = 0;
  225. while (size) {
  226. size_t chunk_size = min(size, kSysexMaxChunkSize);
  227. SysExSendPacket(block_index, data, chunk_size);
  228. size -= chunk_size;
  229. data += chunk_size;
  230. ++block_index;
  231. }
  232. // Send a NULL packet to indicate end of transmission.
  233. SysExSendPacket(block_index, NULL, 0);
  234. }
  235. /* extern */
  236. MidiHandler midi_handler;
  237. } // namespace yarns