Let me tell you a story : let suppose into Ableton live you want to launch a sample, pause it then restart from this stop position ? You think : "oh come on, there must be a feature to do this, no ? ". Well, it seems no. The Launch behaviour will always start from the beginning of the clip sample.
Ok now, what if sonic pi could do this !
function pause(sample), function restart(sample)
I’m looking for this behaviour to create a quizz musical system : 20 songs = 20 samples. A button to trigger the play and pause/restart (interface build with open-stage-control) ; this button would send an osc message to sonicpi on the good osc adress.
But and there is a big but i haven’t no clue how to get these two functions. Maybe it could be native functions in the future
You can get somewhere close to this with the built in functionality:
# Choose a sample
samp = :guit_harmonics
# Make a note of current time
t0 = current_time
# Start playing sample
x = sample samp
# Wait a bit
sleep 1
# Stop the sample
kill x
# Find out how much time has elapsed
t = current_time - t0
# Wait a bit so we can hear the break
sleep 1
# Restart sample where it left off
sample samp, start: t / sample_duration(samp)
I can’t figure out to handle the conditions coming from osc. I guess i will need two osc messages /sample/start 1 to play /sample/start 0 to pause
these are the states of the toggle button
# 13/07/2022
# start quizz musical project
puts 'welcome'
# some osc parameters
# the software openStageControl will be refered as o-s-c
use_osc_logging true;
# o-s-c port input for osc messages ios 7777, on the same machine at the moment
use_osc "127.0.0.1", "7777"
comment do # uncomment to test
4.times do
osc "/sample/start", 1
sleep 2
osc "/sample/start", 0
sleep 2
end
stop
end
# Choose a sample
samp = :loop_amen_full
# if we receive an osc message from the address /sample/start with a value of 1
##| comment do
##| live_loop :oscListener do
##| flag1 = get "/osc*/sample/start"
##| flag2 = get "/osc*/flag2"
##| flag3 = get "/osc*/flag3"
##| flag4 = get "/osc*/flag4" #nothing sent to this address (by me!) so always nil
##| if !(flag1==nil)
##| set :playSample, flag1[0]
##| end
##| puts flag2[0] if !(flag2==nil)
##| puts flag3[0] if !(flag3==nil)
##| puts flag4[0] if !(flag4==nil)
##| sleep 1
##| end
##| end
##| live_loop :lecture do
##| sync "/live_loop/oscListener"
##| use_real_time
##| puts(get :playsample)
##| end
set :alreadyPlayed, false
live_loop :toCatchTheState do
use_real_time
d = sync "/osc:127.0.0.1:7777/sample/start"
# hello will be printed if spi received the osc message
puts "hello"
puts get[:alreadyPlayed]
if d[0]==1 # 1 for the button on
set :t0, current_time
if get[:alreadyPlayed]===true
# Restart sample where it left off
sample samp, start: get[:t] / sample_duration(samp)
else
# Make a note of current time
# Start playing sample
x = sample samp
set :alreadyPlayed, true
end
else
# Stop the sample
puts "Kill me"
kill x
# Find out how much time has elapsed
boo = get[:t0]
set :t , current_time - boo
# Wait a bit so we can hear the break
end
sleep 0.1
end
I had a little play around with it, and I think I got it working:
# 13/07/2022
# start quizz musical project
puts 'welcome'
# some osc parameters
# the software openStageControl will be refered as o-s-c
use_osc_logging true;
# o-s-c port input for osc messages ios 7777, on the same machine at the moment
use_osc "127.0.0.1", 4560
uncomment do # uncomment to test
in_thread do
4.times do
osc "/sample/start", 1
sleep 2
osc "/sample/start", 0
sleep 2
end
end
end
# Choose a sample
samp = :loop_amen_full
set :elapsed, 0.0
live_loop :toCatchTheState do
use_real_time
d = sync "/osc*/sample/start"
if d[0]==1 # 1 for the button on
elapsed = get[:elapsed]
puts "Starting sample at", elapsed
set :t0, current_time
set :sample, (sample samp, start: elapsed / sample_duration(samp))
else
# Stop the sample
kill get[:sample]
# Find out how much time has elapsed
elapsed = get[:elapsed] + current_time - get[:t0]
set :elapsed, elapsed
puts "Stopping sample at", elapsed
end
end
Here’s some of the log output (a screenshot as I couldn’t copy the text):
I had a little play with this too, and adjusted it to use ableton transport via link. I also adjusted it to run continuously, switching to a different sample (if required) once the first one had ended.
#extra code to allow ableton transport to control things via link
use_osc "localhost",4560
link
#the next two live loops convert /link start and stop to osc "/sample/start"
live_loop :start do
use_real_time
sync "/link/start"
osc "/sample/start",1
end
live_loop :stop do
use_real_time
sync "/link/stop"
osc "/sample/start",0
end
#end of extra code
# 13/07/2022
# start quizz musical project
puts 'welcome'
# some osc parameters
# the software openStageControl will be refered as o-s-c
use_osc_logging true;
# o-s-c port input for osc messages ios 7777, on the same machine at the moment
use_osc "127.0.0.1", 4560
comment do # uncomment to test
in_thread do
4.times do
osc "/sample/start", 1
sleep 2
osc "/sample/start", 0
sleep 2
end
end
end
# Choose a sample
samp = :loop_amen_full
set :elapsed, 0.0
live_loop :toCatchTheState do
use_real_time
d = sync "/osc*/sample/start"
puts "d is ",d
if d[0]==1 # 1 for the button on
#rest if end of sample reached: can also choose new sample here
if get(:elapsed) >= sample_duration(samp)
set :elapsed,0
#choose next sample to use
samp = ring(:loop_tabla,:loop_amen_full).tick
end
elapsed = get(:elapsed)
puts "Starting sample at", elapsed
set :t0, current_time
set :sample, (sample samp, start: elapsed / sample_duration(samp))
else
# Stop the sample
kill get[:sample]
# Find out how much time has elapsed
elapsed = get[:elapsed] + current_time - get[:t0]
set :elapsed, elapsed
puts "Stopping sample at", elapsed
end
end
Look in my example above. You test that elapsed is not >= the sample duration and if so reset it to 0 to start again. Then when you work out start = elapsed/sample_duration(samp) it will never be > 1
I actually siwtched to a differnt eample at that point, but you could stay with the same one.