Being a big fan of both Sonic Pi, a live-coding music program, MaKey MaKey, a gadget that makes bananas and other unlikely objects musical, I decided to have a go at running together some code that would let me use them together.
This solution is based on Pygame Zero, a wrapper program for Pygame written by Daniel Pope. Pope designed it as a way for new or newish programmers to create games programs with Python without having to delve into the complexities of Pygame. The available operations map a lot more easily from Scratch, which many new coders will have started with. However, any Pygame command can be used in a Pygame Zero program so it doesn’t restrict people doing more complex things as they gain confidence.
This program doesn’t use many of the capabilities of Pygame Zero, mainly just its built-in recognition of key-press events. (Although, for a bit of decoration, it also changes the colour of the game window as different objects connected to the MaKey MaKey are pressed).
When the object attached to a symbol on the MaKey MaKey is touched a key-press event corresponding to the key for that symbol is generated. When each key-press is recognised by Pygame Zero, an Open Sound Control (OSC) message is sent to a simultaneously running Sonic Pi script saying which symbol has been activated. (This version assumes that both Sonic Pi and Pygame Zero are running on the same machine). The Pygame Zero script looks like this:
from random import randint from pythonosc import osc_message_builder from pythonosc import udp_client # set size of Pygame Zero window WIDTH = 800 HEIGHT = 600 # where to send the OSC messages sender = udp_client.SimpleUDPClient("127.0.0.1", 4559) # screen colors screen_r = 0 screen_g = 0 screen_b = 0 def draw(): screen.fill((screen_r, screen_g, screen_b)) # for LEFT, RIGHT, UP, DOWN and SPACE symbols on MaKey MaKey. # Add extra key connections from jumper wires on back of the # MaKey MaKey here (e.g. w,s,a,d) def on_key_up(key): global screen_r, screen_g, screen_b, sender if key == keys.UP: screen_r = 0 screen_g = 255 screen_b = 255 sender.send_message('/play', 0 ) elif key == keys.RIGHT: screen_r = 0 screen_g = 0 screen_b = 255 sender.send_message('/play', 1 ) elif key == keys.DOWN: screen_r = 0 screen_g = 255 screen_b = 0 sender.send_message('/play', 2 ) elif key == keys.LEFT: screen_r = 255 screen_g = 255 screen_b = 0 sender.send_message('/play', 3 ) elif key == keys.SPACE: screen_r = 0 screen_g = 255 screen_b = 0 sender.send_message('/play', 4 ) else: pass return #for CLICK symbol on MaKey MaKey def on_mouse_up(): global screen_r, screen_g, screen_b, sender screen_r = 255 screen_g = 0 screen_b = 0 sender.send_message('/play', 5 ) return
Meanwhile, over in Sonic Pi, the sound each MaKey MaKey symbol triggers is set:
up = "cue :upcue" down = "sample :misc_crow" left = "sample :perc_snap" right = "sample :ambi_choir" space = "use_synth :hoover \n play :c4" click = "play :g5"
Most of these are single commands that play a note or sample, but it’s possible to trigger a series of commands. The variable up
is set to cue one iteration of this live loop which then goes “back to sleep” until it sees another :upcue
cue.
# loop triggered by pressing 'up' symbol live_loop :uploop do sync :upcue with_fx :echo do sample :bass_trance_c sleep 1 sample :bd_haus sleep 0.5 sample :bd_haus sleep 0.5 end end
Each of the variables relating to MaKey MaKey symbols are stored in a list. This makes it easy to reference them by position in the list, and this position can be sent over as part of the OSC message.
sounds = [up, right, down, left, space, click]
The second live loop in the script keeps a look-out for messages tagged ‘/osc/play’. It then gets the numerical parameter from the message and uses the run_code
command to run the corresponding command in the sounds
list. So touching the “up” symbol would send the message “/osc/play, 0′.
# looks for messages from the MaKey MaKey via Pygame Zero # and runs appropriate command live_loop :get_note do use_real_time set_sched_ahead_time! 0 #prevents 'lag' on sound playing symbol = sync "/osc/play" run_code sounds[symbol[0]] end
To have a go at this yourself, download and install Sonic Pi and Pygame Zero (instructions and files for all platforms are available on their respective websites and both programs are free).
Download the code detailed above here: https://github.com/alcluith/makey-sonic-pi. Open the file makeymakey-demo.rb
in a Sonic Pi buffer and start it running.
Connect your MaKey MaKey to a USB port and run the Pygame Zero script from the terminal by typing pgzrun path-on-your-computer/makey-osc-sonicpi.py
. A new window should open which will be black at first. Click onto this to make sure it’s in focus and it will change colours as different objects connected to the MaKey MaKey are touched, accompanied by your chosen sounds on Sonic Pi.
Robin Newman’s blog on setting up two-way OSC messages between Sonic Pi and the GPIO pins on a Raspberry Pi was very useful for this project. As was Jonathan Hogg’s Sonic Pi Sequencer code.
2 thoughts on “Sonic Pi goes bananas”