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.

292 lines
7.6KB

  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. #ifndef YARNS_MIDI_HANDLER_H_
  29. #define YARNS_MIDI_HANDLER_H_
  30. #include "stmlib/stmlib.h"
  31. #include "stmlib/utils/ring_buffer.h"
  32. #include "stmlib/midi/midi.h"
  33. #include "yarns/multi.h"
  34. namespace yarns {
  35. const size_t kSysexMaxChunkSize = 64;
  36. const size_t kSysexRxBufferSize = kSysexMaxChunkSize * 2 + 16;
  37. class MidiHandler {
  38. public:
  39. typedef stmlib::RingBuffer<uint8_t, 128> MidiBuffer;
  40. typedef stmlib::RingBuffer<uint8_t, 32> SmallMidiBuffer;
  41. MidiHandler() { }
  42. ~MidiHandler() { }
  43. static void Init();
  44. static void NoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
  45. if (multi.NoteOn(channel, note, velocity) && !multi.direct_thru()) {
  46. Send3(0x90 | channel, note, velocity);
  47. }
  48. }
  49. static void NoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
  50. if (multi.NoteOff(channel, note, velocity) && !multi.direct_thru()) {
  51. Send3(0x80 | channel, note, 0);
  52. }
  53. }
  54. static void Aftertouch(uint8_t channel, uint8_t note, uint8_t velocity) {
  55. if (multi.Aftertouch(channel, note, velocity) && !multi.direct_thru()) {
  56. Send3(0xa0 | channel, note, velocity);
  57. }
  58. }
  59. static void Aftertouch(uint8_t channel, uint8_t velocity) {
  60. if (multi.Aftertouch(channel, velocity) && !multi.direct_thru()) {
  61. Send2(0xd0 | channel, velocity);
  62. }
  63. }
  64. static void ControlChange(
  65. uint8_t channel,
  66. uint8_t controller,
  67. uint8_t value) {
  68. if (multi.ControlChange(channel, controller, value) && !multi.direct_thru()) {
  69. Send3(0xb0 | channel, controller, value);
  70. }
  71. }
  72. static void ProgramChange(uint8_t channel, uint8_t program) {
  73. if (!multi.direct_thru()) {
  74. Send2(0xc0 | channel, program);
  75. }
  76. }
  77. static void PitchBend(uint8_t channel, uint16_t pitch_bend) {
  78. if (multi.PitchBend(channel, pitch_bend) && !multi.direct_thru()) {
  79. Send3(0xe0 | channel, pitch_bend & 0x7f, pitch_bend >> 7);
  80. }
  81. }
  82. static void SysExStart() {
  83. sysex_rx_write_ptr_ = 0;
  84. ProcessSysExByte(0xf0);
  85. }
  86. static void SysExByte(uint8_t sysex_byte) {
  87. ProcessSysExByte(sysex_byte);
  88. }
  89. static void SysExEnd() {
  90. ProcessSysExByte(0xf7);
  91. DecodeSysExMessage();
  92. }
  93. static void BozoByte(uint8_t bozo_byte) { }
  94. static void Clock() {
  95. if (!multi.internal_clock()) {
  96. multi.Clock();
  97. }
  98. }
  99. static void Start() {
  100. if (!multi.internal_clock()) {
  101. multi.Start(false);
  102. }
  103. }
  104. static void Continue() {
  105. if (!multi.internal_clock()) {
  106. multi.Continue();
  107. }
  108. }
  109. static void Stop() {
  110. if (!multi.internal_clock()) {
  111. multi.Stop();
  112. }
  113. }
  114. static void Reset() {
  115. multi.Reset();
  116. }
  117. static bool CheckChannel(uint8_t channel) { return true; }
  118. static void RawByte(uint8_t byte) {
  119. if (multi.direct_thru()) {
  120. if (byte != 0xfa && byte != 0xf8 && byte != 0xfc) {
  121. output_buffer_.Overwrite(byte);
  122. }
  123. }
  124. }
  125. static void RawMidiData(
  126. uint8_t status,
  127. uint8_t* data,
  128. uint8_t data_size,
  129. uint8_t accepted_channel) {
  130. }
  131. static void OnInternalNoteOn(
  132. uint8_t channel,
  133. uint8_t note,
  134. uint8_t velocity) {
  135. Send3(0x90 | channel, note, velocity);
  136. }
  137. static void OnInternalNoteOff(uint8_t channel, uint8_t note) {
  138. Send3(0x80 | channel, note, 0);
  139. }
  140. static void OnClock() {
  141. SendNow(0xf8);
  142. }
  143. static void OnStart() {
  144. SendNow(0xfa);
  145. }
  146. static void OnStop() {
  147. SendNow(0xfc);
  148. }
  149. static void PushByte(uint8_t byte) {
  150. input_buffer_.Overwrite(byte);
  151. }
  152. static void ProcessInput() {
  153. while (input_buffer_.readable()) {
  154. parser_.PushByte(input_buffer_.ImmediateRead());
  155. }
  156. }
  157. static inline MidiBuffer* mutable_output_buffer() { return &output_buffer_; }
  158. static inline SmallMidiBuffer* mutable_high_priority_output_buffer() {
  159. return &high_priority_output_buffer_;
  160. }
  161. static inline void Send3(uint8_t byte_1, uint8_t byte_2, uint8_t byte_3) {
  162. output_buffer_.Overwrite(byte_1);
  163. output_buffer_.Overwrite(byte_2);
  164. output_buffer_.Overwrite(byte_3);
  165. }
  166. static inline void Send2(uint8_t byte_1, uint8_t byte_2) {
  167. output_buffer_.Overwrite(byte_1);
  168. output_buffer_.Overwrite(byte_2);
  169. }
  170. static inline void Send1(uint8_t byte) {
  171. output_buffer_.Overwrite(byte);
  172. }
  173. static inline void SendBlocking(uint8_t byte) {
  174. output_buffer_.Write(byte);
  175. }
  176. static inline void SendNow(uint8_t byte) {
  177. high_priority_output_buffer_.Overwrite(byte);
  178. }
  179. typedef void (*SysExHandlerFn)();
  180. struct SysExDescription {
  181. uint8_t prefix[8];
  182. uint8_t prefix_length;
  183. uint8_t expected_size;
  184. SysExHandlerFn handler;
  185. };
  186. static void Flush() {
  187. while (output_buffer_.readable());
  188. }
  189. static void SysExSendPackets(const uint8_t* data, size_t size);
  190. static inline bool calibrating() {
  191. return calibration_voice_ < kNumVoices && calibration_note_ < kNumOctaves;
  192. }
  193. static inline uint8_t calibration_voice() { return calibration_voice_; }
  194. static inline uint8_t calibration_note() { return calibration_note_; }
  195. static inline bool factory_testing_requested() {
  196. return factory_testing_requested_;
  197. }
  198. static void AcknowledgeFactoryTestingRequest() {
  199. factory_testing_requested_ = false;
  200. }
  201. private:
  202. static void SysExSendPacket(
  203. uint8_t packet_index,
  204. const uint8_t* data,
  205. size_t size);
  206. static void DecodeSysExMessage();
  207. inline static void ProcessSysExByte(uint8_t sysex_byte) {
  208. if (!multi.direct_thru()) {
  209. Send1(sysex_byte);
  210. }
  211. if (sysex_rx_write_ptr_ < sizeof(sysex_rx_buffer_)) {
  212. sysex_rx_buffer_[sysex_rx_write_ptr_++] = sysex_byte;
  213. }
  214. }
  215. static void HandleScaleOctaveTuning1ByteForm();
  216. static void HandleScaleOctaveTuning2ByteForm();
  217. static void HandleYarnsSpecificMessage();
  218. static MidiBuffer input_buffer_;
  219. static MidiBuffer output_buffer_;
  220. static SmallMidiBuffer high_priority_output_buffer_;
  221. static stmlib_midi::MidiStreamParser<MidiHandler> parser_;
  222. static uint8_t sysex_rx_buffer_[kSysexRxBufferSize];
  223. static uint8_t sysex_rx_write_ptr_;
  224. static uint8_t previous_packet_index_;
  225. static uint8_t calibration_voice_;
  226. static uint8_t calibration_note_;
  227. static bool factory_testing_requested_;
  228. static const SysExDescription accepted_sysex_[];
  229. DISALLOW_COPY_AND_ASSIGN(MidiHandler);
  230. };
  231. extern MidiHandler midi_handler;
  232. } // namespace yarns
  233. #endif // YARNS_MIDI_HANDLER_H_