Newer
Older
#include "MIDIUSB.h" // see https://github.com/arduino-libraries/MIDIUSB
#define DEBUG
#undef DEBUG
#define OVERALL_VELOCITY_PIN 10
#define VALVE_1 7 // 6mm
#define VALVE_2 6 // 6mm
#define VALVE_3 9 // 6mm
#define VALVE_4 8 // 4mm
#define VALVE_5 5 // 4mm
// array of currently active notes, index 0 is the oldest one
int16_t notes[NUM_VALVES] = {-1, -1, -1, -1, -1};
// array of the length of the tone period required to create the tone
uint16_t periods[NUM_VALVES] = {0, 0, 0, 0, 0};
// array of the current state of the valve pins (for tone periods)
uint8_t states[NUM_VALVES] = {0, 0, 0, 0, 0};
// array for the period timer helpers
uint64_t lastNoteMicros[NUM_VALVES] = {0, 0, 0, 0, 0};
// array of the valve pin numbers
const uint8_t valves[NUM_VALVES] = {VALVE_1, VALVE_2, VALVE_3, VALVE_4, VALVE_5};
// MIDI parameter overview
// First parameter is the event type (0x0B = control change).
// Second parameter is the event type, combined with the channel.
// Third parameter is the control number number (0-119).
// Fourth parameter is the control value (0-127).
void setup() {
#ifdef DEBUG
Serial.begin(115200);
#endif
Serial1.begin(31250); // MIDI baud rate
// initialize valve output pins
for (uint8_t i = 0; i < NUM_VALVES; i++) {
pinMode(valves[i], OUTPUT);
}
pinMode(OVERALL_VELOCITY_PIN, OUTPUT);
// calculates the frequency according to the midi note number
#ifdef DEBUG
Serial.print(number);
Serial.print(" | ");
#endif
double _n = (double)((double)number - (double)69);
#ifdef DEBUG
Serial.print(_n);
Serial.print(" | ");
#endif
d = pow((double)2, _n / (double)12) * (double)440 * (double) 1.015;
} else if (number < 57) { // c4
d = pow((double)2, _n / (double)12) * (double)440 * (double) 1.02;
} else if (number < 60) { // c5
d = pow((double)2, _n / (double)12) * (double)440 * (double) 1.025;
} else {
d = pow((double)2, _n / (double)12) * (double)440 * (double) 1.04;
d = pow((double)2, _n / (double)12) * (double)440;
#ifdef DEBUG
Serial.println(d);
#endif
// puts the note into the notes array or removes it if already present
int8_t putNote(int8_t note, uint8_t state) {
for (uint8_t i = 0; i < NUM_VALVES; i++) {
if (notes[i] == -1 && state == 1) { // note on
notes[i] = note;
return i;
} else if (notes[i] == note && state == 0) { // note off
//notes[i] = -1;
for (uint8_t j = i; j < NUM_VALVES - 1; j++) {
periods[j] = periods[j + 1];
states[j] = states[j + 1];
lastNoteMicros[j] = lastNoteMicros[j + 1];
}
notes[NUM_VALVES - 1] = -1;
periods[NUM_VALVES - 1] = 0;
states[NUM_VALVES - 1] = 0;
lastNoteMicros[NUM_VALVES - 1] = 0;
if (state == 0) {
return -1;
}
// remove oldest note and shift other notes
for (int8_t i = 0; i < NUM_VALVES - 1; i++) {
notes[i] = notes[i + 1];
}
notes[NUM_VALVES - 1] = note;
return NUM_VALVES - 1;
}
void loop() {
if (counter == 100) {
counter = 0;
// handle USB MIDI IN
midiEventPacket_t rx;
rx = MidiUSB.read();
if (rx.byte1 != 0) {
char buffer[256];
sprintf(buffer, "header: 0x%X b1: %d b2: %d b3: %d", rx.header, rx.byte1,
rx.byte2, rx.byte3);
Serial.println(buffer);
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
if ((rx.byte1 & 0xF0) == 0x90 && rx.byte3 > 0 && rx.byte2 < 84) { // handle note on // 84 = C6 = 1046.5Hz
int8_t noteIdx = putNote(rx.byte2, 1);
uint16_t frq = midi2frq(rx.byte2);
periods[noteIdx] = 1000000 / frq / 2;
#ifdef DEBUG
Serial.println("ONNNNNNN " + String(rx.byte2) + " @ " + String(noteIdx));
#endif
} else if (((rx.byte1 & 0xF0) == 0x80 || ((rx.byte1 & 0xF0) == 0x90 && rx.byte3 == 0)) && rx.byte2 < 84) { // handle note off
#ifdef DEBUG
int8_t idx = 0;
#endif
for (int8_t i = 0; i < NUM_VALVES; i++) {
if (notes[i] != -1 && notes[i] == rx.byte2) {
putNote(rx.byte2, 0);
//periods[i] = 0;
#ifdef DEBUG
idx = i;
#endif
break;
}
}
#ifdef DEBUG
Serial.println("OFFFFFFFF " + String(rx.byte2) + " @ " + String(idx));
#endif
} else if ((rx.byte1 & 0xF0) == 0xB0) { // handle CC
if (rx.byte2 == 7) { // CC 7 = Volume
analogWrite(OVERALL_VELOCITY_PIN, 255 - (rx.byte3 * 2));
else {
char buffer[256];
sprintf(buffer, "header: 0x%X b1: %d b2: %d b3: %d", rx.byte1, rx.byte2, rx.byte3);
Serial.println(buffer);
}
#endif
if (Serial1.available() >= 3) {
uint8_t statusByte = Serial1.read();
uint8_t dataByte1 = Serial1.read();
uint8_t dataByte2 = Serial1.read();
if ((statusByte & 0x09) == 0x09) { // handle note on
} else if ((statusByte & 0x08) == 0x08) { // handle note off
}
}
// get current microseconds
uint64_t nowMicros = micros();
// check for notes that require attention
for (uint8_t i = 0; i < NUM_VALVES; i++) {
if (lastNoteMicros[i] + periods[i] < nowMicros && notes[i] != -1) {
lastNoteMicros[i] = nowMicros;
states[i] ^= 1;
digitalWrite(valves[i], states[i]);
} else if (notes[i] == -1) { // be sure to end notes that should be ended
digitalWrite(valves[i], LOW);
}
}