I’ve been having a look at this, and came up with the ideas below.
The program controls 4 percussion liveloops and 4 tune liveloops The content of these is fairly rubbishy, but they are there to show how the setup works, and could have nicer contents substituted.
The idea is that each class has a list of triggers, one for each loop. So for the percussions loops these are
:p1,:p2,:p3 and :p4
For the tune loops they are :t1,:t2,:t3 and :t4
Each class has a playing list which repeats. This can also include a symbol :x (for the percussion loops) and :tx for the tune loops which “substitutes” a silent loop fo the same duration.
So the play list for percussion might be
pl=[:p1,:x,:p2,:x,:p3,:x,:p4,:x,:p1,:p2,:p3,:p4,:x,:x,:x,:x]
and for the tune loops
tl=[:tx,:t1,:tx,:t2,:tx,:t3,:tx,:t4,:tx,:tx,:tx,:tx,:t1,:t2,:t3,:t4]
All of the loops have the same duration (I choose 2 beats, but they could be 4 or 8)
Each live loop is synced to a cue. :goP for percussion and :goT for tune loops
These are triggered by two enable functions, which in turn are launched in a liveloop called conduct.
This is delayed by 0.01 compared to all the other loops, so that it will only issue cues (via the enable functions) when the recipient liveloops are waiting to receive them, so no cues are missed.
Each enable function moves through the relevant play list each time it is triggered, and sets the trigger for the relevant loop to true, setting the others to false. So when the cue is received by ALL the tune of percussion loops, only the one with a true trigger key will sound. The others are set to sleep for the 2 beat duration. Actually they sleep for 1 beat, to make sure that they are ready to receive the next cue.
Including an :x or :tx symbol in the relevant play list means that no liveloop triggers will match and a silent period ensues for 2 beats.
The code is shown below. It can in principle be developed to allow for further classes of liveloops to be added, each with its own enable function. If you want 4 or 8 beat liveloops the conduct liveloop can be modified to issue cues every 4 or 8 beats by changing its sleep time.
I would be interested in any comments on the setup.
#experimental live_loop sequencer by Robin Newman, December 2018
#The program controls 4 percussion and 4 tune liveloops.
#Each has a duration of 2 beats (or less)
#each group has a series of 2 flags. The first list contains an identifier for each loop
#the second lists the sequence playing order. An x signifies a silent loop
#an enable function for each group, enables the loop trigger flat
#matching the current sequence position, and then issues a start cue :goT or :goP.
#These enable functions are called in the conduct live loop.
#This is delayed to start last, and so only send cues when the liveloops are waiting.
#Inside each loop, the rleevant trigger flag enables the content, or else a short sleep
#The sleep is less than 2 beats, ensuring the live_loop is ready for the next cue
#The "playing" liveloops are carefully set up so that they are completed in time
#for the next :goT or :goP cue, so all loops remain in sync.
use_bpm 60
#percussion loop control
pl=[:p1,:x,:p2,:x,:p3,:x,:p4,:x,:p1,:p2,:p3,:p4,:x,:x,:x,:x] #play list for percussion liveloops :x is blank
p=[:p1,:p2,:p3,:p4] #available percussion liveloops triggers
p.each do |x| #disable all initially
set x,:false
end
set :x,false #blank percussion loop flag
define :enablep do |t|
cv=pl[t % (pl.length)] #next flag to be checked
p.length.times do |i| #cycle through all available percussion triggers and enable match
if cv==p[i]
set p[i],true
else
set p[i],false
end
end
cue :goP #cue percussion live_loops
end
#uncomment next loop to get metronome for debugging
##| live_loop :test do
##| sync :goT
##| play 84,release: 0.05
##| end
#tune loop control
tl=[:tx,:t1,:tx,:t2,:tx,:t3,:tx,:t4,:tx,:tx,:tx,:tx,:t1,:t2,:t3,:t4]#[:tx,:t1,:tx,:t2,:tx,:t1] #play list for tune liveloops :tx is blank
tn=[:t1,:t2,:t3,:t4] #available tune liveloop triggers
tn.each do |x| #disable all intially
set x,false
end
set :tx,false #blank tune loop flag
define :enablet do |t|
cv=tl[t % (tl.length)] #next flag to be checked
tn.length.times do |i| #cycle through all available tune triggers and enable match
if cv==tn[i]
set tn[i],true
else
set tn[i],false
end
end
cue :goT #cue tune live_loops
end
live_loop :conduct,delay: 0.01 do
tick
enablep(look) #can comment out to stop all percussion loops
enablet(look) #can comment out to stop all tune loops
sleep 2
end
live_loop :percussion1 do
sync :goP
puts "p1"
if get(:p1)==true
sample :loop_amen,beat_stretch: 2
#no sleep so will be ready for next cue
end
sleep 1 #ready for next cue in plenty of time
end
live_loop :percussion2 do
sync :goP
#puts"p2"
if get(:p2)==true
sample :loop_garzul,beat_stretch: 4,finish: 0.5 #adjusted for 2 beats
#no sleep so will be ready for next cue
end
sleep 1 #ready for next cue in plenty of time
end
live_loop :percussion3 do
sync :goP
#puts "p3"
if get(:p3)==true
sample :loop_compus,beat_stretch: 4,finish: 0.5 #adjusted for 2 beats
#no sleep so will be ready for next cue
end
sleep 1
end
live_loop :percussion4 do
sync :goP
#puts "p4"
if get(:p4)==true
2.times do |i|
sample :bd_haus
sleep 0.5
sample :drum_cymbal_soft
sleep 0.25
sample :drum_cymbal_soft
sleep 0.25 if i==0 #miss last sleep so ready for next cue
end
else
sleep 1 #ready for next cue in plenty of time
end
end
live_loop :tune1 do
use_synth :pluck
sync :goT
if get(:t1)==true
19.times do
play scale(:c4,:major,num_octaves: 2).choose,release: 0.1,amp: 0.4
sleep 0.1
end
play scale(:c4,:major,num_octaves: 2).choose,release: 0.1,amp: 0.4
#no sleep so will be ready for next cue
else
sleep 1 #ready for next cue in plenty of time
end
end
live_loop :tune2 do
use_synth :tri
sync :goT
if get(:t2)==true
19.times do
play scale(:c2,:minor,num_octaves: 2).choose,release: 0.1,amp: 0.4
sleep 0.1
end
play scale(:c2,:minor,num_octaves: 2).choose,release: 0.1,amp: 0.4
#no sleep so will be ready for next cue
else
sleep 1 #read for next cue in plenty of time
end
end
live_loop :tune3 do
use_synth :saw
sync :goT
if get(:t3)==true
9.times do
play scale(:c3,:minor,num_octaves:2).tick,release: 0.2,amp: 0.5
sleep 0.2
end
play [:c3,:c4,:c5],release: 0.2,amp: 0.8
#no sleep so will be ready for next cue
else
sleep 1 #readn for nexrt cue in plenty of time
end
end
live_loop :tune4 do
use_synth :piano
sync :goT
if get(:t4)==true
3.times do
play [:c3,:e3,:g3,:c4],release: 0.5
sleep 0.5
end
play [:c4,:e4,:g4,:c5],release: 0.5
#no sleep so will be ready for next cue
else
sleep 1 #readn for nexrt cue in plenty of time
end
end
You can alter the play lists and rerun and it will pick up the changes