Midi bank controller for Korg R3

title_image

Following a tragic dorm-related incident, the bank selector knob on my Korg R3 synthesizer was rendered unusable. This knob is used to select which of 16 banks should be used to recall stored sounds. Without it, only a small number of preset sounds can be saved and recalled. In order to address this problem, I decided to create a simple MIDI controller using Arduino to send MIDI program change messages to the synth based on two input butt­ons. I had con­sid­ered design­ing my own MIDI controller using Arduino before, but I had never actually built one. A simple bank changing controller would be a great intro­duction to designing more complex controllers, and it could solve the problem of the broken knob on my R3.

Just for reference, here’s a pic­ture of the knob that I will be replacing the function­ality of by sending MIDI messages from the Arduino board:

MIDI is a simple serial comm­unication protocol for inter­facing digital musical instru­ments. The technical details of MIDI can be read at its Wikipedia page. In order to find what messages I need to send, I first looked through R3 MIDI Implemen­tation docu­ment pro­vided by Korg. The pro­vided spec describes that it receives the first program change byte as 0xCn, where n is the channel the message should be sent on, followed by two bytes describ­ing which program should be changed to. This commun­ication was greatly simpli­fied using Arduino’s Serial library. Before I could send any messages, I needed to create the circuit that would allow the Arduino board to read a pair of hardware buttons and send serial­ized messages using the MIDI connector.

Hardware design

Pin 1 on most Arduino boards is hard wired to send serial data (TX), so I decided use it to connect to the data pin on the MIDI port. Arduino provides a great tutorial on how to interface with other MIDI enabled devices, so I decided to use a 220 Ohm resistor before the voltage pin on the MIDI port like their documen­tation suggested. I also decided to use pins 2 and 3 on the board as inputs to read the buttons, and to use pin 4 as an output to light a small LED to indicate that a MIDI message is being sent. This LED isn’t entirely necessary, I just wanted to have a simple mechanism to show that a MIDI message has been sent, and to expect to see the target equipment react to the message.

Here’s the schematic for the circuit I created on a bread­board in order to test the design:

Each of the buttons uses a 10k Ohm pull down resistor in order to keep the input pin at a predict­able low value in order to prevent false readings. Each of the buttons will then operate in an active high mode, so that a digital 1 reading will indicate a pressed button.

After construct­ing the necessary circuit on a bread board, I wrote the software to upload to the board with the help of the Arduino IDE.

Software design

After a trying a few organiza­tional approach­es to writing this program, I found that they mostly involved lots of global variables, or repeated code in order to deal with the differ­ences between the two buttons. I chose to use a class based approach in order to avoid both poor coding practices. I decided to write a class that handles each button so that all data members associated with the button could be encapsulated inside the relevant object. I chose to create two instances of the class, whose initialization parameters would provide all the information about which button and MIDI messages would be associated with the object. Since I did not use any hardware debouncing, I also decided that I would implement debouncing in software. The buttons I had on hand for building this design were very noisy, so some kind of debouncing would definitely need to take place.

Following a few tests to verify I was sending the correct serial messages to change the banks that I wanted to, I wrote the following program:

int currentBank = 0;
int bankArray[16];

#define DEBOUNCE_DELAY 50
#define MIDI_BAUD_RATE 31250

#define BUTTON_BANK_LEFT 2
#define BUTTON_BANK_RIGHT 3
#define LED_PIN 4

enum Direction {LEFT, RIGHT};

class ButtonHandler
{
public:
	unsigned long lastReadingTime;
	int reading, prevReading, buttonState, prevButtonState;
	int buttonPin, advanceDirection;
	int* bankNumber;
	Direction dir;

	ButtonHandler (Direction d, int* b) {
		prevButtonState = buttonState = LOW;
		dir = d;
		bankNumber = b;
		if (dir == LEFT)
		{
			buttonPin = BUTTON_BANK_LEFT;
			advanceDirection = -1;
		}
		else if (dir == RIGHT)
		{
			buttonPin = BUTTON_BANK_RIGHT;
			advanceDirection = 1;
		}
	}

