Thimble Learning Platform
Back to full view

Arduino MIDI Controller Piano

Introduction

This tutorial will guide you through soldering, assembling, and programming the Arduino MIDI Controller kit. MIDI stands for Musical Instrument Digital Interface, it is a technical standard or protocol used for a variety of electronic musical instruments. The end result of this kit will allow you to play the piano on your computer. In other words, this project will turn the Arduino into a MIDI Controller, which will connect to an open source MIDI software called LMMS. The Arduino MIDI Controller will send the a MIDI Message to the MIDI software which will be interpreted and produce a musical note.

Looking at your shield, there are three central areas of pin outs that are made for the analog multiplexers. Placed between the white silkscreen and labeled MUX0, MUX1, and MUX2. One multiplexer will be used to interface the seven piano keys on the laser-cut wood piece to a single analog pin on the arduino. The remaining two multiplexers and their breakouts are there to expand the kit into any musical instrument you can dream of.

We will be making our piano keys out of Velostat, the black plasticy material that may resemble a thick garbage bag. Velostat is a piezoresistive material, meaning it changes it's resistance under pressure.

Objectives

  • Assemble and solder the shield
  • Assemble Velostat pressure sensor system
  • Learn about multiplexers and how the MIDI standard works
  • Learn how to program the MIDI Controller and how to expand upon it
  • Shield Assembly

    Gather Materials 

    Gather the materials below and get ready to set up the PCB for the Thimble MIDI Piano

    Introduction
    This short video introductes the Thimble MIDI Piano.

    Parts

    All Parts x Qty
    Multiplexer 16DIP Package x 3
    10kΩ Resistors x 3
    200Ω Resistor x 1
    LED 3mm Green x 1
    1x10 Female Socket Stackable Header x 1
    1x8 Female Socket Stackable Header x 2
    1x8 Female Socket Header x 3
    1x6 Female Socket Stackable Header x 1
    Small Tactile Button x 1

    You can set two of the multiplexers aside as we won't be using them in this tutorial until we go over expanding your device

    Tools you'll need

    Soldering Iron
    Solder Wire
    Wire Strippers
    Flush diagonal cutters
    Electrical Assembly
    This video walks through the complete eletrical assembly of the MIDI Piano.

    Multiplexer 

    Start with the first multiplexer area on the PCB, **MUX0**. Take one of the multiplexer chips and inspect it with the pins facing downwards. This is the top-down view. Two defining features are a small "U" shaped indent on the short end of the package, as well as the lettering on the top. The indent marks the top orientation of the package and pin 1 is located to the left of the U shape when looking at the package from the top-down view.

    When inserting the chip into the printed circuit board (PCB), the "U" shape should be on the side closest to the label MUX0 with it's Pin 1 being closest to this silk screen indent. Press the chip into the PCB.

    For the purposes of this tutorial, we will only solder the first multiplexer. If you wish to extend the midi device later, the two other multiplexers can be added.

    Once the Multiplexer 16DIP package is fitted into the correct holes, remember to press against the top of the DIP package while you solder a single pin to make sure the chip is all the way in. Check the top of the board to confirm the chip is flat. Then solder the rest of the pins.

    Place the multiplexer in the shield
    Solder pin 1 of the mux to tack it in place
    With Pin 1 soldered ensure the mux is flush to and sitting flat on the circuit board
    Solder the rest of the pins on the multiplexer

    Resistors 

    The next component that can be soldered are the resistors, there are three 10k resistors and one 200 Ohm resistor. Make sure to verify the correct resistor value goes in the correct place.

    If you are unfamiliar with how to read a resistor's color-coding, see this page. The 10k-ohm resistors are Brown-Black-Orange-Gold. The 200-ohm resistor is Red-Black-Brown-Gold. There are a number of online calculators for decoding the color codes.

    It may help to bend the leads of these components into a U shape before putting them in the PCB. Place the three 10k resistors through the top right corner of the PCB and bend the leads back to hold them in place. Then place the remaining singular 200Ohm resistor in the label marked R2 at the bottom of the PCB. Resistors have no polarity; you can put them in either direction. Solder and trim the resistors leads.

    4 Band Resistor Color Code and Chart
    Place the 10k ohm resistors
    Place the 200 ohm resistor
    Solder the resistors
    Trim the resistor leads with the flush cutters

    Reset Button 

    Place the small tactile button through the holes on the area labeled SW1. Push the button through the holes until it sits flat. Turn the PCB over and solder the leads on the other side, but there is no need to clip them.

    Place the button in the PCB at the indicated location
    The button in place
    Solder the button
    Soldered button

    LED 

    This LED is used during calibration of the piano, and will be your indication of the steps. The calibration process of the piano will be explained in software section when it becomes necessary. The LED (Light Emitting Diode) is a polarized component, meaning that there is a particular way to connect it. unlike resistors that can be soldered in either way. Examine the LED, there is normally two indicators for which side negative on a LED: the length of the leads and the shape of the plastic dome on the LED. With the leads, the shorter lead is the negative side; By chance a LED's leads are the same length, a flat side on the base of the plastic dome indicates the negative side. On this small 3mm LED the flattened side may be hard to see. Place the LED in the area marked D1, orienting the short lead into the square hole labeled negative. The Solder and trim the leads.

    Place the LED in the PCB at the indicated location
    Make sure to use the correct orientation. The long lead of the LED goes into the + side.
    Solder the LED in place. Make sure not to short the two leads together.
    Trim the LED leads.

    Headers 

    Take the headers and organize them by pin number, setting aside the three 1x8 Headers with the short leads. The headers with the short leads fit into the center of the PCB, with rows of holes labeled MUXP0, MUXP1, and MUXP2. All other headers fit into the rows on the top and bottom.

    If you look closely at the row of holes along the bottom of the PCB and you will notice they don't line up perfectly. This feature was added to help hold the header pins when soldering by applying slight pressure to both sides.

    Place a header leads down into the PCB, and solder one pin first to confirm the header is set correctly. You want to be careful to solder the header straight so the leads aren't bent or not fully in. When you are sure it is set properly, solder the rest of the pins. Do not trim any of the leads. Complete the rest of the headers in the same way as the first one. Small lead headers not included, once you are done you will be left with half of headers that will go into the uno to extend the pinouts. Set these aside for later.

    This image shows all of the headers. The three headers to the right are the inputs to the multiplexer.
    Since we are only using the first multiplexer in this tutorial, we will set the other two to the side.
    Tack this header into place by soldering just the first pin.
    Tack the header into place.
    Tack the header into place and ensure it is flush to the board.
    Ensure the header is flush to the board.
    Finish soldering the header.
    Repeat this process for each of the stackable headers.

    At this point only one mux is soldered on, this is ok, the others can be added in the future for expansion. Leave these unsoldered for now, expansions can be bread boarded first to test them out.

    Completed shield with only 1 muxCompleted shield with only 1 mux

    The Shield is complete we can get to work on assembling the sensors.

    Force Sensor Assembly

    Overview 

    Gather the materials below and get ready to assemble the force sensor for the piano.

    Parts

    All Parts x Qty
    Velostat sheet x 1
    Copper tape x 1
    Solid core wire x 1
    Electrical tape x 1
    Wood laser cut case x 1
    Wood laser cut template piece x 1
    M3 female to female spacer 17mm x 4
    M3 Screw 10mm x 12
    M3 Nut x 4
    1x10 Female Socket Header x 1
    1x8 Female Socket Header x 2
    1x6 Female Socket Header x 1

    Tools you'll need

    You will need the following tools

    Mechanical Assembly
    This video walks through the completel mechanical assembly of the MIDI Piano.

    Drawing a guideline 

    When you take the wood case out of the box, it will have one spacer screwed in with two M3 screws. This is so the case is not smashed in shipping. Unscrew the top half of this so the case can lay open up. With the wood case laid flat and open, locate the three other outer holes on the lower half of the case similar to the one the spacer is already in. Begin by attaching your remaining spacers into these holes and securing them with one screw on the bottom. Fold the center hinge so the top half of the wood piece rests nicely on the spacers. You do not need to secure the top screw for this part as you'd have to take it out later.

    Now press a key down and look at the side. See how the key hits the case only on the bottom edge of the key? That small amount of contact area of the key to the base is where we want our copper tape to be.

    Take a pencil and using your other hand hold down all the piano keys at once. If you didn't secure the top of the wood piece, check to make sure the holes on top line up with the spacers. With a sharp pencil draw a line as close as possible to the contact point between the keys and the bottom of the case. If any screws were used on the top remove them once a line is drawn, leaving the spacers in place. We now have our guideline for where our ground plane will be.

    Place the standoffs in through the bottom piece of the laser cut piano.
    Screw the standoffs in place.
    You will need to ensure the screw holes in the standoffs line up with the holes in the laser cut piano.
    Press all of the keys and use a pencil to draw a line through the contact point of the keys.
    Line marking contact point of the keys.

    Ground Plane with copper tape 

    This part requires a sharp pair of scissors or an exacto knife to cut the copper tape.

    Measure a piece of copper tape approximately 1.5 times the width of the base of the wood case along the line drawn. It does not have to be exact as it can be cut down later. The goal for this step is to apply the strip of copper tape along the line drawn. The contact point of all of the keys need to be as close to the middle of the copper tape strip as possible. This may involve adjustment to make sure the copper tape is in the correct place.

    Before removing the back paper of the copper tape, be aware the copper tape curls once it is removed. You can avoid this by sticking one end of the tape to the wood and pulling away the paper.

    Start from the right side of the wooden board and place the tape so it centers on top of the guide line drawn. Once at the end of the board we want to fold the tape up toward the spacers. Fold the tape back at a diagonal ** \ ** so the adhesive side faces you. Then fold up towards the spacers so the adhesive sticks down, making a right angle where we folded it.

    Make sure the copper tape's end edge isn't too close to the spacer as we need room to attach a wire to the tape later on.

    Place a piece of copper tape along the line.
    Fold the tape when you get to the end of the line.
    And run the remainder up towards the standoffs.
    Secure the tape. Ensure only one continuous piece of tape is used. If the tape tears, remove all of it and start over.

    Attaching Velostat 

    Grab the Wood laser cut template piece, it's size and engraved lines are going to help you cut the velostat strp for the base. The engraved portion in the middle is where the copper taper will be aligned to. The velostat strip will be the length of the board at the drawn line, and as wide as the template. Feel free to mark the velostat with pencil marks to make a clean cut. Cut two pieces of electrical tape slightly longer than the velostat, with room to fold over the edges of the wood base. Place the velostat evenly over the copper tape. Take on of the pieces of tape and place it over the velostat edge, enough to hold the velostat down but not to cover where the copper tape is underneath. Make sure the velostat is flat against the wood, and place the remainging tape on the other edge. Fold the tape over the edges of the wood to secure it.

    Grab the velostat and template piece.
    Cut the velostat the length of the board and width of the template
    Lay the velostat evenly across the copper tape
    Tape the velostat down with electrical tape
    Fold the of the electical tape over to secure it

    Key Contacts 

    Cut seven copper tape strips slightly longer than the length of the keys, you can be generous with your cuts because the copper tape will wrap around to the other side of the key. Any extra tape can be removed later. Attach the copper tape by starting on the underside of the key right before the key's hinge, and wrap it around the keys edge over the top of the key. Cut the copper tape on the top side of the keys for a clean finish.

    The copper tape on the keys are the last piece to create a finished circuit between the ground plane, velostat and keys. Every press while playing the piano will close the circuit, sending information to the arduino.

    Cut seven copper tape pieces for the keys
    Attach the copper tape so it wraps around the key
    Trim the copper tape on the top of the keys

    Soldering the Copper Tape 

    Soldering to copper tape is like soldering to anything else. The only problem is that copper tape is thin. We don't want to keep our hot soldering iron on the copper tape or close to the wood for an extended period of time. If your soldering iron has the option medium heat is sufficient. Always clean and tin your soldering iron.

    Open up the case so it lays flat and you have every inside end of the copper tape available to you. For the ground tape across the base, the end closest to the spacer will be the one you apply solder to. Take the soldering iron and solder and hold it over the tape. Lightly apply the iron to the tape and feed the solder into the iron, creating a blob of solder on the tape. You can be generous with the amount of solder on the tape, creating a nice round blob about 1/3" long. The goal is to create enough height for the wire to sink into. Do this to each one of the tapes until all eight ends are set. Make sure to clean your iron between each tape to get off the residue from the copper.

    Cut 8 wires approximately the length of the outstretched wood case. These will be longer than you need, but gives you wiggle room later on. Strip both ends of the wire about the width of a finger. Take the soldering iron and place a wire end on the solder blob. The rest of the wire should go towards the end of the tape and the center of the wood case. While resting the wire end on the solder blob, gently apply the soldering iron to the blob. It will heat up the blob and the wire should sink in. Quickly remove the iron and allow the solder to harden before letting go of the wire. Make sure you move quickly so the heated solder doesn't flatten out, leaving nothing to cover the wire. If this happens, leaving the wire unsecured, apply more solder on top of the wire to cover it.

    Do this for every copper tape end, and your result will have 8 wires all pointed towards the center of the wood case. These wires may be in the way for the next step, so feel free to bend them slightly to make room for the arduino mounting on the center of the case. You can optionally cover the new connections with electrical tape to create a finished look.

    Soldering the copper tape on the inside
    Gently feed solder into iron on end of the tape
    Create a solder blob
    All tape ends soldered
    Cut and strip the wires
    Lay the wire on the solder blob and heat it up
    Let the wire set in the melted solder
    Finished wiring

    Mount Arduino 

    Take your Arduino Uno, four M3 screws and the four M3 nuts. Place the Uno so the mounting holes on the Uno match up to the remaining holes on the bottom half of the wood case. The analog and power pins should be closer to the hinge of the case. Take a M3 screw and push it through the hole of both the arduino and case. Screw the nut on the underside until it is secure. Do this to the remaining three screws on the other holes.

    Note: Having the screws come up from the bottom of the case makes them flush with the screws attached to the spacers, but it is harder to attach the nuts on the arduino side.

    Take the remaining female headers and attach them to the pinouts on the arduino. You won't be able to press them in all the way, and about 1/4" of lead will be exposed. You won't have anymore headers remaining after this step.

    Screw in the ArduinoScrew in the Arduino
    Attach the remaining headers to the ArduinoAttach the remaining headers to the Arduino

    Feed Wires 

    On the top half of the wood case is a small slit next to the arduino shaped hole. Bend each wire so it can snugly fit through the slit and stick out to the top of the case. It is recommended to do this in a specific order so you know which wire is which later on.

    Bend the case closed, keeping the wires sticking out through the slit on the top of the case. The wires should not have any tension with the case open or closed. Secure the top of the case closed with the remaining four M3 Screws. The headers coming up from the Uno should stick out of the center hole.

    Wires fed through slit in specific orderWires fed through slit in specific order

    Attach the Shield

    Take the PCB Shield and attach it to the Uno headers, pressing it in until the shield is stable. You may need to gently bend the long leads of the shield to get them to fit into the headers perfectly.

    Wires should be sticking out of the slitWires should be sticking out of the slit
    Attach the shield to the Uno headersAttach the shield to the Uno headers

    Routing the wires correctly 

    Even if you ordered the wires before this step, double checking before trimming the wire could save you from having to replace it. Since all of the wires are the same color and could get out of order while doing previous work, this step guarantees you are working with the right wire. We will be using a Multimeter for this step, if you do not have one you'll have to unattach your shield to open the case to check the order of your wires.

    Most multimeters will have a continuity test feature that can be selected. The continuity test will make a beeping noise if two connection point are a part of the same connection. In other words, if both ends of a wire are connected to each other the multimeter will beep. Now let's put this idea to work and find which wire is suppose to go into which header pin.

    Take one of the multimeter's probes and place it on the copper tape of the 'C' key, now take the other probe and make contact with one of the wires. Does the multimeter beep? If so that wire is connected to the 'C' Copper tape. This wire will go into the '0' pin on the MUX0 header.

    Take the wire for C and gently fold it over the pcb shield to get a general feel for where you should cut it. You don't want to pull it too tight for this step or it will have tension that could keep you from opening the case later. With the wire stretched out over the pin it will be placed in, cut it where it's length goes to the far edge of the multiplexer. This can be cut down a bit more depending on how tight you want your wires to be. Restrip the wire at least 1/4" and place it in the header.

    Repeat this step with all of the following keys, until each wire is connected correctly. Repeat this step with the ground wire, but connect it the the GND pinout on the upper header. You will have empty pinouts on the header left over.

    Here's a quick table of each key and it's wire to the pin on the MUX0 header:

    Key Pin
    C 0
    D 1
    E 2
    F 3
    G 4
    A 5
    B 6
    Tools needed to route the wires
    Use the continuity function on the multimeter to test the wires
    Fold the wire over and measure where it reaches the far side of the multiplexer
    Cut the wire
    Strip the wire about the width of a finger
    Place the wire into the correct pinout
    All wires placed

    When you're all done screw on the last remaining four M3 screws onto the top holes of the wood case, securing it down. The shield does not need to be screwed down. You've now completed setting up your MIDI Piano!

    Code

    Get started coding

    Code
    This video walks through the benchmark code, downloading the MIDI Library, the final piano code, and calibrating your piano.

    Benchmark Code 

    read_keys_raw_benchmark.ino

    Now that the hardware is built, we want to run an sketch that will help us verify that the hardware is connected properly. read_keys_raw_benchmark.ino is a file that reads all of the keys and prints the raw key value in the serial monitor. If anything was incorrectly wired in the hardware setup, or something has become disconnected, This test will serve as the first software test of the hardware before we move onto the final code.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    /* read_keys_raw_benchmark.ino
     *
     *  This is a benchmark test for the hardware of the piano kit,
     *  Uploading and running this code will help verify that the hardware
     *  portion is working as expected. It is always a good idea to test
     *  projects incrementally to ensure they work properly.
     *
     *  This benchmark will read all of the keys 0-6 attached to the mux0
     *  and print out the raw data to the serial monitor.
     */
    
    //Mux0 Chip Enable 0
    #define CE0   2
    #define CE1   3
    #define CE2   4
    
    //Select bits for the Enabled Mux
    #define S0    5
    #define S1    6
    #define S2    7
    
    #define number_of_keys   7
    
    int sensorValue[number_of_keys];
    
    boolean readKeyFlag = false;
    int ISR_count = 0;
    
    //Variable used to determine next Select sequence
    int r0 = 0;
    int r1 = 0;
    int r2 = 0;
    
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
    
      pinMode(S0, OUTPUT);  //S0
      pinMode(S1, OUTPUT);  //S1
      pinMode(S2, OUTPUT);  //S2
    
      pinMode(CE0 ,OUTPUT);   //CE0
      pinMode(CE1,OUTPUT);    //CE1
      pinMode(CE2,OUTPUT);    //CE2
    
      digitalWrite(CE0, LOW);  //On
      digitalWrite(CE1, HIGH); //Off
      digitalWrite(CE2, HIGH); //Off
    
      //This is what it looks like to set bits directly to the Arduino
      //Registers
      //The code here is to set up TIMER 2. This is not an expected learning
      //outcome
      //of the project, so don't be intimidated by this code.
      // TIMER 2 for interrupt frequency 1000 Hz(1ms):
      cli(); // stop interrupts
      TCCR2A = 0; // set entire TCCR2A register to 0
      TCCR2B = 0; // same for TCCR2B
      TCNT2  = 0; // initialize counter value to 0
      // set compare match register for 1000 Hz increments
      OCR2A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256)
      // turn on CTC mode
      TCCR2B |= (1 << WGM21);
      // Set CS22, CS21 and CS20 bits for 64 prescaler
      TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
      // enable timer compare interrupt
      TIMSK2 |= (1 << OCIE2A);
      sei(); // allow interrupts
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    
      if(readKeyFlag == true)
      {
        readKeys();
        readKeyFlag = false;
      }
    
    }
    
    void readKeys()
    {
    
      //Read Pins
      for(int i = 0; i < number_of_keys; i++)
      {
          delay(1);
          r0 = bitRead(i,0);
          r1 = bitRead(i,1);
          r2 = bitRead(i,2);
    
          digitalWrite(S0,r0);
          digitalWrite(S1,r1);
          digitalWrite(S2,r2);
    
          sensorValue[i] = analogRead(A0);
    
          Serial.print(sensorValue[i]);
          Serial.print("\t");
      }
      Serial.println(""); //newLine
    }
    
    //ISR, Interrupt Service Routine
    ISR(TIMER2_COMPA_vect){
       //interrupt commands for TIMER 2 here
       if(ISR_count == 2)//5ms flag trigger
       {
         readKeyFlag = true;
         ISR_count = 0;
       }
       ISR_count++;
    }
    
    

    Code output 

    Open up the Serial Monitor (Tools > Serial Monitor) to see the codes output. The expected output to the serial monitor will be 7 printouts of the number 1023 side by side, separated by some space. From left to right, each key should represent C-B. When you press down on a key, the number will change to represent the pressure measurement being collected. The expected output should look something like the below image, for reference the D key was pressed.

    If the Benchmark code fails for any reason, head to the Troubleshooting section for some tips on common mistakes.

    Piano Code 

    Now that we know the hardware works correctly we're going to move onto the final code that will connect to our MIDI Software. This code is very similar to the benchmark code we just uploaded, so we're going to go through this new code step by step, breaking down the process of what's happening. Open up a new sketch and let's begin.

    Downloading the MIDI Library 

    If you don't already have the MIDI Library in your Arduino IDE, go to the menu bar and select Sketch > Include Libraries > Manage Library. The Library manager window will pop up and type MIDI into the search bar. Scroll down until you see the MIDI Library by Forty Seven Effects, the list is alphabetical so it is easy to find. Select the Library and a button will pop up in the lower right corner saying Install. Click on that button and the library will be downloaded into your IDE.

    Libraries and variables 

    Add the following code to the top of your program #include <MIDI.h> this is telling the Arduino IDE what other code your program will need to access. Below our library we are going to place our variables

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #define LED 13
    
    #define CE0 2 //Chip Enable 0
    #define CE1 3
    #define CE2 4
    
    #define s0 5  //Select 0
    #define s1 6
    #define s2 7
    
    #define number_of_keys 7
    

    These are called Pound Define. This is a naming convention style I prefer for pins because they are constant (unchanging) values in the code. For example #define LED 13 means that any instance of LED in already has the value 13 assigned to it. This process is done at compile time, and doesn't take up memory on the Arduino like normal allocation. To compare int LED = 13; assigns an integer the value. The Arduino will reserve the space for an int which is 16 bits (2 bytes) on the Arduino. The benefit of a #define is that it saves space when you work with variables that do not change.

    Breaking down #defines

    Pin 13 is attached to the LED on the shield, that is why it is labeled LED.

    CE0 is the pin attached to the Chip Enable for Mux0. The Chip Enable is similar to an on/off switch. If the Chip is Enabled, the Chip is on, Disabled is off. For this Multiplexer the Chip Enable is Active Low, Active Low means that, Low(0) is on, and High(1) is off. For other devices High(1) is on, and Low(0) is off.

    CE1 and CE2 are the pins attached to the Chip Enable of Mux1 and Mux2 similar to CE0.

    Multiplexers have Select bits, which determine which mux pin is connected to the output pin. Select bits are based off of binary, or base2. The table below outlines the Input that will be Selected and read. The seven keys we are setting up will scan from Input 0 - 6

    S0 S1 S2 Input
    0 0 0 0
    1 0 0 1
    0 1 0 2
    1 1 0 3
    0 0 1 4
    1 0 1 5
    0 1 1 6
    1 1 1 7

    Below our #defines we have a few more variables:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //Max is zero so the true max of the reading will be captured
    int sensorMax[number_of_keys];
    //True Min will be captured
    int sensorMin[number_of_keys];
    int sensorValue[number_of_keys];
    
    int midi_Num[number_of_keys]= {60,62,64,65,67,69,71};
    boolean readKeyFlag = false;
    boolean isKeyPressed = false;
    int ISR_count = 0;
    int r0 = 0;
    int r1 = 0;
    int r2 = 0;
    

    sensorMax and sensorMin and sensorValue are arrays that will hold the calibration values for each key, and come up later in the calibrate() function.

    The Setup Function 

    Following our variables is our setup() function, what ever code is place inside the setup function brackets { and } is only run once in the beginning of the program. So from Top to Bottom the code will run once. Copy in the setup() function and then we'll break it down.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    void setup()
    {
      //Remember, this code only
      pinMode(LED, OUTPUT);  //LED
    
      pinMode(s0, OUTPUT);  //s0
      pinMode(s1, OUTPUT);  //s1
      pinMode(s2, OUTPUT);  //s2
    
      pinMode(CE0 ,OUTPUT);   //CE0
      pinMode(CE1,OUTPUT);    //CE1
      pinMode(CE2,OUTPUT);    //CE2
    
      digitalWrite(CE0, LOW);  //On
      digitalWrite(CE1, HIGH); //Off
      digitalWrite(CE2, HIGH); //Off
    
      calibrate_sensor();
    
      // TIMER 2 for interrupt frequency 1000 Hz(1ms):
      cli(); // stop interrupts
      TCCR2A = 0; // set entire TCCR2A register to 0
      TCCR2B = 0; // same for TCCR2B
      TCNT2  = 0; // initialize counter value to 0
      // set compare match register for 1000 Hz increments
      OCR2A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256)
      // turn on CTC mode
      TCCR2B |= (1 << WGM21);
      // Set CS22, CS21 and CS20 bits for 64 prescaler
      TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
      // enable timer compare interrupt
      TIMSK2 |= (1 << OCIE2A);
      sei(); // allow interrupts
    
      MIDI.begin(4);          // Launch MIDI and listen to channel 4
    }
    
    

    The first thing in the setup function is seven pinMode() function calls. pinMode() configures a specific pin to behave as either a input or a output. These are setting the LED pin, the Chip Enable pins, and the Select Bit pins all to OUTPUT.

    Following that is three digitalWrite() function calls, which writes HIGH or LOW to a digital pin. If the pin has been set with OUTPUT with pinMode(), it's voltage will be set to 5V(or 3.3V on 3.3V boards) for HIGH and 0V (ground) for LOW. In this case CE0, Chip Enable 0 for Mux0 is set to LOW because the multiplexer used is Active Low. The other two chip enables are set HIGH to disable them, because only one multiplexer should be enabled at a given time.

    pinMode() and digitalWrite() are both Arduino supported functions.

    The next function called in setup is calibrate_sensors(), which is a function made to calibrate the velostat keys. This happens only once in the setup function so you don't have to repeat the process.

    The next block of code in the setup function is the Timer 2 Register setup. This allows Timer 2 to tick at a set interval, Understanding this section is not required for this kit. The Timing code is given, feel free to learn how it works on your own. We will skip over the explanation for this section.

    Finally we begin the MIDI process using MIDI.begin(4); , this will keep the MIDI program listening for our output as we put it together using the outside software.

    Main Loop 

    The main loop function of this sketch is fairly short, consisting of Reading Keys and Sending MIDI Messages. Place this right after the setup() function:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void loop()
    {
      if(readKeyFlag == true)
      {
        readKeys();
        readKeyFlag = false;
      }
    
      for(int i = 0; i < number_of_keys; i++)
      {
        if(sensorValue[i] > 10){
          MIDI.sendNoteOn(midi_Num[i], sensorValue[i],2);
        }else{
          MIDI.sendNoteOff(midi_Num[i], sensorValue[i],2);
        }
      }
    }
    

    The readkeys(); is only called when the readKeyFlag is true. readKeyFlag is set in the ISR (Interrupt Service Routine), which we will talk about later on in this tutorial.

    The for loop in the main loop is where the actual MIDI Message is being generated. For each key, if the sensorValue is greater than > 10 then the MIDI Message MIDI.sendNoteOn(midi_Num[i], sensorValue[i],2); is sent.

    The MIDI Library used in this project has a function, sendNoteOn(inNoteNumber, inVelocity, inChannel)

    Parameters:

    • inNoteNumber Pitch value in the MIDI format (0 to 127).
    • inVelocity Note attack velocity (0 to 127). A NoteOn with 0 velocity is considered as a NoteOff.
    • inChannel The channel on which the message will be sent (1 to 16).

    Later on the reason we set the LMMS Instrument to channel 2, is because the inChannel Parameter is 2 here.

    Calibrate 

    The calibrate_sensor() function is called in the void setup() function will be discussed here in detail. The Velostat material used to make the pressure sensor/keys for the piano kit is a variable resistor. The greater the pressure the less resistive the material is. Unfortunately there are small imperfections in the material causing some spots to react slightly differently to pressure that is applied. In other words, just because the Velostat sheet is one piece on material does not mean the far left side will react the exact same way as the far right side. This is why we need to calibrate the sensor.

    This function follows after our main loop:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    void calibrate_sensor()
    {
      unsigned long adjusted_time;
    
      for(int i = 0; i < number_of_keys; i++)
      {
        sensorMax[i]   = 0;
        sensorMin[i]   = 1023;
        sensorValue[i] = 0;
        adjusted_time = millis();
    
        //Mux select
        r0 = bitRead(i,0);
        r1 = bitRead(i,1);
        r2 = bitRead(i,2);
    
        //Write the current select bits to the select pins
        digitalWrite(s0,r0);
        digitalWrite(s1,r1);
        digitalWrite(s2,r2);
    
        digitalWrite(LED, HIGH);
       // calibrate each key for five seconds
       while (millis() < adjusted_time + 5000)
       {
        delay(1);
         sensorValue[i] = analogRead(A0);
    
         // record the maximum sensor value
         if (sensorValue[i] > sensorMax[i])
         {
           sensorMax[i] = sensorValue[i];
         }
    
         // record the minimum sensor value
         if (sensorValue[i] < sensorMin[i])
         {
           sensorMin[i] = sensorValue[i];
         }
       }
       digitalWrite(LED,LOW);
       delay(1000);
      }
    }/*End of calibrate_sensor()*/
    

    The calibration function is comprised of one big for loop, that will loop through each key. Nested in the for loop is a while loop, that will continue to loop for 5 seconds reading the current key. In those 5 seconds the key will be repeatedly read, storing the Max and Min value read for that key.

    The sensor reading will have a Max Value and Min Value, this will be stored in sensorMax[] and sensorMin[] for each key. The sensor value will range from 0 - 1023.

    The adjusted_time is equal to the current millis() reading. This is used for timing purposes. This is a common method used for timing requirements that aren't strict. The code is still running all the way through, but timing is not exact.

    There is a delay(1) , although the delay function is generally used sparingly, it is used here to make sure the analogRead() is not being called too fast with in the loop.

    Once the delay is finished, the sensor value is read, sensorValue[i] = analogRead(A0); , Remember that i represents the key we are on, and the Mux0 is connected to A0. Additionally right before the while loop, the Select Bits are determined and set.

    The two following if statements are used to record the Sensor Max and Sensor Min

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    // record the maximum sensor value
    if (sensorValue[i] > sensorMax[i])
    {
      sensorMax[i] = sensorValue[i];
    }
    

    If the sensor value is greater than > the sensor maximum, Then, the sensor maximum equals the sensor value.

    This allows us to hold onto the largest value, and ignore new values that are smaller. The following if statement works exactly the same, but is used to capture the minimum value.

    The while loop will continue to loop for approx. 5 seconds, reading and recording, Min and Max values on a single key. Then when the 5 seconds for that key is up, the LED will turn off for 1 second (1000ms), then the process is repeated for the next key.

    Challenge

    There was a section of code in the above section not mentioned. The three lines of code labeled //Mux Select use a function called bitRead(x,n) , I challenge you to research what bitRead(x,n) does, and try to figure out what r0 r1 and r2 are being used for in the calibration function.

    readkeys() 

    The readkeys() has some similar code seen in the calibrate_sensor() , mainly the code used to process and send the Select Bits to the Mux. The new code in this function is for normalizing the raw sensor values recorded into a range we can use. Place this after the calibrate_sensor() function:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    void readKeys()
    {
      //Read Pins
      for(int i = 0; i < number_of_keys; i++)
      {
          delay(1);
          r0 = bitRead(i,0);
          r1 = bitRead(i,1);
          r2 = bitRead(i,2);
    
          digitalWrite(s0,r0);
          digitalWrite(s1,r1);
          digitalWrite(s2,r2);
    
          sensorValue[i] = analogRead(A0);
          sensorValue[i] = map(sensorValue[i], sensorMin[i], sensorMax[i], 127, 0);
          // in case the sensor value is outside the range seen during
          //calibration
          sensorValue[i] = constrain(sensorValue[i], 0, 127);
    
        if(sensorValue[i] <= 10){
          sensorValue[i] = 0;
        }
      }
    }
    

    The first two code blocks should look familiar, the rest of the function is new. The sensor is read for that key, sensorValue[i] = analogRead(A0); , then the value is mapped using the sensorValue[i] , sensorMin[i] , and sensorMax[i] . The Min and Max being the same values captured in the calibrate_sensor() .

    There is a small point that is not very easy to see here, the Velostat sensor gives us a reading from 0 - 1023. 1023 when No Pressure is applied, and 0 when Full Pressure. This is backwards to what we want for volume control, When we press the key really hard we want it to produce a louder note.


    sensorValue[i] = map(sensorValue[i], sensorMin[i], sensorMax[i], 127, 0);

    When mapping the raw values to a new range, we map the SensorMin[i] to 127, and the sensorMax[i] maps to 0. The maximum, and minimum inVelosity for the sendNoteOn MIDI function is listed in the parameters above, which happen to be 0 -127. This swap allows the harder press to produce a larger number, and in turn a louder note.

    Now what happens if we read a value that is out of the range of the values gathered during calibration? This is why we constrain the value to the range of the mapping function. sensorValue[i] = constrain(sensorValue[i], 0, 127); , This will keep us within our 0 - 127 range.


    if(sensorValue[i] <= 10){ sensorValue[i] = 0; }

    The last if statement is used to drop everything less than or equal to <= 10 to 0. This is done to fix a problem where some keys, when not pressed would receive a reading that would persist around 1 or 2, causing that key to never turn off.

    ISR 

    The Interrupt Service Routine function follows the readKeys() function:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ISR(TIMER2_COMPA_vect){
       //interrupt commands for TIMER 2 here
       if(ISR_count == 2)
       {
         readKeyFlag = true;
         ISR_count = 0;
       }
       ISR_count++;
    }
    

    The ISR is triggered by Timer 2, which was set to 1ms, or 1000 Hz, in the setup() .

    Calibrating the Piano 

    Before running the code, there is a process for calibrating the pressure sensor that comes with this code. The calibration begins whenever you give power to the piano or press the reset button on the shield. The process starts with the small led will flash three times, then go out. It will then blink on and off seven times, one for each key. During which you have to press down a single key in order from C to B, switching keys when the light goes out.

    Code output and results 

    Once the code uploads the calibration process of the piano can begin, you can ignore it for now as we won't be getting output until we set up the MIDI software. In your serial monitor you will find a continuous string of backwards **?**s, xXs, and other symbols. This is the correct output even though it is very different than our benchmark code. If you calibrate the piano by pressing the button or reuploading the code, you'll still get a continuous line but with `` and ds inbetween. This is also fine. Now we can move onto the MIDI software that will make this piano play real music.

    Full MIDI Code 

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    #include <MIDI.h>
    
    
    
    /*
      killall ttymidi             End all connections
      ttymidi -s /dev/ttyACM1 &   Set up New one, ACM1 Not always the Case
      aconnect -i                 Print inputs, Arduino is Connected to This ttymidi
      aconnect -o                 Print Outputs, LMMS instrument is the one you want
      aconnect 129:0 128:2        Connect the input/output like This, numbers
                                  subject to change
    */
    
    #define LED 13
    
    #define CE0 2 //Chip Enable 0
    #define CE1 3
    #define CE2 4
    
    #define s0 5  //Select 0
    #define s1 6
    #define s2 7
    
    #define number_of_keys 7
    
    //Max is zero so the true max of the reading will be captured
    int sensorMax[number_of_keys];
    //True Min will be captured
    int sensorMin[number_of_keys];
    int sensorValue[number_of_keys];
    
    int midi_Num[number_of_keys]= {60,62,64,65,67,69,71};
    boolean readKeyFlag = false;
    boolean isKeyPressed = false;
    int ISR_count = 0;
    int r0 = 0;
    int r1 = 0;
    int r2 = 0;
    
    
    
    struct MySettings : public midi::DefaultSettings
    {
       static const long BaudRate = 115200;
    };
    MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, MySettings);
    
    
    
    void setup()
    {
      //Remember, this code only
      pinMode(LED, OUTPUT);  //LED
    
      pinMode(s0, OUTPUT);  //s0
      pinMode(s1, OUTPUT);  //s1
      pinMode(s2, OUTPUT);  //s2
    
      pinMode(CE0 ,OUTPUT);   //CE0
      pinMode(CE1,OUTPUT);    //CE1
      pinMode(CE2,OUTPUT);    //CE2
    
      digitalWrite(CE0, LOW);  //On
      digitalWrite(CE1, HIGH); //Off
      digitalWrite(CE2, HIGH); //Off
    
      calibrate_sensor();
    
      // TIMER 2 for interrupt frequency 1000 Hz(1ms):
      cli(); // stop interrupts
      TCCR2A = 0; // set entire TCCR2A register to 0
      TCCR2B = 0; // same for TCCR2B
      TCNT2  = 0; // initialize counter value to 0
      // set compare match register for 1000 Hz increments
      OCR2A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256)
      // turn on CTC mode
      TCCR2B |= (1 << WGM21);
      // Set CS22, CS21 and CS20 bits for 64 prescaler
      TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
      // enable timer compare interrupt
      TIMSK2 |= (1 << OCIE2A);
      sei(); // allow interrupts
    
      MIDI.begin(4);          // Launch MIDI and listen to channel 4
    }
    
    
    void loop()
    {
      if(readKeyFlag == true)
      {
        readKeys();
        readKeyFlag = false;
      }
    
      for(int i = 0; i < number_of_keys; i++)
      {
        if(sensorValue[i] > 10){
          MIDI.sendNoteOn(midi_Num[i], sensorValue[i],2);
        }else{
          MIDI.sendNoteOff(midi_Num[i], sensorValue[i],2);
        }
      }
    }
    
    
    
    
    void calibrate_sensor()
    {
      unsigned long adjusted_time;
    
      for(int i = 0; i < number_of_keys; i++)
      {
        sensorMax[i]   = 0;
        sensorMin[i]   = 1023;
        sensorValue[i] = 0;
        adjusted_time = millis();
    
        //Mux select
        r0 = bitRead(i,0);
        r1 = bitRead(i,1);
        r2 = bitRead(i,2);
    
        //Write the current select bits to the select pins
        digitalWrite(s0,r0);
        digitalWrite(s1,r1);
        digitalWrite(s2,r2);
    
        digitalWrite(LED, HIGH);
       // calibrate each key for five seconds
       while (millis() < adjusted_time + 5000)
       {
        delay(1);
         sensorValue[i] = analogRead(A0);
    
         // record the maximum sensor value
         if (sensorValue[i] > sensorMax[i])
         {
           sensorMax[i] = sensorValue[i];
         }
    
         // record the minimum sensor value
         if (sensorValue[i] < sensorMin[i])
         {
           sensorMin[i] = sensorValue[i];
         }
       }
       digitalWrite(LED,LOW);
       delay(1000);
      }
    }/*End of calibrate_sensor()*/
    
    
    void readKeys()
    {
      //Read Pins
      for(int i = 0; i < number_of_keys; i++)
      {
          delay(1);
          r0 = bitRead(i,0);
          r1 = bitRead(i,1);
          r2 = bitRead(i,2);
    
          digitalWrite(s0,r0);
          digitalWrite(s1,r1);
          digitalWrite(s2,r2);
    
          sensorValue[i] = analogRead(A0);
          sensorValue[i] = map(sensorValue[i], sensorMin[i], sensorMax[i], 127, 0);
          // in case the sensor value is outside the range seen during calibration
          sensorValue[i] = constrain(sensorValue[i], 0, 127);
    
        if(sensorValue[i] <= 10){
          sensorValue[i] = 0;
        }
      }
    }
    
    ISR(TIMER2_COMPA_vect){
       //interrupt commands for TIMER 2 here
       if(ISR_count == 2)
       {
         readKeyFlag = true;
         ISR_count = 0;
       }
       ISR_count++;
    }
    
    Windows Software Setup

    Setting up the softare

    Depending on the Operating System (OS) of your computer, the software setup with be slightly different for a Mac or Windows users. If you are a Windows user follow below.

    If you are a Mac user move onto the next page for your own setup instrutions.

    Downloading Programs for MIDI 

    The necessary programs used for Window users:

    Windows Software Setup
    This video walks through the software setup for Windows.

    Once downloaded place all three in one folder for easy use. LMMS is the only of the bunch that needs to be formally installed. LoopMIDI and Hairless will just run from the folder.

    Connecting Virtual Cables 

    A standard MIDI device uses a special MIDI connector and communicates in MIDI protocol, or language, with a digital audio workstation (DAW) like Garageband or LMMS. We are not using that connector and are instead using an Arduino and USB Cable. But utilizing some digital trickery our DAW of choice will see the Arduino MIDI Controller as a real MIDI device.

    To do this two connections much be made. A USB to virtual MIDI cable and that virtual MIDI cable to our DAW in this case LMMS. Hairless is our USB to MIDI cable and LoopMIDI is the MIDI to DAW part. By using these two programs, a key pressed on our controller will travel into our computer via USB and into LMMS as a MIDI signal and then into notes on a piano.

    Connecting Virtual Cables Actually 

    The order of opening the programs is important in this process. The LMMS Software will not recognize the virtual cable if the cable isn't set up beforehand.

    If at the end of this process nothing is working for you, close LMMS and restart the piano, make sure hairless is showing activity before moving onto LMMS.

    Open LoopMIDI

    Next to New Port-Name is a input box that says "loopMIDI Port", change this to your preferred MIDI controller name.

    A custom name for the loopMIDI portA custom name for the loopMIDI port

    Press the '+' sign to the left to add your virtual MIDI cable to the list. This is all that needs to be done for LoopMIDI, but keep it open.

    Our port added as a virtual cableOur port added as a virtual cable

    Open Hairless-MIDISerial

    This does not require installation, find the Folder containing Hairless. Click the Hairless Application file. A Security window will pop up, Click Run.

    A new Hairless windowA new Hairless window

    Hairless can be left alone for now, we will come back to it later

    Open LMMS (Only works if LMMS is opened last)

    A new LMMS projectA new LMMS project

    LMMS will open with a UNTITLED project, this is fine for now. On the left hand side is a vertical bar with icons. Select the Music note and it will open a menu called My samples. Double click on the instruments folder to expand it, either double click on the e_piano_accord01.ogg or drag it into the Song Editor window. This will create a new track, if you double clicked it will appear in the Beat + Bassline Editor window. Feel free to select the setting/gear on the premade tracks in the same window to delete it, we are only focusing on the piano one for now.

    Select the piano track where it shows the filename (e_piano_accord01.ogg) this will open up a new window specifically for the track. The track window is separated into multiple tabs, under the general settings tab is a menu bar with PLUGIN, ENV/LFO, FUNC, FX and MIDI on it. Select MIDI and the window will change to the MIDI tab. Select the long button next to ENABLE MIDI INPUT, and it will light up green along with the channel and velocity sections. Hover your mouse over the Channel Box, the mouse should change to hand pointed. To increase or decrease the channel number you have to scroll up on your mouse (if you have a scroll wheel) or using two fingers on your mouse pad, scroll down. We want the Channel to be on number 2 because of how our code is written.

    Where the piano instrument isWhere the piano instrument is

    We now need to connect the LMMS to LoopMIDI. We can do this in two ways, either select the button in the MIDI tab that looks like a Piano in a grey box (not the one at the bottom of the window), or back in the window with the track and select the gear. In the drop down window select MIDI > INPUT> then your controller name. If you select the piano in the MIDI tab you simply select your Piano controller.

    The piano settings windowThe piano settings window

    Go back to Hairless window

    In Hairless select the MIDI Out drop down menu and select your Piano controller.

    My Hairless settingsMy Hairless settings

    Select the Serial port drop down menu and select the COM port your Arduino is plugged into.

    The Connections are now complete the last thing we need to do is turn the Serial Bridge on, Check Serial<->MIDI Bridge box to turn it on. If it is already on, check and uncheck it to restart it. Make sure the Debug MIDI messages box is checked, this will show you the MIDI messages your arduino is sending.

    Hairless doing it's magic!Hairless doing it's magic!

    Press some keys on your MIDI Keyboard, do you hear anything? is the LMMS software registering anything? Check out the Debug window in Hairless, is the proper information coming through?

    Your Virtual connections are complete 

    You have completed making the connections.

    Mac Software Setup

    Setting up the softare

    Depending on the Operating System (OS) of your computer, the software setup with be slightly different for a Mac or Windows users. If you are a Mac user follow below.

    Downloading Programs for MIDI 

    The necessary programs used for Mac users:

    If you navigate to the LMMS download page yourself please choose the BETA version as the Stable version does not yet support Apple MIDI.

    Mac Software Setup
    This video walks through the software setup for Mac.

    Once downloaded place both one folder for easy use. LMMS is the only of the bunch that needs to be formally installed. Hairless will just run from the folder.

    Connecting Virtual Cables 

    A standard MIDI device uses a special MIDI connector and communicates in MIDI protocol, or language, with a digital audio workstation (DAW) like Garageband or LMMS. We are not using that connector and are instead using an Arduino and USB Cable. But utilizing some digital trickery our DAW of choice will see the Arduino MIDI Controller as a real MIDI device.

    To do this two connections much be made. A USB to virtual MIDI cable and that virtual MIDI cable to our DAW in this case LMMS. Hairless is our USB to MIDI cable and the MIDI to DAW part is handled my the Mac OS. By using this method, a key pressed on our controller will travel into our computer via USB and into LMMS as a MIDI signal and then into notes on a piano.

    Connecting Virtual Cables Actually 

    The order of opening the programs is important in this process. The LMMS Software will not recognize the virtual cable if the cable isn't set up beforehand.

    If at the end of this process nothing is working for you, close LMMS and restart the piano, make sure hairless is showing activity before moving onto LMMS.

    Setting up Mac Settings

    Go into the Spotlight or search bar at the top right of your screen and enter "Audio MIDI Setup". Alternatively you can find this program in the Applications then Utility folder in finder.

    Searching the SpotlightSearching the Spotlight

    Navigate to the window tab on top and press "Show MIDI Studio".

    Show MIDI devicesShow MIDI devices

    A new window will appear and we want to double click the red box titled "IAC Driver".

    The IAC DriverThe IAC Driver

    After double clicking that, press the checkbox with the text "Device is online".

    Device is onlineDevice is online

    With that done, one of our virtual cables is ready.

    Open Hairless-MIDISerial

    Double click the Hairless-MIDISerial application

    A new Hairless windowA new Hairless window

    Click the Serial<->MIDI Bridge On thus setting it to the off position. Make sure your Arduino MIDI Controller is plugged IN and you'll want to select it from "Serial Port" drop down menu on the left. Under the MIDI Out drop down on the top right select that IAC Driver.

    Correct Hairless settingsCorrect Hairless settings

    With the right settings input we can click Serial<->MIDI Bridge On again and turn it on.

    Open LMMS (Only works if LMMS is opened last)

    A new LMMS projectA new LMMS project

    LMMS will open with a UNTITLED project, this is fine for now. In order for our Arduino MIDI Controller to show we'll have to change some settings. From the top application bar select LMMS then down to "Preferences".

    Select PreferencesSelect Preferences

    Move down to the speaker icon which is second from the bottom and select "SDL" from the Audio Interface list.

    Audio InterfaceAudio Interface

    Move down another icon to the keyboard picture and select "Apple MIDI" from the MIDI Interface list.

    MIDI InterfaceMIDI Interface

    Press OK to confirm these settings and then restart LMMS. Now we can work on that UNTITLED project. On the left hand side is a vertical bar with icons. Select the Music note and it will open a menu called My samples. Double click on the instruments folder to expand it, either double click on the e_piano_accord01.ogg or drag it into the Song Editor window. This will create a new track, if you double clicked it will appear in the Beat + Bassline Editor window. Feel free to select the setting/gear on the premade tracks in the same window to delete it, we are only focusing on the piano one for now.

    Select the piano track where it shows the filename (e_piano_accord01.ogg) this will open up a new window specifically for the track. The track window is separated into multiple tabs, under the general settings tab is a menu bar with PLUGIN, ENV/LFO, FUNC, FX and "A PICTURE OF A KEYBOARD" on it. Select "A PICTURE OF A KEYBOARD" and the window will change to the MIDI tab. Select the long button next to ENABLE MIDI INPUT, and it will light up green along with the channel and velocity sections. Hover your mouse over the Channel Box, the mouse should change to hand pointed. To increase or decrease the channel number you have to scroll up on your mouse (if you have a scroll wheel) or using two fingers on your mouse pad, scroll down. We want the Channel to be on number 2 because of how our code is written.

    Correct Piano SettingsCorrect Piano Settings

    Select the button in the MIDI tab that looks like a Piano in a grey box (not the one at the bottom of the window), or back in the window with the track and select the gear. In the drop down window select MIDI > INPUT> then IAC Driver. If you select the piano in the MIDI tab you simply select the IAC Driver.

    IAC SelectionIAC Selection

    Press some keys on your MIDI Keyboard, do you hear anything? is the LMMS software registering anything? Check out the Debug window in Hairless, is the proper information coming through?

    Your Virtual connections are complete 

    Troubleshooting

    Benchmark Code Troubleshooting 

    If your serial output will not change when pressing keys

    Your keys aren't connected somewhere. This could mean with the shield, where the wires aren't long enough in the pinouts, or to the ground plane. The contact point where the keys connect to the ground plane is very small, and your ground plane could be misaligned.

    If the wrong key in serial output is changing when you press down the key

    Your keys are connected

    If multiple keys change in the serial output if you press down one key

    Check to see if your wires are touching where they are stripped, if everything is fine then you have a short on your shield. Take you shield out and check the solder on the back. If some of the solder is touching you'll need to fix this using the soldering iron. You can fix this with a solder sucker, solder wick, or some careful reheating on the iron. If you can't see any obvious connections in the solder, you're going to have to go through each pin. Take the soldering iron and reheat each connection until it melts. This should fix the problem.

    Piano Code Troubleshooting 

    Code uploading but LED isn't turning on:

    Check your leads between the shield and arduino, it's possible one isn't in correctly.

    Errors in the code due to #include <MIDI.h>

    Make sure you have the MIDI library downloaded to your Arduino IDE. Watch the tutorial video in the Software section for a step by step if needed.

    Software Setup Troubleshooting 

    No sound is appearing but connections are running through

    Check your MIDI settings in LMMS. You need to have:

    • The "Enable MIDI Input" button selected, so it is green.

    • The correct channel number to match the instrument. For the Piano this is channel 2.

    • The Piano's MIDI controller selected as a input. You can either do this by selecting the button with the piano on it in the MIDI tab, and selecting the controller, or selecting the gear by the track name and selecting the controller under the Input.

    Hairless showing high volume when key isn't being pressed

    If your keys are giving you the max volume (126/127) then your calibration is wrong. Hit the button on the shield to restart the calibration process. If that still doesn't work it means your physical key isn't connected to pin correctly. Check your wires and soldering, using a multimeter if necessary to make sure it's correct.

    Further Reading

    Links to additional resources

    Arduino MIDI Library Page

    MIDI Library Documentation

    ttymidi github

    MIDI Note Number

    Analog Multiplexers

    Laser Cut Hinge

    Expanding your Arduino 

    You've finished your Piano and now what next? You have two more Multiplexers and lots of material at your disposal to create more instruments. In this section we're going to break down how you can take the code you already have and repurpose it for an additional instrument. This code will be very similar to the final software code, but we're going to be adding a example instrument that is two keys. You can use all three multiplexers on the shield at one time, so three instruments can be played together.

    The Shield 

    At the end of the Piano tutorial you should have one Multiplexer soldered on. To extend the functionality of your MIDI controller we will have to add on another (or both remaining) Multiplexer(s). If by chance you hadn't soldered on the short

    In the same way we soldered in the first multiplexer chip, we will solder in the remaining. Orient the multiplexer so the "U" shaped indent is closest to the silk screen label MUX. Press the chip in. Turn the shield over and solder a single pin to hold the chip. Double check that the chip is flush with the shield, then solder the remaining pins. Repeat this with the last multiplexer if needed.

    If you hadn't soldered in the headers with the short leads, you will need them for using the new multiplexers. Take one of the headers and place it in the shield leads down. Flip the shield over, allowing the other headers to hold it up. You should be able to easily adjust the new header from this position, making sure it's flush with the shield and straight. Solder one pin down, and flip the shield over to check that it's correct before soldering the remaining pins. Repeat this for every multiplexer you have in your shield.

    The Instrument 

    The instrument is made up of three parts, the ground plane, the velostat, and the key styled switches that aren't more than 8 per multiplexer. These are your basic requirements for making a new instrument.

    Instrument DiagramInstrument Diagram

    You can use anything for the base of these pieces, but for this walk through a simple two key instrument will be the example. It will be using the wood cut case template piece as the ground plane's base, and the two small square wood pieces as the keys.

    Ground Plane

    In the same way you made your ground plane for the Piano, take your base and cut some copper tape 1 1/2 times the length of your base. The copper tape will need to be where the keys hit, so if you are mounting your key pieces in some way, make sure that's where you measure the tape. Apply the copper tape to the base, folding and turning the tape at the end into a 90 degree angle for where you will solder your wire down. The tape needs to be one solid piece for a stable connection, as tempting as two pieces could be. This is due to the adhesive on the copper tape being less conductive than the tape itself.

    Velostat

    Cut your velostat at the appropriate length and width for the base so it will cover the copper tape on your base piece. Lay it evenly over the tape, and secure it with two pieces of electrical tape.

    Keys

    Take your keys and cut some copper tape slightly longer than the length of the keys. When applying the tape, be aware of the contact point on the key and how much room you're giving yourself to solder on the wires.

    Soldering and Wiring

    You will need one wire for your ground plane, and one for each key you've made. The length of the wires is based on your preferences, but since this instrument will be attached to the piano it's helpful to have some wiggle room for their placement. Strip both ends of the wire, one side a little more for soldering and the other for placing into the header. Take the piece you're soldering, the soldering iron, and the solder. We want to create the same blob of solder on the tape as we did before for the Piano, and then remelt it for the wire. Make sure you have enough room on your pieces for soldering, if you're using the wood cut pieces you won't have much.

    With all your connections soldered now comes the wiring. There are three ground pinouts on your shield, all highlighted with white silkscreen. Two are on side with the switch, and the last one is on the side with the LED. Plug in your ground plane. The wiring for the keys goes into the pinouts next to the multiplexers. But it is dependant on which multiplexer you are using, so make sure you wire to the pinout for the multiplexer you are using. (MUXP1 > MUX1 & MUXP2 > MUX2) Starting from the 0 key from the pinout (see the silkscreen next to MUXP0 for the key labels), attached your instrument keys to the pinouts. You don't need to use all eight pinouts, and this will be addressed in the code later.

    Make sure your instrument is set up for easy calibration later on, which will be the same process as the piano keys. The calibration process run through each instrument in order without delay, so you want your setup to be in easy reach so you don't have to repeat the process.

    The Code 

    The code we'll be using is based off the final piano code, so you can either open up a new sketch or simply edit the one you already have.

    The variables

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #include <MIDI.h>
    
    
    
    /*
     killall ttymidi             End all connections
     ttymidi -s /dev/ttyACM1 &   Set up New one, ACM1 Not always the Case
     aconnect -i                 Print inputs, Arduino is Connected to This ttymidi
     aconnect -o                 Print Outputs, LMMS instrument is the one you want
     aconnect 129:0 128:2        Connect the input/output like This, numbers
                                 subject to change
    */
    
    #define LED 13
    
    #define CE0 2 //Chip Enable 0
    #define CE1 3
    #define CE2 4
    
    #define s0 5  //Select 0
    #define s1 6
    #define s2 7
    

    The start of the program is the same as the old code, these variables don't need to be changed. As a quick refresher these are the multiplexer chips, select bits, and the LED pins. For a more in depth breakdown head over to the software module.

    From here the code starts taking a different turn to make room for multiple instruments. In this example we are going to be calling the two key instrument a Drum, but you can differentiate it in any way you wish.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    //For Piano Chip
    #define number_of_keysP 7
    //Max is zero so the true max of the reading will be captured
    int sensorMaxP[number_of_keysP];
    //True Min will be captured
    int sensorMinP[number_of_keysP];
    int sensorValueP[number_of_keysP];
    int midi_NumP[number_of_keysP]= {60,62,64,65,67,69,71};
    

    Here we are separating the different instruments sensor values and MIDI numbers. If you're using instruments with the same number of keys, differentiating number_of_keys isn't necessary.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    //For Drum Chip
    #define number_of_keysD 2
    //Max is zero so the true max of the reading will be captured
    int sensorMaxD[number_of_keysD];
    //True Min will be captured
    int sensorMinD[number_of_keysD];
    int sensorValueD[number_of_keysD];
    int midi_NumD[number_of_keysD]= {72,74};
    

    Here's similar variables for our new instrument. The most important part is that the MIDI numbers, which equate to the notes being played on the instrument and their octave. There is a link for the MIDI numbers at the top of the page. Repeat this step if you're adding another instrument, make sure the amount for the keys is the same for your instrument.

    commenting: No errors will appear if there isn't a physical key to match the digital key, so if you want to simplify the #define number_of_keys and share it between instruments you can do that. The empty key will come up in MIDI as a uncalibrated key and can give you a full volume noise when you first connect to LMMS.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    boolean readKeyFlag = false;
    boolean isKeyPressed = false;
    int ISR_count = 0;
    int r0 = 0;
    int r1 = 0;
    int r2 = 0;
    
    struct MySettings : public midi::DefaultSettings
    {
       static const long BaudRate = 115200;
    };
    MIDI_CREATE_CUSTOM_INSTANCE(HardwareSerial, Serial, MIDI, MySettings);
    
    

    These are the last variables, which are the same as the old code.

    Setup

    The setup code is unchanged from the Piano software code. But the most important lines are the digitalWrite . This is where we are turning on the multiplexers. If the multiplexer is on set it to LOW, if it is off set it to HIGH. Adjust this to your setup, but otherwise copy this below the variables if you don't already have it:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    void setup()
    {
     //Remember, this code only
     pinMode(LED, OUTPUT);  //LED
    
     pinMode(s0, OUTPUT);  //s0
     pinMode(s1, OUTPUT);  //s1
     pinMode(s2, OUTPUT);  //s2
    
     pinMode(CE0 ,OUTPUT);   //CE0
     pinMode(CE1,OUTPUT);    //CE1
     pinMode(CE2,OUTPUT);    //CE2
    
     digitalWrite(CE0, LOW);  //ON
     digitalWrite(CE1, LOW); //ON
     digitalWrite(CE2, HIGH); //OFF
    
     calibrate_sensor();
    
     // TIMER 2 for interrupt frequency 1000 Hz(1ms):
     cli(); // stop interrupts
     TCCR2A = 0; // set entire TCCR2A register to 0
     TCCR2B = 0; // same for TCCR2B
     TCNT2  = 0; // initialize counter value to 0
     // set compare match register for 1000 Hz increments
     OCR2A = 249; // = 16000000 / (64 * 1000) - 1 (must be <256)
     // turn on CTC mode
     TCCR2B |= (1 << WGM21);
     // Set CS22, CS21 and CS20 bits for 64 prescaler
     TCCR2B |= (1 << CS22) | (0 << CS21) | (0 << CS20);
     // enable timer compare interrupt
     TIMSK2 |= (1 << OCIE2A);
     sei(); // allow interrupts
    
     MIDI.begin(4);          // Launch MIDI and listen to channel 4
    }
    
    

    Loop MIDI notes

    The loop function we originally had is being broken up into some function calls for multiple instruments. This is due to the MIDI note calls we originally make just for the piano.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void loop()
    {
     if(readKeyFlag == true)
     {
       readKeysPiano();
       readKeysDrum();
       readKeyFlag = false;
     }
    PianoMIDI();
    DrumMIDI();
    }
    

    The functions PianoMIDI and DrumMIDI are these new function calls. Originally the code was a for loop, and simply repeating the for loops would cause delays for the new instruments. In this way the loop code simply calls the outside functions without having to wait for a for loop to complete. Here is the code for those functions.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    void PianoMIDI(){
      //set to channel 2
      for(int i = 0; i < number_of_keysP; i++)
      {
        if(sensorValueP[i] > 10){
          MIDI.sendNoteOn(midi_NumP[i], sensorValueP[i],2);
        }else{
          MIDI.sendNoteOff(midi_NumP[i], sensorValueP[i],2);
        }
      }
     }
    
     
    void DrumMIDI(){
      //set to channel 3
      for(int i = 0; i < number_of_keysD; i++)
      {
        if(sensorValueD[i] > 10){
          MIDI.sendNoteOn(midi_NumD[i], sensorValueD[i],3);
        }else{
          MIDI.sendNoteOff(midi_NumD[i], sensorValueD[i],3);
        }
      }
     }
    

    Note the main difference between these functions is that in MIDI.sendNoteOn//Off the functions end with different numbers. These are the channels the two instruments are calling to. We need the instruments on different channels so the digital instrument on LMMS gets the correct input. If you are wishing to extend the amount of keys for one instrument, then you would place it all on one channel.

    Calibrate

    Calibrate has been extended for multiple instruments without breaking it into function calls. The VERY IMPORTANT thing to note is the line sensorValueP[i] = analogRead(An); as this is dependant on the multiplexer the instrument is using. MUX0 outputs to A0, MUX1 outputs to A1, and MUX2 outputs to A2. Make sure this is correct to your instrument.

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    void calibrate_sensor()
    {
      unsigned long adjusted_time;
    
    //Piano
     for(int i = 0; i < number_of_keysP; i++)
      {
        sensorMaxP[i]   = 0;
        sensorMinP[i]   = 1023;
        sensorValueP[i] = 0;
        adjusted_time = millis();
    
        //Mux select
        r0 = bitRead(i,0);
        r1 = bitRead(i,1);
        r2 = bitRead(i,2);
    
        //Write the current select bits to the select pins
        digitalWrite(s0,r0);
        digitalWrite(s1,r1);
        digitalWrite(s2,r2);
    
        digitalWrite(LED, HIGH);
       // calibrate each key for five seconds
       while (millis() < adjusted_time + 5000)
       {
        delay(1);
    	//Set to MUX0 using A0
         sensorValueP[i] = analogRead(A0);
    
         // record the maximum sensor value
         if (sensorValueP[i] > sensorMaxP[i])
         {
           sensorMaxP[i] = sensorValueP[i];
         }
    
         // record the minimum sensor value
         if (sensorValueP[i] < sensorMinP[i])
         {
           sensorMinP[i] = sensorValueP[i];
         }
       }
       digitalWrite(LED,LOW);
       delay(1000);
      }//end Piano
    
    //Drum
       for(int i = 0; i < number_of_keysD; i++)
      {
        sensorMaxD[i]   = 0;
        sensorMinD[i]   = 1023;
        sensorValueD[i] = 0;
        adjusted_time = millis();
    
        //Mux select
        r0 = bitRead(i,0);
        r1 = bitRead(i,1);
        r2 = bitRead(i,2);
    
        //Write the current select bits to the select pins
        digitalWrite(s0,r0);
        digitalWrite(s1,r1);
        digitalWrite(s2,r2);
    
        digitalWrite(LED, HIGH);
       // calibrate each key for five seconds
       while (millis() < adjusted_time + 5000)
       {
        delay(1);
    	//Set to MUX1 using A1
         sensorValueD[i] = analogRead(A1);
    
         // record the maximum sensor value
         if (sensorValueD[i] > sensorMaxD[i])
         {
           sensorMaxD[i] = sensorValueD[i];
         }
    
         // record the minimum sensor value
         if (sensorValueD[i] < sensorMinD[i])
         {
           sensorMinD[i] = sensorValueD[i];
         }
       }
       digitalWrite(LED,LOW);
       delay(1000);
      }//end Drum
    
      //repeat as necessary for your other instruments
      
    }/*End of calibrate_sensor()*/
    

    Read Keys

    The original readKeys() function has been broken up into multiple functions, which are then called in the loop. Both functions are essentially the same minus their variables and the analogRead(An) call. Remember MUX0 outputs to A0, MUX1 outputs to A1, and MUX2 outputs to A2. Make sure this is correct to your instrument. Here is the function for the Piano

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    void readKeysPiano()
    {
     //Read Pins Piano
     for(int i = 0; i < number_of_keysP; i++)
     {
         delay(1);
         r0 = bitRead(i,0);
         r1 = bitRead(i,1);
         r2 = bitRead(i,2);
    
         digitalWrite(s0,r0);
         digitalWrite(s1,r1);
         digitalWrite(s2,r2);
    
         sensorValueP[i] = analogRead(A0);
         sensorValueP[i] = map(sensorValueP[i], sensorMinP[i], sensorMaxP[i], 127, 0);
         // in case the sensor value is outside the range seen during calibration
         sensorValueP[i] = constrain(sensorValueP[i], 0, 127);
    
       if(sensorValueP[i] <= 10){
         sensorValueP[i] = 0;
       }
     }//End Piano
    }
    

    And here is the code for the new instrument:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    void readKeysDrum()
    {
     //Read Pins Drum
     for(int i = 0; i < number_of_keysD; i++)
     {
         delay(1);
         r0 = bitRead(i,0);
         r1 = bitRead(i,1);
         r2 = bitRead(i,2);
    
         digitalWrite(s0,r0);//any race conditions?
         digitalWrite(s1,r1);
         digitalWrite(s2,r2);
    
         sensorValueD[i] = analogRead(A1);
         sensorValueD[i] = map(sensorValueD[i], sensorMinD[i], sensorMaxD[i], 127, 0);
         // in case the sensor value is outside the range seen during calibration
         sensorValueD[i] = constrain(sensorValueD[i], 0, 127);
    
       if(sensorValueD[i] <= 10){
         sensorValueD[i] = 0;
       }
     }//End Drum
    }
    

    Make as many as you need for the instruments

    ISR

    The ISR code is the same as the old code:

    Download file Copy to clipboard
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    ISR(TIMER2_COMPA_vect){
      //interrupt commands for TIMER 2 here
      if(ISR_count == 2)
      {
        readKeyFlag = true;
        ISR_count = 0;
      }
      ISR_count++;
    }
    

    And this finishes up code section. Verify to check for any mistakes and upload to your board. The calibration process will begin starting with the piano. Remember there are no breaks in the calibration as it goes down the line. When calibrating the new instruments the one plugged into Key 0 on the multiplexer pinout goes first, then down the lines

    Software 

    Hairless and loopMIDI

    Now that you've got your code running let's begin our software again. Open up hairless and loopMIDI. We don't need to change anything on loopMIDI from the previous tutorial, as there is only one MIDI controller. On hairless make sure your input and output settings are correct to the port and the MIDI controller name. Make sure the Debug is selected so we can see what messages are being sent. The output we want to see will have multiple channels being listed for the multiple instruments. Hit the Debug button again to pause it. Are all your channel being called? If not go back and make sure you've distinguished them in the PianoMIDI() and DrumMIDI() functions. Are your channels being called but the keys didn't calibrate? You can redo your calibration process by hitting the button on the shield. If this doesn't work though and you keep getting the full volume (127) for your keys, the problem could be cause by a couple things:

    • Your multiplexer isn't turned on: Back in the setup function we have digitalWrite() calls that set the multiplexer chips to either a LOW or HIGH reading. We want our multiplexers to be LOW if we are using them. Check to make sure this is set correctly.
    • Your multiplexer isn't set to the correct Analog output: In calibrate_sensor() and readKeys we call on the Analog output for each instrument. But each multiplexer has a different one. MUX0 outputs to A0, MUX1 outputs to A1, and MUX2 outputs to A2. Make sure this is correct to your instrument.

    LMMS

    We can now open up LMMS and start playing. Delete any premade tracks on the Song Editor window by selecting the Gear icon and clicking 'Remove this Track'. On the left side tab of the LMMS window select the music note icon to open up the instruments list. Click and drag your instrument into the Song Editor. You'll need to redo this for the piano if you aren't using a old file from the previous tutorial. On the track, click on the instruments name to select a button that opens up the instruments window. In the instruments window, above the picture that says Audio File Processor is a menu bar. Select the MIDI tab. We then want to select the Enable MIDI Input button and change the channel to the correct channel for the instrument. In the example code the Piano is set to channel 2, and the Drum is set to channel 3.

    In hairless restart your Serial<->MIDI connection. You may here a burst of notes coming from LMMS. Now you'll be able to play both instruments together. Have fun creating!