Maker.io main logo

AGM Summer Break Edition – Raspberry Pi MIDI Controller & Synthesizer

2019-09-24 | By Evan Browning

License: See Original Project Potentiometers Arduino Raspberry Pi

 

Intoduction

The goal of this project was to create a customizable instrument. While not technically a musical instrument, MIDI controllers are a great way to produce musical electronically by letting computers do most of the work. But many MIDI controllers come in the same typical designs including buttons arranged in grid patterns or piano keyboards. If you’ve ever wanted to make music with your own personal input device, this project is for you.

First, a MIDI controller will be made using a button matrix to reduce the number of pins required with an Arduino Leonardo, and then a Raspberry Pi will be used to make a synthesizer that will be able to produce audio and function as a somewhat portable instrument.

 

 

 

 Parts (BOM)

Tools needed

Part 1: The MIDI Controller

Background

The Arduino Leonardo is the easiest device to get started with since it’s processor has native USB capability. However, the number of pins on the Leonardo are limited, so to use more buttons and simplify the wiring, a button matrix was used. A button matrix works by using wire busses in rows and columns connected as shown in the Scheme-it schematic below. When a switch is pushed, a vertical bus (blue) is connected to a horizontal bus (red). A microcontroller can scan a bus group while turning another bus group on and off on and off one at a time. The diodes in series with the switches allow for multiple switches to be pushed without causing problems such as phantom button presses known as ghosting. Notice how 12 switches can be implemented with just 7 wires. Thankfully, the Library used to create the MIDI controller is already set up to handle a button matrix.

button_matrix_1

Button Matrix Example

Below, an example on a perf board is shown. I used this design to first learn how to program a button matrix. First the top, and then the bottom. The through hole diodes are bent in a standing shape with the anode pointing down, just like the previous schematic. This was only an experimental design, but any other design should work if the schematic is followed and you can expand on it.

example_2

The parts used here are:

Programming a Button Matrix

This example uses the perf board button matrix example to create a MIDI controller, but any matrix with the same dimensions will do. You’ll need to have the Arduino IDE installed on your computer.

First, go to the page for this MIDI Controller Library. Once there, click on the green “Clone or download” button on the left side, and select “Download ZIP.” Then, open the Arduino IDE. Click on “Sketch” on the top of the window, then Include Library >> Add .ZIP Library… Navigate to the downloads folder, select “MIDI_controller-master.zip” and click Open. The library should now be installed.

Now you can open the button matrix example program by going to File >> Examples >> MIDI Controller >> Ex.11.Button-Matrix. Some changes will have to be made to this program so highlight all the text and copy it. Then start a new project by clicking File >> New and paste the code into the new project.

In the program towards the middle, there should be an array called addresses. This is a two-dimensional array meaning that is arranged with rows and columns. The array is a 4x3 (4 rows, 3 columns) which is a problem because the button matrix I made is 3x4. Start by switching the 4 and 3 around in the brackets to what is shown below.

Copy Code
addresses[3][4]

Now the dimensions of the array do not match. To correct this, move the numbers around to look like this.

Copy Code
{  1,  2,  3,  4 },
  {  5,  6,  7,  8 },
  {  9, 10, 11, 12 },

The numbers in the array represent the key map of the matrix. In the orientation I used shown below, the map matches the arraignment of buttons on my matrix. The array defines what MIDI note goes with each button. The numbers in the example array are low notes. They are so low in fact that we cannot hear them! For something more standard let's start at middle C with MIDI note 60. I used a line of code to make it easy to change the octave of the MIDI controller by basing the note value of the first note of the controller.

Copy Code
const uint8_t c = 60;

Apply this change to the button matrix by using the variable c in the address array as shown below.

Copy Code
{c+0, c+1, c+2, c+3},
  {c+4, c+5, c+6, c+7},
  {c+8, c+9, c+10, c+11},

I connected my matrix as shown below.

matrix_3

Next, we need to program our pins. A few lines down, you’ll see a line that says:

Copy Code
ButtonMatrix<4, 3> buttonmatrix({2, 3, 4, 5}, {6, 7, 8}, addresses, 1, velocity);

This line of code states what pins are used for the rows (2,3,4,5) and columns (6,7,8). This is not how the button matrix is wired to the Leonardo in the picture above and is also the wrong dimension. You may have noticed in the schematic that the 3 horizontal bus groups are all connected to cathodes from the diodes. For the program to work, the row pins must be the pins attached to the cathodes. Knowing that the pins for the rows are 7, 6, 5 and for the columns 11, 10, 9, 8, for the columns change the code to the line below.

Copy Code
ButtonMatrix<3, 4> buttonmatrix({7,6,5}, {11,10,9,8}, addresses, 1, velocity);

