Pipe arguments (ruby q)

Hey all, not sure if anyone can shed any light here…

I was playing with some limited randomness.
I’ve got a live loop running, randomly augmented with extra loop samples.

So as to avoid the main loop being delayed by sample playback and wait time, I’ve called the sample from within a thread via a method within the live_loop.

After some success with this looped oneshot nonsense I then tried to tinker to allow multiple voices. I’m sure there’s questionable logic (at many levels!)

One thing I’d like to do is additionally pipe any arguments that are provided as *args
I’ve seen examples using .merge previously , and even some currying (anyone else think of Ruby Murray when seeing that method?! Just googled, never knew she was a she or a singer… I digress : )

max_voices = 3
active_voices = 0

define :oneshot do |s, fx, *args|
  if active_voices < max_voices
    in_thread name: ("samples" + active_voices.to_s).to_sym do #can args be injected in here?!
      active_voices += 1
      t = sample_duration s
      puts s, fx
      sample s
      wait t
      active_voices -= 1
      stop
    end
  end
end

live_loop :l1 do
  fxlist = fx_names.to_a
#exc. record fx as not needed, & throws an error if selected as requires an argument
  fx = fxlist.reject {|fx| fx == :record}.choose 

  with_fx fx, reps: rand(1..4) do
    oneshot (sample_names :loop).choose , fx
  end
  
  with_fx :wobble, pulse_width: 0.1 do |wob| #reps kill_delay #, filter: 0
    density 1 do
      play :c
      # stop
      wait 2
    end
  end
end

Ideally additional arguments can be piped, initially just thread args, eg something like

oneshot (sample_names :loop).choose , fx, delay: 1, sync: :l2

I’ve worked out the logic to get to the (hash) elements within the (args) array

args.each_with_index {|a,i| a.each_pair \  
{|h,v| "#{i.zero? ? ', ' : '' }#{h}: #{v}"}}`

but even if I assign this a variable I’m still not sure how to inject this.


Also I’ve now got some new random popping currently (using speakers as headphones AWOL) . which may require a lower attack or release or something to fix, on the fx/playback… any ideas on how to troubleshoot/fix this also most welcome!

After fiddling around with it for a bit, I think this seems to do what you want. You don’t need the *, as the trailing args already seem to get collected into a hash (I don’t know Ruby well enough to understand exactly why…):

max_voices = 3
active_voices = 0

define :oneshot do |s, fx, args|
  if active_voices < max_voices
    args[:name] = ("samples" + active_voices.to_s).to_sym
    puts args
    in_thread args do
      active_voices += 1
      t = sample_duration s
      puts s, fx
      sample s
      wait t
      active_voices -= 1
      stop
    end
  end
end

oneshot :loop_amen, :some_fx, sync: :l2, delay: 1

sleep 2

cue :l2
1 Like

Thanks! This is so helpful :pray:t2:
I first encountered *args when looking at optional arguments.
So it seems in_thread expects and requires just one hash for it’s arguments, and injecting the name into the args as you demonstrate is the way to do it. Thanks!

I tried with the other param type ** and that works whils allowing for nil args. I think the logic you mention is that * gets you an auto-array, whilst ** gets you a hash.

:+1:t2:

1 Like