But before that, I would like to say thanks to all members of this great community.
I really like this idea of using code as a creative tool.
I have learned a lot from all of you, in particular reading Martin’s , @robin.newman’s and samaaron’s posts in this forum.
CONTEXT:
Recently I have started a mini project that involves Sonic Pi. I have created an interface with Html and javascript that communicates with Sonic Pi via OSC. That works just fine. The project is a drum machine. You can select between all the sonic pi’s percussion instruments and add it to your drum machine.
WHAT I HAVE SO FAR :
On my js application, each time a user adds a new instrument, Sonic pi receives a new OSC message. I parse the address and get the name of the instrument using a function called parse_sync_address created by robin.newman.
MY PROBLEM :
I don’t know how to CREATE A LIVE_LOOP only and only if I receive a new OSC message indicating the new instrument to add.
I’ve read this: Create live_loops dynamically with a for loop
but this is different to what I want to achieve because the iteration is defined in advance with all the needed elements.
If anyone could point me on the right direction I will finish this
little project and I will make it available to everyone in github.
I would create all live_loops in advance an run these constantly. Otherwise you 1. would have to reevaluate the code to start a loop and 2. you probably would have some hard work to ensure the synchronisation of the different loops.
I have done some projects quite similar to yours (e. g. this one); the code is quite old and messy. Currently I am working again on a Monome application and will release a working version soon (it is running with much better performance with SP 3.2.x now ).
can you give an example of the live loop you want to create. Also do you want to alter the live loop once it has started playing, for example its content, or to stop it again.
live_loop :get_input do
use_real_time
sync "/osc*/instrument/**"
input_inst = parse_sync_address "/osc*/instrument/**"
set :current_action, input_inst.slice(2, 1)[0]
set :instrument_name, input_inst.slice(3, 1)[0]
end
# HOW CAN I MAKE THIS DYNAMICALLY ?
if get[:current_action] == "remove_instrument"
# Remove a live loop called like the :instrument_name
# I know i can just set the volume to zero, but
# I would like to kill the loop in order to
# waste as less ressources as possible
end
# HOW CAN I MAKE THIS DYNAMICALLY
if get[:current_action] == "add_instrument"
# Add a live loop like the one below.
# of course this is not working right now because it
# executes only each time I click play and not
# dynamically
live_loop "play_#{get[:instrument]}" do
16.times do |i|
# Along with the sample, I use some logic
# to get the current pattern,
# but for the purposes of brevity
# I don't include it
sample get[:instrument], amp: 0.8
sleep 0.25
end
end
end
As you can see I would like to do two things:
Create a live_loop each time an add_instrument message is received
Kill or stop a loop each time a remove_instrument message is received
I know I can make this thing in a simpler manner using the advise of @Davids-Music-Lab and @Martin, but I’m curious about how I could do it dynamically.
Thank you for your help @Davids-Music-Lab,
I figure it out how to do this like you propose.
Anyways, I’m curious about how to achieve the same result in
a dynamic way (I think I can learn some interesting things in the process).
@Martin , as I said to Davids I have took in consideration the
idea of defining in advance the live loops. Anyway, I asked robin his advice too.
I took a look of your projects and I’ve been really surprised while watching the monome application video. That’s really cool!!
I tried to read the readme in your github but I’m not quite sure I understand well enough how this thing working. I will take a closer look and try to understand it better.
I really appreciate the work you guys do sharing your knowledge.
That includes @Davids-Music-Lab too, I also learned things from his videos
here is some code which will define live_loops for you and stop them when asked too.
It should work for any built in sample (provided there duration is short enough for the timings in your specimen live loop.
If you want the live loops all completely different, you can define a separate defLoop function for each one you expect to use. The basic principle should work though.
In the example, I’m sending all the osc input from sonic-pi rather than from an external source.
use_osc "localhost",4560
use_debug false
define :parse_sync_address do |address|
v= get_event(address).to_s.split(",")[6]
if v != nil
return v[3..-2].split("/")
else
return ["error"]
end
end
live_loop :getdata do
use_real_time
sync "/osc*/instrument/**"
input_inst = parse_sync_address "/osc*/instrument/**"
puts input_inst
set :current_action, input_inst.slice(2, 1)[0]
set :instrument_name, input_inst.slice(3, 1)[0]
inst= get(:instrument_name)
if get(:current_action)=="add_instrument"
puts inst
defLoop inst #create and start live_loop
end
if get(:current_action) == "remove_instrument"
set ((inst+"k").to_sym),1
end
end
define :defLoop do |name| #function to define and start live loop
live_loop ("ll"+name).to_sym do
16.times do |i|
sample name.to_sym
#whatever else you like in here
sleep 0.25
#stop section for loop
if get((name+"k").to_sym)==1
set ((name+"k").to_sym),0
stop
end
end
end
end
#trial run
osc "/instrument/add_instrument/bd_haus"
sleep 4
osc "/instrument/add_instrument/drum_cymbal_hard"
sleep 4
osc "/instrument/remove_instrument/drum_cymbal_hard"
sleep 4
osc "/instrument/remove_instrument/bd_haus"