Once finished, upload the code to the Leonardo. You should now be able to connect to any USB MIDI compatible interface, including many online MIDI synthesizers, to produce audio.

My design

To make the assembly easier, a circuit board was designed with KiCad and milled using a bantam tools mill. Mechanical keyboard switches were used along with 3d printed keycaps. Surface mount diodes were used for a single layer board. Additionally, my board allowed for two potentiometers to be connected, which are very easy to set up in programming. To connect to the Leonardo, the column pins are connected to pins 11,10,9,8 and the row pins are connected to pins 7,6,5. This is the same as the previous perf board example. The potentiometers are connected to VCC and ground, and their outputs are connected to the analog pins A0 and A1.

pins_4

To make the connections easier, I also designed a shield using KiCad and a bantam mill. This shield also helps to secure the Leonardo in my enclosure. The wires are for NeoPixels added for lighting effects, an optional feature.

NeoPixels_5

Programming the button matrix is very similar to the perf board example with some additional features. As I mentioned earlier, there are two potentiometers on this board. The library makes it very easy to program these for volume and pitch bend which are popular among MIDI controllers. To program them, open the potentiometer example called “Ex.01.Potentiometer.” Copy the line below and paste it into the new project.

Copy Code
Analog potentiometer(A0, MIDI_CC::Channel_Volume, 1);

Then open the “Ex.05.HiRes-Potentiometer” example and copy the line into the new project.

Copy Code
AnalogHiRes potentiometer(A0, 1);

The program will not compile since there are two potentiometer objects with different parameters. To fix this, change the two lines to the code below. You can program more potentiometers using these formats and by looking at the MIDI_Constants folder on the GitHub page.

Copy Code
Analog potentiometer1(A0, MIDI_CC::Channel_Volume, 1);
Copy Code
AnalogHiRes potentiometer2(A1, 1);

MIDI Controller Full Code

Below is the full program, with long comments removed for clarity.

Copy Code
#include "MIDI_Controller.h" // Include the library

const int c = 60;

const uint8_t velocity = 0b1111111; // Maximum velocity (0b1111111 = 0x7F = 127)
const uint8_t addresses[3][4] = {   // button keymap
 {c+0, c-5, c+2, c+3},
 {c+4, c+5, c+6, c+7},
 {c+12, c+9, c+14, c+11},
};

ButtonMatrix<3, 4> buttonmatrix({7, 6,5}, {11, 10, 9, 8} , addresses, 1, velocity);

// Create a new instance of the class 'Analog', called 'potentiometer', on pin A0, 
// that sends MIDI messages with controller 7 (channel volume) on channel 1
Analog potentiometer1(A0, MIDI_CC::Channel_Volume, 1);

// Create a new instance of the class 'AnalogHiRes', called 'potentiometer', on pin A1, 
// that sends MIDI Pitch Bend messages on channel 1
AnalogHiRes potentiometer2(A1, 1);

void setup() {}

void loop() {
  MIDI_Controller.refresh();
}

 The Final MIDI Controller is below

controller_6

Part 2: The Pi synth

Background

This portion of the project turns the MIDI controller into a portable instrument. It uses a program called Pure Data to make a MIDI synthesizer. I’m using the latest version of Raspbian which I installed according to the Raspberry Pi Website.

Installing Software

1. After installing the latest version of Raspbian on the pi, open terminal. Check for any updates by typing sudo apt-get update. Type Y when asked.

2. Install pure data by typing sudo apt-get install puredata.

3. Then install ALSA, connect GUI by first typing sudo apt-get install alsa-base alsa-utils, and then sudo apt-get install acconectgui.

Connecting a MIDI Controller

Open pure data by navigating to the menu in the upper left corner of the desktop and go to sound and video >> Pure Data. The main Pure Data window should open. In the window that opens, click on media in the top bar. Make sure that ALSA-MIDI is selected. Then click on MIDI settings. Select the box next to In Ports and type 1. Save all settings, select apply, and then ok.

Connect your MIDI controller into a USB port on the pi and connect some speakers or headphones using the 3.5mm jack. Open aconnectgui which should also be in the sound and video category. The window should show Arduino Leonardo 1 and Pure Data MIDI-In 1. Click the patch cord icon next to the scissors, click and hold on the Arduino Leonardo MIDI 1 with the arrow pointing right, and release when the cursor gets to Pure Data MIDI-IN 1 with the arrow pointing left. A line should connect these two as shown below.

ALSA_7

