2015. február 7., szombat

Arduino based midi patch changer for Zoom MS-50G


6 switches
accessing 6 patches directly
USB midi connection between zoom and patch changer
USB power supply (It's a risk, because power and midi connectors are the same type USB :)
Using Arduino Uno and USB host shield



Works with Korg Pandora Stomp as well.



USB ports
The code:

Should be cleaned up, but I have no time for that:)

#include <Usb.h>
#include <usbh_midi.h>

#define ledpin 14
int buttonState = 0;         // variable for reading the pushbutton status
int ledlight = 0;
int mode = 1;
int pushedbutton = 41;
unsigned long t1 = 0;        // timer for usb keeping on
unsigned long t2 = 0;       //  timer for midi change
unsigned long t3 = 0;      //  timer for led turn off after change
unsigned long t4 = 0;     //timer for mode change
USB  Usb;
USBH_MIDI  Midi(&Usb);

byte data;

void setup()
{
  // start the library
  // Serial.begin(9600);
  Usb.Init();
  data = 1;
  SendMIDI(0);
  pinMode(ledpin, OUTPUT);
  for (int i = 0; i < 4; i++) {    // flash led for indicating arduino start
    digitalWrite(ledpin, HIGH);
    delay(300);
    digitalWrite(ledpin, LOW);
    delay(200);
  }
  // Setup Switches, pull up because of floating
  for (int i = 2; i < 8; i++) {
    pinMode(i, INPUT_PULLUP);
  }
}
void loop()
{
  // read the state of the pushbutton value:
  if (millis() > t1 + 1000) {   // keeping the usb state active, this way the change will happen
    Usb.Task();  // immediatley after button push, so we're sending usb initiate every 1 sec.
    t1 = millis();
  }
  if (millis() > t3 + 100 && ledlight == 1) { // turn off led after midi change, iff 100 ms has passed.
    digitalWrite(ledpin, LOW);
    ledlight = 0;
  }
  for (int i = 41; i < 47; i++) {    // checking momentary pushbutton state, in Zoom the patches are from patch 41 to 46.
    buttonState = digitalRead(i - 39);  // but the switches are from 2 to 7.
    if (buttonState == LOW && millis() > t2 + 500) { //accept push only if 500ms has past since last push
      if (i == pushedbutton && millis() < t2 + 800 && millis() > t4 + 2000) { // mode change if pushed button is the same as before and longpush and enough time has been passed since last mode change
        for (int j = 0; j < 4; j++) {  //flashing the led to indicate mode change
          digitalWrite(ledpin, HIGH);
          delay(100);
          digitalWrite(ledpin, LOW);
          delay(100);
        }
        if (mode == 1) {  //mode change to 2 if it was 1, else to 1.
          mode = 2;
        }
        else {
          mode = 1;
        }
        t4 = millis(); //mode change starts timer, not being able to start new action too soon
      }
      if (millis() > t4 + 1000) { //make midi change only if enough time has passed since mode change
        if (mode == 2) {   // if in mode 2, make relative change
          switch (i) {
            case 41:
              data = data - 1;
              if (data < 1) {
                data = 50;
              }
              break;
            case 44:
              data = data + 1;
              if (data > 50) {
                data = 1;
              }
              break;
            case 42:
              data = data - 5;
              if (data < 1) {
                data = data + 50;
              }
              break;
            case 45:
              data = data + 5;
              if (data > 50) {
                data = data - 50;
              }
              break;
            case 43:
              data = data - 10;
              if (data < 1) {
                data = data + 50;
              }
              break;
            case 46:
              data = data + 10;
              if (data > 50) {
                data = data - 50;
              }
          }
        }
        else {   // if not in mode 2, make simple change to absolute value
          data = i;
        }
        SendMIDI(data);
        t2 = millis();
        pushedbutton = i;
      }
    }
  }
}
// Send "Program Change" MIDI Message

void SendMIDI(byte number)
{
  //Serial.println("called");
  //  Serial.println(callcount);
  number -= 1;                       // Change 1 to 0, 100 to 99.
  t1 = millis();
  Usb.Task();
  if ( Usb.getUsbTaskState() == USB_STATE_RUNNING )
  {
    byte Message[2];                 // Construct the midi message (2 bytes)
    Message[0] = 0xC0;               // 0xC0 is for Program Change (Change to MIDI channel 0)
    Message[1] = number;             // Number is the program/patch (Only 0 to 99 is valid for ZOOM G3)
    Midi.SendData(Message, 0);         // Send the message
    digitalWrite(ledpin, HIGH);  // light led on
    ledlight = 1;
    t3 = millis();
    delay(10);
    //digitalWrite(ledpin, LOW);
    //Serial.println("sent");
  }

}