/// \file midi2stepper.ino /// \brief main routine for midi to stepper tool /// \author GrumpyDeveloper https://contentnation.net/en/grumpydevelop /// \license MIT #include #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(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(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 \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'); } } }