Sunday, 8 April 2012

My DIY Arduino MIDI controller - 6. MIDI communication, Part I: Most basic stuff :)

Ok so I'm back to MIDI communication!

In case you want to follow my steps this is the list of the few components I use in this chapter:

  • 1 x tact switch
  • 2 x 10 kΩ resistors
  • 1 x 240 Ω resistor (220 ohm is supposed to be better)
  • 1 x female MIDI DIN socket (5 pins)
  • 1 x LDR
  • 1 x SPDT switch
  • Wire jumpers
  • 1 x Arduino!

I tried MIDI communication before I started the blog, and successfully sent notes over to Reason (a music software in case you don't know) via MIDI. I had already forgotten how to do so I checked again this basic tutorial. Since I (believe it or not) don't have 220 Ω resistors, I used a 240 Ω resistor instead, and it worked fine.

Next step is just for fun: sending notes according to the reading of a LDR (Light Dependent Resistor). I followed this tutorial (scroll down to the 6th chapter) and modified the code:
const int switchPin = 10;  // The switch is on Arduino pin 10
const int middleC = 60;    // Middle C (MIDI note value 60) is the lowest note we'll play
const int LEDpin = 13;     //  Indicator LED

// Variables:
byte note = 0;              // The MIDI note value to be played
int AnalogValue = 0;        // value from the analog input
int lastNotePlayed = 0;     // note turned on when you press the switch
int lastSwitchState = 0;    // state of the switch during previous time through the main loop
int currentSwitchState = 0;
int tempo = 480;

void setup() {
  //  set the states of the I/O pins:
  pinMode(switchPin, INPUT);
  pinMode(LEDpin, OUTPUT);
  //  Set MIDI baud rate:
  Serial.begin(31250);
}

void loop() {
  //  My potentiometer gave a range from 0 to 1023:
  AnalogValue = 1023-analogRead(0);
  //  convert to a range from 0 to 127:
  note = AnalogValue/8;
  currentSwitchState = digitalRead(switchPin);
  // Check to see that the switch is pressed:
  if (currentSwitchState == 1) {
    // set the note value based on the analog value, plus a couple octaves:
    note = note + 20; // you might want to change that value depending on the sensor you're using
    // start a note playing:
    noteOn(0x90, note, 0x40);
    delay(60000/tempo); // 60000 milliseconds = 1 min
    // play same note with a 0 velocity
    noteOn(0x90, note, 0x00);
  }
}

//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void noteOn(byte cmd, byte data1, byte  data2) {
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}



The problem I have is on sketch upload (not on reset), the Arduino sends seemingly random notes to Reason, which I have to turn off by pressing them in Reason's integrated software keyboard. Looks like it is sending data interpreted as notes on, and no notes off (or not the good ones). Since the MIDI and Arduino to PC data are sent to the same pin, my MIDI device is receiving the data that the Arduino is sending to the PC during the sketch upload process, and apparently interprets it at notes ons. Shouldn't be a problem anyway after the prototyping stage, since we wouldn't upload the code to the final controller each time we use it. It should simply not be connected to a MIDI device during upload...

I'm currently studying MIDI control changes so I guess next post will get closer to what I actually want to do: control synth parameters using LDRs & pots.

<< Previous: 5. Finding more pins, part III: the shift register

Monday, 2 April 2012

My DIY Arduino MIDI controller - 5. Finding more pins, part III: the shift register

As I said in a previous post, I might need to expand the digital outs as well as the analog ins, so I followed Grumpy_Mike's advice on the Arduino forums and got a 74HC595 shift register to control my LEDs instead of the 4051. The 8 bit shift register is a very convenient way to drive 8 LEDs with only 3 digital pins: you just send it a series of 8 HIGHs or LOWs and it lights on/off the LEDs accordingly when you tell it so. Looks exactly like what I need. I followed this ShiftOut tutorial to learn how to handle the chip, then I modified the second code example from the tutorial to make something like this:



This is the circuit:


And the code I came up with, slightly modified from the tutorial:

/*
  Shift Register Example
 for 74HC595 shift register

 This sketch turns reads serial input and uses it to set the pins
 of a 74HC595 shift register.

 Hardware:
 * 74HC595 shift register attached to pins 2, 3, and 4 of the Arduino,
 as detailed below.
 * LEDs attached to each of the outputs of the shift register

 Created 22 May 2009
 Created 23 Mar 2010
 by Tom Igoe
 
 Modified 1 Apr 2012 by Yann Guillermou

 */

//Pin connected to latch pin (ST_CP) of 74HC595
const int latchPin = 8;
//Pin connected to clock pin (SH_CP) of 74HC595
const int clockPin = 12;
////Pin connected to Data in (DS) of 74HC595
const int dataPin = 11;

// the bits you want to send (a byte is 8 bits, one per LED)
byte bitsToSend = 0;

void setup() {
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
}

void loop() {
  for (int i = 0; i < 8; i++) {
    registerToggle(i);
    delay(100);
  }
}

// This method sends bits to the shift register:
void registerToggle(int pin) {
  //  turn of the output so the pins don't light up
  //  while we're shifting bits
  digitalWrite(latchPin, LOW);
  
  // read bit state
  int state = bitRead(bitsToSend, pin);
  
  // change bit state
  state = -state + 1;
  
  // toggle the bit in bitsToSend:
  bitWrite(bitsToSend, pin, state);
  
  // shift the bits out:
  shiftOut(dataPin, clockPin, MSBFIRST, bitsToSend);

  // turn on the output so the LEDs can light up:
  digitalWrite(latchPin, HIGH);
}

The mod' consisted in making the bitsToSend variable global because I wanted to be able to toggle an LED without affecting the others, and above all keep track of each LED state. I also replaced the registerWrite() function by this registerToggle() function, just to check if I had understood well enough how to do.

This code only loops and toggles the LEDs on then off but with the registerToggle() and registerWrite() functions you can easily tell the chip which LED to turn on or off, this way it is as easy as a digitalWrite().

Next post will be about MIDI out, as I got a couple of breadboard friendly MIDI connectors!

<< Previous: 4. Finding more pins, part II + LDR Calibration