Pan from left to right iterating in a loop?


I’m having a lot of fun learning and leading a group of grade 8 students creating with Sonic Pi. One student would like to make a tone and/or drum sound start panned -1 and then iterate by 0.1 to the other side(panned to 1) and then reverse this. And this process should loop indefinitely. So the effect for the listener will be the sound starting in one ear or on one side of the stage and gradually moving past center to the other ear/side of the stage and keep going back and forth. We have dabbled with a variable and if statements and also tried a range with .reverse, but nothing has worked yet.

Ideas? Thanks in advance.


1 Like

Hi Paul,

(range …) is definitely one way to achieve what you want. Here is one solution:

# panning in discrete increments,
# where the pan value changes once per loop iteration
live_loop :test do
  # increment the internal counter by 1
  # construct a ring of numbers for the pan values, eg:
  # (ring -1.0, -0.9, ..., -0.1, 0.0, 0.1, ..., 1.0)
  # add to it a reversed copy of itself, (minus the duplicated middle element)
  # and use look to 'look up' the next number in this ring to use for pan:
  with_fx :pan, pan: (range -1, 1, step: 0.1).reflect.look do
    sample :loop_amen, beat_stretch: 2
    sleep 2

You could also do a similar thing but with continuous instead of discrete pan changes like this:

# slightly simpler method, but with continuous change instead of discrete increments,
# where the pan value changes continuously *within* a single loop iteration
live_loop :test2 do
  # use :panslicer FX with triangle wave
  # (use invert_wave: 1 to start panning from the left)
  with_fx :panslicer, phase: 8, wave: 2, invert_wave: 1 do
    sample :loop_amen_full, beat_stretch: 8
    sleep 8

Here is another solution

#program to pan a note back and forth by Robin Newman
maxtime = 50 #duration of long note
set :pantime,0.05 #store time_state variable to adjust speed of pan change suggest range 0.02 to 0.2
set :stopflag,false #flag used to stop program at end of long note
at maxtime do #use at to initiate end of program
  set :stopflag,true

set :ppos,-1 #time-state variable to hold pan setting
set :flag, 0 #time-state variable to hold inc/dec flag
use_synth :tri
n = play 72,sustain: maxtime, release: 0.5,pan: get(:ppos) #start initial long note
set :nv,n #store control pointer
live_loop :panner do
  if get(:flag)==0 #find whether incrementing
    p = get(:ppos)+0.1 #increment pan position
    set :flag,1 if p >0.9 #swap flag to decrement if right limit reached
  if get(:flag)==1 #decrementing
    p = get(:ppos) -0.1 #decrement pan position
    set :flag,0 if p < -0.9 #set flag to increment if left limit reached
  set :ppos,p #update stored pan position
  control get(:nv),pan: p,pan_slide: get(:pantime) #control pan position and slide to new value
  sleep get(:pantime)
  stop if get(:stopflag)

Perhaps not as elegant as Ethan’s


Awesome! Thank you so much. Now I see how to use the range in the way that we were guessing could work. Your other solution is beyond me at the moment, but hopefully I’ll get to thinking about wave forms eventually. Cheers!

Although the IF statements are a bit more complex, I appreciate seeing how this one works. We had tried to set up IFs but could not get it. Thank you for furthering our understanding!

Hi! This is my first ever reply on in_thread… not sure how to use this properly yet (has someone already replied (I can’t see if they have))…

I was searching for info on “panning” and I was playing with a test today, to make a sound (the same sound) play in both ears, (hard left & hard right) slowly “moving” towards the centre.

When I first tried :

pan = range(-1, 1, 0.1).mirror #(makes a ring that loops forwards & backwards)
nap = range(1, -1, 0.1).mirror
live_loop :pans do
x = tick
sample :bd_boom, pan: pan[x]
sample :bd_boom, pan: nap[x]
sleep 1

the result was just a centralised sound (both pans “cancelling” each other out making).
I added a tiny sleep (0.01) after the first sample, then took away the 0.01 from the 2nd sleep & it works a treat, you get a shifting “pan” going from “outside” to “centre” (as I expected).

pan = range(-1, 1, 0.1).mirror
nap = range(1, -1, 0.1).mirror

live_loop :pans do
x = tick
sample :bd_boom, pan: pan[x]
sleep 0.01
sample :bd_boom, pan: nap[x]
sleep 0.99


The easiest solution by far is using the panslicer effect with the wave setting at 2 (using a sine wave instead of a square wave). use the phase opt to decide how much time the pan takes.