mixture-art@Q
技術+アイディア+世俗+なんとなく思ったこと、すべての融合がmixture-art
Arduino MIDI Controller @Maker Faire by “kuz lab”

The project called “Arduino MIDI Controller Project”, it’s succeeded to exhibit at Maker Faire in Bay Area.
As for record and help for undestanding what this project made, here I wrote some explanatinos.

First of all, let’s see the video of first prototyping.

What Arduino does?

For ease of understand, here is the case only six switches and one slider.

#include "assign_map.h"

#include <MIDI.h>

uint8_t switch_state[6] = {0, 0, 0, 0, 0, 0};
uint8_t temp[6] = {0, 0, 0, 0, 0, 0};

uint16_t ad_value = 0;

#define DEBUG 0
#define ANALOG_SLIDER_ENABLE 1

void setup()
{
  Serial.begin(38400);  
  delay(5000);
  
  for(int i = 0; i < 6; i++){
    pinMode(pins[i], INPUT);
    digitalWrite(pins[i], HIGH);
    switch_state[i] = digitalRead(pins[i]);    
  }
#if ANALOG_SLIDER_ENABLE
  ad_value = analogRead(PIN_AD0);
#endif

#if DEBUG
  Serial.print("AD_MAX = ");
  Serial.println(AD_MAX);
  Serial.print("AD_DIV = ");
  Serial.println(AD_DIV);
#endif
}

void loop()
{
  uint8_t data[3];
  
  uint16_t ad_temp = analogRead(PIN_AD0);
#if DEBUG  
  Serial.print("AD = ");
  Serial.println(ad_temp);
#endif

#if ANALOG_SLIDER_ENABLE
  if(abs(ad_temp - ad_value) > 2* AD_DIV){    
      Serial.print('$');
      Serial.print(MIDI_AD0_0);
      Serial.print(',');
      Serial.print(MIDI_AD0_1);
      Serial.print(',');
      ad_value = ad_temp;
      ad_temp = (uint8_t)((double)ad_temp/AD_DIV);
      if(ad_temp > 0x7F){ad_temp = 0x7F;}
      Serial.print(ad_temp);
      Serial.println('$');
  }
#endif  
  for(int i = 0; i < 6; i++){
    temp[i] = digitalRead(pins[i]);    

    if(temp[i] != switch_state[i] && temp[i] == 0){
      Serial.print("$");      
      Serial.print(mapping[3*i]);
      Serial.print(",");
      Serial.print(mapping[3*i + 1]);
      Serial.print(",");
      Serial.print(mapping[3*i + 2]);
      Serial.println('$');
      delay(1);      
    }
    
    switch_state[i] = temp[i];
  }
  delay(50);
}

assign_map.h describes just pin confgurations as below.

#ifndef _ASSIGN_MAP_H_
#define _ASSIGN_MAP_H_

#define PIN_SW0 2
#define PIN_SW1 1
#define PIN_SW2 3
#define PIN_SW3 4
#define PIN_SW4 6
#define PIN_SW5 5

#define PIN_AD0 A0

#define MAX_RES 50
#define PULLUP_RES 10

#define AD_MAX 1024
double AD_DIV = (double)AD_MAX/128;

const char pins[6] = {PIN_SW0, PIN_SW1, PIN_SW2, PIN_SW3, PIN_SW4, PIN_SW5};

#define MIDI_0_0 0xb0
#define MIDI_0_1 0x01
#define MIDI_0_2 0x7f

#define MIDI_1_0 0xb0 
#define MIDI_1_1 0x02
#define MIDI_1_2 0x7f

#define MIDI_2_0 0xb0
#define MIDI_2_1 0x03
#define MIDI_2_2 0x7f

#define MIDI_3_0 0xb0
#define MIDI_3_1 0x04
#define MIDI_3_2 0x7f

#define MIDI_4_0 0xb0
#define MIDI_4_1 0x05
#define MIDI_4_2 0x7f

#define MIDI_5_0 0xb0
#define MIDI_5_1 0x06
#define MIDI_5_2 0x7f

#define MIDI_AD0_0 0xb0
#define MIDI_AD0_1 0x07

const unsigned int mapping[3*6] = 
{
  MIDI_0_0, MIDI_0_1, MIDI_0_2,
  MIDI_1_0, MIDI_1_1, MIDI_1_2,
  MIDI_2_0, MIDI_2_1, MIDI_2_2,
  MIDI_3_0, MIDI_3_1, MIDI_3_2,
  MIDI_4_0, MIDI_4_1, MIDI_4_2,
  MIDI_5_0, MIDI_5_1, MIDI_5_2,
};

#endif

How Arduino signal converted to MIDI signal?

Simply thinking “how can I read MIDI signal from external device?”, here would be two typical solutions, use USB MIDI or use MIDI signal and connect it to Mac through USB MIDI Converter.

However… for Arduino, it is possible to write USB MIDI Driver on Arduino micro controller but usually it needs ISP(In System Programmer) tools. It’s not comfortable for happy, easy DIY life!
Generating MIDI signal and put converter before Mac… it’s messy.

Finally I chose to connect USB Serial signal(default) to Mac. And then, it’s translated to CoreMIDI signal by Python code.
Here is Python code working on Mac.

Before execute this code, please install “simplecoremidi” and pyserial.

sudo pip install simplecoremidi

sudo pip install pyserial

F.Y.I. From line 6 to 24, it’s detecting USB Port automatically.

from simplecoremidi import send_midi
import time
import serial
import os

class Command(object):
    """Run a command and capture it's output string, error string and exit status"""
    def __init__(self, command):
        self.command = command 
    def run(self, shell=True):
        import subprocess as sp
        process = sp.Popen(self.command, shell = shell, stdout = sp.PIPE, stderr = sp.PIPE)
        self.pid = process.pid
        self.output, self.error = process.communicate()
        self.failed = process.returncode
        return self
    @property
    def returncode(self):
        return self.failed

com = Command("ls /dev |grep tty |grep usb").run()
print com.output

usbport = '/dev/' + com.output.rstrip('\n')
ser = serial.Serial(usbport, 38400, timeout=1)

while (1):
    result=ser.read(ser.inWaiting())
    while(result.find("$") < 0):
        result=ser.read(ser.inWaiting())
    temp = result.find("$")
    while(result.rfind('$') == temp):
        result=ser.read(ser.inWaiting())
    data = result.split("$")[1].split(",")
    if len(data) >= 3:
        for i in range(len(data)):
            data[i] = int(data[i])
        print data        
        send_midi((data))

ser.close()

I confirmed these codes on Yosemite.

Maker Faire version

These codes above are simplified for ease of understand.
Actually I’m using over 10 switches and 5 analogs, 2 USB devices and 1 BLE devices.
The final version for Maker Faire demo,

github link
https://github.com/kuzlab/midi_controller_pj

If you did not visit “kuz lab” boose at Maker Faire yet, please check #50521 in ZONE2 EXPO hall!



Comments are closed.