Summary

It's been just under a decade since my last write up here on Hack A Day and I am grateful that I was able to envision, plan, create and complete this USB MIDI adapter without too much hassle as a weekend project thanks to Chat GPT and the fantastic Arduino community, libraries and tooling.

Background

After eyeing off a cheap Roland digital piano for sale, I went to inspect it thinking that at least one or two keys were not going to be functioning. To my surprise all keys were working and it was in pretty good shape for what I later found out to be a 34 year old (1989) keyboard.

The feel of this keyboard is one of the best I have ever encountered, the action not unlike a high end acoustic grand piano and pretty soon I had put my 2 month old M-Audio controller keyboard aside focusing on using the Roland for my music production.

I ordered a cheap MIDI adapter from EBay for under $10 and forgot about using the keyboard until the adapter arrived.

First adapter failure

Once it arrived, I was eager to get it going, connected it and there was a constant blinking light flashing when connected to the MIDI out of the keyboard (active sensing) so that was a positive sign. Next firing up Reason (music production software) I found that the keyboard would sporadically work, with missing notes here and there. After some debugging, it seemed like it was only picking up one note at any given time (monophonic) even though the keyboard itself, with it's onboard sound canvas and amplifier was working correctly (polyphonic). There wasn't much more to do here, it just seemed like this adapter was no good.

Second adapter failure

I then read some forums online and opted for a more expensive MIDI adapter from M-Audio, for about 6x the price of the cheap EBay one. Surely now, with a reputable brand and less money in my wallet I was going to be able to use the Roland properly, but no. Surprisingly, the adapter behaved in exactly the same manner as the cheap one. Hmmm, this pointed to an issue with the keyboard instead... damn...

Keyboard Diagnosis

Going deeper, I opened the case and found that the PSU section was overheating and there were signs on the circuit board to support this. The incoming PSU (from Roland) was rated at 12V DC however I was measuring 17V DC going in. That seemed a little high so I decided to replace it. Of course Roland decided to "be different" and make their adapter with the center pole as GND instead of VCC. Annoying but not a blocker as I quickly reversed the polarity of an existing 12V DC adapter I had and then gave it another go.

It was better, the PSU components were no longer heating up as before and I had also changed a few of the capacitors in the PSU for good measure. I thought that would be the end of the repair, as we all know PSU problems present a large majority of faults seen in hardware.

Unfortunately I was wrong...

Reading the MIDI data

With the same issues persisting, it was time to bust out the oscilloscope and see exactly what was going on. I found some clock jitter in the main CPU and initially thought that was the source of my problems since naturally a non uniform clock signal would surely be interfering with the MIDI out signals. After some thought though, it was unlikely to be the case as the clock was running at 16MHZ and the MIDI baud rate is a very slow 31,250. That's quite a difference and even some shift in the 16MHZ (as seen) would not be affecting the output of such a slow protocol.

It was time to read the MIDI out data directly to analyse it. Luckily, there is a 74LS04 buffer IC used between the MCU and the MIDI out port so I could tap that to get some readings. My cheap digital scope gave me enough information to start to paint the picture of what was going on.

MIDI frames

For a single note (that worked fine), I could see three bytes being sent, with a start bit at the front. No problem here as a MIDI message for a Note On consists of:

[ Status Byte ; Note; Velocity ]

There is an optional four byte for a checksum in the MIDI spec but this is not a requirement.

Back in the day, I would need to consult a MIDI implementation chart to decode these bytes, but Chat GPT was able to decode them for me! It certainly made this part of the diagnosis quicker and it was quite good at it. For example, I could say:

Please decode this MIDI message:

b10010001 b01011100 b01101101

And it was able to do so and give me the corresponding Status, Note and Velocity values!

Now, for two or more notes, the data seemed to just keep running, with no clear distinction between messages (no stop / start bit). After some online research, I determined that what I was seeing was a data conservation technique Roland and others use called Running Status. The idea here is that if there is no change in the Status byte (say Note On), then there is no need to send that Note On status byte again, so multiple notes become:

[ Status Byte ; Note1 ; Velocity1 ; Note2 ; Velocity2 ; Note3 ; Velocity3 ...] 

Running status is not supported by the USB MIDI specification so even though the keyboard itself seemed to be sending the correct signals and it was perhaps the MIDI adapters that weren't interpreting / decoding this correctly or just attempting to pipe through these additional notes without the Status bytes which is never going to work.

Time for a custom solution

At this point, I questioned whether it was worth continuing or not, after all this was a 34 year old keyboard and I had a shiny new controller keyboard that worked just fine. However, as mentioned, I really enjoyed the Roland's feel and it felt like I was playing a real piano. So it was time to roll my own MIDI adapter.

Hardware Preparation

My first thought was to use an Arduino as it has great support community and I could get one from my local Jaycar (here in Australia). After purchasing a Lilypad Arduino for under $20, I found that I needed to do a 3.3V to 5V TTL level conversion in order to prevent damaging the input of the Arduino. Luckily, I had a few spares around from previous projects so that wasn't an issue.

Since the Lilypad Arduino has limited IOs connected to the ATMega34u4 MCU, I used Pin 9 as a SoftwareSerial receiver and used the onboard USB serial to emulate a real USB MIDI adapter.

I tried to keep the line runs as small as possible to prevent stray capacitance and decoupled the input using a 22pF capacitor. The hardware was done and it was time for the software.

Software

Thanks to the fantastic Arduino community and IDE I was able to emulate a USB MIDI adapter and test a three note chord output in less than five minutes! Great, so half of the project was complete, now for that other half of interpreting the input and passing the note / control change data to the virtual MIDI port.

Less than 30 lines of code later, the project seemed complete, I was able to play more than one note on the Roland and have the Arduino send these notes to my computer. All screws put back in and that was that, or was it...

Issues with SoftwareSerial

The next day, I sat to play the keyboard and found that there were intermittent issues, with stuck notes and phantom notes played here and there, grrrrrr...

I had nothing to blame but the SoftwareSerial used to read in the MIDI. Switching over to HardwareSerial in the software was a piece of cake, but since I opted to use an Arduino Lilypad, I had to somehow get to the pin, as this board does not have the onboard RX pin available easily. That involved soldering the RX line directly to the QFP! I knew this was going to be quite challenging and eventually I settled on shorting the pin adjacent (SDA) to the RX pin and setting the SDA to be an input pin so that it wouldn't interfere with the serial signal coming into the RX pin. This worked fine and I was finally able to get the correct MIDI signals decoded from the Roland, regardless of the polyphony! Success!

 Source Code

The source is public on GitHub. Note that I don't interpret MIDI IN signals coming from the USB side and translate them into traditional MIDI IN signals for the Roland, essentially this is a one-way communication line however it would not be difficult to also set up the other direction if you needed to do that.

Why make the adapter internal instead of external?

I could've opted to make this the same as the other two failed adapters, that is, external to the keyboard with opto-couplers to isolate and read the signal but decided not to. The reasoning here is that if this keyboard is going to become my master controller, then I will eventually opt to connect one or two analog pots and send out Control Change messages for greater control. These pots would be connected to the Arduino so it makes better sense for the adapter to remain internal.

Final thoughts

It was a short but fun roller coaster ride to get this project going and thanks to Chat GPT and the Arduino community, this was a weekend project rather than a 3-4 week project had I needed to code this all myself from scratch.

If I had to do this again, I would opt to use the Leonardo board instead, as it has 5V IOs and the serial RX / TX pins are available to use out of the box.