Skip to content

Instantly share code, notes, and snippets.

@rbnpi
Last active May 6, 2024 10:12
Show Gist options
  • Save rbnpi/2c6d2da3246f64f4d97e to your computer and use it in GitHub Desktop.
Save rbnpi/2c6d2da3246f64f4d97e to your computer and use it in GitHub Desktop.
Tuning Sonic Pi for best performance

Tuning Sonic Pi for best performance

Several of the programs I write for Sonic Pi push it fairly close to the limit when run on a Raspberry Pi. This note gives some tips on to how to maximise the performance on that platform. Of course, if you run Sonic Pi on Mac OSX,or a Windows PC then the performance is much better on these more powerful platforms and some of the issues may not arise.

Over-clocking your Pi

By increasing the voltage applied to the Pi processor, and running it at a higher clock frequency than normal it is possible to achive significant gains in performance. The down side is that you may reduce the lifetime of your Pi. There are five levels that can be configured: None, Modest, Medium, High and Turbo. I routinely run my Raspberry Pis with Medium Overclocking and have noticed no ill effects on any of them.

If you wish to apply some over-clocking you do so by running the program raspi-config from the command line. Having logged on, from the command line before you start the graphical user interface, or if you have, then from a terminal window type: sudo raspi-config A small window will be created with 9 choices. Use the down arrow key to select choice 7 Overclock and press the return key. Read the warning and press return again. Use the up and down arrow keys to select the overclock level you want to use, and press return again. After a short pause, whist the overclock lvel is set, press return again to move back to the initial menu of choices. There press the tab key twice to highlight the word in red, and press the Return key again. In order to activate the new overclock setting you have to Reboot your Pi. You can use the tab key again to select whether to do it immediately or leave it till later Finally press the Return key once more to select and activate your choice, and exit the raspi-config program.

Using Set_Sched_Ahead_Time!

Sonic Pi has a user adjustable feature which can help it cope with severe processing demands, and still play the music generated in perfect time. The help file states:

"Using Set_Sched_Ahead_Time

Specify how many seconds ahead of time the synths should be triggered. This represents the amount of time between pressing 'Run' and hearing audio. A larger time gives the system more room to work with and can reduce performance issues in playing fast sections on slower platforms. However, a larger time also increases latency between modifying code and hearing the result whilst live coding."

A typical command might be: set_sched_ahead_time! 4 At the end of the piece you can reset it with set_sched_ahead_time! 1

Experiment wiht a piece which is showing a tendency to come adrift by adding a set_sched_ahead_time! command and increasing the value bit by bit until it runs smoothly.

One thing to realise about this command is that when you change the ahead time the new value remains in force until either you restart Sonic Pi, or you change it for a new value. The default value on a Raspberry Pi is 1. On one or two programs I have written I have had to use values of 8 or 10 or even higher, but usually a more moderate setting of 2 or 4 can improve program performance. The down side is that there is a gap in time when you press run before the program starts playing. For a linear piece this is not too much of a problem, but if you are doing live coding then it means there is quite a slow response when you change the code and re-run before the change takes place.

Turning off output messages

One of the easiest ways to improve performance is to switch off printed output whilst Sonic Pi is running a program. This can be done in the Preference Settings where you can untick the settings Print output and check synth args.The settings are remembered and restored when you stop and restart Sonic Pi. Alternatively you can insert the code use_debug false at the beginning of your program. Note if your program includes statements like puts "print this string" then these will still be printed, as will certain other statements like cues and sample loaded statements, but these should not affect the performance too much.

Not running other programs at the same time

This is probably fairly obvious. The more your Raspberry Pi has to do, then the fewer resources it can devote to Sonic Pi. If possible quit other programs when using Sonic Pi.

Avoiding situations that may create problems

This is not always possible but you should be aware that the following will increase the processing load in Sonic Pi.

The more threads you have running simultaneously the greater the loading

Having several different synth voices running at the same time increases loading

Adding effects can incresae loading, especially when these become nested. So for example, applying reverb AND echo together can make things difficult.

Running effects settings INSIDE a loop is more taxing than enclosing the loop inside an effects wrapper. In the former case you are setting up multiple effects processors.

If your program uses many samples consider preloading them before the program starts running in earnest. This can be done using a statement like load_samples [:elec_plip, :elec_blip] where the samples to be loaded are put into a list. Note however that you may also have to put a sleep statement in after this load statement to make sure the samples have enough time to load. This is more important when you use your own externally added samples as I often do when adding other musical instrument voices to Sonic Pi.

Symptoms of things going wrong

If notes start falling over one another or a thread stops running or Sonic Pi becomes unresponsive when playing, with the processor load (top right on the screen on the new desktop interface, or a green graph bottom right on the older one) showing 100% or solid green, then Sonic Pi is having problerms in running the code. Another thing to be careful about is that you are allowing notes or samples sufficient time to complete, especially in looped code. For example loop do play 72,sustain: 5 sleep 0.1 end will run into problems, because the notes are sounding for 5 seconds but you are only allowing 0.1 second between them. After playing for a bit the thread will fall over.

Recovery when things go wrong

Symptoms of things going wrong are when notes start to run together, or the timing of notes in separate threads that should play together start going wrong. I usually like to stop the program running fairly quickly at this stage, as otherwise all the processing power of the Raspberry Pi is utilised in trying to play your notes and samples and the program can become unresponsive to the stop button being pressed, sometimes taking many seconds to respond. On occasion, I have to quit Sonic Pi to restore things, but usually have to do this from a separate terminal window typing a command like sudo killall ruby which knocks out the ruby language called by Sonic Pi and causes it to quit. No harm is done, and you can restart Sonic Pi again. If all else fails you might have to pull the power plug from the Raspberry Pi which is a bit drastic, and not to be recommended unless absolutely necessary.

Final note

You can avoid most of these problems when using Sonic Pi on a Mac or Windows PC. However, you should remember that most users, are likely to be using a Raspberry Pi, and so, if at all possibly you should check programs on the Raspberry Pi before publishing them, and if necessary take steps to make them run OK. Certainly for any published program you should make it clear that it will NOT work satisfactorilly on a Raspberry Pi IF that is the case.

Don't let this article put you off. The majority of programs will run perfectly happily on an unclocked Pi. It is only when you start to use more ambitious programs that you will have to take into consideration the topics raised in this article.

Enjoy your Sonic Pi coding!!!

@jonnyhotchkiss
Copy link

Great tips! Just found whilst investigating how set_sched_ahead_time! affects timing issues.
Also, wondering if even old pi's out perform windows, and the limits and best possible performance of each.

MME / ASIO / JACK / WASAPI

Arguments in favour of almost all online, latency (s.rate/size?) ~ 0.02 to 0.09 seconds (20-90ms)

  • as expected, improvements observed with initial ramping of sched_ahead_time, but
  • when sched_ahead is raised, no sound is heard after first performance, even after setting it back to a lower value (restart required to fix)

Is this normal?

The test script I'm using is the "max cooper-esque" one
https://in-thread.sonic-pi.net/t/jumping-off-point-resynthesis-by-max-cooper/7863/1

I've dropped the bpm (from default 60) to 42, and the performance works, with sched_ahead 1
Additionally, I've added a loop delay for equal time, so the performance begins when ready

n = 1
set_sched_ahead_time! n

live_loop :a1,delay: n do

(NB: I've also commented out a couple of lines that I thought were performing faster; some may be okay, as the increased rate is used with a beat_stretch)

sample :glitch_perc3, beat_stretch: [0.25,0.5, 1,2,4].choose, rate: [2,4].choose, slice: rrand_i(1,10), amp: 2, pan: rdist(0.5) if bools(1).look and one_in(2) #L131
sample :sn_generic, slice: 1, rate: 3, amp: 1.5, pan: rdist(0.75)  if bools(0,0,0,0, 1,0,0,0, 0,0,0,0, 0,0,0,0,).look #and one_in(2) #L136

After success @ bpm 42, sched 1, these were enabled, and also ran ok.

Current block size = 128 (doubled from 64, as that seemed to fix an issue with no audio after stop with high sched_ahead ).
and process priorities default normal (as admin on windows I can set processes to real-time! but this seems to have little to no effect).

I haven't yet pre_loaded samples prior to loop_run, from debug messages that may help further...


test 2: n 8, bpm 48 💥

This is running now, so far no timing issues, even with all samples with beat_stretches and rates, and rev_fx! Don't think this worked last time; only difference I can think of is system had a shutdown last night (normally it wakes from sleep).

On stop, however, the no sounds issue is observed, and restart required: scsynth.log reports

late 0.004804611
late 0.004804611
late 0.033833981
late 0.033833981
late 0.062866211
late 0.020715714
late 0.035224438
late 0.058437824
late 0.058437824
late 0.072952271
late 0.087461948
late 0.000247002
late 0.020557880
late 0.020557880
FAILURE IN SERVER /n_free Node 15459 not found
FAILURE IN SERVER /n_free Node 15464 not found
FAILURE IN SERVER /n_free Node 15470 not found
FAILURE IN SERVER /n_free Node 15475 not found
FAILURE IN SERVER /n_free Node 11583 not found
FAILURE IN SERVER /n_free Node 22569 not found
FAILURE IN SERVER /s_new Group 22747 not found
FAILURE IN SERVER /s_new Group 22747 not found
FAILURE IN SERVER /s_new Group 22747 not found

test 3: bpm 51 (+3)

no sound so restarting, and retesting 2 to see if any sounds after stop, issue reproduced.

from the 910k Google results it looks like it's an sc issue, but can it be avoided, or can some sort of quicker server.restart be accomplished?

Is this issue only seen on windows, or (more likely) is it perhaps inevitable regardless of platform?

does everyone get similar performance issues?
is it possible to limit the available resources in linux to try to reproduce the issue, or even statistics on available cpu etc, if that's pertinent, either from sys or via ruby or using some additional benchmarking + cpu tools?

Many thoughts thunk, many tests planned! Many thanks!! 🙏🏻🤲🏻

@jonnyhotchkiss
Copy link

after further testing, it seems

  • issue prevalent regardless of audio driver (ASIO4ALL WASAPI MME)
  • issue persists with increased max synthdefs, max nodes, more block size
  • issue caused by fx, no problem with no sound after stopping code if fx commented out...

What remains to be seen is if this normal, or just a windows thing, or just me... and what the breaking point is on windows (10 vs others, perhaps) , and the rest...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment