Create a gist now

Instantly share code, notes, and snippets.

@rbnpi /ReadMe.md
Last active Mar 15, 2018

What would you like to do?
Sonic Pi Loop Controller. UPDATED VERSION 2 with NEW PROGRAM AND TOUCHOSC TEMPLATE ALSO PI3 VERSION This program arose out of a question on in-thread.sonic-pi.net inquiring how to control switching a live_loop on and off via a push button see https://in-thread.sonic-pi.net/t/osc-loop-machine-makeymakey/850 See video at https://youtu.be/cEz-fOEF3M0

NOW UPDATED TO INCLUDE CONTROL OF THE BACKGROUND PULSE AND SCREEEN BOTH PROGRAM AND TOUCHOSC TEMPLATE CHANGED

A SEPARATE VERSION TUNED FOR Pi3 IS ALSO INCLUDED The original question was concerned with using mekey-makey as the "switch input" source. Here I have used a TouchOSC template with 11 pushbuttons on it as the input source. To make it more interesting, I also drive a large "LED" on the TouchOSC screen with OSC commands from the Sonic Pi program. The program has been streamlined to use just ONE live loop to detect the switches being pushed, and another to detect them being released. Sonic Pi supports wild cards in OSC addresses, and using the undocumented get_event function I have parsed the received address and obtained the information as to which switch has been activated. In the original development separate live Loops were used for each button. Also, in the first versions I developed separate functions for dealing with each button, which led to some repetition in code. In this version I have developed generic functions for each required use, into which the samples to be used, plus information about which button has been pressed, can be fed.

To produce the TouchOSC template, download the index.xml file and compress, or zip it. REname the resulting .zip file as Loop.Control.touchosc YOu can then load it into the TouchOSC editor and send it via WiFi to the tablet or phone with TouchOSC on it. TouchOSC is produced by https://hexler.net/

The Sonic PI file SPloopController.rb should be copied to a Sonic Pi buffer and run there. You should adjust the IP address in the program to suit your Tablet or Phone running TouchOSC, and set that to point to the IP address of the machine running Sonic Pi USE THE SEPARATE VERSION FRO PI3. Differences: slightly less agressive timings in the functions and live loops places less stress on the program. Most fx wrappers removed which stops distortion and crashing. It works quite well, although response time is slightly worse. YOu may get better performacne using a wired network connection, rather than wireless. I have also tried this on a new Pi3 B+ just released. This has much faster wifi access.

<?xml version="1.0" encoding="UTF-8"?><layout version="16" mode="0" orientation="horizontal"><tabpage name="MQ==" scalef="0.0" scalet="1.0" li_t="" li_c="gray" li_s="14" li_o="false" li_b="false" la_t="" la_c="gray" la_s="14" la_o="false" la_b="false" ><control name="bGVkMQ==" x="19" y="81" w="275" h="275" color="brown" scalef="0.0" scalet="1.0" type="led" ></control><control name="cHVzaDE=" x="132" y="84" w="45" h="45" color="red" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDI=" x="194" y="106" w="45" h="45" color="green" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDM=" x="238" y="164" w="45" h="45" color="blue" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDQ=" x="237" y="226" w="45" h="45" color="orange" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDU=" x="194" y="283" w="45" h="45" color="yellow" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="bGFiZWwx" x="19" y="26" w="268" h="25" color="yellow" type="labelh" text="U29uaWMgUGkgTG9vcCBDb250cm9sbGVy" size="18" background="true" outline="false" ></control><control name="bGFiZWwy" x="29" y="372" w="247" h="25" color="red" type="labelh" text="UHJlc3MgYnV0dG9ucyB0byBjb250cm9sIGxvb3Bz" size="14" background="true" outline="false" ></control><control name="cHVzaDY=" x="132" y="306" w="45" h="45" color="red" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDc=" x="74" y="281" w="45" h="45" color="yellow" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDg=" x="32" y="226" w="45" h="47" color="orange" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDk=" x="31" y="167" w="45" h="45" color="blue" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDEw" x="73" y="110" w="45" h="45" color="green" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="cHVzaDEx" x="134" y="193" w="45" h="45" color="pink" scalef="0.0" scalet="1.0" type="push" local_off="false" sp="true" sr="true" ></control><control name="bGFiZWwz" x="64" y="408" w="178" h="20" color="blue" type="labelh" text="d3JpdHRlbiBieSBSb2JpbiBOZXdtYW4=" size="14" background="true" outline="false" ></control><control name="Ymc=" x="277" y="397" w="40" h="40" color="yellow" scalef="0.0" scalet="1.0" type="toggle" local_off="false" ></control><control name="bGFiZWw0" x="286" y="406" w="22" h="22" color="yellow" type="labelh" text="Ymc=" size="14" background="true" outline="false" ></control></tabpage></layout>
#Sonic Pi Loop Controller by Robin Newman
#VERSION 2 ADDS CONTROL OF BACKGROUND PULSE AND SCREEN
#Tested on a Mac: this version NOT sutiable for Pi3
#in particular uses some new :loop samples only in version 3.1
#These can be copied to teh samples folder on version 3.0.1 if required
#or you can specify different ones.
#Also may have to cut down use of fx calls on Pi3 as may overload it otherwise.
#This version uses 11 push buttons on TouchOSC for input and 1 LED on TouchOSC for output
#Can be modified to use any suitable OSC source thant can give on/off signals when a button is pressed
use_real_time
use_osc "192.168.1.240",9000 #adjust for output IP to which to send LED on/off signals (TouchOSC)
use_bpm 120
path="~/Desktop/samples/"
#turn background sound and led offloo
set :bg,0
osc "/1/bg",0
use_debug false
use_osc_logging false
#input on and off live_loops to detect inputs
define:parse_sync_address do |address|
v= get_event(address).to_s.split(",")[6]#[address.length+1..-2].to_i
if v != nil
return v[3..-2].split("/")
else
return ["error"]
end
end
live_loop :pon do
b = sync "/osc/1/push*"
if b[0]==1
r=parse_sync_address "/osc/1/push*"
ns= r[2][4..-1]
set ("c"+ns).to_sym,1
doCommandSelect(ns .to_i)
end
end
live_loop :poff do
b = sync "/osc/1/push*"
if b[0]==0
r=parse_sync_address "/osc/1/push*"
ns= r[2][4..-1]
set ("c"+ns).to_sym,0
end
end
define :doCommandSelect do |n|
puts n
case n
when 1
with_fx :gverb,room: 25,mix: 0.8 do
doLoop 1,0.5,:loop_amen,4 #parameters: channel,vol,samplename,beatstrech value
end
when 2
doLoop 2,0.5,:loop_garzul,16
when 3
with_fx :gverb,room: 25,mix: 0.8 do
doLoop 3,0.8,:loop_compus,16
end
when 4
doLoop 4,0.9,:loop_mehackit1,4
when 5
with_fx :gverb,room: 25,mix: 0.8 do
doLongNote 5,0.5,:fm,:c3,4 #parameters channel, vol,synth,note,repeat duration*****
#*** can add an optiona beat_stretch, but probably not required
end
when 6
with_fx :gverb,room: 25,mix: 0.8 do
doLoopSequence 6,0.1,:tb303 #parameters channel, vol,synth
end
when 7
doLoop 7,0.7,:loop_mika, 16
when 8
doLoop 8,0.7, :loop_weirdo, 4
when 9
doLoop 9,0.9,:loop_safari,16 #doSingleSample
when 10
doLoop 10,0.7, :loop_mehackit2,4
when 11
with_fx :gverb,room: 20,mix: 0.8 do
doOneShot 11,4,path+"testsample.flac" #parameters channel,vol,sample
#as a singleShot plays once so only sync the start
end
else
puts "nothing"
end
end
#general function to set up stoppable live_loop
define :doLoop do |n,vol,sampleName,bs,|
set ("kill"+n.to_s).to_sym,false
ln=("name"+n.to_s).to_sym
in_thread do
loop do
if get( ("c"+n.to_s).to_sym)==0
s= get( ("s"+n.to_s).to_sym)
kill s
set ("kill"+n.to_s).to_sym, true
stop
end
sleep 0.1
end
end
live_loop ln, sync: :metro do
s=sample sampleName,beat_stretch: bs,amp: vol
set ("s"+n.to_s).to_sym,s
k=(bs/0.1).to_i
k.times do
sleep bs.to_f/k
stop if get( ("kill"++n.to_s).to_sym)
end
end
end
#general function to start stoppable single shot sample
define :doOneShot do |n,vol,sampleName,bs=0|
sync :metro
if bs >0
s=sample sampleName,beat_stretch: bs,amp: vol
else
s=sample sampleName,amp: vol
end
in_thread do
loop do
if get( ("c"++n.to_s).to_sym)==0
kill s
stop
end
sleep 0.1
end
end
end
#general function to set up long repeating note
define :doLongNote do |n,vol,synth,note,dur|
set ("kill"+n.to_s).to_sym,false
ln=("name"+n.to_s).to_sym
in_thread do
loop do
if get( ("c"+n.to_s).to_sym)==0
s= get( ("s"+n.to_s).to_sym)
control s,amp: 0,amp_slide: 0.05
sleep 0.05
kill s
set ("kill"+n.to_s).to_sym, true
stop
end
sleep 0.1
end
end
live_loop ln, sync: :metro do
use_synth synth
s=play note,sustain: dur-1,release: 1,cutoff: 100,amp: vol
set ("s"+n.to_s).to_sym,s
k=(dur/0.1).to_i
k.times do
sleep dur.to_f/k
stop if get( ("kill"++n.to_s).to_sym)
end
end
end
#function to setup sequence of notes (stoppable)
define :doLoopSequence do |n,vol,synth|
set ("kill"+n.to_s).to_sym,false
ln=("name"+n.to_s).to_sym
in_thread do
loop do
if get( ("c"+n.to_s).to_sym)==0
set ("kill"+n.to_s).to_sym, true
stop
end
sleep 0.1
end
end
live_loop ln, sync: :metro do
use_synth synth
play scale(:c3,:minor_pentatonic,num_octaves: 2).choose,release: 0.20,amp: vol,cutoff: rrand_i(60,120)
10.times do #do this to get a quicker response time
sleep 0.25 / 10
stop if get(("kill"+n.to_s).to_sym)
end
end
end
live_loop :metro do #metronome to sync stuff together
sleep 1
end
live_loop:background do
b = sync "/osc/1/bg"
set :bg,b[0]
end
#Optional repeating pulse
with_fx :gverb,room: 15,mix: 0.8,amp: 0.5 do
live_loop :alwaysplaying,sync: :metro do #runs continuously playing
use_synth :fm
play :c3,release: 1,amp: 1,pan: -0.8 if get(:bg)==1
play :c4,release: 2,amp: 0.2,pan: -0.8 if get(:bg)==1
osc "/1/led1",1 if get(:bg)==1#switch on large LED on TouchOSC screen
sleep 1
osc "/1/led1",0 #switch on large LED on TouchOSC screen
sleep 1
play :c3,release: 2,amp: 1,pan: 0.8 if get(:bg)==1
osc "/1/led1",1 if get(:bg)==1#switch on large LED on TouchOSC screen
sleep 1
osc "/1/led1",0 #switch off large LED on TouchOSC screen
sleep 1
end
end
#Sonic Pi Loop Controller by Robin Newman
#VERSION 2 ADDS CONTROL OF BACKGROUND PULSE AND SCREEN
#THIS VERSION TESTED ON Pi3 B and Pi3 B+
#in particular uses some new :loop samples only in version 3.1
#These can be copied to teh samples folder on version 3.0.1 if required
#or you can specify different ones.
#Also may have to cut down use of fx calls on Pi3 as may overload it otherwise.
#This version uses 11 push buttons on TouchOSC for input and 1 LED on TouchOSC for output
#Can be modified to use any suitable OSC source thant can give on/off signals when a button is pressed
use_real_time #use_sched_ahead_time 0.2 #if problems
sleep 1
use_osc "192.168.1.240",9000 #adjust for output IP to which to send LED on/off signals (TouchOSC)
use_bpm 120
path="~/Desktop/samples/"
#turn background sound and led offloo
set :bg,0
osc "/1/bg",0
use_debug false
use_osc_logging false
#input on and off live_loops to detect inputs
define:parse_sync_address do |address|
v= get_event(address).to_s.split(",")[6]#[address.length+1..-2].to_i
if v != nil
return v[3..-2].split("/")
else
return ["error"]
end
end
live_loop :pon do
b = sync "/osc/1/push*"
if b[0]==1
r=parse_sync_address "/osc/1/push*"
ns= r[2][4..-1]
set ("c"+ns).to_sym,1
doCommandSelect(ns .to_i)
end
end
live_loop :poff do
b = sync "/osc/1/push*"
if b[0]==0
r=parse_sync_address "/osc/1/push*"
ns= r[2][4..-1]
set ("c"+ns).to_sym,0
end
end
define :doCommandSelect do |n|
puts n
case n
when 1
doLoop 1,0.5,:loop_amen,4 #parameters: channel,vol,samplename,beatstrech value
when 2
doLoop 2,0.5,:loop_garzul,16
when 3
doLoop 3,0.8,:loop_compus,16
when 4
doLoop 4,0.9,:loop_mehackit1,4
when 5
doLongNote 5,0.5,:fm,:c3,4 #parameters channel, vol,synth,note,repeat duration*****
#*** can add an optiona beat_stretch, but probably not required
when 6
doLoopSequence 6,0.3,:tb303 #parameters channel, vol,synth
when 7
doLoop 7,0.7,:loop_mika, 16
when 8
doLoop 8,0.7, :loop_weirdo, 4
when 9
doLoop 9,0.9,:loop_safari,16 #doSingleSample
when 10
doLoop 10,0.7, :loop_mehackit2,4
when 11
doOneShot 11,4,path+"testsample.flac" #parameters channel,vol,sample
#as a singleShot plays once so only sync the start
else
puts "nothing"
end
end
#general function to set up stoppable live_loop
define :doLoop do |n,vol,sampleName,bs,|
set ("kill"+n.to_s).to_sym,false
ln=("name"+n.to_s).to_sym
in_thread do
loop do
if get( ("c"+n.to_s).to_sym)==0
s= get( ("s"+n.to_s).to_sym)
kill s
set ("kill"+n.to_s).to_sym, true
stop
end
sleep 0.2
end
end
live_loop ln, sync: :metro do
s=sample sampleName,beat_stretch: bs,amp: vol
set ("s"+n.to_s).to_sym,s
k=(bs/0.25).to_i
k.times do
sleep bs.to_f/k
stop if get( ("kill"++n.to_s).to_sym)
end
end
end
#general function to start stoppable single shot sample
define :doOneShot do |n,vol,sampleName,bs=0|
sync :metro
if bs >0
s=sample sampleName,beat_stretch: bs,amp: vol
else
s=sample sampleName,amp: vol
end
in_thread do
loop do
if get( ("c"++n.to_s).to_sym)==0
kill s
stop
end
sleep 0.2
end
end
end
#general function to set up long repeating note
define :doLongNote do |n,vol,synth,note,dur|
set ("kill"+n.to_s).to_sym,false
ln=("name"+n.to_s).to_sym
in_thread do
loop do
if get( ("c"+n.to_s).to_sym)==0
s= get( ("s"+n.to_s).to_sym)
control s,amp: 0,amp_slide: 0.05
sleep 0.05
kill s
set ("kill"+n.to_s).to_sym, true
stop
end
sleep 0.2
end
end
live_loop ln, sync: :metro do
use_synth synth
s=play note,sustain: dur-1,release: 1,cutoff: 100,amp: vol
set ("s"+n.to_s).to_sym,s
k=(dur/0.25).to_i
k.times do
sleep dur.to_f/k
stop if get( ("kill"++n.to_s).to_sym)
end
end
end
#function to setup sequence of notes (stoppable)
define :doLoopSequence do |n,vol,synth|
set ("kill"+n.to_s).to_sym,false
ln=("name"+n.to_s).to_sym
in_thread do
loop do
if get( ("c"+n.to_s).to_sym)==0
set ("kill"+n.to_s).to_sym, true
stop
end
sleep 0.1
end
end
live_loop ln, sync: :metro do
use_synth synth
play scale(:c3,:minor_pentatonic,num_octaves: 2).choose,release: 0.20,amp: vol,cutoff: rrand_i(60,120)
2.times do #do this to get a quicker response time
sleep 0.25 / 2
stop if get(("kill"+n.to_s).to_sym)
end
end
end
live_loop :metro do #metronome to sync stuff together
sleep 1
end
live_loop:background do
b = sync "/osc/1/bg"
set :bg,b[0]
end
#Optional repeating pulse
with_fx :gverb,room: 15,mix: 0.8,amp: 0.5 do
live_loop :alwaysplaying,sync: :metro do #runs continuously playing
use_synth :fm
if get(:bg)==1
play :c3,release: 0.9,amp: 1,pan: -0.8
play :c4,release: 1.8,amp: 0.2,pan: -0.8
end
osc "/1/led1",1 if get(:bg)==1#switch on large LED on TouchOSC screen
sleep 1
osc "/1/led1",0 #switch on large LED on TouchOSC screen
sleep 1
if get(:bg)==1
play :c3,release: 1.8,amp: 1,pan: 0.8
osc "/1/led1",1#switch on large LED on TouchOSC screen
end
sleep 1
osc "/1/led1",0 #switch off large LED on TouchOSC screen
sleep 1
end
end #fx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment