Reverb takes a lot of resource? & How to control global reverb?

I have a script with multiple loops with their own reveb fx because I wanted to control them - each placed on the outermost part of the loop for efficiency. But the resource use was getting high enough to cause sound breakup on the RPi.

I’ve moved to a global resource fx on the outside of all the loops, and that’s brought down the CPU dramatically. Not ideal, but it’s OK. Only thing is, I can’t control it once it’s running. Either by editing the parameters and hitting Alt-R or by using a control object. Why is that, and is there a way to do it?

Why is reverb so resource heavy, out of interest?

1 Like

Why is reverb so resource heavy, out of interest?

It’s like recording over and over then playing back over and over .

Indeed - and don’t forget that it’s happening in real-time too.

With respect to controlling FX that wrap around live loops, the only way to do it currently is to store the FX node via set and then control it from another thread.

For example:

with_fx :lpf do |fx|
  set :global_krush, fx
  live_loop :foo do
    sample :loop_amen, beat_stretch: 2
    sleep 2
  end
end

live_loop :bar do
  control get[:global_krush], cutoff: (range 70, 130, 10).tick
  sleep 1
end

For more information about controlling FX see section 7 of the tutorial and section 7.2 in particular (https://sonic-pi.net/tutorial#section-7-2).

Thanks, I’d tried that get/set pattern already. But I found I couldn’t do it as below (using your example) i.e. type in a new value for the cutoff in the moment, hit Alt-R and hear a change. (I can now hear it works with the cutoff set from a tick though)

with_fx :lpf do |fx|
  set :global_krush, fx
  live_loop :foo do
    sample :loop_amen, beat_stretch: 2
    sleep 2
  end
end

live_loop :bar do
  control get[:global_krush], cutoff: 30
  sleep 1
end

Whereas I’ve been used to doing this, changing the fx parameter on the fly…

live_loop :foo do
  with_fx :lpf do |fx|
    control fx, cutoff: 100
    sample :loop_amen, beat_stretch: 2
  end
  sleep 2
end

But never mind, I’ll just not do it, or use an outboard reverb pedal.

Ah ok, I see what’s happening in your situation, the first time you hit run, it creates the reverb FX and stores it in the Time State via set all well and good.

However, when you modify the code and hit run again, it creates a new reverb which it also stores in the Time State “overriding” the previous value as it’s newer (the previous value is still there as the Time State stores a series of values based on time, but get always returns the latest). Due to the way Sonic Pi is currently implemented, this reverb is then thrown away as the previous one is still running and attached to the existing live loop thread.

This is why it’s not working for you, your control is modifying the newer reverb which isn’t attached to the original thread and actually just gets thrown away.

A work-around would be to comment out the set line after you have run it the first time. This will stop subsequent runs from “clobbering” the original reverb node allowing you to retrieve and control it.

This is currently an area where something like a live_fx would definitely be useful which behaved similar to live_audio. However, this needs to be implemented.

Hope that this helps,

Sam

1 Like

Thanks. With that new info, I tried this below. Which does work, but only after a restart of SP. Otherwise, the fx survives through an ALT-s, ALT-r.

Interesting stuff, but I think I’ll steer clear of this idea for now. For most songs reverb is ‘set and forget’, it was just one. I have learnt to go easy with these delay-based effects anyway. Echo isn’t too bad.

For special fx I’m going to record the elements solo, then include them as samples.

with_fx :lpf do |fx|

  if !get[:global_krush] then
    puts “setting fx”
    set :global_krush, fx
  end

  live_loop :foo do
    sample :loop_amen, beat_stretch: 2
    sleep 2
  end
end

live_loop :bar do
  control get[:global_krush], cutoff: 10 
  sleep 1
end

You can also do set :global_krush, nil to stop you requiring to restart Sonic Pi :slight_smile:

True, so then it works after alt-s, alt-r. But I’d need it to work with just an alt-r. I feel I’m flogging a dead horse with this one! Honestly it’s fine as is :smile:

Before my whole body immersion in SPi I was using a DAW for this, and pre-recording samples for live use rather than relying on real-time effects. For the same reason, to keep things robust.

Hi Soxsa,

Please forgive me… I’m a bit of a ‘tinkerer’, I mess with
other people’s code, trying to find nice sounds… sometimes
I come up with stuff I think is nice…

Eli…

use_random_seed 667766
use_bpm 50

cmaj = scale(:c2,:major,num_octaves: 5) # list of 36 notes
dmaj = scale(:d2,:major,num_octaves: 5)
emin = scale(:e2,:minor,num_octaves: 5)
fmaj = scale(:f2,:major,num_octaves: 5)
fmin = scale(:f2,:minor,num_octaves: 5)
gmaj = scale(:g2,:major,num_octaves: 5)
amin = scale(:a2,:minor,num_octaves: 5)
bmaj = scale(:b2,:major,num_octaves: 5)

revtrag = [cmaj, amin, emin, gmaj]
lotr = [emin, cmaj, gmaj, dmaj]
glass = [emin, cmaj, gmaj, bmaj]
wagon = [gmaj, dmaj, emin, cmaj]
purty = [cmaj, emin, fmaj, fmin]

arp = [0,2,4,7,9,11,14,16,18,21,23,25,28,30,32,35]

iter = 1
frame = 0

live_loop :test do
  
  notein = rand_i(16)
  mynote = arp[notein] # select note from arp list, by datain value
  # myrand = arp[rand_i(16)] # random value from the arp
  
  if ((iter % 16) == 0)  # at the end of the sequence
    frame = frame+1
  end
  
  #play (revtrag[(frame % 4)])[mynote]
  #play (lotr[(frame % 4)])[mynote]
  #play (purty[(frame % 4)])[mynote]
  
  puts mynote
  if mynote > 11 then
    use_synth :blade
    play (lotr[(frame % 4)])[mynote] , attack: 2, sustain: 1, release: 0.5, amp: 1
  else
    use_synth :fm
    play (lotr[(frame % 4)])[mynote]+12, sustain: 0.5, amp: 1.5
  end
  
  iter = iter+1
  sleep 0.25
end

Soxsa
If you add
set :global_krush, nil #comment line after first press of run
as the first line of Sam’s program and then comment it after the first time you press run, then you can alter the cutoff value and it will update every time you press alt-r without having to stop SP. Basically it keeps a record of the first fx krush wrapper and always uses that to control the cutoff setting via the separate comtrol live loop.
If you do stop SP uncomment first line and it will select the next created fx krush when you run SP again.

Thanks Robin. The problem with that is if I forget to comment out the set before I hit the next alt-R, then the control is lost until another alt-S.

However, I think I’ve got a solution now. Using a specific tick to only do the set first time through, means it’s robust against alt-R. Unless you shoot me down in flames, I think this is the one!

Not knowing the object lifecyle puts means I have to experiment, that’s how it is.

Thanks for your help guys!

with_fx :lpf do |fx|
  live_loop :foo do
    if tick("start")==0 then
      set :global_krush, fx
    end
    sample :loop_amen, beat_stretch: 2
    sleep 2
  end
end

live_loop :bar do
  control get[:global_krush], cutoff: 100
  sleep 1
end

EDIT - btw I thought defonce might have been the answer, but seems like set doesn’t work in there.

Hi Eli, yes that is very nice. Did you mean to post it in this thread?