Sunday, 14 January 2018

Midi Light Show


For a class, my teammate and I decided to develop a MIDI based system that has a responsive light for each note played.  For example, if you plug our little setup to a keyboard, pending on which note you press, you'll get a specific color.  You'll need a list of several items, but the reward is quite nice!  Plus, there are a lot of possible improvements and developments from the original idea, so please take the liberty to expand on this concept once you've put everything together.

Step 1: What You'll Need...























Step 1 -- Materials Needed:
1 Arduino- The Arduiono used for this project was a Freeduino v 1.22.  This did not come pre-assembled, Other boards can be used, as long as the pins are able to line up with those used on the midi shield

1 Midi Shield-  DF Robot Midi Shield (http://www.dfrobot.com/index.php?route=product/product&product_id=526). This Midi Shield did NOT come with extended headers, so we needed to replace the pins connecting the shield to the arduino with extended headers. This process requires desoldering and soldering tools, so consider this when choosing your midi shield.

1 LED- RGB LED (4 pins) -- Check the information on your LEDs before using them. You can use an LED calculator http://led.linear1.org/1led.wiz to determine the proper resistors needed for your circuit. The Arduino produces 5 volts.

1 MIDI Cable (USB to MIDI is optional, it depends on the instrument used with your midi shield

2 1kΩ resistors (Brown-Black-Red)

1 560Ω resistor (Green-Blue-Brown)

The resistors used depends on the LED. These resistors produced a consistent brightness between all three colors. the 1kΩ resistors were used for the blue and green legs, and the 560Ω resistor was used with the red leg.

Wires -- For the simplest experience, choose Red, Green, and Blue wires for the different legs of the LED, and a black wire as the ground.

Breadboard

4 Extended Headers (Optional) Only used if the Midi shield needs to be modified.

Step 2: Putting It All Together

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
The main format of this schematic is that each pin of the LED is connected to a different pin on the Midi Shield.  note the lower voltage for the red leg of our LED. The cathode goes to ground.  The midi shield connects on top of the Arduino, which is why extended headers are necessary for the function of our lights. This is an extremely simple and straightforward build, but it provides a lot of room for expansion as well.

Step 3: Midi Concepts...

To program with Midi, you must understand a few key concepts that determine how the information is read.

Midi sends information with 3 bytes of information at a baud rate of 31250. The first byte determines whether a note is turned on, the next byte determines what pitch is played, and the third byte determines the volume of the note.  It is important to note the order of the information as if you don’t set the code to read in this order for only 3 bytes, funny things start happening. Trust us.

Consider the following code:


//reads the serial port to see if there is any incoming information
boolean check_midi()
{
   while (Serial.available() >= 3)//when three bytes available
   {
     if (Serial.available())
     {
       digitalWrite(3,HIGH);    
       location_byte = Serial.read();//read first byte
       in_note = Serial.read();//read next byte
       in_volume = Serial.read();//read final byte
       return true;
     }
   }
}
This function checks when there are 3 available bytes to read, and puts them into the  appropriate variables, and finally returns true when the job is complete.  The variables are global since they are used in other functions.  Sure, there are many other great ways that would probably be much neater within C++, but for the sake of memory size, it doesn’t hurt to be a little messy in the Arduino. (Just as long as you can keep track of what’s going on!) As for the output, should you wish to send your music out of the shield as well, consider this code:
 
 //Here is the internet function for writing out the pitch
 void midi_send(byte cmd, byte note, byte volume)
 {
   Serial.write(cmd);
   Serial.write(note);
   Serial.write(volume);
 }
 
This code receives 3 bytes and writes them (in order!) to the serial port on the Arduino.  This will send the on or off command, the pitch, and the volume through the out line. IMPORTANT! -- If you’re using a USB cable to travel from the computer to the Arduino, note that the cables are reversed such that the in cable goes to the out; and the out goes into the in.  Otherwise, there will be many problems and you’ll be left with frustration. Trust us...

Step 4: Optional Ubuntu Setup

For those of you using Ubuntu and what to set up your Arduino to run off of your computer, here are some quick instructions to get that set up!

Install ALSA and VMPK in the Ubuntu software center

Open a console, and run 'qsynth' -- select a sound font in the settings.

Plug in your Midi to USB cable.

Open ALSA, and wire it where the Midi-In goes to the VMPK-In, VMPK-Out to the qsynth-In

Step 5: LED Concepts

We used a multi colored LED to help differentiate the notes played on the keyboard.  With this particular light, there are 4 pins, 1 for Red, 1 for Green, 1 for Blue, and one ground pin.  Different colors are made possible by the combination of the other pins.  (I.E.-Red and Blue pins make purple!)  This offers 7 combinations of colors at our disposal.  Since there are 7 tones within a musical scale, we decided to only handle the input from the C Major scale (or only the white keys for the non-music theory-savvy people out there).

Consider this little snippet of code:

digitalWrite(3,HIGH);
digitalWrite(4,HIGH);
digitalWrite(5,HIGH);
 
This bit of code will turn on juice to the 3, 4, and 5 pins.  This will actually result in a white color on the LED. The following code turns it off.

 digitalWrite(3,LOW);
 digitalWrite(4,LOW);
 digitalWrite(5,LOW);
That pretty much covers what you need to know for the LED concepts. Let’s move on.

Step 6: Coding Concepts

Here is the first major chunk of our code.

 //These are the midi commands to interact with the arduino
 byte midi_on = 0x90;
 byte midi_off = 0x80;
 
 /* These global variables are used specifically with
    the check_midi() function listed later in the program */
 byte location_byte;
 byte in_note;
 byte in_volume;

First we set a constant variable for the midi_on message and the midi_off message so that we can quickly refer to the them in the code. Next, we create 3 byte variables for the input of the midi functions as you noticed earlier.

Next are the midi functions again:

 //Here is the internet function for writing out the pitch
 void midi_send(byte cmd, byte note, byte volume)
 {
   digitalWrite(3,LOW);
   Serial.write(cmd);
   Serial.write(note);
   Serial.write(volume);
 }
 
 //reads the serial port to see if there is any incoming information
 boolean check_midi()
 {
   while (Serial.available() >= 3)//when three bytes available
   {
     if (Serial.available())
     {
       digitalWrite(3,HIGH);    
       location_byte = Serial.read();//read first byte
       in_note = Serial.read();//read next byte
       in_volume = Serial.read();//read final byte
       return true;
     }
   }
 }

Here are functions we mentioned earlier.  They are copied simply for continuity’s sake. Moving on...

 //arduino specific setup
 void setup ()
 {
 Serial.begin(31250);
 pinMode(3,OUTPUT);
 pinMode(4,OUTPUT);
 pinMode(5, OUTPUT);
 
 digitalWrite(3,LOW);
 digitalWrite(4,LOW);
 digitalWrite(5, LOW);
 }
 
This is a very important part of the Arduino.  This sets the baud rate, or the rate at which the Arduino reads the bits that it’s being sent to the rate that midi systems require.  Next it sets pins 3, 4, and 5 to output pins.  Finally it writes the output pins to off or LOW.

 void light_on()
 {
   int switch_note = in_note % 12;
   switch(switch_note)
   {
     //C
     case 0:
       digitalWrite(3,HIGH);
       break;
     //D
     case 2:
       digitalWrite(4,HIGH);
       break;
     //E
     case 4:
       digitalWrite(5, HIGH);
       break;
     //F
     case 5:
       digitalWrite(3,HIGH);
       digitalWrite(4,HIGH);
       break;
     //G
     case 7:
       digitalWrite(4,HIGH);
       digitalWrite(5,HIGH);
       break;
     //A
     case 9:
       digitalWrite(3,HIGH);
       digitalWrite(5,HIGH);
       break;
     //B
     case 11:
       digitalWrite(3,HIGH);
       digitalWrite(4,HIGH);
       digitalWrite(5,HIGH);
       break;
   }
 }
 
 //quick call to turn all the lights off
 void light_off()
 {
   digitalWrite(3,LOW);
   digitalWrite(4,LOW);
   digitalWrite(5,LOW);
 }

The first function is really the meat of the code, while the second is simply a quick reference call to turn off all the LEDs at once.  The first function reads the input from the in_note variable, divides it by 12 (since there are 12 tones in music).  Based on what note it is, it turns on the appropriate color by writing the pins to HIGH.  Now for the final culmination of all these:


 //the main loop
 void loop()
 {
   //checks if there is a midi to use, then sends it out (echoes echoes echoes echoes)
   if(check_midi()) midi_send(location_byte,in_note,in_volume);
 
   if(location_byte == midi_on && in_volume != 0)
     { light_on(); }
   else light_off();
 }

Here is the main loop of the function.  First, it checks to see if there in midi input coming and if it is, it sends it through the midi_send function.  Since the check_midi() fills the global variables, we check to see if there is a midi_on call and that the volume of the incoming note isn’t 0.  If those conditions are met, it runs through the light_on() function and turns on the lights. Otherwise, it turns the lights off as a default.  And that’s it!

Step 7: Continuation...


Here are some possible things that could be changed/added!
Allow the light to stay on even when an off signal is sent
Store the pitches and keep track of which ones go on and off
Manage LED intensity to handle chromatic notes (black keys)

There are many possible things that could be added to this project and we encourage you to use our code and build designs as a basis for your own project/your own additions.  Keep us posted on what you do!

No comments:

Post a Comment