Saturday, May 11, 2013

Samsung Galaxy S4 and TouchDAW As Wired and Driver-less USB MIDI Controller

Overview
Smart phones can make great music controllers, but the connection from smart phone to computer DAW can be difficult to manage. Sometimes its just easy to have a wired connection, but most wired connections require a third party software platform to act as a go-between between smart phone and computer DAW.

This is a method for controlling Live and many other DAWs using a wired connection that shows up in the computer DAW as a USB MIDI device that requires no USB driver and is simply plug and play.

The basic idea is Android phone to TouchDAW to OTG cable to USB interface to Teensy to USB cable to computer to DAW.


Demo Video

Setup
Follow this guide on hacking and connecting a cheap, class compliant USB MIDI interface to a Samsung Galaxy S4.

Connect the MIDI interface TX output and MIDI interface ground to Teensy UART RX input and Teensy ground.

Upload the code to the Teensy. This will transmit any note on, note off, continuous controller and pitch bend messages via MIDI as a driver-less USB device signal to Live, Logic, ProTools etc.

Setup TouchDAW for use with the MIDI interface. 




Arduino / Teensyduino Code
// Teensy UART MIDI Input

// MIDI input variables
byte channel;
byte pitch;
byte velocity;
byte ccnumber;
byte ccvalue;
byte ccvalue2;
byte bendLSB;
byte bendMSB;
byte rstat;
byte dataIn;
int flag_previous = 0;

// Initialise hardware

HardwareSerial Uart = HardwareSerial();



void setup() {
  Uart.begin(31250);
  Serial.begin(57600);
  pinMode(11, OUTPUT);
  digitalWrite(11, HIGH);
}




void loop() { 
    if(Uart.available() > 0) {

    dataIn = Uart.read();
    Serial.print(dataIn, BYTE);
    if(dataIn < 0x80 && flag_previous == 0) {
      doMidiIn(rstat);
    }
    doMidiIn(dataIn);
  }
}

void doNote(byte channel, byte pitch, byte velocity) {
  usbMIDI.sendNoteOn(pitch, velocity, channel);
}

void doNoteOff(byte channel, byte pitch, byte velocity) {
  usbMIDI.sendNoteOff(pitch, velocity, channel);
}


void doCC(byte channel, byte ccnumber, byte ccvalue) {
  usbMIDI.sendControlChange(ccnumber, ccvalue, channel);
}

void doBend(byte channel, unsigned int bend_usb) {
  usbMIDI.sendPitchBend(bend_usb, channel);
}






void doMidiIn(byte data) {
    
    // running status set
   
   if((data >= 0x80) && (data < 0xf0) && (flag_previous == 0)) {
     rstat = data;
   }
   
    // deal with note on
    if((data >= 0x90) && (data < 0xa0) && (flag_previous == 0)) {
      channel = data & B00001111;
      flag_previous = 1;
    }
    else if((data < 0x80) && (flag_previous == 1)) {     
      pitch = data;
      flag_previous = 2;
    }
    else if((data < 0x80) && (flag_previous == 2)) {
      velocity = data;
      doNote(channel, pitch, velocity);
      flag_previous = 0;
    }
    // done with note on

    // deal with note off (as discrete status byte)
    else if((data >= 0x80) && (data < 0x90) && (flag_previous == 0)) {
      channel = data & B00001111;
      flag_previous = -1;
    }
    else if((data < 0x80) && (flag_previous == -1)) {
      pitch = data;
      flag_previous = -2;
    }
    else if((data < 0x80) && (flag_previous == -2)) {
      velocity = data;
      doNoteOff(channel, pitch, velocity);
      flag_previous = 0;
    }
    // done with note off (as discrete status byte)

    // deal with cc data
    else if((data >= 0xb0) && (data < 0xc0) && (flag_previous == 0)) {
      channel = data & B00001111;
      flag_previous = 3;
    }
    else if((data < 0x80) && (flag_previous == 3)) {
      ccnumber = data;
      flag_previous = 4;
    }
    else if((data < 0x80) && (flag_previous == 4)) {
      ccvalue = data;
        doCC(channel, ccnumber, ccvalue);
      flag_previous = 0;
    }
    // done with cc data

    // deal with bend data
    else if((data >= 0xe0) && (data < 0xf0) && (flag_previous == 0)) {
      channel = data & B00001111;
      flag_previous = 5;
    }
    else if((data < 0x80) && (flag_previous == 5)) {
      bendLSB = data;
      flag_previous = 6;
    }
    else if((data < 0x80) && (flag_previous == 6)) {
      bendMSB = data;
      doBend(channel, bendLSB + (bendMSB << 7));
      flag_previous = 0;
    }
    // done with bend data
   
}

1 comments:

Anonymous said...

Nice, but unless it's primarily for the sake (and fun) of soldering and coding, why not just use 2 of those MIDI interfaces and crosswire them? Should be cheaper, would not require any skills whatsoever and should support all of the app's MIDI messages that are not handled in your code so far (Aftertouch, Program Changes, SysEx) right away.