Introduction: Arduino Midi Controller With a ZX Distance and Gesture Sensor

Welcome to this instructable on how to build a very basic Midi Controller with the SparkFun ZX Distance and Gesture Sensor. This instructable is part of a school assignment.

Note: This is no coding tutorial. The final code will be included at the end.It also requires you to have a bit of experience with the Arduino IDE and C++.

https://vimeo.com/152138259

Step 1: The Hardware

First off, there are a couple of things you'll need.

  • Arduino Yún (I made mine with the Yún but you can also use others. I will try and give the proper instructions for other devices)
  • Jumper wires (Make sure you have enough)
  • Breadboard
  • ZX Sensor (You can get it here, but you can use essentially any input)
  • Beakable male headers (when using the ZX Sensor)
  • Two led lights
  • USB cable (off course)
  • At least two resisters (for the leds)

Because I made my controller with the Arduino Yún, there will be a couple of things different. I haven't really got the chance to play around with other Arduino's but I'll do my very best to accommodate people who use other Arduino's.

Step 2: Software

Trying to send Midi via a non midi controller device can be a bit tricky, but some software can really make your live a lot easier. I know that you can simply upload different firmware to your Arduino, but then you can no longer upload programs to your Arduino. We'll play it safe, we'll use software!

  • Arduino IDE (get it here)
  • Hairless Serial to Midi converter (get it here)
  • Loop Midi (get it here)
  • A DAW or other software that can receive midi input of your choice (I used Ableton Live 9)

To use the sensor and to send midi signals (and to make your life easier) you can use libraries. The libraries used in this instructable are

  • Wire library (comes default with the Arduino IDE)
  • Midi library (get it here)
  • ZX Sensor library (get it here)

Step 3: Let's Get Started!

Make sure you installed all software and libraries. After that we can start to build something! We'll need to hook up the ZX Gesture Sensor. Check here on how to do that. It would be a perfect world if everything we did worked right the first time. Unfortunately that's not the case. Ever. Because Arduino boards differ in layout we cannot assign the I2c outputs to analog output 4 and 5. At least not for the Yún. You can see which board has which pin here.

For the Yún we need to use the SDA and the SCL pin on the digital side of the board. This is the default schema for hooking up the sensor.

Arduino Pin ZX Sensor Board Function
---------------------------------------

5V | VCC | Power

GND | GND | Ground

A4 | DA | I2C Data

A5 | CL | I2C Clock

In our case it needs to be changed to this:

Arduino Yún Pin ZX Sensor Board Function
---------------------------------------

5V | VCC | Power

GND | GND | Ground

SDA | DA | I2C Data

SCL | CL | I2C Clock

Since we got that little hiccup out of our way, we can now check if we hooked up the sensor correctly.

We can do this by running the I2C_ZX_DEMO that came with the library.Open up the Serial Monitor to see if it is working.

Step 4: Implementing the MIDI Library

Once we have the sensor up and running we can start te implement the Midi Library.

We start with including the Midi Library

#include

Now, according to the official documentation we need to initialize the library by creating an instance of it. This is done by putting MIDI_CREATE_DEFAULT_INSTANCE(); after the include of the library. However, for me this did not work. In my case I needed to use this line:

MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);

With this line, we specify a custom serial port to be used. Now we have instantiated the library and made it ready for our use.

In the setup function you need to put MIDI.begin(); above the Serial.begin(9600) line. 9600 is our baudrate (code will be included). Otherwise our program wil not work with the Hairless Serial to midi converter (more on that later).

for more documentation on the MIDI library, check here.

Step 5: Sending Midi Notes and Make a DAW Receive Them

Now we have our Midi Library included and set up, we can start to send midi notes.

The Midi Library comes with a variety of neat functions. We'll only be using three of them.

  • MIDI.sendNoteOn(note, velocity, midi_channel);
  • MIDI.sendNoteOff(note, velocity, midi_channel);

  • MIDI.sendControlChange(cc_number, value, midi_channel);

These functions are pretty self explanatory but if you need more information about them on how they work exactly, you can find it here.

For testing purposes we'll create a function called SendNotes(). In this function we'll send a note using the sensor's input as the value.

void SendNotes() { if ( zx_sensor.positionAvailable() ) {
    x_pos = zx_sensor.readX();
    if ( x_pos != ZX_ERROR ) {
      //Serial.print("X: ");
      //Serial.print(x_pos);
    }
    z_pos = zx_sensor.readZ();
    if ( z_pos != ZX_ERROR ) {
      if (z_pos != last_z_pos)
      {
        MIDI.sendNoteOn(z_pos, 127, midi_channel);
        // delay(100);
        // MIDI.sendNoteOff(z_pos, 127, midi_channel);
      }
      last_z_pos = z_pos;
    }
  }
}

This function will send a MIDI.sendNoteOn() method to the computer. In order to use this midi message in your DAW we'll need to setup and route a couple of things. Our schema will look like this:

Arduino -> *Sends message to computer as Serial Data* -> Computer receives data and goes to Hairless Serial to MIDI converter ->Midi messages go to a virtual MIDI port (LoopMidi) -> DAW sees virtual MIDI port and in the DAW preferences it can be setup as a controller.

Set up Hairless

It is fairly straightforward on how to use this software. But there a few things to keep in mind.

  1. Make sure that the baudrate is the same in the code that you're writing and Hairless. I use 9600 in my example so I have 9600 in Hairless
  2. You cannot upload anything to your Arduino while Hairless is on. Because only when instance can use the Serial connection. So if you want to upload a new program to your Arduino, make sure to disable Hairless.
  3. Before you can see a MIDI signal coming through Hairless, you need to open up and close the Serial Monitor in the Arduino IDE before turning on Hairless. Otherwise the Serial connection will not be opened.

Set up LoopMIDI

To set up LoopMIDI, simply create a new MIDI port by clicking the "plus" icon and give it a cool name. Once you have created a virtual MIDI port you can select that port in Hairless and in your DAW. Note: You need to keep LoopMIDI running when you want to use your device.

Step 6: Building the Modes

We want our controller to consist of three modes. In the first mode we will send notes to the computer. In the second mode we will send Control Changes (CC) to the computer and in the third mode we will be able to enter a "configure mode" in which we will be able to change the output midi channel.

We'll switch between these modes by swiping left, right and up using the sensor.To see in which mode you currently are, we're going to build in two leds. Blue will be Note mode, yellow will be CC mode and both leds on will be configure mode.

We'll do this by creating an Enum. This way we can keep our code readable and understandable to the human eye.

enum Mode {
CC,
Note,
Configure
};

Mode currentMode = Note;

When that's been done it is fairly straight forward. When the user swipes left, the currentMode becomes Note Mode. When the user swipes right, currentMode becomes CC Mode.

void CheckForGestures() {  if ( zx_sensor.gestureAvailable() ) {<br>    gesture = zx_sensor.readGesture();
    gesture_speed = zx_sensor.readGestureSpeed();
    switch ( gesture ) {
      case NO_GESTURE:
        break;
      case RIGHT_SWIPE:
        currentMode = Note;
        break;
      case LEFT_SWIPE:
        currentMode = CC;
        break;
      case UP_SWIPE:
          currentMode = Configure;
      default:
        break;
    }
  }
}

Now, we simply have to check in our void loop() method what to to when the current mode is something.

if (currentMode == Note) {<br>    SendNotes();
  }
  if (currentMode == CC) {
    SendCC();
  }
  else if (currentMode == Configure) {
    ConfigureMode();
  }

if (currentMode != Configure) {
CheckForGestures(); }

Once again: The full code will be downloadable at the final step.

Step 7: Defining the Modes

Our first and default mode will be the Note Mode as mentioned before.

void SendNotes() {

if ( zx_sensor.positionAvailable() ) { z_pos = zx_sensor.readZ(); if ( z_pos != ZX_ERROR ) { if (z_pos != last_z_pos) { MIDI.sendNoteOn(z_pos, 127, midi_channel); // delay(100); // MIDI.sendNoteOff(z_pos, 127, midi_channel); } last_z_pos = z_pos; } } }

It is possible to send the NoteOff method after a delay, but this is purely personal and you can choose either way. You can also increase or decrease the delay to give the note message a certain effect.

In this next method is our second mode. As you can see this method sends the Control Changes to control an effect for example. It reads the X and the Y axis of the sensor. This way it can simulate an X-Y pad found on some midi controllers. To give the value a bit more stability we make sure that the new value can never be the same as the old value. That way the output value will be a bit more consistently.

void SendCC() {
if ( zx_sensor.positionAvailable() ) { x_pos = zx_sensor.readX(); if ( x_pos != ZX_ERROR ) { int ccX = constrain(x_pos, 0, 127); MIDI.sendControlChange(3, ccX, midi_channel); } z_pos = zx_sensor.readZ(); if ( z_pos != ZX_ERROR ) { if (z_pos != last_z_pos) { int cc = constrain(z_pos, 0, 127); MIDI.sendControlChange(2, cc, midi_channel); } z_pos = last_z_pos; } } }

Our third and final mode was the Configure Mode. In this mode you can increase or decrease the output MIDI channel. This can come in handy when you would like to switch instruments.

void ConfigureMode() {

if ( zx_sensor.gestureAvailable() ) { gesture = zx_sensor.readGesture(); gesture_speed = zx_sensor.readGestureSpeed(); switch ( gesture ) { case NO_GESTURE: break; case RIGHT_SWIPE: if (midi_channel < 16) { midi_channel++; } break; case LEFT_SWIPE: if (midi_channel > 1) { midi_channel--; } break; case UP_SWIPE: currentMode = CC; default: break; } } }

I tried to write the code as self explanatory as possible. You can always ask me if something is not clear.

Step 8: Enjoy Your New MIDI Controller!

This is the easiest and most flexibel way to build a DIY MIDI controller. There still are a lot of open endings like the design and surroundings. But this is the ultimate mini Midi controller.

If you have any questions, drop them down below and I'll try to do my best at answering them.

<pre>

Test code block

</pre>