SynthMaker

Why almost every software synthesizer suffers from clicks?

Archive · 2007 16 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

Acrobat ·

I made a long and careful search through lots of plugins, commercial and freeware, but they all show this issue somehow or at particular settings. I know it is related to sudden value changes, but I think that if anyone has the proper knowledge and programming skills should take the bull by the horns. Even in the forthcoming Tone2 product, named "Gladiator", beta testers are already lamenting this issue. So I assume it's not just SM and not just a "newbie" issue...

Indeed, in my modest attempts to avoid it, I just managed to modify the classic portamento coding (the one you find inside MIDI2Poly) and apply elsewhere, and i.e. I succeeded in creating a perfect "velocity to volume" without clicks. But I still don't know how to avoid those clicks coming from very sudden, very different value in a filtering section: cutoff and resonance. Resonance in particular seems to generate the worse glitchy effects.

The first time I heard clicks was in 1998, with Native Instruments ProFive software synthesizer, Novation BassStation and Waldorf Q (this last 2 were FAKE hardware!). Before that I never needed to worry about this things with REAL analogue or digital hardware. Filters could be good or bad, envelopes could be fast, snappy or loose but surely they ALL never clicked...

I know it is already been discussed, but the problem is still there and so I'll be very pleased to hear some other voices on the argument....good or bad experiences, whatever! 🙂 😕 🙂 Andrea

TomC ·

Acrobat wrote: Before that I never needed to worry about this things with REAL analogue or digital hardware. Filters could be good or bad, envelopes could be fast, snappy or loose but surely they ALL never clicked...

[Disclaimer: the following statements come from an absolute DSP newbie, so don't kill me if it's bullshit]

What you describe as 'fast' in hardware is actually extremely(!) slow from a DSP programming point of view.

Within the DSP world you can easily produce a min(samplevalue) after a max(samplevalue) on a sample accurate base, that's something that can't happen in an analog world. So a first idea would be to average consecutive samples with each other to smooth the changes. But with doing this you'd change a lot in the frequency domain of the signal, so you'd have to look at a lot of samples to compensate for this. This would mean you'd mess the time domain.

That are a least the basics of the problems I'm encountering right now. Seems like a can of worms to me 🙂

Tom

Acrobat ·

oh.. interesting, so it seems I was watching the problem from the wrong perspective.... I'll try to think about it and understand....thx! 😕

Acrobat ·

TomC wrote: So a first idea would be to average consecutive samples with each other to smooth the changes. But with doing this you'd change a lot in the frequency domain of the signal,

That's exactly the point where I'm at, infact I used 6db cutoff coding (the portamento) and it works with amplitude, but not so well with frequency...

It's what you say here: "so you'd have to look at a lot of samples to compensate for this. This would mean you'd mess the time domain." that I'm still trying to understand...

oddson ·

TomC wrote: ...a first idea would be to average consecutive samples with each other to smooth the changes. But with doing this you'd change a lot in the frequency domain of the signal, so you'd have to look at a lot of samples to compensate for this. This would mean you'd mess the time domain.

I'm no DSP expert either but what you've said sounds about right to me.

I think the first step in avoiding them is to avoid the causes of the signal having 'discontinuities'.

But where it's not possible, what about a bit of code that watches 1 sample out and where the difference between n and n-1 exceeds some threshold then and only then you engage a low-pass filter (averaging) for a handful of samples only. (This would work better where the sample rate puts the Nyquist frequency well above the audible range and if it's high enough you could just leave one running all the time but I wonder if it might have some merit under certain circumstances. )

I've been toying with the idea for my long-loop projects. I've had some interesting results from jumping the delay length from spot to spot but it sometimes generates terrible clicks and those get looped back into the sound over and over.

An extension of this idea is to watch the difference signal itself and trigger filtering [edit!]only when the second-order difference does not excede a threshold (the reverse of what I said yesterday!)[/edit]

I.e.:

|(x[n] - x[n-1])-(x[n-1] - x[n-2])| > c

or perhaps

||(x[n] - x[n-1])| - |(x[n-1] - x[n-2])|| > c

The absolute value of the difference of the absolute values of the differences - or some kind of difference of squared values.

This should(?) prevent the filtering from triggering where a high frequency component is causing the first-order difference signal to have larger values and where you tend not to be able to hear clicks (I think... but I'm a bit over my head here.😕)

A final thought is to engage a low-pass only when known causes of clicking are present. In my case, when the delay length change occurs and not otherwise. But this is difficult right now because of the timing issue around event data.

Well that's enough semi-coherent rambling on this issue for now 😉

Acrobat ·

oddson wrote: Well that's enough semi-coherent rambling on this issue for now 😉

Oh yes thankyou very much there' a lot of things to learn now for me...

oddson wrote: But where it's not possible, what about a bit of code that watches 1 sample out and where the difference between n and n-1 exceeds some threshold then and only then you engage a low-pass filter (averaging) for a handful of samples only. (This would work better where the sample rate puts the Nyquist frequency well above the audible range and if it's high enough you could just leave one running all the time but I wonder if it might have some merit under certain circumstances. )

m think I got it... a sort of an auxiliary circuit... 😮

oddson ·

Don't spend too much time thinking about it. I'd like to hear from Sam or Rudolph or Stefan or anyone else who knows far more DSP than myself to tell me whether I'm talking junk or not.

TomC ·

oddson wrote: A final thought is to engage a low-pass only when known causes of clicking are present. In my case, when the delay length change occurs and not otherwise. But this is difficult right now because of the timing issue around event data.

Well that's enough semi-coherent rambling on this issue for now 😉

This special case should be simple:

streamin in; streamout out; streamin delay; float mem[44100]; float index; float old_delay; stage(2) { mem[index] = in; } stage(3) { index = index + 1; index = (index<=delay)&index; out = (delay == old_delay)&mem[index] + (delay != old_delay)&((mem[index]+mem[index-1])/2); old_delay = delay; }

If the delay value hasn't changed, the 'normal' delay code (out = mem[index]) is executed.

If it has changed, the smoothed low-pass value (out = mem[index] + mem[index-1]) is executed.

Of course some range checking and tasteful coefficients must be added, and maybe even more samples must be averaged on your case, but this should give you an idea. If you don't change the delay TOO often the low-passing shouldn't be audible (but I haven't tested my code at all, that's up to you 🙂).

Tom

TomC ·

TomC wrote: Oh my good, I follow up to my own posting. Must be bored or sumpthing...

On a second though, the whole low pass issue when you average something can probably be avoided if you:

1: save the sign of the sample:

sign = 1 - (mem[index]<0)&2;

2: average the absolute values

average = (abs(mem[index])+abs(mem[index-1]))*0.5;

3: assign the sign back

out = sign * average;

(abs isn't available, but it's easy to compute).