Test the connection in pure data by going to media >> test audio and MIDI. This new window that opens will test your MIDI and audio. Make sure your volume is at the lowest setting on the pi and select 60 under test tones in the patch. Slowly turn up the volume until you hear a sine wave. One thing to note is that in the main Pure Data window, the box next to DSP is checked. This means that the audio is on for Pure Data. If you ever need to quickly mute Pure Data, uncheck this box. To test if Pure Data is receiving MIDI data, push a button on your MIDI controller. You should see the portion under MIDI IN produce a number in the box under “stripnote” and a box flash, such as what is shown below.

If you disconnect the MIDI controller and want to connect it again, or if Pure Data quits unexpectedly, you’ll have to use aconnectgui to reconnect the controller to Pure Data. It is also always a good idea to use the test audio and MIDI patch if you run into problems.

Downloading the synth

The easiest way to get started is to download the synth by heading over to this github page. Once there, click on clone or download. Once the file finishes downloading, unzip the file and open MidiSynth-Main. The setup pure data as shown in the section above. Turn the volume all the way down, make sure DSP is checked in the main Pure Data. Push a button on your MIDI controller and slowly increase the pi’s volume until you hear something. From here, you can adjust the ADSR envelope and the harmonic sliders. Initially, the controller volume of the synth is set to maximum so if you’re using a volume knob/slider, be sure to adjust it and it will adjust the volume.

Programming the synth

This section walks through how the synth was made. There is a lot of info for programming pure data on the internet, but this should show you all you need to know.

Pure Data programs are called patches. In Pure Data, start a new patch by going to File >> New and title it MidiSynth-Main by going to File >> Save As. Begin by pressing ctrl-1 on your keyboard to place an object or by going to Put >> Object. A blue box will appear under the cursor. Place this object by clicking towards the top of the window. Type “midiin” and click somewhere in the blank space to deselect it. Hitting return adds a new line to the object, which we don’t want. The box should turn black. Place another object below and type “mtof”, another object that says “osc~”, and an object that says “dac~”. The thick black lines at the bottom of the objects are called outlets and the ones at the top are called inlets. If you hover over an outlet with your cursor, you should see a black circle. Click on the leftmost outlet in [midiin] and drag until you get to the inlet on [mtof]. Connect the outlet of [mtof] to the leftmost outlet of [osc~]. Then connect the outlet of [osc~] to the left and right inlets of [dac~]. This example is shown below. To delete a connection, hover over it and when a black x appears, click to delete the connection. Objects can be moved either by dragging or using the arrow keys on your keyboard. To select one or multiple objects, click in the blank space to drag a rectangle that will select the objects and use the arrow keys to move them. To move them faster, hold shift while pressing the arrow keys.

move_8

Now, make sure the DSP is checked in the main Pure Data window and that the volume is low. Setup a MIDI connection to Pure Data, press a MIDI on the MIDI controller, and slowly adjust the volume until a sine wave is heard. This patch works because the [midiin] receives MIDI data and sends this data to its outlets. The leftmost outlet is the MIDI note number. The MIDI note number is turned into a frequency value by mtof, MIDI TO Frequency. This frequency is sent to the inlet of the oscillator and sets the frequency of the oscillator to that value. The outlet of [osc~] sends its signal to the audio out, the left and right inlets of [dac~]. This example is very primitive, however, and needs some work to be made better.

To simplify the programming, make a patch within this patch. This is called a subpatch. Start a new patch. In this new patch, add an [inlet] object at the top and an [outlet~] object at the bottom. Then save the patch as “note”. Back in the main patch, create a new object called [note]. Notice that it has inlets and outlets. This note object is similar to putting the note subpatch in the main patch. Whatever is added to the note subpatch will automatically be applied to the note object in the main patch when the subpatch is saved. We will return to the note patch later so go back to MidiSynth-Main.

Now that we know how to make subpatches, we’ll need a few more objects to complete the program. The first ones are sliders. They are the main way that the synth is adjusted in this program. They can be found by going to Put >> Vslider. Hslider is another type of slider that lays horizontal. Also, you’ll need a message by going to Put >> Message. The box with 127 is a message. There are also some optional comments above the sliders. The program is shown below.

program_9

Place the silders shown above. Edit the properties of the sliders by right clicking on the slider and selecting the properties option. You’ll see an option to change the low value and high value, and also the scaling the slider uses. I used a log scale which is a common practice in audio levels. Lastly, after I had finished programming, I set all the sliders to the settings I liked and selected the init button. This initializes the slider to the value it was at whenever the patch is opened again. This is how the downloaded synth defaults to its initial slider values. To adjust the slider, get out of edit mode by going to Edit >> Edit Mode and select it to uncheck edit mode. The properties for the sliders are shown below. The red boxes indicate the properties you’ll have to change for it.

ADSR Properties

