Hacking a guitar hero
[2019]
Here's a random project that I thought would be fun to make.
A few months ago I started playing around with digital audio software and learned about MIDI. I decided it might be cool if I took an old Guitar Hero controller and repurposed it to actually play music. I used to love playing Guitar Hero as a kid, but those days are long gone, and my Les Paul controller sat in my basement collecting dust for the past 10 years. I figured I could re-wire the controls and use an Arduino to play notes, either through MIDI or a speaker and actual wav files stored on an SD card. Read below to see how I built it!
stage 1: Research
With this project I did a lot more technical research than design work, given that my design was already constrained by the guitar controller I was working with. I had worked with Arduino before on my rocket project, but still didn't know much about audio processing.
I first wanted to turn the guitar into a "real" guitar that you could plug into an amp and play. However, it turned out that Arduinos are pretty terrible at audio production. They don't have a DAC (digital-to-analog converter), and Arduinos are digital devices, while audio files are analog. There are ways to simulate a DAC on an Arduino, one of which is called an R-2R ladder (see right). It's basically a network of resistors that "weights" the outputs of digital pins to produce one analog voltage. If you want to output 8-bit audio (2^8 different voltage levels), you need 8 digital pins and a resistor ladder with 16 resistors. As you can see from the image, the MSB voltage drops through the least amount of resistance, so its contribution to the final Voltage Va is highest. The downside of R-2R ladders is that they're highly dependent on the accuracy of the resistor values, especially at higher bits–if one resistor is slightly off, it throws off the value of the whole network.
Given that I didn't have access to high-precision resistors, I looked into other ways to produce audio. I stumbled upon an Arduino library, tmrpcm, that allows you to output analog signals using the Arduino's built-in PWM (pulse width modulation) feature. PWM works by quickly switching a voltage signal from 5V to 0 (490 times per second). If within each cycle the voltage is high for 1/2 the time, then the signal will effectively output half of its maximum output, or 2.5V in this case. By varying the duty cycle (% of time that the voltage is high within each cycle), I can effectively change the analog output of the signal.
Wav files are uncompressed audio files which represent sound as an array of voltage values. Important characteristics of a wav file are its sample rate (in Hz) and the bit depth. Sample rate is the number of samples of the audio per second. Since digital files cannot represent analog signals perfectly, they have to sample the audio at a set rate. Songs on Spotify are likely sampled at 44.1 kHz, but tmrpcm can only take up to 32 kHz, so I opted for 22.05 kHz. Bit depth defines the number of bits used to represent each sample. 16-bit is CD quality, but tmrpcm only allows for 8-bit. The more bits the better, because each bit effectively doubles the amount of voltage values you can approximate your audio with. If you have 2 bits, you can only approximate your sound at 4 voltage levels. 8-bit allows for 256.
The tmrpcm library uses pwm to approximate each voltage in the wav file. In the image on the left, you can see how a sine wave might be digitally sampled by a wav file. At each sampled point in the wav file, the Arduino then changes the duty cycle of the pwm signal to match that point's analog voltage value. Tmrpcm makes use of the Arduino's internal clock to do this. Arduino controls pwm duty cycles using its internal clock, which runs at 16 MHz. The clock continuously counts from 0 to 255 and keeps the pwm signal high until the clock matches an output compare register. It then sets the signal low until the clock repeats again. Check out the image below for a visual explanation. Manipulating the internal clock is a very low-level, tedious task, so I was happy to find a library that already packaged this in.
Okay, so I output an audio signal, now what? Well, I can't just plug it straight into a speaker. There are a few steps I need to take to pre-process the signal before it can be fed into a speaker. First would be a low-pass filter. This attenuates any high-frequency noise in the signal via a simple RC filter. I chose a resistor and capacitor such that my corner frequency is 10 kHz, since I didn't think I'd have any audio frequencies above that. Next is a voltage divider. For passive speakers, this isn't needed. Since I was planning to use a powered speaker, however, I needed to cut the signal voltage down to line-level, which is about +/- 1.5V. A passive speaker would've needed an audio amplifier like an LM386 to amplify the current enough to drive the speaker coil. Finally, I needed a DC bias capacitor. An Arduino can only output positive voltages, so in order to make the signal oscillate around 0 V, rather than 2.5 V, a large capacitor (1000 uF) is used to filter out the DC component. The image below shows the audio circuit that I built.
Even with a library like tmrpcm, direct audio output on an Arduino is pretty limited. I wanted a feature that could pack in a lot more functionality, so I also added MIDI output. If you're not familiar with MIDI (don't worry, neither was I 6 months ago), it's the Musical Instrument Device Interface, which is the standard protocol for electronic music instruments. If you've ever seen a keyboard or beat pad that plugs into your computer and connects with a digital audio program like GarageBand, those use MIDI. After researching a bit, I realized that MIDI is actually a really simple protocol. It sends all data over serial ports and each message contains three bytes: status, data 1, and data 2. Status usually corresponds to the type of command you want to send. For example, note on is 144, or 0x90 in hexadecimal. The note on command takes pitch and velocity as its first and second data bytes, respectively. Velocity is basically just the volume of the note.
The interesting thing about MIDI is how broad it is. The commands that I send do not correspond to any specific instrument, they only convey what note to play and how loud. MIDI is not an audio signal. That means that I can connect my guitar to GarageBand and play notes with a grand piano, then switch it to a bass guitar, synthesizer, or anything I want. My computer does all the audio processing so the Arduino doesn't have to. I can also use MIDI to play with pitch bend (Whammy Bar) and volume control. All these features made me excited about turning my guitar from an amusing toy into something with real functionality.
stage 2: Build
I started out by tearing down my controller to get a better idea of how the internal components worked. I was surprised to see how simple a few of the components were–the whammy bar is just a spring-loaded potentiometer, and the strum button is just two push buttons with a pivoting lever arm. I made note of every wire so that I could repurpose the buttons for Arduino.
After disconnecting the wiring from the Guitar Hero boards, I re-connected each one to begin testing the hardware. I found this to be more difficult than I thought it would be, given that the hardware came from a production-level product. Many of the wire connections were poor and the solder was low-quality. I even had to replace the button connector from the guitar neck to the base (the black thing with pins sticking out in the first photo), because of faulty connections that I couldn't fix.
The Arduino code was not particularly complicated, mostly just a mix of checking button presses and calling the correct 'play music' function. Just like in Real Guitar Hero, you can only play a note if you press the strum button at nearly the exact same time. There are two modes–audio and MIDI–you can change them by pressing the guitar's select button. The entire sketch is attached here.
As I built the guitar, my main concerns centered around packing everything inside the small enclosure. The wiring was messy and hard to keep track of. I would often forget which wire went where, and spend extra time re-checking the wiring. I gutted out most of the guitars internal supports to make room for electronics. When I designed the final internal layout, I made sure to use custom wire lengths in order to prevent extra wiring from getting in the way. I also replaced my breadboard with a soldered perfboard, which is more secure and takes up a fraction of the space.
After finishing up with the internal layout, I moved on to more stylistic features. For one, I wanted to add some design to the plain black guitar face, so I decided to laser engrave a cool graphic. I engraved a Led Zeppelin logo (my favorite band) with my initials underneath. It turned out great and I'm happy with the result.
Another issue was that the battery compartment was too small for my 9V battery, so I decided to design and 3D-print a new battery cover.
Another issue was that the battery compartment was too small for my 9V battery, so I decided to design and 3D-print a new battery cover.
Finished product
This is it! The guitar can play MIDI and audio output. I especially love the volume knob that goes to 11. Be sure to check out the video to see it in action.
Some thoughts on the process
Throughout the entire process of finishing this project, I couldn't help but compare the process of hardware development with software development. I'm sure I'm not the first person to notice this, but having done both, it's interesting to note that hardware development depends on a lot more external factors.
For one, there's the notion of craftsmanship. The easiest part of this project was designing the schematic and writing the code. I was so frustrated that I was getting tripped up on problems like wires getting in the way of each other or solder connections breaking off. These were things that seemed trivial to me at first, but I didn't realize how much emphasis needs to be put on the quality of craftsmanship in my design. I found that the solution came from simply having more patience, rather than thinking of a clever solution. I spent a large chunk of time soldering and re-soldering wires together, applying heat-shrink tubing, and crimping wires. In software, while you could argue that typing words, optimizing algorithms, and playing with design layouts is the same type of work, but I just feel like there's a lot less of it. I'd say that 20% of my time was spent thinking about how to implement solutions, and 80% was spent actually making them. I can only imagine how much cleaner my finished product would look, or how much quicker I would have finished, if I only had better hands. There's a a quote from The Hard Thing About Hard Things by Ben Horowitz that I think sums up this idea pretty well:
"There are no silver bullets for this, only lead bullets"
He originally meant it in terms of business strategy, but the principle applies here too. There's no clever way to get around having to route 50 wires inside of a 2 inch tall enclosure. In hardware development, you just have to embrace the time spent working on tedious tasks.
Hardware development also depends more on tools. I'm extremely lucky to have access to my school's prototyping labs with 3D printers, CNC milling machines, laser cutters, and tons of hand tools. This is equipment that might cost hundreds of thousands of dollars in total. With software, anyone with a computer and an internet connection has the basic tools to make amazing projects. I wish that there were some way to make hardware development more accessible to everyone. Part of the reason I decide to take advantage of Duke's prototyping labs so much is that I know I'll never have access to this stuff again. Even so, they don't have everything. Our soldering irons are pretty mediocre, so I spent more time than I should have on soldering. When I realized that I needed a part/tool that wasn't available, I'd have to order it. (Thank god for Amazon Prime!) With software, if I don't have access to something, I can instantly download a library or a module. These delays probably doubled my time on this project.
I'm not saying that hardware is more difficult than software. It's just that it depends a lot more on factors that I wouldn't really consider thought-intensive. I think that software development is much more limited by thought-intensive problems, like not knowing how to implement an algorithm, and less by tools and craftsmanship.