	void updateState()
	{
		reading = digitalRead(buttonPin);

		// Reset the timer if the state changes
		if (reading != prevReading)
			lastReadingTime = millis();

		// If this state has lasted longer than the debounce delay parameter,
		// actually count it as a reading
		if ((millis() - lastReadingTime) > DEBOUNCE_DELAY)
		{
			if (reading != buttonState)
				buttonState = reading;

			if (buttonState == HIGH && prevButtonState == LOW)
				changeBank();

			prevButtonState = buttonState;
		}

		prevReading = reading;
	}

private:
	void changeBank()
	{
		*bankNumber += advanceDirection;

		// Range checking, make array loop around
		if (*bankNumber < 0)
			*bankNumber = 15;
		if (*bankNumber > 15)
			*bankNumber = 0;

		Serial.write(0xC0);
		Serial.write(bankArray[*bankNumber]);

		digitalWrite(LED_PIN, HIGH);
		delay(50);
		digitalWrite(LED_PIN, LOW);
	}

}; // end class ButtonHandler

ButtonHandler leftButtonHandler(LEFT, &currentBank);
ButtonHandler rightButtonHandler(RIGHT, &currentBank);

void setup()
{
	Serial.begin(MIDI_BAUD_RATE);

	// Set pin modes
	pinMode(BUTTON_BANK_LEFT, INPUT);
	pinMode(BUTTON_BANK_RIGHT, INPUT);
	pinMode(LED_PIN, OUTPUT);

	// Populate array
	for(int i = 0; i < 16; i++)
		bankArray[i] = i*8;
}

void loop()
{
	leftButtonHandler.updateState();
	rightButtonHandler.updateState();
}

In the constructor for the ButtonHandler class, two variables are accepted as parameters: one of type Direction that represents whether the instance of the class represents the left or the right button, and a pointer to an integer that is used to reference the variable currentBank that indicates the which bank is selected. These two parameters provide enough information for all of the data members of the class to be initialized.

In the method updateState(), The variables reading and prevReading represent raw readings from the input pins. This method also includes all of the logic to perform software debouncing on the buttons. In order to remove the noise in the input signal that occurs as a result of bouncing, a timer starts whenever the present reading from the button pin is not equal to the previous reading. If the present reading and the previous reading have the same value for at least the number of milliseconds specified in the macro DEBOUNCE_DELAY, then this will be treated as a valid reading of the button’s state. If this is a rising edge of the button, then the bank number will advance to either the next or previous value, depending on which button has been read.

The private method changeBank(), the actual advancing of the bank number occurs, as well as bounds checking to make sure that bankNumber is never less than 0 or greater than 15. This bounds checking has to occur because there are only 16 valid program banks on the Korg R3. Four bytes are then written to the serial output, two that come from the hexadecimal number 0xC0 (12 in decimal, or 1100 0000 in binary), as listed in the R3 MIDI spec, and two that come from bankArray, which stores the MIDI program numbers that will be sent to change the banks on the synthesizer. The LED pin is then lit for a moment to indicate that a message has been successfully sent.

Following all of the descriptions for the ButtonHandler class, the setup() method sets the appropriate baud rate for MIDI communication, sets the I/O pins to their appropriate mode, and populates the bankArray with the relevant values to send to the synth. The main loop of the program simply alternates between the updateState() method of each button to check and see if either have been pressed.

One bug that I ran into with this design was that the debouncing effect would seem to stop after about 30 seconds, and the very noisy input of the small buttons that I was using would directly affect the outgoing serial messages. This created a symptom where one press of the button would cause the synthesizer to advance through several banks at a time. I found was that behavior was a result of the variable lastReadingTime overflowing. Since Arduino uses 16 bits to represent its signed int value, the variable would overflow after the value returned from Arduino’s millis() function exceeded 32767 = (2^15 – 1), making my debouncing function stop working after 32 seconds. As shown in this version of the program, I decided to make lastReadingTime of type unsigned long, meaning that the maximum value of the counter would now be 4,294,967,295 = (2^31 – 1). This means that this program will operate accurately for 49.71 days. So this program will definitely not work correctly if you are trying to play a show that lasts continuously for two months or longer.