ADSR_Properties_10

Harmonic Slider Properties

Harmonic_11

Volume Properties

Volume_12

Now create a subpatch called adsr. Make this new patch look like the one below with the same objects and connections. Stop is a message.

adsr_13

Create subpatch called tone which is shown below. This patch will create a tone for each note that can contain multiple frequencies called harmonics that will make the tone a little more interesting than a sine wave alone. The r objects receive the data from the harmonic sliders in MIDI synth main.

tone_14

Lastly, go back to note. This patch will create a note for each MIDI note. It also will allow for pitch to bend notes if a pitch bend knob is being used.

note_15

After finishing the program and setting up a successful MIDI connection, get out of edit mode and make sure DSP is checked. Now you should be able to play the synthesizer with your MIDI controller using both pitch and volume control depending on the controller you use.

Changing the Synth

The program only plays four notes a time. If you’d like to add more notes, go into edit mode. Then change the route object to count up to how many notes you want and place the same number of note objects and connect them the same as the previous ones by not using the rightmost outlet of route.

Additionally, you can experiment with different ways to produce the sound of each note by changing what is in the tone patch. You can also add more harmonic sliders by following the same conventions as the other sliders.

The full project is below.

project_16

制造商零件编号 MX1A-11NW
SWITCH PUSH SPST-NO 0.01A 12V
Cherry Americas LLC
制造商零件编号 1N4148W-TP
DIODE GEN PURP 100V 150MA SOD123
Micro Commercial Co
制造商零件编号 P090S-14T20BR10K
POT 10K OHM 1/32W PLASTIC LINEAR
TT Electronics/BI
制造商零件编号 1226-L
KNOB SERRATED 0.236" PLASTIC
Davies Molding, LLC
制造商零件编号 PRPC040SAAN-RC
CONN HEADER VERT 40POS 2.54MM
Sullins Connector Solutions
制造商零件编号 PRPC040SBAN-M71RC
CONN HEADER R/A 40POS 2.54MM
Sullins Connector Solutions
制造商零件编号 A000057
ARDUINO LEONARDO W/ HDRS ATMEGA3
Arduino
制造商零件编号 3597
CASE CLR 3.000" L X 2.400" W
Adafruit Industries LLC
制造商零件编号 UR050-06N
CBL USB2.0 A PLUG-MCR B PLG 0.5'
Tripp Lite
制造商零件编号 689
SHT MTL SCREW PAN PHILLIPS #4
Keystone Electronics
制造商零件编号 3118
WASHER FLAT #4 NYLON
Keystone Electronics
制造商零件编号 A9BBG-0406F
FLEX CABLE - AFF04G/AF04/AFF04G
TE Connectivity AMP Connectors
制造商零件编号 A9BBG-0306F
FLEX CABLE - AFF03G/AF03/AFF03G
TE Connectivity AMP Connectors
制造商零件编号 29300
MACH SCREW PAN SLOTTED M2.5X0.45
Keystone Electronics
制造商零件编号 V6516D
HEX STNDFF M2.5X0.45 BRASS 12MM
Assmann WSW Components
制造商零件编号 WR9QA3000USBC-CIMR6B
AC/DC WALL MOUNT ADAPTER 5V 15W
GlobTek, Inc.
制造商零件编号 Q-NA(R)
INPUT PLUG N AMER FOR WALL ADAPT
GlobTek, Inc.
制造商零件编号 P570-003-MICRO
CBL HDMI-A M - MCR HDMI-D M 3'
Tripp Lite
制造商零件编号 AP16GMCSH4-B
MEM CARD MICROSD 16GB CLASS 4
Apacer Memory America
制造商零件编号 JIC-1626
WIRE STRIPPER 16-26 AWG
Jonard Tools
制造商零件编号 TOL-10602
TWEEZERS POINTED VERY FINE 4.72"
SparkFun Electronics
制造商零件编号 B3F-6050
SWITCH TACTILE SPST-NO 0.05A 24V
Omron Electronics Inc-EMC Div
制造商零件编号 B32-2010
CAP TACTILE ROUND BLACK
Omron Electronics Inc-EMC Div
制造商零件编号 1N4001-G
DIODE GEN PURP 50V 1A DO41
Comchip Technology
制造商零件编号 290
HOOK-UP SOLID 22AWG 300V BLK 25'
Adafruit Industries LLC
制造商零件编号 8029
BREADBOARD GENERAL PURPOSE PTH
Vector Electronics
制造商零件编号 PRT-12794
JUMPER WIRE M/F 6" 20PCS
SparkFun Electronics
制造商零件编号 10521EC
CUTTER SIDE TAPERED FLUSH 5.03"
Aven Tools
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum