| 
							- #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;
 - 	int64_t frame = -1;
 - 
 - 	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);
 - 			m.setFrame(frame);
 - 			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]);
 - 			m.setFrame(frame);
 - 			onMessage(m);
 - 		}
 - 		if (changedNote || enabledGate) {
 - 			// Note on
 - 			midi::Message m;
 - 			m.setStatus(0x9);
 - 			m.setNote(note);
 - 			m.setValue(vels[c]);
 - 			m.setFrame(frame);
 - 			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);
 - 		m.setFrame(frame);
 - 		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);
 - 		m.setFrame(frame);
 - 		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);
 - 		m.setFrame(frame);
 - 		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);
 - 		m.setFrame(frame);
 - 		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);
 - 			m.setFrame(frame);
 - 			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);
 - 			m.setFrame(frame);
 - 			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);
 - 			m.setFrame(frame);
 - 			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);
 - 			m.setFrame(frame);
 - 			onMessage(m);
 - 		}
 - 	}
 - 
 - 	void setFrame(int64_t frame) {
 - 		this->frame = frame;
 - 	}
 - 
 - 	virtual void onMessage(const midi::Message& message) {}
 - };
 - 
 - 
 - } // namespace dsp
 - } // namespace rack
 
 
  |