Skip to content

Instantly share code, notes, and snippets.

@rbnpi
Last active November 2, 2020 00:15
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rbnpi/d7d99bb9cd06680aed468ec90273b4d9 to your computer and use it in GitHub Desktop.
Save rbnpi/d7d99bb9cd06680aed468ec90273b4d9 to your computer and use it in GitHub Desktop.
Control Sonic PI 3 from a wireless PS3 games controller See video at https://youtu.be/8HcHKyhZaSM
#!/usr/bin/env python3
#ps3 wireless controller interface by Robin Newman July 2017
#converts controller inputs to OSC messages
#which can be output to Sonic Pi 3, running on the local computer, or on an external machine
#rtested with ps3 "afterglow" wireless controller, dongle in Pi usb socket
#needs sudo apt-get install joystick after sudo apt-get update
#also needs sudo pip3 install python-osc
#Version 2. Modified to ensure clean exit on Ubuntu
import subprocess,pygame,sys
from signal import pause
from pythonosc import osc_message_builder
from pythonosc import udp_client
import argparse
from time import sleep
pygame.display.init()
pygame.joystick.init()
clock=pygame.time.Clock()
ps3 = pygame.joystick.Joystick(0)
ps3.init()
def control(spip):
gate=0.1
sender=udp_client.SimpleUDPClient(spip,4559) #sender set up for specified IP
while True:
try:
print("ps3.py: Python ps3-> OSC interface")
print ("Specify external Sonic Pi with ./ps3.py --sp [SP3 IP ADDRESS] on command line")
print("For local Sonic Pi 3 just use ./ps3.py")
print ("Ctrl-C to exit")
pygame.event.pump()
lud=ps3.get_axis(1)
llr=ps3.get_axis(0)
rud=ps3.get_axis(3)
rlr=ps3.get_axis(2)
if abs(rud) > gate:
sender.send_message('/rud',-rud)
if abs(lud) > gate:
sender.send_message('/lud',-lud)
if abs(rlr) > gate:
sender.send_message('/rlr',rlr)
if abs(llr) > gate:
sender.send_message('/llr',llr)
b0=ps3.get_button(0)
if b0>0:
sender.send_message('/b0',b0)
b1=ps3.get_button(1)
if b1>0:
sender.send_message('/b1',b1)
b2=ps3.get_button(2)
if b2>0:
sender.send_message('/b2',b2)
b3=ps3.get_button(3)
if b3>0:
sender.send_message('/b3',b3)
b4=ps3.get_button(4)
if b4>0:
sender.send_message('/b4',b4)
b5=ps3.get_button(5)
if b5>0:
sender.send_message('/b5',b5)
b6=ps3.get_button(6)
if b6>0:
sender.send_message('/b6',b6)
b7=ps3.get_button(7)
if b7>0:
sender.send_message('/b7',b7)
b8=ps3.get_button(8)
if b8>0:
sender.send_message('/b8',b8)
b9=ps3.get_button(9)
if b9>0:
sender.send_message('/b9',b9)
b10=ps3.get_button(10)
if b10>0:
sender.send_message('/b10',b10)
b11=ps3.get_button(11)
if b11>0:
sender.send_message('/b11',b11)
b12=ps3.get_button(12)
if b12>0:
sender.send_message('/b12',b12)
hat=ps3.get_hat(0)
if hat[0]!=0 and hat[1]!=0:
sender.send_message('/hat',hat)
clock.tick(20)
subprocess.call("clear")
except KeyboardInterrupt:
print("\nExiting")
sys.exit()
if __name__=="__main__":
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("--sp",
default="127.0.0.1", help="The ip to listen on")
args = parser.parse_args()
spip=args.sp
print("Sonic Pi on ip",spip)
sleep(2)
control(spip)
#Demo program showing Sonic Pi 3 and PS3 control
#written by Robin Newman, July 2017
#uses a python script on the Raspberry Pi to
#interface to an "AfterGlow" wireless ps3 controller
#The script sends OSC messages with the PS3 data to Sonic Pi
#Which can be running on the Pi, or on a remote machine
# inputs are from:
#osc messages from the following
#llr and lud values for left left-right and left uo-down jopystick -1->+1
#rlr and rud values for right -left-right and right up-down joystick -1->+1
#hat values from the hat control [a,b] where a is -1 or 1 and b is -1 or 1
#b0 to b12 values for the 13 buttons. (1)
#sender ignores 0 values and doesn't send them (threshold +-0.1 for joysticks)
#this cuts down a huge amount of OSC messages
#sender program polls values in a loop and sends when not 0 or > threshold
use_debug false
use_cue_logging false
#initialise set values. These are used to communicate with the various live_loops
set :vinc,1 #used to hold controlled volume level
set :ncontrol,72 #used to hold controlled note for "long note"
set :kill,0 #used to kill "long note"
set :mutevol,1 #used to mute/unmute "long note"
set :cutoff_val,80 #cutoff value for "long note"
set :opt_in, 1 #lets ps3 buttons opt in/out of controlled volume
set :syn_pointer, 0 #pints to current synth for buttons and "long note"
set :syn,:tri #current synth name for buttons and "long note"
define :pdec2 do |n| #for nice printing
return (n.to_f*100).round.to_f/100
end
###################### CONTROL SECTION ADJUSTING VOLUME, SYNTHS, MUTING ETC ################
define :vv do |a| #function to switch control of amp setting according to "a"
if a==1
return get(:vinc)
else
return 1
end
end
live_loop :hat do #used to adjust controlled volume level
use_real_time
b=sync "/osc/hat"
val=b[1]
set :vinc,[get(:vinc)+0.1,2].min if b[1]==1
set :vinc,[get(:vinc)-0.11,0].max if b[1]==-1
puts "volume set",pdec2(get(:vinc))
end
live_loop :kill do #used to kill "long" note (and set vol to 0 for remainder)
b=sync "/osc/b12"
set :kill,1
sleep 1
set :kill,0
end
live_loop :long_pitch do #used to change pitch of "long" note
use_real_time
b= sync "/osc/rud"
#puts "long_pitch",pdec2((b[0]*36+72)),"cutoff"
set :ncontrol,b[0]*36+72
puts "Long Note pitch:",pdec2(get(:ncontrol)),"Cutoff:",pdec2(get(:cutoff_val))
end
live_loop :mute do #used to temporarily mute "long note"
use_real_time
b=sync "/osc/b8"
set :mutevol,0
end
live_loop :unmute do #used to unmute "long note"
use_real_time
b=sync "/osc/b9"
set :mutevol,1
end
live_loop :control_btn_vols do #osed to opt buttons in/out of controlled volume
use_real_time
b=sync "/osc/b10"
set(:opt_in,get(:opt_in)*-1)
if get(:opt_in) ==1
puts "Button volume controlled"
else
puts "Button volume NOT controlled"
end
sleep 0.4
end
live_loop :rlr do #used to adjust "long note" cutoff
use_real_time
b= sync "/osc/rlr"
set :cutoff_val,b[0]*40+80
puts "Long Note pitch:",pdec2(get(:ncontrol)),"Cutoff:",pdec2(get(:cutoff_val))
end
live_loop :llr do #used to select synth for buttons
use_real_time
slist=[:sine,:tri,:saw,:prophet,:tb303,:fm,:mod_saw,:mod_fm]
b= sync "/osc/llr"
p=get(:syn_pointer)
p=[p+1,slist.length-1].min if b[0] > 0.4
p=[p-1,0].max if b[0] < -0.4
set :syn_pointer,p
set(:syn,slist[p])
puts "syn is",get(:syn)
sleep 0.4
end
############################ PLAYING SECTION BELOW ############################
with_fx :reverb,room: 0.99 do #start playing section here inside reverb
live_loop :continuous_note do #setup up "long note" and control it
use_real_time
x= sync "/osc/b11" #start the "long" note
use_synth get(:syn)
n= play 72,sustain: 200,amp: 0 #start "long note" with zero volume
control n,note: 72
2000.times do
control n,note: get(:ncontrol),note_slide: 0.1,amp: get(:mutevol)*get(:vinc),amp_slide: 0.1,cutoff: get(:cutoff_val),cutoff_slide: 0.1
sleep 0.1
break if get(:kill)==1 #if kill set abort loop and set vol of note to 0
end
control n, amp: 0
end
live_loop :lud do #adjust pitch of :sine synth with joystick
use_real_time
f = sync "/osc/lud"
synth :sine,note: f[0]*24+60,attack: 0.15,release: 0.2,amp: get(:vinc) #or use synth get(:syn)
end
live_loop :bt0 do #play set note :c4 with chosen synth
use_real_time
b= sync "/osc/b0"
synth get(:syn),note: :c4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt1 do #remaining buttons similar with pitch increased each button
use_real_time
b= sync "/osc/b1"
synth get(:syn),note: :d4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt2 do
use_real_time
b= sync "/osc/b2"
synth get(:syn),note: :e4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt3 do
use_real_time
b= sync "/osc/b3"
synth get(:syn),note: :f4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt4 do
use_real_time
b= sync "/osc/b4"
synth get(:syn),note: :g4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt5 do
b= sync "/osc/b5"
use_real_time
synth get(:syn),note: :a4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt6 do
use_real_time
b= sync "/osc/b6"
synth get(:syn),note: :b4,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
live_loop :bt7 do
use_real_time
b= sync "/osc/b7"
synth get(:syn),note: :c5,attack: 0.1,release: 0.2,amp: vv(get(:opt_in)) if b[0]==1
end
end #fx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment