How to change the AMP progressively playing a sample


Hi all
I’m tryng to set incremental volume with the following code, but it does not work

set :sample3,"/path/to/my/file.ogg"
set :length3,(sample_duration get(:sample3))

in_thread do
  live_loop :test do
    set_sched_ahead_time! 0
    if c == 101
      c = 0
    cs = ( get(:length3)*0.01) * c
    ce = cs + (get(:length3) * 0.01)
    s = sample get(:sample3), start: cs ,finish: ce, amp: (c * 0.01)
    sleep get(:length3)*0.01
    c = c +1

But the sample overwrite themeself emitting noise.
Anyone can help me?


You want to increase the amp as the sample plays. That’s actually really simple – you’re overthinking it. Also, you’re using semicolons to end lines, which is NOT part of Ruby/Sonic Pi syntax. It’s unneeded, although it does technically work. Also, use_real_time is a statement, not the beginning of a block.

mySamp = "/path/to/my/Sample"
a = 0
q = 0
t = sample_duration mySamp #no need to use the set statement. Just use variables. Readability ftw.
live_loop :test do
 sample mySamp, amp: a, amp_slide: (t / 5) #takes one fifth of the sample's duration to change amp
 sleep t + 0.5 #sleeps for half of a beat beyond the sample duration.

 live_loop :incr do
 while (q < 10) do
  q += 1
  a += 0.1
  sleep (t / 10)

If this doesn’t fix your problem, let me know.


I try your code, but It seems that:

  1. Sorry for the semicolumns, I’m coming from Javascript/PHP and I will try to omit them
  2. thanks for the use_real_time suggestion (I think I got some indentetion errors)
  3. it increments the AMP any time the sample is played (and not while playing, for that i was using start and finish, in order to control the AMP of the single sample chunk)
  4. My sample is 10 secs long and it takes only 2 increment

I’m using SonicPI 2.Something wrong with my version?

Let me know
Thanks for the help


I see one of the errors in my code, thanks for alerting me. I checked it and the sleep (t / 10) line in the second loop should be on the OUTSIDE of the while block but still in that live_loop. Live loops are finnicky and they have to sleep on the root (outermost) level of the loop because of the way Sonic Pi does all steps in a sequence at once. I’m not totally sure how to fix it so it changes the amp over time, but you could just have a REALLY high attack. That would work if you don’t want the amplitude to spike.

Other than that, I got nothin’, but I’ll experiment to see if I can get something. Maybe @samaaron or somebody can tell you before I do.


Perhaps I’m just totally misunderstanding, but I’m not really sure what you mean here. In what aspect(s) do you find live loops finicky? Also, what do you mean by root/outermost? The only time-based restriction of live loops as far as I understand them is that they have to sleep/sync at some point within their execution - otherwise they turn into infinite loops attempting to operate in zero time which clearly doesn’t make much sense :slight_smile:


Hi Sam
Nice to speak with you. Your SonicPI is one of the best thing of these days.

Could it be possible to:

  1. Split the sample in 10 chunks (playing it with sample "/path/to/sample.ogg",start:x,finish:y)
  2. each loop plays only the correct chunk in order to control each sample’s chunk AMP
  3. after 10 loops the entire sample is complete

If this is possible, I can decrease progressively the sample’s chunk AMP parameter.
If you look at the first post you can see an example code but it seems doesn’t work.
Can you help me founding a solution?


Hi @bahamut657

How about something like this:

live_loop :foo do
  num_chunks = 10
  sample "/foo/bar/baz.wav", slice: look, num_slices: num_chunks, amp: (line 1, 0, steps: num_chunks).look
  sleep sample_duration("/foo/bar/baz.wav") / num_chunks
  stop if look >= num_chunks


Wow! Fast and clear answer.

Tomorrow I will try out you piece of code and make you know.
Now is time for me to take a break (10h non-stop of SonicPI programming via OSC) :slight_smile:

Thanks a lot


I tried your code and it seems to work perfectly.
I’ve corrected only the final if statement, otherwise the track repeat the first chunk.

stop if look >= num_chunks-1

Where can I find some explanation about the syntax used in the line below ( I come from Javascript/NodeJS/PHP and cannot understand it easly :frowning: … thinking I’m becoming old… :smile: )
sample "/foo/bar/baz.wav", slice: look, num_slices: num_chunks, amp: (line 1, 0, steps: num_chunks).look

In particular, the piece slice: look,amp: (line 1, 0, steps: num_chunks).look
It seems a sort of variable look assigned and self-incremented on each loop, but (line 1, 0, steps: 10).look sounds misterious :slight_smile:

