Time error with higher tempo. Some advices

Hi,

Have some fun with sonic pi to prepare some sessions for pupils. The goal : play with samples.
So i met an issue if tempo is higher.

# nlb - 01/07/2020
# small sequencer with samples
#

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = :loop_3d_printer

# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  with_fx :reverb do
    sample drums_sn, start: 0.25, finish: 0.5, amp: 3
  end
end

define :drums_hithat_play do
  with_fx :hpf, cutoff: 110 do
    sample drums_hithat, sustain: 0.1, release:0.15,
      start: 0.1, end: 0.25,
      amp: [4, 2, 3, 1.5].tick('vol')
  end
end

define :drums_voice_play do
  sample drums_voice, slice: [2, 7].tick("foo"), num_slices: 8, finish: 0.25
end


# bpm = 60 >> no problem
# bpm = 120 >> issues... :-(

use_bpm 60

bd_pattern = (ring 1, 1, 0, 0,  0, 0,0, 0,  1, 0, 1, 0,  1, 0, 0, 0)
sn_pattern = (ring 0, 0, 0, 0,  1, 0,0, 0,  0, 0, 0, 0,  1, 0, 0, 1)
hithat_pattern = (ring 1, 0, 1, 0)

voice_pattern = (spread 4,7)
##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)

live_loop :sequencer do
  
  tick
  
  bd_on = bd_pattern.look
  sn_on = sn_pattern.look
  hithat_on = hithat_pattern.look
  voice_on = voice_pattern.look
  
  with_fx :lpf, cutoff: 60, mix: 0.5, pre_amp:1 do
    drums_bd_play if bd_on==1
  end
  
  drums_sn_play if sn_on==1
  drums_hithat_play if hithat_on==1
  drums_voice_play if voice_on # spread send back us true or false
  
  sleep 0.25
end

If i set tempo to 120, bim bam boum

{run: 73, time: 0.0, thread: :live_loop_sequencer}
 ├─ sample "C:/Program Files/Sonic Pi/etc/samples",
 │           "drum_heavy_kick.flac", {sustain: 0.25, amp: 3, compress: 1}
 ├─ sample "C:/Program Files/Sonic Pi/etc/samples",
 │           "loop_amen.flac", {sustain: 0.1, release: 0.15, start: 0.1, end: 0.25, amp: 4}
 └─ sample "C:/Program Files/Sonic Pi/etc/samples",
             "loop_3d_printer.flac", {slice: 2, num_slices: 8, finish: 0.2813, start: 0.25}
 
{run: 73, time: 0.125, thread: :live_loop_sequencer}
 ├─ Timing warning: running slightly behind...
 └─ sample "C:/Program Files/Sonic Pi/etc/samples",
             "drum_heavy_kick.flac", {sustain: 0.25, amp: 3, compress: 1}
 
{run: 73, time: 0.25, thread: :live_loop_sequencer}
 ├─ Timing warning: running slightly behind...
 ├─ sample "C:/Program Files/Sonic Pi/etc/samples",
 │           "loop_amen.flac", {sustain: 0.1, release: 0.15, start: 0.1, end: 0.25, amp: 2}
 └─ !! Out of time, skipping: sample "C:/Program Files/Sonic Pi/etc/samples/loop_3d_printer.flac", {slice: 7, num_slices: 8, finish: 0.9063, start: 0.875}
 
{run: 73, time: 0.375, thread: :live_loop_sequencer}
 └─ Timing warning: running slightly behind...
 
=> Completed run 72

{run: 73, time: 0.5, thread: :live_loop_sequencer}
 ├─ Timing warning: running slightly behind...
 ├─ !! Out of time, skipping: sample "C:/Program Files/Sonic Pi/etc/samples/loop_breakbeat.flac", {start: 0.25, finish: 0.5, amp: 3}
 ├─ !! Out of time, skipping: sample "C:/Program Files/Sonic Pi/etc/samples/loop_amen.flac", {sustain: 0.1, release: 0.15, start: 0.1, end: 0.25, amp: 3}
 └─ !! Out of time, skipping: sample "C:/Program Files/Sonic Pi/etc/samples/loop_3d_printer.flac", {slice: 2, num_slices: 8, finish: 0.2813, start: 0.25}
 
{run: 73, time: 0.625, thread: :live_loop_sequencer}
 └─ Timing error: can't keep up...
 
{run: 73, time: 0.75, thread: :live_loop_sequencer}
 ├─ Timing error: can't keep up...
 ├─ !! Out of time, skipping: sample "C:/Program Files/Sonic Pi/etc/samples/loop_amen.flac", {sustain: 0.1, release: 0.15, start: 0.1, end: 0.25, amp: 1.5}
 └─ !! Out of time, skipping: sample "C:/Program Files/Sonic Pi/etc/samples/loop_3d_printer.flac", {slice: 7, num_slices: 8, finish: 0.9063, start: 0.875}
 

Some ideas to resolve that ? What am i doing wrong ?
Cheers

Most likely this function.
In your :sequencer live_loop, you play several samples, sleep for 0.25, and repeat.
However, your :drums_sn_play function wraps a sample in a :reverb fx.
Reverb is one of the sorts of fx that need to be used carefully, as they can quickly use up system resources if too many are triggered at once. Here, the :drums_sn_play is being called fairly frequently, with very little time in between for each reverb to terminate. The result is that the stacking up of the reverb fx would cause the system to struggle to keep up.

Thanks for your answer

yep you’re right i was looking a very simple way to achieve so ok i will create one live_loop by sample and use reverb with care !

EDIT : just add that it’s a bit annoying to have a code working that means you do it good and with a higher tempo it fails. this gives me an example for pupils that a software has his limites.

Let’s try with a lighter version

  • live_loop per instrument
  • apply fx on live_loop not in methods

and it works better.

# nlb - 01/07/2020
# small sequencer with samples
# version 02
# with one live_loop by instrument
# fx applied on live_loop not inside the definition of the sample

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = :loop_3d_printer



# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  ##| with_fx :reverb do
  sample drums_sn, start: 0.25, finish: 0.3, amp: 3
  ##| end
end

define :drums_hithat_play do
  sample drums_hithat, sustain: 0.1, release:0.15,
    start: 0.3, end: 0.4,
    amp: [4, 2, 3, 1.5].tick('vol')
  ##| end
end

define :drums_voice_play do

sample drums_voice, slice: [1, 4].tick("foo"), num_slices: 8, finish: rrand(0.1,0.5)
  
end

use_bpm 120

bd_pattern = (ring 1,0,0,0, 0,0,0,0, 1,0,1,0, 1,0,0,0)
sn_pattern = (ring 0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1)
hithat_pattern = (ring 1, 0, 1, 0)
voice_pattern = (spread 4,7)
##| voice_pattern = (spread 1,16)


##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)

live_loop :loop_bd do
  bd_on = bd_pattern.tick
  drums_bd_play if bd_on==1
  sleep 0.25
end

live_loop :loop_sn do
  sn_on = sn_pattern.tick
  drums_sn_play if sn_on==1
  sleep 0.25
end

with_fx :hpf, cutoff: 110 do
  live_loop :loop_hithat do
    hithat_on = hithat_pattern.tick
    drums_hithat_play if hithat_on==1
    sleep 0.25
  end
end

with_fx :echo, mix: [1, 0.25].choose do
  live_loop :loop_voice do
    voice_on = voice_pattern.tick
    drums_voice_play if voice_on # spread sends back us true or false
    sleep 0.25
  end
end

At the end add conductor to synchronise live_loops and play with an second pattern for snares.

# nlb - 01/07/2020
# small sequencer with samples
# version 02
# with one live_loop by instrument
# fx applied on live_loop not inside the definition of the sample

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = :loop_3d_printer



# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  ##| with_fx :reverb do
  sample drums_sn, start: 0.25, finish: 0.3, amp: 3
  ##| end
end

define :drums_hithat_play do
  sample drums_hithat, sustain: 0.1, release:0.15,
    start: 0.3, end: 0.4,
    amp: [4, 2, 3, 1.5].tick('vol')
  ##| end
end

define :drums_voice_play do
  sample drums_voice, slice: [1, 4].tick("foo"), num_slices: 8, finish: rrand(0.1,0.5)
  
end

use_bpm 96

bd_pattern = (ring 1,0,0,0, 0,0,0,0, 1,0,1,0, 1,0,0,0)

sn_pattern =    (ring 0,0,0,0, 1,0,0,0, 0,0,0,0, 1,0,0,1)
sn_pattern_02 = (ring 0,0,0,0, 1,0,0,0, 0,0,0,1, 1,1,1,1)



hithat_pattern = (ring 1, 0, 1, 0)
voice_pattern = (spread 4,8)
##| voice_pattern = (spread 1,16)


##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)


live_loop :conductor do
  
  sleep 1
end


live_loop :loop_bd, sync: :conductor do
  bd_on = bd_pattern.tick
  drums_bd_play if bd_on==1
  sleep 0.25
end

with_fx :reverb, amp: 2 do
  live_loop :loop_sn, sync: :conductor do
    sn_on = sn_pattern.tick
    drums_sn_play if sn_on==1
    sleep 0.25
  end
end

with_fx :hpf, cutoff: 110 do
  live_loop :loop_hithat, sync: :conductor do
    hithat_on = hithat_pattern.tick
    drums_hithat_play if hithat_on==1
    sleep 0.25
  end
end

with_fx :echo, mix: [1, 0.35].choose do
  live_loop :loop_voice, sync: :conductor do
    voice_on = voice_pattern.tick
    drums_voice_play if voice_on # spread sends back us true or false
    sleep 0.25
  end
end

1 Like

Hi there,

the original code works fine here on Debian 10 with Sonic Pi 2.10. Maybe timing is here lesser an issue depending on the system used.

Cu.

hi @minced_mind,

Have you changed the bpm value to 120 or you just tried with 60 bpm ?

my tests are on Windows 10 - Sonic pi 3.2.2. RAM : 8Go - i3- 4170 à 3.7GHz

Hi,

I tried with 120 bpm, too. The only exception is, I don’t have the sample :loop_3d_printer because of my old Sonic Pi version. So not fully compareable.

So, I tested it again. Downloaded the missing sample and changed the code for the missing sample:

# nlb - 01/07/2020
# small sequencer with samples
#

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = "~/tmp/loop_3d_printer.flac"

# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  with_fx :reverb do
    sample drums_sn, start: 0.25, finish: 0.5, amp: 3
  end
end

define :drums_hithat_play do
  with_fx :hpf, cutoff: 110 do
    sample drums_hithat, sustain: 0.1, release:0.15,
      start: 0.1, end: 0.25,
      amp: [4, 2, 3, 1.5].tick('vol')
  end
end

define :drums_voice_play do
  sample drums_voice, slice: [2, 7].tick("foo"), num_slices: 8, finish: 0.25
end


# bpm = 60 >> no problem
# bpm = 120 >> issues... :-(

use_bpm 120

bd_pattern = (ring 1, 1, 0, 0,  0, 0,0, 0,  1, 0, 1, 0,  1, 0, 0, 0)
sn_pattern = (ring 0, 0, 0, 0,  1, 0,0, 0,  0, 0, 0, 0,  1, 0, 0, 1)
hithat_pattern = (ring 1, 0, 1, 0)

voice_pattern = (spread 4,7)
##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)

live_loop :sequencer do
  
  tick
  
  bd_on = bd_pattern.look
  sn_on = sn_pattern.look
  hithat_on = hithat_pattern.look
  voice_on = voice_pattern.look
  
  with_fx :lpf, cutoff: 60, mix: 0.5, pre_amp:1 do
    drums_bd_play if bd_on==1
  end
  
  drums_sn_play if sn_on==1
  drums_hithat_play if hithat_on==1
  drums_voice_play if voice_on # spread send back us true or false
  
  sleep 0.25
end

Runs perfectly fine here with around 15% CPU usage. I have an old laptop with a Dualcore Haswell CPU and Hyperthreading. Maybe this is more related with your soundcard driver and Windows specific stuff.

Cu.

ok thanks. it’s good to know. I will test on linux systems to see. And as you say it’s maybe most a question of soundcard.

I think in most cases a Linux system is more suited for production stuff. Way more stable, reliable and performant. Robin Newman has created some nice building scripts and deb packages if you want to try newer Sonic Pi versions. I don’t need it so far, but this can change in the future :slight_smile:
Hope this helps a bit.

Cu.

by the way i hope it’s not a question of sonic pi version. Is there somewhere to download the latest 2 version ?

@nlb all available previous releases can be found here:

1 Like

yep https://github.com/sonic-pi-net/sonic-pi/releases/tag/v2.11.1

ouch :frowning:

it seems it’s a question of version…
i get this following code works without pb on spi 2.1.1 at 160 bpm. I replace loop_3d_printer by loop_amen_full

EDIT 01 : i have to do more tests to be sure and it would be great to be able to specify the setup path when installing the sonic pi. It may allows us to have several versions on a same computer. Is it possible @samaaron ?

EDIT 02 : i do test the same code with sonic pi 3.2.2 right now and get time error and sonic pi 3.2.2 stops. So sorry about that…

# Welcome to Sonic Pi

# nlb - 01/07/2020
# small sequencer with samples
#

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = :loop_amen_full


# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  with_fx :reverb do
    sample drums_sn, start: 0.25, finish: 0.5, amp: 3
  end
end

define :drums_hithat_play do
  with_fx :hpf, cutoff: 110 do
    sample drums_hithat, sustain: 0.1, release:0.15,
      start: 0.1, end: 0.25,
      amp: [4, 2, 3, 1.5].tick('vol')
  end
end

define :drums_voice_play do
  sample drums_voice, slice: [2, 7].tick("foo"), num_slices: 8, finish: 0.25
end


# bpm = 60 >> no problem
# bpm = 120 >> issues... :-(

use_bpm 160

bd_pattern = (ring 1, 1, 0, 0,  0, 0,0, 0,  1, 0, 1, 0,  1, 0, 0, 0)
sn_pattern = (ring 0, 0, 0, 0,  1, 0,0, 0,  0, 0, 0, 0,  1, 0, 0, 1)
hithat_pattern = (ring 1, 0, 1, 0)

voice_pattern = (spread 4,7)
##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)

live_loop :sequencer do
  
  tick
  
  bd_on = bd_pattern.look
  sn_on = sn_pattern.look
  hithat_on = hithat_pattern.look
  voice_on = voice_pattern.look
  
  with_fx :lpf, cutoff: 60, mix: 0.5, pre_amp:1 do
    drums_bd_play if bd_on==1
  end
  
  drums_sn_play if sn_on==1
  drums_hithat_play if hithat_on==1
  drums_voice_play if voice_on # spread send back us true or false
  
  sleep 0.25
end

For extra info, I can confirm this runs just perfectly on my Mac at 160BPM with the latest code from GitHub main.

There’s a couple of moving parts since v2.1:

  • The codebase has obviously changed significantly
  • The Ruby versions have been updated

It would be interesting to hot swap an older version of Ruby into the latest codebase to see if that “fixes” things. Out of interest, what version of Ruby is provided with v2.1.1? You can find out by running:

puts RUBY_VERSION

well i have to reinstall version 2.1.1 :slight_smile: to give you the info. Sorry no time to do that now.

Hmm, Sam beated me to it. Wanted to propose https://sonic-pi.net/files/releases/ to download official older releases :slight_smile:
Who knows if these still work on a moving target like Windows 10.
You can swap the loop_3d_printer sample like I did through using the path of a copied version of the sample from the original Sonic Pi release. So that you can test it without introducing any hearable changes.
I’m using the official Debian version 2.10 of Sonic Pi with a small patch from my side to integrate the run_file command.
I hope, you can narrow it down.

Cu.

On ubuntu 18.04, spi3.2.2 no pb until 160 with 4 Gb ram and old processor. Focusrite soundcard.

# nlb - 01/07/2020
# small sequencer with samples
#

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = :loop_3d_printer

# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  with_fx :reverb do
    sample drums_sn, start: 0.25, finish: 0.30, amp: 3
  end
end

define :drums_hithat_play do
  with_fx :hpf, cutoff: 110 do
    sample drums_hithat, sustain: 0.1, release:0.15,
      start: 0.1, end: 0.25,
      amp: [4, 2, 3, 1.5].tick('vol')
  end
end

define :drums_voice_play do
  sample drums_voice, slice: [7, 15].tick("foo"), num_slices: 16, start: 0.4, finish: 0.9
end


# bpm = 60 >> no problem
# bpm = 120 >> issues... :-(

use_bpm 160

bd_pattern = (ring 1, 1, 0, 0,  0, 0,0, 0,  1, 0, 1, 0,  1, 0, 0, 0)
sn_pattern = (ring 0, 0, 0, 0,  1, 0,0, 0,  0, 0, 0, 0,  1, 0, 0, 1)
hithat_pattern = (ring 1, 0, 1, 0)

voice_pattern = (spread 4,7)
##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)

live_loop :sequencer do
  
  tick
  
  bd_on = bd_pattern.look
  sn_on = sn_pattern.look
  hithat_on = hithat_pattern.look
  voice_on = voice_pattern.look
  
  with_fx :lpf, cutoff: 60, mix: 0.5, pre_amp:1 do
    drums_bd_play if bd_on==1
  end
  
  drums_sn_play if sn_on==1
  drums_hithat_play if hithat_on==1
  drums_voice_play if voice_on # spread send back us true or false
  
  sleep 0.25
end

Which it’s very cool as this method is simpler than one live_loop per instrument.

Hello !

Back to tests !

# Welcome to Sonic Pi v2.11.1

puts version
puts RUBY_VERSION

sleep 4

# nlb - 01/07/2020
# small sequencer with samples
#

# définir quel sample pour chaque instrument
# set up samples


drums_bd = :drum_heavy_kick
drums_sn = :loop_breakbeat
drums_hithat = :loop_amen
drums_voice = :loop_safari

# S'assurer que les samples sont bien chargés en mémoire
# to load samples to be sure they are loaded :-)
load_sample drums_bd
load_sample drums_sn
load_sample drums_hithat
load_sample drums_voice



# methodes pour jouer chaque instrument
# methods to play each instrument with fx if wanted

define :drums_bd_play do
  sample drums_bd, sustain: 0.25, amp:3, compress:1
end

define :drums_sn_play do
  with_fx :reverb do
    sample drums_sn, start: 0.25, finish: 0.30, amp: 3
  end
end

define :drums_hithat_play do
  with_fx :hpf, cutoff: 110 do
    sample drums_hithat, sustain: 0.1, release:0.15,
      start: 0.1, end: 0.25,
      amp: [4, 2, 3, 1.5].tick('vol')
  end
end

define :drums_voice_play do
  sample drums_voice, slice: [1, 5].tick("foo"), num_slices: 8, start: 0.2, finish: 0.45
end


# bpm = 60 >> no problem
# bpm = 120 >> issues... :-(

use_bpm 120

bd_pattern = (ring 1, 1, 0, 0,  0, 0,0, 0,  1, 0, 1, 0,  1, 0, 0, 0)
sn_pattern = (ring 0, 0, 0, 0,  1, 0,0, 0,  0, 0, 0, 0,  1, 0, 0, 1)
hithat_pattern = (ring 1, 0, 1, 0)

voice_pattern = (spread 4,7)
##| voice_pattern = (knit false, 1, true,2, false,1, true,2, false,4, true,1, false,3)

live_loop :sequencer do
  
  tick
  
  bd_on = bd_pattern.look
  sn_on = sn_pattern.look
  hithat_on = hithat_pattern.look
  voice_on = voice_pattern.look
  
  with_fx :lpf, cutoff: 60, mix: 0.5, pre_amp:1 do
    drums_bd_play if bd_on==1
  end
  
  drums_sn_play if sn_on==1
  drums_hithat_play if hithat_on==1
  drums_voice_play if voice_on # spread send back us true or false
  
  sleep 0.25
end

os : windows 10

I do test with the portable version of
sonic pi 2.1.1 portable version with ruby version “2.3.1”

sonic pi 3.2.2. with ruby version “2.7.1”

and the winner is sonic pi 2.1.1 :slight_smile: or i would rather say :frowning: while i would prefer the latest version to win.

a gif to illustrate my test

cheers

@nlb - very useful - thanks for this.

If you have time, could you also run the same experiment using portable versions between 2.1.1 and 3.2.2?