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.

237 lines
4.0KB

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