108 lines
3.6 KiB
C++
108 lines
3.6 KiB
C++
/// \file midi2stepper.ino
|
|
/// \brief main routine for midi to stepper tool
|
|
/// \author GrumpyDeveloper https://contentnation.net/en/grumpydevelop
|
|
/// \license MIT
|
|
|
|
#include <EEPROM.h>
|
|
#include "midi2stepper.h"
|
|
|
|
extern Midi2Stepper m2s;
|
|
|
|
int numChannels; ///< number of channels
|
|
uint16_t channels[8]; ///< channel frequencies
|
|
uint8_t msg[4]; ///< input messages over serial
|
|
uint8_t nextChannel = 0; ///< next channel to test
|
|
bool power; ///< current power status
|
|
bool sendStatus = true; ///< send current output over serial
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
m2s.begin();
|
|
numChannels = EEPROM.read(0); // read number of channels from eeprom
|
|
if (numChannels < 1 || numChannels > 8) { // unreasonable value
|
|
numChannels = 8;
|
|
}
|
|
memset(channels, 0, sizeof(uint16_t) * numChannels); // clear channel frequencies
|
|
power = false; // power is off
|
|
pinMode(LED_BUILTIN, OUTPUT); // set LED pin to output
|
|
}
|
|
|
|
void loop() {
|
|
while (Serial.available()) {
|
|
Serial.readBytes(msg, 3);
|
|
uint8_t nibble = msg[0] >> 4;
|
|
if (nibble == 0b1001) { // note on
|
|
if (!power) { // not powered on yet?
|
|
// enable steppers
|
|
power = true;
|
|
m2s.power(true);
|
|
}
|
|
// calculate frequency from midi note
|
|
uint16_t freq = pow(2, (static_cast<double>(msg[1]) - 69.0)/12.0) * 440.0;
|
|
// velocity byte 2 is ignored
|
|
// loop through channels, starting with nextChannel to find the next free one
|
|
uint8_t channel = nextChannel;
|
|
bool good = false;
|
|
do {
|
|
if (channels[channel] == 0) {
|
|
m2s.setChannel(channel, freq);
|
|
channels[channel] = freq;
|
|
nextChannel = (channel + 1) % (numChannels); // next channel = current channel + 1 modulo num channels
|
|
good = true;
|
|
break;
|
|
}
|
|
channel = (channel + 1) % numChannels;
|
|
} while (channel != nextChannel); // if we end at our start channel, no free channels, ignore note
|
|
if (!good && sendStatus) {
|
|
Serial.print(F("\ntoo many channels\n"));
|
|
}
|
|
}
|
|
if (nibble == 0b1000) { // note off
|
|
uint16_t freq = pow(2, (static_cast<double>(msg[1]) - 69.0)/12.0) * 440.0;
|
|
// velocity byte 2 is ignored
|
|
// loop through channels to find an active one with that frequency
|
|
for (uint8_t channel = 0; channel < numChannels; ++channel) {
|
|
if (channels[channel] == freq) {
|
|
m2s.setChannel(channel, 0);
|
|
channels[channel] = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (nibble == 0b1011) { // control
|
|
switch (msg[1]) {
|
|
case 121: // reset
|
|
case 123: // all notes off
|
|
if (power) {
|
|
power = false;
|
|
m2s.power(false);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
// hack to set number of channels via simple usb connection:
|
|
// send <number of channel>\r\n
|
|
if (msg[0] > '0' && msg[0] < '9') {
|
|
numChannels = msg[0] - '0';
|
|
Serial.print(F("channel count set to "));
|
|
Serial.println(numChannels);
|
|
// clear channel frequencies
|
|
memset(channels, 0, sizeof(uint16_t) * numChannels);
|
|
// save new value to EEPROM
|
|
EEPROM.write(0, numChannels);
|
|
}
|
|
if (sendStatus) {
|
|
// send current status over serial connection
|
|
char buf[8]; ///< status message buffer
|
|
buf[0] = power ? '+' : '-';
|
|
buf[1] = ' ';
|
|
Serial.write(buf, 2);
|
|
for (uint8_t i = 0; i < numChannels; ++i) {
|
|
uint8_t len = snprintf(buf, sizeof(buf) - 1, "%5i ", channels[i]);
|
|
Serial.write(buf, len);
|
|
}
|
|
Serial.write('\r');
|
|
}
|
|
}
|
|
}
|