This hardware and software combination on the Arduino Uno implemented all of the features that I needed for this project, but I wanted to try and use a smaller board to see if I could create the same functionality with a smaller physical footprint and lower power usage. I chose to use the 3.3v 8Mhz Arduino Pro Mini based on its low price, included power conditioning and internal clock.

Shrink-ifying the design

This was the first time I had used an Arduino board that did not have an onboard USB programmer, and I was really impressed with how easy it was to set up. I followed the instructions in this forum post to program the Pro Mini using the Uno. Since the Pro Mini board comes without connections to its pins, I decided to solder wires into the programming pins, and header pins into the board’s I/O. It probably would have been neater to use right angle header pins for the programming connections, but I didn’t have any on hand. I decided not to attach header pins to every I/O pin on the board, just because I knew exactly how many of them I would be using for this project.

Here’s a picture of how I decided to set mine up:

The Pro Mini has a simple voltage regulator on board, so it will be able to accept a raw voltage of 12v. I had a 9v battery and the necessary connectors on hand, so I decided to use that for this design.

Here’s the final configuration of this prototype on some breadboards:

The circuit implemented here is the same as the one described in the schematic shown above. This configuration totally worked, and it was pretty cool.

Conclusion

Overall, the Arduino platform made this project fairly painless, and really fun to put together. I used serial, MIDI communication, and a board without a USB programmer successfully for the first time. While I completed the design of the bank selector with all the features that I wanted, there are a few more optimizations that could improve it.

First, this design is pretty inefficient from a power standpoint.  By my measurements, about 4.16mA are drawn from the 9v battery when the board is waiting for input, and a peak of about 6mA are drawn when pushing either button and powering the LED indicator. Following the calculations presented in this post from CyberGibbons.com, this means that the Arduino Pro Mini is using a maximum of 0.0198 Watts = (3.3v x 6mA) after power conditioning, and the voltage regulator will dissipate a maximum of 0.0342 Watts = ([9v – 3.3v] x 6mA). With a typical alkaline 9v battery’s capacity of  565mAh, this design should last for at least 94 hours = (565mAh / 6mA). This is an adequate life for one battery with this application, but choosing a voltage source closer to the board’s 3.3v would help reduce wasted power that is dissipated by the voltage regulator.

The method I used for debouncing is also not optimal, but it minimized the amount of hardware used for the project. Using a Schmitt trigger or an RC filter would both allow for simplified software logic for detecting when a button has been pushed, without bouncing. With a cleaner input signal, perhaps with the Schmitt trigger, interrupts could be used to put the processor to sleep when no events are detected. This would greatly reduce power use when no buttons have been pushed for a while. Since I have not implemented any of these solutions on Arduino before and power use is not a significant concern for this application, I decided to leave these out of the initial design. I would like to explore these options in the future though, since I am interested in being able to create the more power efficient designs at reasonable costs.

I plan to post a follow up to this post where I describe the design process and construction for this project’s case. Thanks for reading this post, and feel free to let me know if you have any questions about anything I discussed!

Advertisements

3 thoughts on “Midi bank controller for Korg R3

  1. Why didn’t you implement a proper MIDI over USB connection? The old style current loop MIDI serial is slow and poorly supported these days. By using USB MIDI you could have made the device much more usable.

    • That’s actually a great idea, you’re right! That never even occurred to me. I wouldn’t agree that the old MIDI spec is poorly supported since new devices are still coming out with those physical ports, but MIDI over USB is faster and is increasingly well supported. Thanks for the suggestion, I will definitely look into running Arduino as a USB MIDI host.

      • If you choose an Arduino WITH USB and a 16U2 or 8U2 that controlles tis USB then u only need to flash the Hiduino Firmware (use Google to find it) and your Arduino will send the MIDI patterns via USB. The device will be recognized as a HID MIDI device. So there is no need for any driver on Windows, Mac OSX or Linux.
        I actually built an eletronic drum kit this way and it work quite well with Garageband an Logic Pro.
        The only thing to keep in mind: with the Hiduino firmware on the Arduino you cant upload any program to it. You have to use ISP to program your sketch. As long as you have more than one Arduino this is not a big deal. Use one of them as ISP programmer. An HowTo you find on the Arduino website.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s