I have deleted the original content of this post, which had errors, and was inefficient.
Instead, below is a function which enables you to extract data on all the onsets of a given sample.
It is based on the last example (35) on the sample command in the lang section of the help file.
l = lambda {|c| puts c ; c[0]}
sample :loop_tabla, onset: l
This uses a lambda function to print maps of all the onsets detected for a sample as it plays the first onset (number 0)
The function below, stores this list of maps in a time state variable :listOnsets, from where you can retrieve and use the data. A second function uses it to return the maximum number of onsets available for a given sample. (If you exceed this number it wraps around.
You only need this function if you want to use the onset data directly, as you can just play any onset using the opt :onset where is the number of teh offset you want, and there are several examples of doing this in the documentation for the sample command.
define :listOnsets do |s|
set :onsetsMaps,[] #initialise a blank list
l = lambda {|c| set :onsetsMaps,c.to_a; c[0]} #set the info obtained in :listonsets
sample s, onset: l,amp: 0,finish: 0 #trigger the lambda function played sample at 0 volume and finish=0
return get(:onsetsMaps)
end
returns a list of onset maps for sample s.
define :numOnsets do |s|
return listOnsets(s).length
end
returns the max number of offsets available for sample s
examples of use for these functions
puts numOnsets(:loop_amen) #=> 8
puts listOnsets(:loop_amen) #=> [(map start: 0.0, finish: 0.12092446149936513, index: 0), (map start: 0.12092446149936513, finish: 0.2489362505535867, index: 1), (map start: 0.2489362505535867, finish: 0.3793794731283408, index: 2), (map start: 0.3793794731283408, finish: 0.506343699835505, index: 3), (map start: 0.506343699835505, finish: 0.624888468941305, index: 4), (map start: 0.624888468941305, finish: 0.7459810636067014, index: 5), (map start: 0.7459810636067014, finish: 0.8765794755668737, index: 6), (map start: 0.8765794755668737, finish: 1.0, index: 7)]
puts listOnsets(:loop_amen)[3] #=> (map start: 0.3793794731283408,
# finish: 0.506343699835505,
# index: 3)
puts listOnsets(:loop_amen)[3][:index] #=> 3
puts listOnsets(:loop_amen)[3][:start] #=> 0.3793794731283408
puts listOnsets(:loop_amen)[3][:finish] #=> 0.506343699835505
A further more substantial example, uses all the loop samples in Sonic Pi and plays them with the onsets on random order, and also adjusts the proportion of the onset that is played, thus leaving gaps, but with the overall duration of the loop unaltered. loops with only 1 onset are ignored.
define :listOnsets do |s|
set :onsetsMaps,[] #initialise a blank list
l = lambda {|c| set :onsetsMaps,c.to_a; c[0]} #set the info obtained in :listonsets
sample s, onset: l,amp: 0,finish: 0 #trigger the lambda function played sample at 0 volume and finish=0
return get(:onsetsMaps)
end
define :numOnsets do |s|
return listOnsets(s).length
end
live_loop :choppedSample do
onsets=[] #set list empty to ensure pass of while loop
while onsets.length<2 #process onsets, until number of onsets >1
sm=(sample_names :loop).tick #get next sample name
onsets=(listOnsets sm)
sleep 0.01
end
4.times do |k|
p=range(0,onsets.length).shuffle #shuffled onset order to be played
fraction=[0.3,0.6,0.8,1.0][k]
puts "using sample #{sm}"
puts "onset order is #{p}"
puts "fraction of offset played is #{fraction}"
onsets.length.times do |i| #cycle through onset values playing them
sample sm,start: onsets[p[i]][:start],finish: onsets[p[i]][:finish]-(1-fraction)*(onsets[p[i]][:finish]-onsets[p[i]][:start])
sleep sample_duration sm,start: onsets[p[i]][:start],finish: onsets[p[i]][:finish]
end
end
sleep 1
end