Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simon musical game for Sonic Pi and leds and buttons and LCD display (optional) on a Pi3 video at https://youtu.be/bCSlFwBt2iY
#!/usr/bin/env python3
#SPoschandler.py written by Robin Newman, July 2017 amended for this project Feb 2018
#Provides the "glue" to enable the GPIO on Raspberry Pi
#to communicate with Sonic Pi. Sonic Pi can control LEDs etc,and receive
#input from devices like push buttons connected to GPIO pins
#Sonic Pi can be running either on the Raspberry Pi,
#or on an external networked computer
#The program requires gpiod daemon to be running. Yu can install this with
#sudo apt-get update followed by sudo apt-get install pigpio if you don't have it
#best to set it up to auto start on boot using
#sudo systemctl enable pigpiod.service (followed by a reboot)
#The program also requires gpiozero to be installed and python-osc
from gpiozero import LED, Button
from pythonosc import osc_message_builder
from pythonosc import udp_client
from pythonosc import dispatcher
from pythonosc import osc_server
from time import sleep
import argparse
import sys
from Adafruit_CharLCD import * #add library to deal with lcd display
#for connection details see https://learn.adafruit.com/drive-a-16x2-lcd-directly-with-a-raspberry-pi/wiring
#library available from https://github.com/adafruit/Adafruit_Python_CharLCD download to same folder as this file
lcd=Adafruit_CharLCD() #set up instance for lcd display
#Specify connections for leds and buttons
#You can specify your own pin numbers if different
green = LED(14)
red = LED(16)
blue = LED(19)
yellow = LED(21)
dummy = LED(8)
button = Button(13)
button2 = Button(15)
button3 = Button(18)
button4 = Button(20)
#This function is called when the button connected to the GPIO is pushed
def mon1():
sender.send_message('/mon', [1,"g"])
def mon2():
sender.send_message('/mon', [2,"r"])
def mon3():
sender.send_message('/mon', [3,"b"])
def mon4():
sender.send_message('/mon', [4,"y"])
button.when_pressed = mon1
button2.when_pressed = mon2
button3.when_pressed = mon3
button4.when_pressed = mon4
#This is activated when /led/control OSC message is received by the server.
#two arguments r and b contain 0 or 1 and are used to control the red and blue leds
def handle_leds(unused_addr,args,v):
print("Sent from Sonic Pi",v)
if v=="g":
green.on()
else:
green.off()
if v=="r":
red.on()
else:
red.off()
if v=="b":
blue.on()
else:
blue.off()
if v=="y":
yellow.on()
else:
yellow.off()
def handle_score(unused_addr,args,sc,hsc):
print("Sent from Sonic Pi scores ",sc,hsc)
lcd.clear()
lcd.message("Your score "+str(sc)+"\nHi-score "+str(hsc))
#The main routine called when the program starts up follows
if __name__ == "__main__":
try: #use try...except to handle possible errors
#first set up and deal with input args when program starts
parser = argparse.ArgumentParser()
#This arg gets the server IP address to use. 127.0.0.1 or
#The local IP address of the PI, required when using external Sonic Pi
parser.add_argument("--ip",
default="127.0.0.1", help="The ip to listen on")
#This is the port on which the server listens. Usually 8000 is OK
#but you can specify a different one
parser.add_argument("--port",
type=int, default=8000, help="The port to listen on")
#This is the IP address of the machine running Sonic Pi if remote
#or you can omit if using Sonic Pi on the local Pi.
parser.add_argument("--sp",
default="127.0.0.1", help="The ip Sonic Pi is on")
args = parser.parse_args()
if args.ip=="127.0.0.1" and args.sp !="127.0.0.1":
#You must specify the local IP address of the Pi if trying to use
#the program with a remote Sonic Pi aon an external computer
raise AttributeError("--ip arg must specify actual local machine ip if using remote SP, not 127.0.0.1")
#Provide feed back to the user on the setup being used
if args.sp == "127.0.0.1":
spip=args.ip
print("local machine used for SP",spip)
else:
spip=args.sp
print("remote_host for SP is",args.sp)
#setup a sender udp-client to send out OSC messages to Sonic Pi
#Sonic Pi listens on port 4559 for incoming OSC messages
sender=udp_client.SimpleUDPClient(spip,4559) #sender set up for specified IP
#dispatcher reacts to incoming OSC messages and then allocates
#different handler routines to deal with them
dispatcher = dispatcher.Dispatcher()
#A handler routine handle_leds is specified
#which deals with the OSC message /led/control being received
dispatcher.map("/led/control",handle_leds,"v")
# handler routie handle_receives the score and hiscore
dispatcher.map("/sendscores",handle_score,"sc","hsc")
#The following handler responds to the OSC message /testprint
#and prints it plus any arguments (data) sent with the message
dispatcher.map("/testprint",print)
#Now set up and run the OSC server
server = osc_server.ThreadingOSCUDPServer(
(args.ip, args.port), dispatcher)
print("Serving on {}".format(server.server_address))
#run the server "forever" (till stopped by pressing ctrl-C)
server.serve_forever()
#deal with some error events
except KeyboardInterrupt:
print("\nServer stopped") #stop program with ctrl+C
#Used the AttributeError to specify problems with the local ip address
except AttributeError as err:
print(err.args[0])
#handle errors generated by the server
except OSError as err:
print("OSC server error",err.args)
#anything else falls through
#Game of Simon for Sonic Pi, swtiches and leds and LCD display
#by Robin Newman, February 2018
use_osc 'localhost',8000
use_debug false
use_osc_logging false
use_random_seed(Time.now.nsec/10000)
osc "/led/control","o"
osc "/sendscores",0,0
sleep 0.2
set :button,""
set :pattern,[]
set :score,0
set :hiscore,0
set :currentstep,0
use_real_time
define :ledon do |s|
osc "/led/control",s
case s
when "g"
play :e3,release: 0.3
when "r"
play :cs4,release: 0.3
when "b"
play :e4,release: 0.3
when "y"
play :a4,release: 0.3
end
sleep 0.3
osc"/led/control","o"
sleep 0.01
end
define :getbutton do
b = sync "/osc/mon"
set :button, b[1]
puts "Pushed",b[1]
if get(:inputmode)
p=get(:pattern)
c=get(:currentstep)
if b[1] == p[c]
ledon p[c]
sleep 0.2
c+=1
if c == p.length
sc=get(:score)
hsc=get(:hiscore)
set :score,sc+1
hsc=sc+1 if sc+1 > hsc
set :hiscore,hsc
puts "Your score is",sc+1
puts "Hi-score is",hsc
osc "/sendscores",sc+1,hsc
set :currentstep,0
sample :perc_till
puts "well done"
sleep 1
set :inputmode,false
else
set :currentstep, c
end
elsif
b[1] != p[c]
set :pattern,[]
set :currentstep,0
set :score,0
sample :misc_crow
puts "you made a mistake"
osc "/sendscores",0,get(:hiscore)
use_random_seed(Time.now.nsec/10000) #reset random seed
sleep 1
set :inputmode,false
end
end
end
live_loop :game do
use_real_time
set :inputmode,false
if get(:inputmode) == false
p=get(:pattern)
set :pattern, p+ [["g","r","b","y"].choose]
p=get(:pattern)
puts "pattern set to ",p
p.length.times do |x|
ledon p[x]
sleep 0.2
end
set :inputmode,true
until get(:inputmode)==false
getbutton
sleep 0.05
end
end
end
@rbnpi
Copy link
Author

rbnpi commented Feb 20, 2018

These two files enable you to play the musical Simon game on a Raspberry Pi3 using Sonic Pi 3.0.1 or later and breadboard connections containing the circuitry for 4 LEDs and 4 buttons and an optional LCD display. I used a Rasp.IO ProHat with the LCD mounted on it (plus the contrast pot), and a separate breadboard with the LEDS and pushbuttons. I haven't done a wiring diagram (yet) but there is a link to the dafruit site for the LCD wiring, and the pins connected to the LEDs and Buttons are detailed in the python program. LEDs are wired directly between these pins and ground without seires reistors which are unneccessary on teh ProHat but may be needed if wired direct to the GPIO pins (around 330ohms). The buttons are wired directly from the button pins to ground, again the pins detailed in the program.
The pythion program requires the python-osc library which can be loaded using sudo pip3 install python-osc

YOu can use the programs with Sonic Pi running on the Raspberry Pi in which case launch the python script with
python3 OSChanderwithscore.py
or you can use Sonic Pi on a remote machine in which case launch it with
python3 OSChanderwithscore.py --ip IPaddress.of.local.machine --sp IPaddress.of.sonicpi.computer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment