Although they look deceptively simple on the outside, FX are actually quite complex beasts internally. Their simplicity often entices people to overuse them in their pieces. This may be fine if you have a powerful machine, but if - like me - you use a Raspberry Pi to jam with, you need to be careful about how much work you ask it to do if you want to ensure the beats keep flowing.
Consider this code:
loop do
with_fx :reverb do
play 60, release: 0.1
sleep 0.125
end
end
In this code we’re playing note 60 with a very short release time, so it’s a short note. We also want reverb so we’ve wrapped it in a reverb block. All good so far. Except…
Let’s look at what the code does. First we have a loop
which means
everything inside of it is repeated forever. Next we have a with_fx
block. This means we will create a new reverb FX every time we
loop. This is like having a separate FX reverb pedal for every time you
pluck a string on a guitar. It’s cool that you can do this, but it’s not
always what you want. For example, this code will struggle to run nicely
on a Raspberry Pi. All the work of creating the reverb and then waiting
until it needs to be stopped and removed is all handled by with_fx
for
you, but this takes CPU power which may be precious.
How do we make it more similar to a traditional setup where our guitarist has just one reverb pedal which all sounds pass through? Simple:
with_fx :reverb do
loop do
play 60, release: 0.1
sleep 0.125
end
end
We put our loop inside the with_fx
block. This way we only create
a single reverb for all notes played in our loop. This code is a lot
more efficient and would work fine on a Raspberry Pi.
A compromise is to use with_fx
over an iteration within a loop:
loop do
with_fx :reverb do
16.times do
play 60, release: 0.1
sleep 0.125
end
end
end
This way we’ve lifted the with_fx
out of the inner part of the loop
and we’re now creating a new reverb every 16 notes.
This is such a common pattern that with_fx
supports an opt to do
exactly this but without having to write the 16.times
block:
loop do
with_fx :reverb, reps: 16 do
play 60, release: 0.1
sleep 0.125
end
end
Both the reps: 16
and 16.times do
examples will behave
identically. The reps: 16
essentially repeats the code in the do/end
block 16 times so you can use them both interchangeably and choose the
one that feels best for you.
Remember, there are no mistakes, just possibilities. However, some of these approaches will have a different sound and also different performance characteristics. So play around and use the approach that sounds best to you whilst also working within the performance constraints of your platform.