This is all theory (I'm not at my DAW right now), but I'm pretty sure you'll test this for me, right? 🙂

Tom

Andrew J ·

Andrea - could you capture some waveforms of some of these clicks and post images of some typical ones so we can see what's happening at a sample level? This could help us suggest some other strategies for avoiding them.

Tom's suggestion about the sign prompted me to think about the case where you have a sudden transition in phase. I'm not sure his technique would help much in that case.

-Andrew

Acrobat ·

Andrew J wrote: Andrea - could you capture some waveforms of some of these clicks and post images of some typical ones so we can see what's happening at a sample level? This could help us suggest some other strategies for avoiding them.

Tom's suggestion about the sign prompted me to think about the case where you have a sudden transition in phase. I'm not sure his technique would help much in that case.

-Andrew

sure! Just moving to my DAW...

Acrobat ·

Andrew J wrote: Andrea - could you capture some waveforms of some of these clicks and post images of some typical ones so we can see what's happening at a sample level?

Here it is 24bit 44100Khz rendered WAV file from my Alieno synth, effects all off. The first shot is the "clickiest", it seems phase as you're arguing, because the wave actually goes to 0-cross very abruptly... on the second shot clicking is almost inaudible because the transition is very tiny..call it a lucky case but when you add saturation it will eventually jump up to the ears... 😕

The synth has a fixed release time of 1764 (guess they're samples at SR of 44.1K, 0.1 as "knob value"), but I'd like to add customizable release times when clicking is solved! But the funny thing is I've fixed release times to avoid clicks and I have them anyway, my strategy seems useless because I recently realized that different CPUs would need different amount of samples!! ...I put effects off because they mask out the issue.. d:)

Hope you can confirm or even give some clue!

http://www.blank-media.it/synthmaker/testclick-05-24bit-44K-WAV.zip

oddson ·

The click at the end of the first pulse is a classic signal discontinuity. The signal shut down at a point leaving a large first-order difference in what was otherwise a near sinusoidal signal of a relatively low frequency (compared with the sample rate). You wouldn't have to fill in the exact path to zero that the signal would have taken if it had not been interrupted to remove the audible click. Any gentle path down to zero would be an improvement and a few dozen samples would do the trick.

If using a first-order IIR a fairly high cutoff should be OK if it's only in effect in the areas where clicks are a certainty and not in areas where high frequency signals are present (and clicks are not detectable).

But again... prevention is better than cure. What occurred to cause the problem and is there a way to prevent it from happening that way (better envelope control?).

The usual caveat that I don't really know what I'm on about applies here as well. 😉

Andrew J ·

Acrobat wrote: The synth has a fixed release time of 1764 (guess they're samples at SR of 44.1K, 0.1 as "knob value"), but I'd like to add customizable release times when clicking is solved! But the funny thing is I've fixed release times to avoid clicks and I have them anyway, my strategy seems useless because I recently realized that different CPUs would need different amount of samples!! ...I put effects off because they mask out the issue.. d:)

1764 samples would be 0.04 seconds at 44.1KHz, which looks about right from the waveform.

BTW, use the knob to set the release time in seconds or milliseconds, and then calculate the number of samples this would be by using the sample rate primitive. E.g. 0.05 seconds = 0.05 * S.R. = 2205 samples at 44.1KHz.

As for the click, if the signal is a nice tidy wave like your example - then you can prevent the click by muting the waveform at it's zero crossing. You need to do a few things to achieve this inside SM.

First, you need to know when the sound is meant to stop (i.e. end of the release stage). I haven't actually looked at any synth stuff in SM yet, but it looks like the current stage output of the ADSR may help you with this. I'm in unfamiliar territory here, but I suspect that the voice disappears entirely after the release stage finishes, so you'd have to watch for the end of the sustain stage and look for the last zero crossing before the end of the release stage. If the voice didn't disappear immediately, you could keep listening after the R stage finishes and find the next zero crossing.

To identify the last zero crossing before the end of the release stage, you'll need to know the frequency of your fundamental note and then convert this to how long the period of the waveform is in samples. This can be done by doing a P-F and then a 1/x. If the waveform is sinusoidal, then you know there'll be zero crossing at the half period also. I probably wouldn't want to assume this though.

So now you should know the start of the release stage, the release length (R) and the period (P) all in samples. Thus the time you should start looking for a zero crossing is (R - P) samples after the start of the release stage.

You then need a bit of code that takes three inputs:

(a) - the audio stream (b) - the current stage output from the ADSR (c) - the value of (R-P)

You can identify the start of the release stage by looking for the transition of (b) from 3 to 4. Next start a counter that counts for (c) samples. Next observe the absolute value of (a) and wait until it is within say 60dB of zero (might have to tweak this threshold). Then mute the signal and keep it muted for another (R-P) samples. (This last step might not be needed if the end of the voice ends the code automatically.)

I might have a bit of a play around with this myself (if I can find enough time!).

-Andrew

Andrew J ·

Well I had a play and found that this method really depends on how the ADSR envelope works. My test synth wasn't producing clicks at the end of the release phase anyway because the ADSR was fading to zero nicely.

So Andrea, if you like, I can post you my example and you can try it with your synth - or you can send me your synth and I'll see what I can do with it.

-Andrew

infuzion ·

[old link]

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.