Keytar Hero (Using a Wii Guitar Controller As a Synthesizer)

Introduction: Keytar Hero (Using a Wii Guitar Controller As a Synthesizer)

About: VFX Artist, Painter, Musician, Maker

The Guitar Hero games were all the rage a dozen years ago, so there's bound to be a lot of old guitar controllers lying around gathering dust. They have a lot of buttons, knobs, and levers, so why not put them to good use again? The guitar controller doesn't normally make any sound on its own, but in this tutorial I'll show you how to convert a Wii Guitar Hero Controller so it can be played as a synthesizer.

Supplies:

  • Guitar Hero Wii Controller
  • Nunchucky breakout board (available on Adafruit here)
  • 4ea jumper wires (female to female)
  • 2ea crimp connectors (optional)
  • Raspberry Pi (3 B+ or 4 preferred)
  • 16GB MicroSD card

Step 1: Step 1: Raspberry Pi (Initial Setup)

A Raspberry Pi is the brains and brawn of this project, so the first thing we'll need to do is to set one up for our project. I've tried this project on both a Raspberry Pi 3 B+ and a 4, and they both seem to work fine.

Raspberry Pi's are microcomputers which store everything on a microSD card instead of a hard drive...including the OS. The typical way to use them is to download the latest OS and burn an image of it onto a microSD card as follows:

  • On a separate PC or laptop, go to https://www.raspberrypi.org/downloads/raspbian/
  • Download the latest Raspbian OS. (Buster at the time of this writing). There are multiple versions available on the page which give more or less included software depending on your preference. They should all work fine, but I like to use the option "Raspbian Buster with desktop and recommended software" because it includes some programming IDEs and other handy apps. Easiest way is to download the zip version.
  • Burn Raspbian image to microSD card. There are many applications you can use to burn the Raspbian image to your microSD card but I used the balenaEtcher program which you can get here. Insert the microSD card into your computer and run balenaEtcher. For the disk image, select the zip file you downloaded, then select your SD card, and hit flash. The tool will unzip the disk image files and burn them to the SD card. IMPORTANT: Make sure the drive you're selecting is the microSD card...the tool will overwrite whatever drive you specify so make sure you've chose the correct one.
  • Fire up your Raspberry Pi. Insert the microSD card into your Raspberry Pi. Connect up your power, mouse, keyboard, and speakers. If you follow the prompts, it's pretty self-explanatory...set your location/time, set a password, and connect the WiFi.

This is all standard setup for a Raspberry Pi so if you need more details, you can find them here. We'll be doing the rest of our steps on the Raspberry Pi.

Step 2: Step 2: Enable I2c

The Guitar Hero Controller uses i2c to communicate (i2c is a fairly common protocol used by electronic devices to talk to each other), so we need to enable this feature on the Raspberry Pi:

  • Install libraries for i2c. The i2c libraries now seem to be part of the Buster standard build, but just in case, we'll run the installer for them. Open a shell (there's an icon for it on the taskbar at the top) and type the following:
    • sudo apt-get install -y python-smbus
    • sudo apt-get install -y i2c-tools
  • Enable i2c on Raspberry Pi. In your shell type: sudo raspi-config. This will bring up your configuration window. Arrow down to InterfacingOptions->I2C to enable i2c for the device. To get out of the window, right arrow to Back and then to Finish to save the settings.
  • Reboot. In your shell, type: sudo reboot
  • Set custom i2c parameters. The default i2c baudrate (100k) seems to confuse the guitar occasionally, so we'll slow it down to 50k as follows:
    • In a shell type: sudo nano /boot/config.txt
    • This will open your config file in a text editor. Arrow down and find the line that says dtparam=i2c_arm=on. If it is commented out, uncomment it. If you don't have that line, add it. Below that line also add the following:
      • dtparam=i2c1=on
      • dtparam=i2c1_baudrate=50000
    • Hit Ctrl + O to save the config file and then hit Ctrl + X to exit.
  • Reboot. In your shell, type: sudo reboot

Step 3: Step 3: Install Pure Data

    For the synthesizer sounds we'll use a program called Pure Data. This is a generative sound and interactive display tool that has been around for quite a while. It has a couple of features that make it ideal for this project...it has a node-based UI which is fairly easy to use, and it can receive signals from external sources such as python scripts.

    • Install Pure Data. In a shell type: sudo apt-get install puredata
      • This should install the software on your Raspberry Pi, but if it complains in the shell about not being able to locate all the files it needs, try this:
        • sudo apt-get update
        • Then run the install command again: sudo apt-get install puredata
      • During install it will prompt you if you want to create directories for extensions, you can say Yes.
    • Launch Pure Data. If it installed correctly you should see the program listed in the Desktop Start Menu under Sound & Video. Run it to make sure it launches.
    • Set up Pure Data audio. The audio in Pure Data isn't usually on by default so you'll need to enable it.
      • Set audio output to ALSA. When Pure Data launches you should see it's console window. Go the Media menu and Select ALSA as your output. You might see warning messages in the console shell that say it can't find certain files, but you can ignore this.
      • Turn on DSP audio. In the console window, check the checkbox that says DSP.
    • Test audio output. In the Pure Data console window, go to Media->Test Audio & MIDI. This will open a test file we can use to make sure Pure Data is working and that we can hear the audio. Turn on your speakers but keep them at a low volume at first (sometimes the audio can be very loud by default). In the test file, on the left side you should see a section called Test Tones. Click on the box that says 60 first and see if you hear any sound from your speakers. If not, try clicking the 80 box and then turn up your speakers until you hear sound. If you hear sound, try dragging in the box that says Pitch to the right of the Test Tones where you can change the frequency of the tones and see what happens.

    If you are able to launch Pure Data and hear a sound from the test patch, then you're ready to go on to the next step. But Pure Data can get a bit finicky about the audio output the first time, so if you still aren't getting audio try the following:

    • It's possible that the audio is routing through the HDMI cable, so to force it to use the headphones jack:
      • In a shell type: sudo raspi-config
      • Go to Advanced Options->Audio->Force 3.5mm ('headphone') jack
    • Try rebooting. Sometimes this does the trick.
    • Check your speakers and connection to the Raspberry Pi.

    Step 4: Step 4: Connecting the Guitar

    The easiest way to connect the guitar controller to the Raspberry Pi is with an inexpensive breakout board such as the Nunchucky*. This board allows you to access the signal coming from the guitar without cutting off the plug or breaking open the guitar. On one side of the board are flat traces designed to fit perfectly into the plug coming from the guitar. There are also two small notches that allow the plug to click into place thus preventing it from coming loose. The traces lead to four header pins on the opposite side of the board.

    Note: The Nunchucky comes with header pins but they are not soldered on so you'll need to do this yourself. For mine, I used 90 degree header pins instead which allows it to lay flat in the final project.

    You'll need four wires to connect the Nunchucky to the Raspberry Pi. Connect the wires from the Nunchucky header pins to the Raspberry Pi's GPIO pins as follows:

    • 3.3v -> Pin 1
    • Data -> Pin 3
    • Clk -> Pin 5
    • Gnd -> Pin 9

    In my project I used crimp connectors for the wires so that they didn't pull out as easily. But if you don't have crimp connectors, four individual female-to-female jumper wires will work fine. If you DO use the crimp connectors, make sure you pay attention to the order of the wires on the header pins and the GPIO pins. Also note, that on the GPIO pins, we skip pin 7. To account for this, I used a five-wire crimp connector on one end and skipped one slot.

    To verify that your Raspberry Pi can detect the guitar controller, open a shell and type: sudo i2cdetect -y 1

    It should print a grid in the shell with mostly double dashes in them. If the computer can detect the guitar, you should see the guitar's ID# 52 in one of the slots...on my machine it showed up in column 2, row 5...but it doesn't matter which one, as long as you see the number 52 somewhere in there.

    If the computer can't detect it here are some things to try:

    • Make sure your wires are tightly connected.
    • Make sure you've got everything connected to the right pins.
    • Flip the Guitar plug around. The Nunchucky doesn't prevent you from connecting the plug upside down, so it might but inverted.
    • Make sure i2c is enabled on the Raspberry Pi (as shown in step 2)

    *If the plug on the guitar controller looks familiar, it's because it is the same as the standard Wii Nunchuck controller...hence the name Nunchucky! This also means that you can use this same breakout board to connect to nunchuck controllers as well.

    Step 5: Step 5: Putting It All Together

    Now that everything is set up on the Raspberry Pi we just need a little bit of code to make it work. You can download the code and other necessary files as follows:

    • To download the code and other files onto the Raspberry Pi, open a new shell and type the following command (you might need to put 'sudo' before it): git clone https://github.com/analogsketchbook/keytarHero.git
    • This will create a directory in your home directory called keytarHero (i.e. /home/pi/keytarHero) and download the files into it.

    There are three main files in this package:

    • WiiGHController.py: This is a python script opens up an i2c connection to the guitar and returns the values of the various controls. By default it also prints the values it's reading to the shell so you can see what it's doing.
    • keytarHero.pd: This is the Pure Data patch file I created to create the music you'll hear. It is set up to read the values coming in from the guitar and routes them to various nodes to generate the sounds. I'll discuss the details of the patch in the next step, but ultimately you could modify this to do whatever you want from here.
    • keytarHero.py: This is the script that kicks off the whole process and glues everything together. It launches Pure Data and opens the keytarHero.pd patch. It opens up a connection to the patch and passes the values from guitar to the patch.

    The moment of truth! Make sure the guitar is connected to the Raspberry Pi and then your ready to go. To kick it off, you just need to run the keytarHero.py script. To do this:

    • Open a new shell and type: cd keytarHero
    • Then run the command: python keytarHero.py

    That's it! If everything is working correctly Pure Data should launch and start playing the patch. You should hear a sequence of notes being played, and when you press buttons on the guitar, it should respond to it.

    Troubleshooting

    If it's not working, here's a few things to check:

    • Pure Data patch not launching or getting an error about not finding files? The keytarHero.py script has the path to the Pure Data patch file hardcoded to '/home/pi/keytarHero/keytarHero.pd'. If you've moved your keytarHero folder or that patch file somewhere else, you'll need to update the script to use your path instead. To do this, open up the keytarHero.py file and look for the variable called PD_PATCH_PATH and change it to point to the directory where your keytarHero.pd file lives. Save the script and re-run it and you should be good to go.
    • Is the guitar emitting a signal? The script should be printing the signal it's getting from the guitar to the shell continuously as a string of numbers, each representing the value of a control on the guitar. When you use a control on the guitar it should cause these numbers to change. If not, check that you've done the i2c setup and guitar connections correctly in the steps above.
    • Is Pure Data audio turned on? The Pure Data patch provided in this package should automatically turn on the audio but verify that the DSP checkbox in the Pure Data console is checked on. Also check your audio settings as shown in Step 3.
    • Is Pure Data receiving the signal from the guitar? In the upper right corner of the patch is a bunch of nodes responsible for reading the signal from the guitar and transmitting it to the rest of the patch. As you press the buttons on the guitar, the numbers in this section should update as well telling you that it is receiving the signal properly.
    • Initializing variables in the patch. Pure Data can be a bit finicky about values in the patch not getting initialized. I've added mechanisms to trigger variables when it opens but it might be worth just clicking on some of the message boxes (the ones that look like they've got a bite taken out of them). This causes them to initialize and can wake them up.

    Step 6: A Tour of the Pure Data Patch

    The setup described so far in this tutorial will get things working for you but one of the nice things about using Pure Data for this project, is that it can be customized to do whatever you want. When the patch is open if you hit Ctrl + E it puts the patch into Edit mode and you can change the patch. The details of using Pure Data are beyond the scope of this tutorial (there's lots of tutorials online for that) but it can be fun to tinker with it, so here's a general tour of what is happening in the keytarHero.pd patch in case you want to customize it:

    • Guitar communication: In the upper right of the patch is a tree of nodes responsible for handling the signal from the guitar. The values from the guitar are a long string, so these nodes break up the string into individual values for each control, convert them to numbers, and then pass them to 'send' nodes (the ones that start with an s). Send nodes are assigned a name and emit the signal to 'receive' nodes of the same name. For example the 's whammy' node, emits the values coming from the guitar's whammy bar and the 'r whammy' node in the middle of the patch receives that signal and uses that signal to halt the sequencer. Send/receive nodes help reduce clutter of connection lines in the patch. I don't recommend messing with this section as it's kind of fussy to get right, but you can definitely add additional receive nodes throughout the patch as needed to receive signals from it as needed.
    • Sequencer section: The middle section of the patch controls the sequencer. On the left side is a bar with a moving black square that shows you which note of a 16-note sequence it is playing. The strum key controls whether the sequence is playing forward or backward. The plus/minus buttons increase/decrease the speed. On the right side are five sets of numbers that control which notes play during each step. Each sequence is assigned to play when one of the five buttons on the fret is pressed. These numbers are MIDI values and you can change them to play whatever notes you want...just give them values between 0 and 127.
    • Oscillator/FX section: In the lower left are the oscillator and FX nodes that actually make the sound. The primary oscillator is on the left. The midi values from the sequencer section are converted to frequencies and fed to the oscillator. It is mixed with a second oscillator coming from the right side. It's frequency is also controlled by the midi values but with an additional frequency offset driven by the X-axis of the joystick. This causes a detuned or whistling effect when you move the joystick to the left or right. In the lower right there is also a low pass filter node whose cutoff frequency is tied to the joystick's Y-axis. A low pass filter determines how much high frequency sound is removed from the sound. When the the joystick is moved to the downward position it cuts off much of the high frequencies which results in a muffled sound. When moved to the upward position it passes all the frequencies through resulting in a brighter sound.
    • Initialization: In the upper left of the patch there are a series of nodes that initialize the patch when it launches such as turn on the audio and 'touch' various nodes to wake them up. Again you probably don't need to mess with this section, but if there are things you want to have happen when the patch launches, connect them to the node called 'loadbang'.
    • I've tried to document the patch with comments in the patch itself, so hopefully that will give you enough information to explore different options from here.

    Enjoy!

    Step 7: Additional Things to Try

    Running the guitar 'headless'

    It should be possible to run this project without being connected to a monitor/keyboard/mouse if you ran your Raspberry Pi off of a suitable portable power source. The Raspberry Pi doesn't quite fit into the opening on the back of the guitar but if you're feeling brave, you could make modifications to the guitar to fix that...or just mount the Pi to the back with screws and have it sticking out a bit. There are plenty of tutorials online about how to run scripts on the Raspberry Pi headless, but basically you'd want to run the command 'python /home/pi/keytarHero/keytarHero.py&' when it boots up. Theoretically then, you'd have a guitar with only one cable coming out of it to the speaker...just like a real electric guitar!

    Additional Pure Data modifications

    I had some other ideas for how the guitar could control the Pure Data patch but didn't get around to trying. These would be changes in the patch that might be fun to experiment with:

    • Whammy bar: In the current patch the whammy bar simply halts the sequence playback, but I think it'd be better if the whammy bar also pitched up frequency at the same time just like a real whammy bar would. I tried to make it work for a while, but it was trickier than I thought. I think it might just be a matter of of adding an expression down in the oscillator section that adds a bit higher frequency to oscillator based on the value coming from the whammy bar.
    • Strum bar: Currently the strum bar plays the sequence forward when pressed down and backwards when pressed up, but might be better to have it cycle through different sequencing options such as random step, etc.
    • Plus/minus buttons: The plus/minus buttons change the beats-per-minute but it's a bit underwhelming unless you hit them several times. Might be good to have it increase by a greater amount each time. Or perhaps have it switch the sequencer between 16-beat, 8-beat, 4-beat, triplet playback.
    Instrument Contest

    Participated in the
    Instrument Contest

    Be the First to Share

      Recommendations

      • Microcontroller Contest

        Microcontroller Contest
      • Automation Contest

        Automation Contest
      • Make it Glow Contest

        Make it Glow Contest

      6 Comments

      0
      carbar
      carbar

      10 months ago

      Would this work for GHWT drums? I've got a set connected to my Pi, but I'm a bit flummoxed by the I2C stuff

      0
      analogsketchbook
      analogsketchbook

      Reply 9 months ago

      Yeah, it should but, because each GH controller uses a slightly different data structure, you'll need to customize the wiiGHController.py to understand the drums. But I don't think that'd be too hard, at least when it comes to the i2c part, especially since folks have already worked out the mappings. First, you can check how the byte is structured by looking at the table on this website: http://wiibrew.org/wiki/Wiimote/Extension_Controll...
      The table shows you the specifics of how the data packet looks coming from the drums, and there is other info to help with the setup. Most of the stuff is already worked out in my python code for the overall connection to the drums (since they look more or less identical to the guitar) so you'll just need to change things up to work with the drum-specific mappings.

      Here's the general idea of what's going on with the i2c stuff. There's basically three things you do to get the data from the controller: 1) decrypt the i2c signal, 2) read six bytes, 3) get the values from the specific bits within those bytes that you want.

      The decryption is pretty easy and I don't think you need to change any of the existing code for that. But just for clarity, this is done starting on line 51 of the python code. We send the value 0x55 to address 0x40 on device 0x52, then we send a value of 0x00. This then allows the decrypted data to be transmitted. Looking at that webpage, these lines should still work for the drums without any changes since all the values for addresses appear to be the same as far as I can tell.

      The second step, reading the byte is done in the function called read() at line 63. This simply reads 6 bytes of the data and returns those as a list with each item being one byte. I think this should work for the drums as-is also without any modifications.

      The last thing to do is to extract out the specific bits you need from each byte. That is done in the various functions after the # Guitar Hero Mappings comment on line 73. For these, you'll need to change these functions (or make new ones) to suit the drum data based on the table from the website. Each function follows the same general pattern, for example the red button function at line 99 first reads the 6 bytes with the self.read() call. On the guitar, the red button is in byte 5 in the 6th bit so to get that data the next line looks like :
      br = (data[5] >> 6) & 0x01
      So basically, when you're trying to access a specific single bit in the table, you change the data index to be the row from the table you need (5 in this case) and you shift the bits by the column you need (6 in this case). Looking at the drum's table, they're close to the guitar mappings (red and orange are in exactly the same spot, the others are also on bytes 4 and 5 just in different bit positions) so those should be fairly straightforward to modify.

      Some of the data uses more than one bit, for example on the guitar the whammy bar needs 5 bits and the joystick x and y values each use 6 bits, so getting the data is slightly different. For the joystick x, for example, I only need the last six bits of byte 0. So I cast that bit as binary and then grab the last six digits using the lastSix = fullbyte[4:]. Finally, in the return statement, I cast the value as a two digit integer which can then be used in the rest of the program as needed.

      While overall accessing the data is the same, it looks like, from that website, the drums have a lot of extra functionality that manages the velocity each drum is struck. I think it basically works like, if there is velocity, it sets byte2, bit 6 to a value of zero. Then it uses some bits on bytes 2 and 3 to indicate which drum the velocity is for, an how hard it was hit. So you'd probably have to add some functions to read those bits and return velocity values. That webpage lists the details on what bits are for what, and what values they send back.

      When working this out it'd probably be helpful to reference the table I'm using for the guitar to see how my code compares to the table for the guitar: https://wiibrew.org/wiki/Wiimote/Extension_Control...

      Sound like this could be a cool approach for driving a synth or drum module. I'd be curious to see how it turns out. Maybe if you get new controller code, we could add it to the git hub repository for others to benefit from.

      Hope this helps.

      0
      analogsketchbook
      analogsketchbook

      Reply 8 months ago

      Nice! I don't have the drums so I can't try it out myself, but it looks like you had to work through a lot of stuff to get that working. It's funny how these little "I-wonder-if-I-could" projects take us down the rabbit hole :) I hope folks can make use of it.

      0
      analogsketchbook
      analogsketchbook

      Reply 1 year ago

      Great idea!Thanks for the heads up.