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.

midi.hpp 3.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #pragma once
  2. #include <dsp/common.hpp>
  3. #include <midi.hpp>
  4. namespace rack {
  5. namespace dsp {
  6. /** Converts gates and CV to MIDI messages.
  7. CHANNELS is the number of polyphony channels. Use 1 for monophonic.
  8. */
  9. template <int CHANNELS>
  10. struct MidiGenerator {
  11. int8_t vels[CHANNELS];
  12. int8_t notes[CHANNELS];
  13. bool gates[CHANNELS];
  14. int8_t keyPressures[CHANNELS];
  15. int8_t channelPressure;
  16. int8_t ccs[128];
  17. int16_t pw;
  18. bool clk;
  19. bool start;
  20. bool stop;
  21. bool cont;
  22. MidiGenerator() {
  23. reset();
  24. }
  25. void reset() {
  26. for (int c = 0; c < CHANNELS; c++) {
  27. vels[c] = 100;
  28. notes[c] = 60;
  29. gates[c] = false;
  30. keyPressures[c] = -1;
  31. }
  32. channelPressure = -1;
  33. for (int i = 0; i < 128; i++) {
  34. ccs[i] = -1;
  35. }
  36. pw = 0x2000;
  37. clk = false;
  38. start = false;
  39. stop = false;
  40. cont = false;
  41. }
  42. void panic() {
  43. reset();
  44. // Send all note off commands
  45. for (int note = 0; note <= 127; note++) {
  46. // Note off
  47. midi::Message m;
  48. m.setStatus(0x8);
  49. m.setNote(note);
  50. m.setValue(0);
  51. onMessage(m);
  52. }
  53. }
  54. /** Must be called before setNoteGate(). */
  55. void setVelocity(int8_t vel, int c) {
  56. vels[c] = vel;
  57. }
  58. void setNoteGate(int8_t note, bool gate, int c) {
  59. bool changedNote = gate && gates[c] && (note != notes[c]);
  60. bool enabledGate = gate && !gates[c];
  61. bool disabledGate = !gate && gates[c];
  62. if (changedNote || disabledGate) {
  63. // Note off
  64. midi::Message m;
  65. m.setStatus(0x8);
  66. m.setNote(notes[c]);
  67. m.setValue(vels[c]);
  68. onMessage(m);
  69. }
  70. if (changedNote || enabledGate) {
  71. // Note on
  72. midi::Message m;
  73. m.setStatus(0x9);
  74. m.setNote(note);
  75. m.setValue(vels[c]);
  76. onMessage(m);
  77. }
  78. notes[c] = note;
  79. gates[c] = gate;
  80. }
  81. void setKeyPressure(int8_t val, int c) {
  82. if (keyPressures[c] == val)
  83. return;
  84. keyPressures[c] = val;
  85. // Polyphonic key pressure
  86. midi::Message m;
  87. m.setStatus(0xa);
  88. m.setNote(notes[c]);
  89. m.setValue(val);
  90. onMessage(m);
  91. }
  92. void setChannelPressure(int8_t val) {
  93. if (channelPressure == val)
  94. return;
  95. channelPressure = val;
  96. // Channel pressure
  97. midi::Message m;
  98. m.setSize(2);
  99. m.setStatus(0xd);
  100. m.setNote(val);
  101. onMessage(m);
  102. }
  103. void setCc(int8_t cc, int id) {
  104. if (ccs[id] == cc)
  105. return;
  106. ccs[id] = cc;
  107. // Continuous controller
  108. midi::Message m;
  109. m.setStatus(0xb);
  110. m.setNote(id);
  111. m.setValue(cc);
  112. onMessage(m);
  113. }
  114. void setModWheel(int8_t cc) {
  115. setCc(cc, 0x01);
  116. }
  117. void setVolume(int8_t cc) {
  118. setCc(cc, 0x07);
  119. }
  120. void setBalance(int8_t cc) {
  121. setCc(cc, 0x08);
  122. }
  123. void setPan(int8_t cc) {
  124. setCc(cc, 0x0a);
  125. }
  126. void setSustainPedal(int8_t cc) {
  127. setCc(cc, 0x40);
  128. }
  129. void setPitchWheel(int16_t pw) {
  130. if (this->pw == pw)
  131. return;
  132. this->pw = pw;
  133. // Pitch wheel
  134. midi::Message m;
  135. m.setStatus(0xe);
  136. m.setNote(pw & 0x7f);
  137. m.setValue((pw >> 7) & 0x7f);
  138. onMessage(m);
  139. }
  140. void setClock(bool clk) {
  141. if (this->clk == clk)
  142. return;
  143. this->clk = clk;
  144. if (clk) {
  145. // Timing clock
  146. midi::Message m;
  147. m.setSize(1);
  148. m.setStatus(0xf);
  149. m.setChannel(0x8);
  150. onMessage(m);
  151. }
  152. }
  153. void setStart(bool start) {
  154. if (this->start == start)
  155. return;
  156. this->start = start;
  157. if (start) {
  158. // Start
  159. midi::Message m;
  160. m.setSize(1);
  161. m.setStatus(0xf);
  162. m.setChannel(0xa);
  163. onMessage(m);
  164. }
  165. }
  166. void setContinue(bool cont) {
  167. if (this->cont == cont)
  168. return;
  169. this->cont = cont;
  170. if (cont) {
  171. // Continue
  172. midi::Message m;
  173. m.setSize(1);
  174. m.setStatus(0xf);
  175. m.setChannel(0xb);
  176. onMessage(m);
  177. }
  178. }
  179. void setStop(bool stop) {
  180. if (this->stop == stop)
  181. return;
  182. this->stop = stop;
  183. if (stop) {
  184. // Stop
  185. midi::Message m;
  186. m.setSize(1);
  187. m.setStatus(0xf);
  188. m.setChannel(0xc);
  189. onMessage(m);
  190. }
  191. }
  192. virtual void onMessage(const midi::Message &message) {}
  193. };
  194. } // namespace dsp
  195. } // namespace rack