Sound quality:crackling, pops, klicks, hisses?

The past year I’ve not done much with Soundcollider. All the extra, unwanted, noises “it” makes started to annoy me. So I postponed using it until I could get a new machine. I thought the old one (12 years) was the problem. Now, with an i9-12900, 32Gb, Win11 pro, the sounds are still there.

So, what is the cause? A demo code below, it uses 20%.

There are little clicks, cracks. These can be seen in the spectrum scope. The output from the synth is limited to 1500Hz by nature of what I made. When it clicks the right leg of the graph kicks up. Sometimes just a little. Sometimes a lot with “noise” on it.

As it is seen in the scope I doubt it has anything to do with the sound device UMC404HD (latest driver, v5.30.0). Switching from the ASIO driver to using WASPI changes nothing, as I expected.

Using different settings for the numOutputBusChannels (2, 4), hardwareBufferSize, numWireBufs, blockSize, sampleRate, or the bit-depth through the OS didn’t change a thing.

I tried the LeakDC and Intergrator in the scene file with no avail.

Is it something in Windows?
Is it something in Supercollider?
Is it how I write the code?

TIA,

ingo

(
~shuheiKawachi = {
	arg x, y, a, b;
	((cos(x) * cos(y))
	+ (cos((sqrt(a) * x - y) / b)
		* cos((x + (sqrt(a) * y) ) / b))
	+ (cos(( sqrt(a) * x + y) /b)
		* cos((x - (sqrt(a) * y*y)) / b)));  // /3;
};
)

(
/*
Major circle 'sweeps' minor circle through xy-space.
Minor circle samples the function on 'segments' points.
These values are amplitudes for DynKlang.
*/
Ndef.new(\circSegs, {
	arg segments = 50
	, xMajor = 0.0
	, yMajor = 10.0
	, rMajor = 30.1
	, rMinor = 0.1
	, circlefreq = 0.0001 //1.0
	;
	var arr, grey, xMinor, yMinor, freqs, amps, phase;
	freqs = Array.exprand(50, 50, 1500).sort; //segments?
	phase = #[0.0]!50; //segments?
	amps = Array.new;  //set max segments?
	xMinor = xMajor + (rMajor * SinOsc.ar(circlefreq));
	yMinor = yMajor + (rMajor * SinOsc.ar(circlefreq, pi/2));
	amps = Array.fill(
		50, //segments?
		{
			arg seg;
			x = xMinor + (rMinor * sin(seg*2*pi/segments));
			y = yMinor + (rMinor * cos(seg*2*pi/segments));
			grey = ~shuheiKawachi.(x, y, 2*pi, 0.5);
			grey = Wrap.ar(grey, 0, 1)/segments;
			grey
		}
	);
	d = DynKlang.ar(`[freqs, amps, phase]);
	//d = Integrator.ar(d, 0.3, 1.0, 0.1);
	//d = LeakDC.ar(d);
	Out.ar(0,d!2)
});
)

Ndef(\circSegs).clear;
1 Like

One suggestion for troubleshooting is to simplify: start with a simple case and build up from there, until it breaks. Then, whatever changed before it breaks is the culprit.

You have 50 sine waves with some highly complex amplitude modulation.

How does it behave with one?

To estimate the interaction between dozens of partials, it would be helpful to understand what’s happening with one of them first. Then try, oh, 5… then 10. Is it clean with fewer partials and goes wrong somewhere later?

The question seems to be written from the perspective of, “I know/believe that the formula should produce a clean signal, but SC is producing a dirty signal, so perhaps there is something wrong with SC” but I’m not certain what the formula really does (and don’t have access to my machine temporarily). How to rule out a problem with the formula? One way would be other software. If csound renders it cleanly but SC doesn’t, that could be convincing. Another way would be incremental testing as suggested above.

hjh

1 Like

Oh, very nice! Thanks for posting.

Pleasantries aside, it runs fine here, Sc-3.13 / Debian-5.18.

So it’s not in the code, or in Sc generally speaking.

I can’t help with Windows I’m afraid, but hopefully someone else can!

Bad. From 1 to 88 the noises increase, but not in a way that points to a machine congestion problem.

That gave me an interesting morning. I went through many different sources and many have problems. Then I fired up the old machine and the problems there are bigger. But there are also scenes that are free of problems…

ShuheiKawachi_smooth
ShuheiKawachi_clamp
ShuheiKawachi_abs

Three images of the same function. The function is smooth and its output varies between -3 and 3, no noise. An image can’t show that. My renderer auto-clamps and folds the result. Image 2. This gives a lot more “detail”. To get more “detail” in the sound I use the Wrap.

Then it slowly dawned on me that the transitions are quite sharp. Square wave like. So when the “scanner” goes over that the amplitude of a single sine wave goes from 1 to 0, or 0 to 1. That then results in the high frequency “crackling” sounds.

So I have to find a way to smooth things a bit, without creating dull grey “images”. In graphics I would use the smoothstep function or manually remap values. I know there is a SmoothFoldS2 by @dkmayer . I have not investigated that.

For this specific case there is no need for the negative part of the function. Taking the absolute of it and scaling it down to the 0-1 range (last image) works fine, smooth and without crackles. Sounds different though.

Thanks! The “dirty signal” did it.

(
~shuheiKawachi = {
	arg x, y, a, b;
	((cos(x) * cos(y))
	+ (cos((sqrt(a) * x - y) / b)
		* cos((x + (sqrt(a) * y) ) / b))
	+ (cos(( sqrt(a) * x + y) /b)
			* cos((x - (sqrt(a) * y*y)) / b)))/3;
};
)

(
/*
Major circle 'sweeps' minor circle through xy-space.
Minor circle samples the function on 'segments' points.
These values are amplitudes for DynKlang.
*/
Ndef.new(\circSegs, {
	arg segments = 49
	, xMajor = 10.0
	, yMajor = 1.0
	, rMajor = 100.1
	, rMinor = 1.1
	, circlefreq = 0.0001 //1.0
	;
	var arr, grey, xMinor, yMinor, freqs, amps, phase;
	freqs = Array.exprand(49, 50, 1500).sort; //segments?
	freqs.postln;
	freqs.plot;
	phase = #[0.0]!49; //segments?
	//phase = Array.rand(49, 0, 2*pi); //segments?
	amps = Array.new;  //set max segments?
	xMinor = xMajor + (rMajor * SinOsc.ar(circlefreq));
	yMinor = yMajor + (rMajor * SinOsc.ar(circlefreq, pi/2));
	amps = Array.fill(
		49, //segments?
		{
			arg seg;
			x = xMinor + (rMinor * sin(seg*2*pi/segments));
			y = yMinor + (rMinor * cos(seg*2*pi/segments));
			grey = abs(~shuheiKawachi.(x, y, 2*pi, 0.5))/12;
			grey
		}
	);
	d = DynKlang.ar(`[freqs, amps, phase]);
	Out.ar(0, d!2)
});
)

Ndef(\circSegs).clear;

Apologies, I was just listening quietly before, and it sounds nice! To clamp the spectrum the below change to the first graph works also (it just smooths the amplitude signal…)

			grey = Wrap.ar(grey, 0, 1).lag(0.01)/segments;

I’ll have a look, listen at that. Have fun with the sounds.