Is there a way to create a more dense version of the live_loop and other loop structures? One may be tempted to do something like this:
live_loop :test do ; play 50 ; sleep 1 ; end
What I would like to do is to define a type of loop that is limited to one line only and that can accept any number of arguments and things nested inside. Something like this:
ll :test play 50 ; sleep 1
The idea behind this would be to quickly create a large number of loops synchronised to each other, like this:
ll :test play 50 ; sleep 1
ll :test2, sync: :test ; play 50 ; sleep 0.5
ll :test3, sync:: test ; et caetera
It may not be the best idea for what concerns code organization and language design, but I would still enjoy to play with something like this.
For the record, the Sonic Pi way of defining functions is using define.
define :lsample |name, sample_name, sleep_time| do
live_loop name do
sync :zync
sample sample_name, beat_stretch:sleep_time
sleep sleep_time-0.001
end
end
Whilst def does currently work, it’s not supported and may break in a future version without warning.
@bradgonesurfing : yes but you lost the possibility of adding more parameters than those that you defined when writing the function in the first place.
@samaaron : Cool! I just have to wait then! Thanks!
@bubo Within live_loop you can do pretty much anything so if you want a more compact DSL you have to decide on what you want. However you can pass through abitrary keyword value maps using splats to the inner code making it more flexible. @samaaron thanks for the headsup on def vs define.
use_bpm 120
define :lsample do |name, sample_name, sleep_time, fx_name, **fx_parts|
live_loop name do
sync :zync
with_fx fx_name, fx_parts do
sample sample_name, beat_stretch:sleep_time
end
sleep sleep_time-0.001
end
end
lsample :a, :loop_amen, 2, :wobble, mix:0.1
lsample :b, :ambi_piano, 20, :wobble
lsample :c, :ambi_piano, 4, :flanger, decay:0.5, amp: 2
lsample :d, :ambi_piano, 8, :none
lsample :e, :bass_woodsy_c, 8, :none
lsample :e, :bass_woodsy_c, 12, :none
live_loop :zync do
sleep 0.5
end
I’d assume the following would play both parts at the same time, but it doesn’t.
use_bpm 130
define :run do |parts|
parts.each { |part|
in_thread do
part
end
}
end
define :one do
notes = (ring :a2, :a3, :a4, :a5)
8.times do
play notes.tick
sleep 1
end
end
define :two do
notes = (ring :a2, :a3, :a4, :a5).reverse
8.times do
play notes.tick
sleep 1
end
end
run [one, two]
you actually are evaluating the functions rather than passing the method pointer. Ruby evaluates functions without brackets. Easy mistake to make. You could solve it by passing procs
use_bpm 130
define :run do |parts|
parts.each { |part|
in_thread do
part.call
end
}
end
define :one do
notes = (ring :a2, :a3, :a4, :a5)
8.times do
play notes.tick
sleep 1
end
end
define :two do
notes = (ring :a2, :a3, :a4, :a5).reverse
8.times do
play notes.tick
sleep 1
end
end
run [->() {one}, ->(){two}]
or by passing symbols and using send to evaluate them
use_bpm 130
define :run do |parts|
parts.each { |part|
in_thread do
send part
end
}
end
define :one do
notes = (ring :a2, :a3, :a4, :a5)
8.times do
play notes.tick
sleep 1
end
end
define :two do
notes = (ring :a2, :a3, :a4, :a5).reverse
8.times do
play notes.tick
sleep 1
end
end
run [:one, :two]