Friday, November 17, 2017

Plastic Pitch Microtonal MIDI Machine



I made this other Arduino microtonal MIDI device a couple years ago, and I wanted to try a different approach.  It's certainly interesting to play with more than 12 tones per octave, but it's also awkward on a piano style keyboard.  (How do you reach an octave when playing with 17 tones per octave?)

So I limited Plastic Pitch to 12 tones per octave to take advantage of the muscle memory that every keyboard player already possesses, but I gave each of the tones an independent pitchbend setting.  This allows the player to tune each of the 12 notes according to however the pitchbend range is set on the connected MIDI synth.  For example, if the synth's pitchbend range is set to 2 semitones (a whole step), then the knobs on Plastic Pitch range from down a whole step to up a whole step.  Change the pitchbend range on the MIDI synth, and the knob range changes accordingly.

Another design consideration that is different for Plastic Pitch is that I opted for what I would consider more of a musician's approach than an engineer's approach to microtuning.  An engineer might approach microtuning as I did with my previous device by using very precise pitchbend values that are carefully calculated to match specific numeric frequencies.

In contrast, I kept the interface simple and immediate.  Simple because the only indication of relative tuning is the line on each knob.   Twelve o'clock is neutral, left is down in pitch, and right is up.  And, immediate because tunings can be changed dynamically while playing in response to what is heard, not unlike how a violinist, for instance, makes small tuning adjustments as they play.

But why?

Am I just destroying all that is good about music?  I don't think so.

My initial pursuit into microtonality was inspired by the book Tuning, Timbre, Spectrum, Scale by William Sethares.  It presents a methodology that relates timbres to musically interesting microtonal scales.

The common 12-tone equal temperament (12-TET) scale works fine for timbres that are rich with harmonics, like the ones produced by all the traditional Western musical instruments.  However, if timbres are chosen that feature prominent inharmonic spectral content--gamelan is one example in the book, then a scale other than 12-TET would be more musically suitable for creating the interplay between consonance and dissonance that often characterizes tonal music.

The book has computational methods for coming up with possible scales for a given inharmonic timbre.  That is great for approaching microtonality as an engineer, however, as noted above, Plastic Pitch is an attempt to approach this differently, perhaps as a musician.

I want one!

I made this primarily for my own microtonal exploration of inharmonic timbres, but please contact me with the form on the right sidebar if you'd be interested in purchasing parts, a parts kit, or even a fully assembled one.  I just made this and am not sure about prices, but I'll see what I can come up with if others are interested.  I for one would like to hear more microtonal music.


Technical notes:

It has two standard MIDI 5-pin DIN ports, one IN and one OUT.  The IN port listens for MIDI Note On (key press) and Note Off (key release) events from any MIDI channel.  The OUT port sends Note On, Note Off, and Pitchbend events on the first twelve channels.  All other MIDI events are ignored.

When playing a monophonic or non-multitimbral polyphonic synth, only the pitchbend for the last played note is used.  This is possibly a feature or possibly a problem to workaround depending on perspective.  The simple workaround is to only play one key at a time and not hold down multiple keys.  Or, do hold multiple keys, and get unpredictable pitch behavior.

Monday, May 15, 2017

GameSquare Software Notes

Introduction here.  Hardware notes here.

The Raspberry Pi 3 is running the current standard Raspbian image.  Here are the relevant contents of my /boot/config.txt file.

gpu_mem_1024=512
overscan_scale=1
overscan_left=-16
overscan_right=0
overscan_top=-16
overscan_bottom=-16
framebuffer_width=400
framebuffer_height=240
sdtv_mode=0
sdtv_aspect=3

I wrote two custom programs:  "WiiClassicPi" allows the Wii Classic Controller plus volume knob and halt button to control the Raspberry Pi, and "emu.py" is a bare-bones file browser for launching games.

WiiClassicPi code and configuration:

WiiClassicPi reads the Wii Classic Controller data over I2C and translates it to virtual keyboard presses thru the linux uinput device and system commands.

Set up the uinput device by adding a line for "uinput" in /etc/modules.  Make it accessible for all users by adding the following line to /etc/udev/rules.d/99-com.rules: KERNEL=="uinput",MODE="0666"

After a reboot, confirm that it shows up with read/write privileges for all.

pi@raspberrypi:~ $ ls -l /dev/uinput
crw-rw-rw- 1 root root 10, 223 Feb  2 13:36 /dev/uinput

I installed libsuinput to generate keyboard presses thru /dev/uinput.  I installed Wiring Pi for the I2C library.  I2C can be enabled on the Raspberry Pi using raspi-config.

The delay times after I2C transactions can be customized at the top of my code.  The delay times provide enough time for I2C transactions to occur.  They probably can be less, but the values I've chosen seem to work okay.  According to wikipedia, input lag becomes distracting around 200 ms, so keep the delay times much less than that.

The valid key codes to be listed in the keys[] array can be found in /usr/include/linux/input.h.  The key codes should be listed in the same order as the commented list of Wii Classic buttons.

Notice that the ZL button is mapped along with the select (-) button to perform a system halt, and the LX analog joystick is mapped to the 10 K potentiometer and used to adjust the volume.

Also, line 147 of the code contains a workaround for a glitch.  When the Raspberry Pi is running something CPU intensive (like an emulator) the I2C read sometimes results in garbage (0xFF)) in the 2nd and 3rd of the 6 bytes.  So the code throws away those reads and moves on.  This might cause some noticeable controller latency if too many reads in a row produce garbage, but I haven't noticed any problems.

Compile using:  gcc -lwiringPi -lsuinput WiiClassicPi.c -oWiiClassicPi

Run as "./WiiClassicPi verbose" to see controller data.

emu.py code and configuration:

I initially considered using RetroPie, however it would not recognize the virtual keyboard presses from /dev/uinput.  I also find it way too complex for such a simple thing as launching an emulator, especially on a small screen.

So I wrote emu.py, a Python 3 barebone curses-based frontend for launching emulators.  All the customization happens at the top of the code.  The keys are mapped to work with WiiClassicPi (except for the exit key (F1) to be used with an attached keyboard), and the extensions, directories, and launch commands have corresponding entries for each system.

# GUI keys
exit_key = curses.KEY_F1
up_key = curses.KEY_UP
down_key = curses.KEY_DOWN
left_key = curses.KEY_LEFT # back 1 page
right_key = curses.KEY_RIGHT # forward 1 page
launch_key = ord("j")
a_key = ord("x") # back 5 pages
b_key = ord("z") # forward 5 pages

# rom file extensions
file_ext = [".gb", ".gbc", ".nes", ".smc"]

# rom directories
romdir = ["/home/pi/roms/gb",
          "/home/pi/roms/gbc",
          "/home/pi/roms/nes",
          "/home/pi/roms/snes"]

# emulator launch commands
emulator = ["/home/pi/emu/./gambatte_sdl -i j g x z up down left right -s 8",
            "/home/pi/emu/./gambatte_sdl -i j g x z up down left right -s 8",
            "mednafen",
            "/home/pi/emu/./snes9x"]

GameSquare Hardware Assembly Notes

Introduction here.  Software notes here.

First, some photos for inspiration and reference.




Case:

The case slots together from the laser cut parts, and the screws and standoffs hold it together.  The four longer (31 mm) standoffs go in the four corners of the case, and the four shorter standoffs (25 mm) go in the back of the case to hold the controller PCB in place.  The screws fit snugly in the laser cut holes, so take care to ease them in the first time.

The two switches, three buttons, one potentiometer, headphone jack, and micro USB jack panel mount on the case.  The LCD is hot-glued on the face plate.  The controller buttons just sit on the PCB and are carefully wiggled into place when the face plate is fastened.  Velcro holds the battery, the speaker, and the Raspberry Pi in place.  I also used some Lego to hold the Raspberry Pi in place when plugging in a USB device.  Hot glue and electrical tape were used as needed to fasten parts and to prevent accidental short circuits.

LCD screen:

The plastic outer case can be pried open.  This photo shows where the composite video (yellow), ground (black), and 5V (blue) wires are to be soldered to the control board for the LCD.  (I used different colored wires in the final assembly shown above.)




Wii Classic Controller:

Open the controller case with a tri-wing screwdriver, and separate the PCB with a phillips screwdriver.  Desolder all the connections at J1, J2, J3, J4, ZL, and ZR.  Save the main PCB and the buttons and membranes on face of the controller.  I snipped off an empty corner of the PCB under J4 to make it fit in the case.

Battery:

In initial tests the 2500 mAh LiPo battery provides about 2 hours of play time.  When the battery goes low, the LED next to the power switch turns off.  The next thing that happens is the I2C bus stops working.  This is problematic since system halt (without an attached keyboard) relies on buttons connected to the I2C bus.  (If I can stop playing video games) I may add functionality to monitor the Powerboost 1000C LBO pin with a Raspberry Pi pin to force a system halt when it drops to ground (indicating low battery).

Powerboost 1000C:

Powerboost 1000C documentation 

PAM8302 audio amplifier:

PAM8302 datasheet

Wiring:

The wiring schematic shows all the relevant parts except the Raspberry Pi 3.  The Raspberry Pi pins are simply labeled.  This is a good reference for the forty-pin connector.  The PP# pins are labeled on the underside of the PCB near the analog audio/video TRRS connector.  I made all the Raspberry Pi connections by soldering to pins on the underside.





Presenting the GameSquare!





Design Considerations:

I wanted to design my own Raspberry Pi handheld gaming system.  I logged most of my gaming hours in the early '90s.  So I have a soft spot for games from that era, and I particularly like the Wii Classic controller for its SNES-like layout.  

I knew from a previous project that Wii controllers can communicate over an I2C bus such as the one available on a Raspberry Pi.  I chose a 5" LCD screen based on being a similar width as a Wii Classic Controller.

When designing the case I realized the dimensions were roughly square.  So I decided to make it square and the name came naturally as an homage to the GameCube.  

The case is 160 mm x 160 mm x 37 mm.  The face has D-pad, select (-), home, start (+), A, B, X, and Y.  The back has the L and R buttons.  The bottom has a headphone jack and micro B USB jack for charging.  The right side has access to two of the Raspberry Pi USB ports which is good for connecting a keyboard.  The top has heat vents, a power switch for the external amp/speaker, a volume knob, a halt button, a power switch, and an LED that indicates battery high or low.  In initial tests I am getting about two hours of play time running on only the battery while using the external amp/speaker and with the Wi-Fi turned on. 

Parts List:

Purchase the Inkscape design file for the laser cut case here.  My case was laser cut by Ponoko using a P2 sheet of Amber Bamboo.

See the hardware assembly notes here.   

See the software notes here.






















Tuesday, February 14, 2017

Simple Emulator Frontend for Raspberry Pi

I was annoyed by how complex the Raspberry Pi emulator frontends are, and I was looking for an excuse to write my first Python program.  So, here it is, a barebone curses-based frontend for launching emulators.  But really it could also be used to launch anything, like videos, ebooks, etc.

All the customization happens at the top of the code.  The extensions, directories, and launch commands will need corresponding entries for each emulator to be included.


# GUI keys
exit_key = 27 # ESC key
up_key = curses.KEY_UP
down_key = curses.KEY_DOWN
left_key = curses.KEY_LEFT
right_key = curses.KEY_RIGHT
launch_key = ord("j")
a_key = ord("x")
b_key = ord("z")

# rom file extensions
file_ext = [".gb", ".gbc", ".nes", ".smc"]

# rom directories
romdir = ["/home/pi/roms/gb",
"/home/pi/roms/gbc",
"/home/pi/roms/nes",
"/home/pi/roms/snes"]

# emulator launch commands
emulator = ["/home/pi/emu/./gambatte_sdl -i j g x z up down left right -s 8",
"/home/pi/emu/./gambatte_sdl -i j g x z up down left right -s 8",
"mednafen",
"mednafen"]

Thursday, February 2, 2017

Wii Classic Controller over I2C to Raspberry Pi

I wanted to connect my Wii Classic Controller to my Raspberry Pi 3.  Here is how I did it.

The Hardware:

The Wiibrew extension controller page explains how to connect an official Wii Classic Controller via I2C.  (I tried a cheap ZettaGuard one, and I couldn't figure out the appropriate I2C initialization codes to make it work.)

The site Robot Electronics has an I2C tutorial that explains the need for pull up resistors when making I2C connections.  I used two 10 K pull up resistors and connected the four pins (3v3, SDA, SCL, and ground) from the Wii Classic Controller to the Raspberry Pi connector (pins 1, 3, 5, and 6).



The Software:

I am using a stock Raspbian image (as of January 2017).  The goal is to read the Wii Classic data and translate it to virtual keyboard presses thru the linux uinput device.

First, set up the uinput device by adding a line for "uinput" in /etc/modules.  Make it accessible for all users by adding the following line to /etc/udev/rules.d/99-com.rules:
KERNEL=="uinput",MODE="0666"

After a reboot, confirm that is shows up with read/write privileges for all.
pi@raspberrypi:~ $ ls -l /dev/uinput
crw-rw-rw- 1 root root 10, 223 Feb  2 13:36 /dev/uinput


Now, this page has useful lower level info about writing C code to use uinput, but ultimately I installed libsuinput to handle the details.

I installed wiringPi to use the I2C library.  I2C can be enabled on the Raspberry Pi using raspi-config.

Here is my code.

The delay times after I2C transactions and keys to output can be customized.  The delay times provide enough time for I2C transactions to occur.  They probably can be less, but the values I've used seem to work okay.  According to wikipedia, input lag becomes distracting around 200 ms, so keep the delay times much less than that.

The valid key codes to be listed in the keys[] array can be found in /usr/include/linux/input.h.  The key codes should be listed in the same order as the commented list of Wii Classic buttons.

Compile using:  gcc -lwiringPi -lsuinput WiiClassicPi.c -oWiiClassicPi

Monday, January 23, 2017

Chuanganzhuo 5" TFT LCD Monitor Plus Raspberry Pi 3





I recently got this 5" TFT LCD composite monitor, and I was able to connect it to and power it from a Raspberry Pi 3.  Here is how I did it.

I opened up the case to expose the bare LCD and driver board.  The case is just two pieces of plastic snapped together, so I pried it open with a screwdriver.  You can see the original input wires connected to the board:  red - 12-24 VDC, black - ground, yellow - composite video 1, and white - composite video 2.



I removed the original wires and connected the three wires shown below:  yellow - composite video, black - ground, and blue - 5 VDC.  The blue wire is (thin) 30 AWG wire that is easily soldered onto the PCB.



I connected the three wires to the Raspberry Pi as shown below using a TRRS connector:  yellow - composite video (S), black - ground (R adjacent to S), and blue - 5 VDC (pin 2 of the Raspberry Pi connector).




Here are the relevant /boot/config.txt settings I am using.

overscan_left=-24
overscan_right=-24
overscan_top=-20
overscan_bottom=-20
framebuffer_width=400
framebuffer_height=240
sdtv_mode=0
sdtv_aspect=3

Enjoy!