I’m going to buy the inprint version of the SonicPI official manual but I’d like to know if there are any API documentation (oriented to developers) on the net

Thanks a lot for the piece of code


Hi there,

that example I gave you contains a lot of ideas, if you haven’t come across them individually before, it makes sense that it won’t be easy to understand it in one go - that’s completely normal :slight_smile:

sample "/foo/bar/baz.wav", slice: look, num_slices: num_chunks, amp: (line 1, 0, steps: num_chunks).look

There’s a few things going on here:

  1. A call to sample with a number of different options being set
  2. A ring which is generated by the line function
  3. A call to look on this ring

Let’s look at each in turn. Once you’ve worked through all the parts, try then to combine them in your head. It may take a little time, but be patient and walk away and come back to it a few times. Eventually it might click and make sense, but if it doesn’t, (and that’s also totally normal) let me know and I’ll try and find a different way of explaining things :slight_smile:

1. Sample

Calls to sample have one required argument (the name/path of the sample to trigger) some filter options (if the path is a list of paths or a folder containing multiple sample files), and some options. In this case, we’re not using any filter options (for more information about this look up the sample documentation).

However, we are specifying a path to a wav file "/foo/bar/baz.wav" and some opts: slice:, num_slices: and amp:. The amp: opt is the most obvious, this is an amplitude (1 being default) with which to play back the sample: an amp: of 0 is silent, 0.5 is half amplitude and 2 is double amplitude.

The slice: and num_slices: opts are more interesting. The num_slices: opt lets you specify how many equally spaced slices of the original audio we should consider and slice: sets the start: and finish: opts implicitly.

(See A.12 Sample Slicing in the tutorial for a manual version of this which sets start: and finish: opts directly and was written before slice: was available).

2. Rings

For a nice description of rings take a look at section 8.4 of the built-in tutorial.

As a quick summary, they’re essentially lists of things that when indexed into always return an element within the original list. For example:

  • [1, 2, 3, 4][100] #=> nil - the list only has 4 elements, so indexing 100 is off the end, therefore return nil.
  • (ring 1, 2, 3, 4)[100] #=> 1 - the ring only has 4 elements, but indexing 100 wraps around internally (using mod) so we get a value within the ring. Indexing 101 would return 2 etc.

In this case we have a ring generated from the line function which will build a ring containing an ordered sequence of numbers with starting value 1 and finish value 0 and 10 steps:

 (line 1, 0, steps: 10) #=> (ring 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1)

Using the line function is a shorter and neater way of creating the above ring rather than writing it out by hand.

3. Look

look is part of the counting system which is documented in section 9.4 of the built-in tutorial. Please also look through the examples of the look docstring. Essentially calls to tick increment a live-loop-local counter and calls to look will return the current value of that counter. However, when called on rings, look will not just look up the current value of the counter, it will use that value as an index into the ring itself. This will always return a value within the ring no matter how big or small the counter value (due to the index-wrapping property of rings).


Hello guys,
I am new in Sonic PI.
I have a question: How can i do to change parameters without re-trigger a sample?
Here my code:

define :cc do
  num, val = sync "/midi/icon_icontrols_v2.00_porta_1/0/1/control_change "

define :player do
  amp = cc[1] if(cc[0] == 12)
  sample :perc_bell, amp: amp
  sleep 0.1

Thank you in advance


Here is an example which uses control change 12 to adjust the volume using an fx :level wrapper.
This controls the volume of the sound in the loop_amen_full. Note the use of time-state to set and retrieve the volume level and set and retrieve a reference to the fx :level so that it can be controlled.
Initially there is no sound. As soon as you adjust midi control 12 the volume changes.

set :vol,0 #set initial volume

live_loop :getVol do #get midi input control change 12
  b = sync "/midi/*/*/*/control_change" I used wild cards * so that it matches any midi input device
  if b[0]==12
    set :vol, (b[1]/127.0) #store volume value range 0->1

with_fx :level, amp: 0 do |v| #use fz :level to adjust volume
  set :vref,v #store reference to fx :level

  live_loop :setVolume do
    control get(:vref),amp: get(:vol),amp_slide: 0.1
    sleep 0.1

  live_loop :pl do #play soume sound, volume controlled by fx :level
    sample :loop_amen_full
    sleep sample_duration :loop_amen_full

end #fx levels


Thank you so much!
Is there a detailed manual for this language?


My example uses commands detailed in the Sonic Pi help file Language Section, and techniques detailed in the Tutorial. To learn the use of Sonic Pi the built in tutorial is a good starting point. Then looking at some of the example files also in the built in help documentation. You can get to the help files by clicking on the Help button.


Try here: