Note control delayed with synth `dsaw`

Hi together!

While working on a track, in the more calm sections I had the impression that something is slightliy off in terms of timing/synchronization.

After some investigation, I found out that this is probably caused by a small delay when controlling the note played by the dsaw synth I use there (using control syn, note: ...).

Using Audacity, I could visualize it with the spectrogram view (screenshot below). At the top is the dsaw, with the cursor at the beat position. The change of the synth note is to the right of it, so somewhat delayed (0.03 - 0.04 sec). In the middle is saw, which shows a similar delay, but to a lesser extent. At the bottom is tb303, which does not show the delay, or at least it is too short to be visible.

Here is a minimal code example that reproduces the effect. It was also used for recording for the above image.

live_loop :tick, delay: 0.01 do
  8.times do
    use_sample_defaults finish: 0.05
    sample :elec_twip
    sleep 0.5
  end
end

live_loop :bass, sync: :tick do
  with_synth :dsaw do
    use_synth_defaults detune: 0, sustain: 8, release: 0, amp: 0.4
    syn = play :e2
    4.times do
      control syn, note: (scale :f2, :minor_pentatonic).choose
      sleep 2
    end
  end
end

Does anybody know whether this is expected behaviour for these synths, or if it might be a bug? I am quite sure it is not a performance problem (scsynth is below 1% CPU load).

Many thanks!

Hi there,

this is expected behaviour. Both the initial call to play and the subsequent call to control are converted to separate messages which are sent to the synthesis engine. At this stage, it’s possible for the messages to be received out of order. In order to guarantee that the order is preserved, in the case where both the initial trigger and and a following control are set to the same time stamp, (i.e. no call to sleep happens between them) then the control is delayed just slightly to ensure it arrives afterwards.

To avoid this, always ensure that there’s a sleep between the play and control.

In the future it may be possible to detect that this is happening prior to sending the messages out and then to automatically merge any similarly timed control into the play of a specific synth node as if you were just adding additional options to the play. However, this would require a considerable amount of “smarts” to be added to that layer of the system and isn’t particularly high priority at this stage.

Following on from @samaaron 's answer you could try this:

live_loop :tick, delay: 0.01 do
  8.times do
    use_sample_defaults finish: 0.05
    sample :elec_twip
    sleep 0.5
  end
end

live_loop :bass, sync: :tick do
  with_synth :dsaw do
    use_synth_defaults detune: 0, sustain: 8, release: 0, amp: 0.4
    syn = play (scale :f2, :minor_pentatonic).choose
    sleep 2
    3.times do
      control syn, note: (scale :f2, :minor_pentatonic).choose
      sleep 2
    end
  end
end

Hi Sam and Robin,

thanks a lot for your comprehensive answers! I will try the suggested solution ASAP.

Do I understand correctly that subsequent calls to control are delayed the same as the first one?

Is there a logic reason why the effect is not visible with tb303?

Thanks again!

I tried the code suggested by @robin.newman, but the delay did not change significantly:

In my “real” project, it is the same. Currently, I shorten the first note by 0.06 beats / 0.03 sec to compensate, but it is not so cool to have to measure the delay for every synth to be used with note control.

I wonder if the detune affects the attack that you hear. Do you notice any difference if you set detune to 0, or to 12?

No, not really. It is on 12 in the original project, and to change it to 0 was the first thing I tried. The example for the images also uses 0.

I will try the recommendation of not immediatly using control, with the saw synth, to see if it changes anything there.

I can confirm that the problem also persists for the saw synth, although using sleep 2 between play and control

I had the idea that the issue might be caused by the relatively low frequencies used in the tests, like maybe a new note only starts when an already running wave/period finishes. But using high frequencies like :f5 does not change anything either.

EDIT: Further, I tried to control different opts, still with sleeping between play and control. It appears that cutoff (top) changes with a delay, while amp (bottom) does not (or at least less delay than the length of the tick sound, here 0.03):

Should I report this as a potential bug on GitHub, so it does not slip away in case devs consider it as important?

Hi, could you try changing the following in the source code of your app to 0 and see if that improves things for you:

No, it’s still the same (tested for controlling the note played by dsaw, again).

Also, if the default_control_delta is in seconds or beats, the observed delta is an order of magnitude larger, with around 0.03 seconds.

1 Like

In that case, it’s quite likely to be related to the audio buffer size. Supercollider can’t issue a synth control change in the middle of computing an audio buffer. It can only do it at the buffer boundaries. Therefore the larger the buffer size, the larger the potential error for each control message. Note that the error is always there and bounded by the buffer size. Happy to explain this more if it doesn’t make sense.

You can play with the audio buffer size if you edit the new audio settings toml file in the config dir. this is located within the .sonic-pi dir within your home dir.

Let me know if changing the buffer size changes the results you see :slight_smile:

Thanks for this further suggestion! So you refer to sound_card_buffer_size here?

When I go below 512, I get no sound at all. With 512, the delay seems unchanged, but I get artifacts in the sound. With 1024 and above, sound is ok, but the delay if still there. Not being able to go lower is probably a limitation of my sound card…

Also, I am wondering why the tb303 does not show any visible delay, as it should also be affected by the buffer boundary “error”.

In the project where the issue first appeared for me, I could circumvent its audible effect by shortenting the first note played by the respective synth (published to in_thread here). But still, I would be interested in ways to preventing the issue from ground.

Just a proposal. Eliminating the choose operation just before the control excludes a potential influence on the timing:

live_loop :tick, delay: 0.01 do
  8.times do
    use_sample_defaults finish: 0.05
    sample :elec_twip
    sleep 0.5
  end
end

live_loop :bass, sync: :tick do
  with_synth :dsaw do
    use_synth_defaults detune: 0, sustain: 8, release: 0, amp: 0.4
    syn = play (scale :f2, :minor_pentatonic).choose
    notes = (scale :f2, :minor_pentatonic).pick(3)
    sleep 2
    notes.each do |n|
      control syn, note: n
      sleep 2
    end
  end
end

I haven’t done measurement, but when listening to it I somehow got the impression it is more on the point now. But it is hard to hear a difference at all.

Thanks, @Nechoj!

However, the code shown here is only a minimal reproducing example. It uses choose only incidentially. The original project plays notes from arrays that are generated before any live loop starts.

For details on that project, see this forum thread (which you already commented on :wink:). Code and documentation are linked there. The recorded track there is already corrected through a shortened first note.

EDIT: it is the bass live loop that is affected there. bass_delay is the correction.

I haven’t done measurement, but when listening to it I somehow got the impression it is more on the point now. But it is hard to hear a difference at all.

In the example presented here, I also don’t hear the delay, but visualized it (see screenshots). In the original project, however, it was audible in the uncorrected version.

Now I did some measurement as well. For that purpose I just changed controlline to

control syn, note: n, amp: [0.2, 0.6].tick

because then the Ableton recording shows the amplitude envelope. In most cases I see this:

test1

or this

test2

And in about 1 out of 10 it looks like that

test3

It looks as if there is some task switching in the OS going on which affects the timing of SPI. Is the control command executed within a new thread?

1 Like

Thanks for this test! For me, the delay in the note change is consistent in every call to control. As already reported here, the delay seems to affect only some of the opts, which does not include amp. However, I used the spectroscope visualization (in Audacity) as I found it better suited to see the relatively short delay.

Is the control command executed within a new thread?

Yes, playing the melody in the original is “released” to a separate thread using at do, in order to control other opts of the synth and an FX while playing.

Ok, if its consistent in every call on your machine and only in the note opt, then my observation apparently is a different issue and can be caused by the separate thread. The delay in the above picture is 1/32 = 0.03125 s.