Page 1 of 1

Arduino based MIDI Controller for Raspberry Pi

Posted: Thu Apr 16, 2020 12:18 pm
by jAMer
Hi, this is my first post/guide and I am relatively new to this whole RPi and programming topic.

I really like using QLC+ on a headless Raspberry Pi to control a few lights with the GPIO plugin and physical buttons. Unfortunately it is not possible to control any knobs or faders with that solution.

The idea is now to use an Arduino that outputs serial MIDI data over USB to Control QLC+ running on a Raspberry Pi

So far I did not find an easy tutorial with all steps in one place on that topic, so maybe the following guide can help anyone that is as new to the whole Raspberry Pi/MIDI/Arduino world as I am.

For this short tutorial you will need:

1. Raspberry Pi with QLC+ installed
2. any Arduino device
3. a few jumper wires and at least one potentiometer (10KOhm recommended)

There are a few posts that describe how to use an Arduino MIDI-Controller with Windows and Hairless MIDI, but the RPi is running a form of Linux, so this won't work.
The Linux alternative to Hairless MIDI is called TTYMIDI and can easily be installed on the RPi (source: https://zuzebox.wordpress.com/2015/12/1 ... softsynth/) :

Open a console window and execute the following commands:

Code: Select all

sudo apt-get install libasound2-dev
This should be already installed, but just to be sure...

Code: Select all

wget http://www.varal.org/ttymidi/ttymidi.tar.gz

Code: Select all

tar -zxvf ttymidi.tar.gz

Code: Select all

cd ttymidi/
The makefile needs to be modified so it works with Rasbian:

Code: Select all

sudo nano Makefile

now just add -lpthread to line

Code: Select all

gcc src/ttymidi.c -o ttymidi -lasound
Then save the file by pressing: "CTRL+O" then confirm with "RETURN" and close it with "CTRL+X"
The next Commands are:

Code: Select all

make
and

Code: Select all

sudo make install
Now you are able to create a virtual MIDI device that is recognized by QLC+! We want to start this device automatically with every reboot, so lets create simple bash scripts for that(I am using two separate scripts because if I want to manually connect I can disable one) :

Code: Select all

nano /home/pi/Desktop/startMIDI.sh
Insert this line into the file:

Code: Select all

ttymidi -s /dev/ttyUSB0 -v &
Then save the file by pressing: "CTRL+O" then confirm with "RETURN" and close it with "CTRL+X"

Create the next skript with:

Code: Select all

nano /home/pi/Desktop/conMIDI.sh
Insert this line into the file:

Code: Select all

aconnect 129:0 128:0
Then save the file by pressing: "CTRL+O" then confirm with "RETURN" and close it with "CTRL+X"

The last bit with the numbers might vary for your setup, you need to connect the correct client numbers.

ttymidi creates an ALSA MIDI input and output ports that can be interfaced to any compatible program. This is done in the following manner:

# start ttymidi
ttymidi -s /dev/ttyUSB0 &

# start some ALSA compatible MIDI
# program (timidity, in this case)
timidity -iA &

# list available MIDI input clients
aconnect -i

# list available MIDI output clients
aconnect -o

# connect
aconnect 128:0 129:0

# ...where 128 and 129 are the client
# numbers for ttymidi and timidity,
# found with the commands above
Source: http://www.varal.org/ttymidi/

Now we want to make those scripts executable.

Code: Select all

chmod g+rwx,u+rwx,o-rwx /home/pi/Desktop/startMIDI.sh

Code: Select all

chmod g+rwx,u+rwx,o-rwx /home/pi/Desktop/conMIDI.sh
We almost got the RPi part right now! Just automatically execute them after booting by editing:

Code: Select all

sudo nano /etc/rc.local
Now insert

Code: Select all

/home/pi/Desktop/startMIDI.sh
/home/pi/Desktop/conMIDI.sh
at the end of the file, right in front of the "exit 0" statement

Now comes the fun and easy part, programming the Arduino!
You should have basic Arduino skills to be able to configure your own MIDI-Controller, there are plenty of amazing tutorials on the Arduino IDE out there.
We want to use the Arduino MIDI library (https://github.com/FortySevenEffects/ar ... di_library), so install and include this to your Arduino Code.

The only important step is in the setup part of the code so just use this basic template and then go crazy with everything that the MIDI library provides:

Code: Select all

#include <MIDI.h>
// Created and binds the MIDI interface to the default hardware Serial port
 MIDI_CREATE_DEFAULT_INSTANCE();
 
 void setup()
 {
     //this is the important part
     MIDI.begin(4);  // Listen to all incoming messages
     Serial.begin(115200); //set the baud rate
     
 }
 
 
 void loop()
 {   
  //Here you can do whatever you want
  
  while (MIDI.read()) {
    }

 }
 
That was easy right?

For testing you can just connect a potentiometer to pin A0 of your Arduino, load my sample code onto the Arduino (see the end of this post) and connect the Arduino to the raspi via USB.
Then reboot the raspi, and a new MIDI input should be available in QLC. Check it as an input and configure a MIDI profile for it. Then you should be able to control a fader in the Virtual Console with your physical poti.

If you have any questions feel free to ask. I hope I saved you some time searching for all the bits and pieces that are required to accomplish such a project.

See this as some kind of bonus material. This is the Arduino code that I am using for my setups. It is not finished yet and the comments are mostly in German but it works for testing. If your struggle with the Arduino MIDI library this might help you aswell.

Code: Select all

#include <MIDI.h>

//Konfiguration:

 //Anzahl der verbauten Potis/Fader
#define pZ 2
//Anzahl der verbauten Buttons
#define bZ 1

// Created and binds the MIDI interface to the default hardware Serial port
 MIDI_CREATE_DEFAULT_INSTANCE();
 
//Buffer for potivalues
 
int potiwert[pZ];
 
//MidiNoteNumber array
int noteNum[bZ];


//Buttonpin array
int buttonPin[bZ];


 

 
 void setup()
 {
     
     MIDI.begin(4);  // Listen to all incoming messages
     Serial.begin(115200);
     pinMode(2, INPUT_PULLUP);
     

     //Poti Zwischenspeicher auf null setzen
    for (int i = 0; i < pZ; i = i + 1) {
        potiwert[i] = 0;
      }
    //MidiNoteNumber button configuration
    noteNum[0] = 42;

    //Buttonpin configuration
    buttonPin[0] = 2;
 }




 

 void loop()
 {   
  midiPoti(0, 81, 1); 
  potiFresh();
  buttonFresh();
  while (MIDI.read()) {
    }
  delay(10);  
 }
//LOOP ENDE












//++++++++++++++++++++Nützliche Funktionen++++++++++++++++++++

//Alle Potiwerte aktualisieren: potiFresh
void potiFresh(){
  for (int i = 0; i < pZ; i = i + 1) {
      potiwert[i] = averead(i);
     }
  delay(5);
}

//Poti auslesen und bei Veränderung Midi Signal senden: midiPoti( Potipin, Controllernummer, Midi-Channel(eigentlich immer 1))

void midiPoti(int pPin, int ctnr, int channel){
  int wert = averead(pPin)/8;
  if(wert != potiwert[pPin]/8){
    MIDI.sendControlChange(ctnr, wert, channel);
  }
}

//Alle Knöpfe kontrollieren und Status per Note auf Midi-Channel 1 senden: buttonFresh
void buttonFresh(){
  for (int i = 0; i < bZ; i = i + 1) {
    if(digitalRead(buttonPin[i]) == LOW){
      MIDI.sendNoteOn(noteNum[i], 50, 1);
      while(digitalRead(buttonPin[i]) == LOW){
        delay(2);
      }
    }
  }
}      


//Glättungsfunktion averead
 int averead(int apin){
  int werte[8];
  int sum = 0;
  
  for (byte i = 0; i < 8; i = i + 1) {
    werte[i]=analogRead(apin);
    delay(1);
   }
  
  for (byte i = 0; i < 8; i = i + 1) {
    sum = sum + werte[i];
   }

  return sum/8;
 }