|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- #pragma once
- #include <dsp/common.hpp>
- #include <midi.hpp>
-
-
- namespace rack {
- namespace dsp {
-
-
- /** Converts gates and CV to MIDI messages.
- CHANNELS is the number of polyphony channels. Use 1 for monophonic.
- */
- template <int CHANNELS>
- struct MidiGenerator {
- int8_t vels[CHANNELS];
- int8_t notes[CHANNELS];
- bool gates[CHANNELS];
- int8_t keyPressures[CHANNELS];
- int8_t channelPressure;
- int8_t ccs[128];
- int16_t pw;
- bool clk;
- bool start;
- bool stop;
- bool cont;
-
- MidiGenerator() {
- reset();
- }
-
- void reset() {
- for (int c = 0; c < CHANNELS; c++) {
- vels[c] = 100;
- notes[c] = 60;
- gates[c] = false;
- keyPressures[c] = -1;
- }
- channelPressure = -1;
- for (int i = 0; i < 128; i++) {
- ccs[i] = -1;
- }
- pw = 0x2000;
- clk = false;
- start = false;
- stop = false;
- cont = false;
- }
-
- void panic() {
- reset();
- // Send all note off commands
- for (int note = 0; note <= 127; note++) {
- // Note off
- midi::Message m;
- m.setStatus(0x8);
- m.setNote(note);
- m.setValue(0);
- onMessage(m);
- }
- }
-
- /** Must be called before setNoteGate(). */
- void setVelocity(int8_t vel, int c) {
- vels[c] = vel;
- }
-
- void setNoteGate(int8_t note, bool gate, int c) {
- bool changedNote = gate && gates[c] && (note != notes[c]);
- bool enabledGate = gate && !gates[c];
- bool disabledGate = !gate && gates[c];
- if (changedNote || disabledGate) {
- // Note off
- midi::Message m;
- m.setStatus(0x8);
- m.setNote(notes[c]);
- m.setValue(vels[c]);
- onMessage(m);
- }
- if (changedNote || enabledGate) {
- // Note on
- midi::Message m;
- m.setStatus(0x9);
- m.setNote(note);
- m.setValue(vels[c]);
- onMessage(m);
- }
- notes[c] = note;
- gates[c] = gate;
- }
-
- void setKeyPressure(int8_t val, int c) {
- if (keyPressures[c] == val)
- return;
- keyPressures[c] = val;
- // Polyphonic key pressure
- midi::Message m;
- m.setStatus(0xa);
- m.setNote(notes[c]);
- m.setValue(val);
- onMessage(m);
- }
-
- void setChannelPressure(int8_t val) {
- if (channelPressure == val)
- return;
- channelPressure = val;
- // Channel pressure
- midi::Message m;
- m.setSize(2);
- m.setStatus(0xd);
- m.setNote(val);
- onMessage(m);
- }
-
- void setCc(int8_t cc, int id) {
- if (ccs[id] == cc)
- return;
- ccs[id] = cc;
- // Continuous controller
- midi::Message m;
- m.setStatus(0xb);
- m.setNote(id);
- m.setValue(cc);
- onMessage(m);
- }
-
- void setModWheel(int8_t cc) {
- setCc(cc, 0x01);
- }
-
- void setVolume(int8_t cc) {
- setCc(cc, 0x07);
- }
-
- void setBalance(int8_t cc) {
- setCc(cc, 0x08);
- }
-
- void setPan(int8_t cc) {
- setCc(cc, 0x0a);
- }
-
- void setSustainPedal(int8_t cc) {
- setCc(cc, 0x40);
- }
-
- void setPitchWheel(int16_t pw) {
- if (this->pw == pw)
- return;
- this->pw = pw;
- // Pitch wheel
- midi::Message m;
- m.setStatus(0xe);
- m.setNote(pw & 0x7f);
- m.setValue((pw >> 7) & 0x7f);
- onMessage(m);
- }
-
- void setClock(bool clk) {
- if (this->clk == clk)
- return;
- this->clk = clk;
- if (clk) {
- // Timing clock
- midi::Message m;
- m.setSize(1);
- m.setStatus(0xf);
- m.setChannel(0x8);
- onMessage(m);
- }
- }
-
- void setStart(bool start) {
- if (this->start == start)
- return;
- this->start = start;
- if (start) {
- // Start
- midi::Message m;
- m.setSize(1);
- m.setStatus(0xf);
- m.setChannel(0xa);
- onMessage(m);
- }
- }
-
- void setContinue(bool cont) {
- if (this->cont == cont)
- return;
- this->cont = cont;
- if (cont) {
- // Continue
- midi::Message m;
- m.setSize(1);
- m.setStatus(0xf);
- m.setChannel(0xb);
- onMessage(m);
- }
- }
-
- void setStop(bool stop) {
- if (this->stop == stop)
- return;
- this->stop = stop;
- if (stop) {
- // Stop
- midi::Message m;
- m.setSize(1);
- m.setStatus(0xf);
- m.setChannel(0xc);
- onMessage(m);
- }
- }
-
- virtual void onMessage(const midi::Message &message) {}
- };
-
-
- } // namespace dsp
- } // namespace rack
|