"Loop Pedal" in Sonic Pi

Curious how to sample live instruments and play them back/manipulate them in real time in sonic pi.

I do lots of sessions with live instrumentalists and would love to also be able to incorporate something like this into live performances.

<3

1 Like

Hey @dj_dave I love the concept of using Sonic Pi as a “loop pedal”! Opens up a lot of possibilities.

So from what I can tell, there are two parts to making this happen: Getting a live_audio stream into Sonic Pi and then use the :record fx to store an audio file that you can access and manipulate in your code.

To get the audio going into Sonic PI, you first need to select the Enable Audio Inputs in the preferences window under the ‘audio’ tab

Sonic PI will most likely ask you to restart at that point as it can’t switch audio sources while running.

When starting up Sonic Pi again, you might get this error window:

I got one like this because I was using Looppack as an audio output which was a 6 channel out but when I switched to headphones, it worked fine. If it comes up, you may just have to fiddle with what you are using for I/O sources.

If you are trying to record live instruments, you should also have some type of USB audio interface that the instruments can plug into. I use a Sterling Harmony H224 which you can see listed as the in in the preferences window under ‘Audio Hardware Information’

With that set up, you can get an audio stream up and running pretty quick with the live_audio function. You just give it a specific name and you should hear the instrument coming through Sonic Pi

live_audio :guitar

Once you have that, you can wrap that function inside a with_fx :record block. You will need to provide a buffer name where there recorded audio will be stored

with_fx :record, buffer: :take1 do
  live_audio :guitar
  end

When you run that code, it will create an 8 beat .wav file of whatever audio was coming through the live_audio stream at that time. 8 beats is the default amount. According to the docs, the actual amount of time will depend of the bpm. You can specify a specific amount of beats for the buffer this way

with_fx :record, buffer: [:take1, 16] do #this makes a 16 beat .wav file
  live_audio :guitar
  end

When going to play this back, you will need to write the buffer name along with the amount you gave it. Otherwise, you will override the buffer you made with another one. More on this in a bit…

To play it back, you can just use the sample function along with the command buffer and the name you gave the buffer in the :record fx

sample buffer[:take1]

If you made a specific size buffer, you would need to put that when you call the sample function

with_fx :record, buffer: [:take1, 16] do #this makes a 16 beat .wav file
  live_audio :guitar
  end

sample buffer[:take1, 16] #plays the 16 beat buffer you recorded

However, from experimenting with this, you can’t just play this sample without making some changes to the code you used to record it, otherwise you will just record over the buffer you just made with a new one.

For instance, in the code below

with_fx :record, buffer: :take1 do
  live_audio :guitar
end

sample buffer[:take1]

if you run the code, even if you add the sample code after running the first block of code, the first block of code will override the initial :take1 buffer that you recoded with a new one and so by the time you get to the sample line playing that buffer, you won’t hear what you originally recorded.

There are a few ways you can work around this.

  1. Comment out the recoding block of code
  2. Change the name of the buffer in the with_fx :record line
with_fx :record, buffer: :take2 do #changed to:take2 after recording :take1
  live_audio :guitar
end

sample buffer[:take1] #plays audio from original run when buffer was named :take1
  1. You can add :stop as an option to the live_audio function
with_fx :record, buffer: :take1 do
  live_audio :guitar, :stop #stops audio input from being recorded
end

sample buffer[:take1] 

From here, you can put the sample buffer into a live loop and do whatever you want with it. You can also record multiple different audio files as you go. Just make sure to change the buffer name each time you record something new and then remember to use one of the methods to make sure you don’t override it when you go to play it back.

Another thing I noticed playing around with this, from the instrumentalist perspective, was knowing exactly when to come in so that whatever I played would loop up correctly. One method that worked ok was to add a block of code as a count off before the record block ran:

#gives a 4 beat countoff to set the tempo for the instrumentalist to play to
4.times do
  sample :elec_blip
  sleep 1
end

#Starts recording after the 4 beat countoff
with_fx :record, buffer: :take1 do
  live_audio :guitar
end

Again, when it came time to play it back, I had to comment out that countoff clock of code and add the :stop to the live_audio and then write in the sample line of code to play it, but it did work.

I was also able to get things working in a more dynamic setting with live loops and adding more recorded audio as I went. I started by recording a starting riff with the countoff to set the tempo using the code above. Once I had that, I played the recorded audio in a live loop. From there, I created a countoff live loop that would sync up with the original riff I had going:

live_loop :a do
  sample buffer[:take1]
  sleep 4
end


live_loop :countoff, sync: :a do
  ##| stop #Uncomment this when I want to run the buffer I just recorded
  4.times do
    sample :elec_blip
    sleep 1
  end
  with_fx :record, buffer: :take2 do
    with_fx :reverb, room: 1 do
      live_audio :guitar
      sleep 4
    end
  end
  stop #stops loop so it doesn't go back and re-record over the audio buffer
end

From there, each time I want to add another buffer, I just change the buffer name and rerun the code. I get the 4 beat countoff which now syncs up with the original loop I made and then play another piece of audio. The stop at the bottom keeps the loop from going back and overriding what I just did and then I add the stop at the top once I’m ready to play the new buffer in a different live loop:

live_loop :a do
  sample buffer[:take1]
  sleep 4
end


live_loop :countoff, sync: :a do
  stop
  4.times do
    sample :elec_blip
    sleep 1
  end
  with_fx :record, buffer: :take2 do
    with_fx :reverb, room: 1 do
      live_audio :guitar
      sleep 4
    end
  end
  stop
end

live_loop :b, sync: :a do
  sample buffer[:take2]
  sleep 4
end

The one issue I ran into was that for some reason after running it the countoff loop a second time and then using the stop commands, it wouldn’t run again even if I commented out the stops. A quick workaround was to just change the name of the countoff live loop each time I ran it, just to something like countoff2 which worked but it wasn’t ideal. If anyone is still reading who might know why, I got this message in the log
=> Thread :live_loop_countoff exists: skipping creation

But other then that, it seemed to work pretty well!

Hope that is helpful. I know it was somewhat longwinded, but I really got into playing around with it and I imagine there are others who will find this useful. I 'm gonna try to put all of this into a tutorial soon.

Lemme know if it works for you (or anyone else)

3 Likes