Unwanted artefacts in sound

Hey!

I am trying to modulate from a more sinewavesh sound to an impuls. The following code works so far, but I get unwanted artefacts when the MouseX - Courser is all the way to the right side of the screen. The artifacts (quick jumps in amplitude) pop up very every few seconds … Does anyone know how to avoid these?

Thanky you very much!

Best regards,
Matthias


(//from examples
SynthDef(\Sine2, { |out, i_freq = 440, i_sustain = 1, i_pan = 1, i_amp = 0.1, width = 0.25 |
    var env = LFGauss.ar(i_sustain, width, loop: 0, doneAction: Done.freeSelf).range;
    var son = FSinOsc.ar(i_freq, 0.5pi)*env;
    OffsetOut.ar(0, Pan2.ar(son, i_pan, i_amp));

}).add;

~vbus1 = Bus.control(s, 1);
)

(
{Out.kr(~vbus1, MouseX.kr(0.000001, 0.2, 1))}.play;

Tdef(\synth1, {
	loop{
			(
			\instrument: \Sine2,
			\freq: 400,
			\sustain:0.1,
			\width: ~vbus1.asMap,
			\amp: 0.3
		).play;
		 0.01.wait;
	}
}).play;
)

You cannot avoid this with language-triggered sequencing in realtime. I’ve described the reason here:

It can also be observed with Pbind writing:

(
{ Out.kr(~vbus1, MouseX.kr(0.000001, 0.2, 1))}.play;

Pbind(
	\instrument, \Sine2,
	\freq, 400,
	\sustain, 0.1,
	\width, ~vbus1.asMap,
	\amp, 0.3,
	\dur, 0.01
).play;
)

Only options: do it in NRT or server-side. It should be noted also that this unavoidable inaccuracy only plays a role with smooth regular sound material. For many if not most granulation applications it doesn’t play a role in perception.

This is really a shame I think ! ChucK purports to surmount this (although there are other deal-breaker issues there in my experience)…

I don’t see it so negative. It’s mainly about becoming aware of each tool’s limits. In most cases there are alternative solutions in SC itself. E.g. here we can easily rewrite the example as Synth (panning omitted, but also possible):

(
x = { 
	var sustain = 0.1, freq = 400, amp = 0.1, width = MouseX.kr(0.000001, 0.2, 1), env, son;
	son = FSinOsc.ar(freq, pi/2);
	env = { |i| DelayL.ar(LFGauss.ar(sustain, width, loop: 1), 0.2, i * 0.01) } ! 10;	
	(son * env).sum * amp ! 2;
}.play
)

x.release

// plot the envelopes alone

{ 
	var sustain = 0.1, env;
	env = { |i| DelayL.ar(LFGauss.ar(sustain, 0.2, loop: 1), 0.2, i * 0.01) } ! 10;
}.plot(1)

Thank you for the responses! Not sure if I fully get the NRT/RT process. The code will be manipulated by sensors, there will also be an OSC-connection to another Software. So I guess NRT will not be an option, right?

Also thank you on how to solve it another way! I have rewritten your code a little bit (see below).
My goal is to have an impulse at the end with a frequency of less than 1Hz. I tried to alter the duration of LFGauss and the delaytime to get from a high freuqency impuls to a low frequency one, but it also creates artifacts. Makes sense to me since I am manipulating the delaytime.

So what works good is getting from a sinewave to a high frequency impulse. But getting from a high to a low frequency impulse doesn’t really work. I cant think of a smooth way of solving it. Do you guys have any suggestions or workarounds?

Thank you very much!
Best regards,
Matthias

(
SynthDef(\x, { |duration = 0.01, delaymod = 0.01|
var sig, freq = 400, amp = 0.1, width = MouseX.kr(0.000001, 0.8, 1), env;
env = { |i| DelayL.ar(LFGauss.ar(duration, width, loop: 1), 1, i * delaymod) } ! 10;
sig = FSinOsc.ar(freq, pi/2);
sig = (sig * env).sum*amp!2;
Out.ar(0, sig);
}).add;
)

(
Ndef(\duration, {MouseY.kr(1, 0.01, 1)});
Ndef(\delaymod, {MouseY.kr(0.000001, 0.01, 1)});
)

x = Synth(\x, [\duration, Ndef(\duration).asControlInput, \delaymod, Ndef(\delaymod).asControlInput])

This would only have modulation effects with fast delaytime changes, so this is not or at least not the main reason. But you’re setting width to 0.8 which causes a bumpy envelope, see

{
	var sustain = 0.1, env;
	env = { |i| DelayL.ar(LFGauss.ar(sustain, 0.8, loop: 1), 0.2, i * 0.01) } ! 10;
}.plot(1)

Moreover you’re triggering a complicated modulation process with three simultaneously changing parameters and consequently get AM artefacts. Another point: When starting with LFGauss of width = 0.2, you are already starting with a slighty AM-modulated sine wave. Higher width values of LFGauss on the other hand would need more overlaps, so an array of higher size. Controling the LFGauss ‘as Impulse’ is also problematic at least because of amplitude.
A powered sine can be an alternative to LFGauss, though with high power values, close to impulse, it suffers the same problem of control with low frequencies. So I’d suggest a different approach: do a crossfade between a powered sine and impulse. Variant: taking a transition from a constant 1 signal to a powered sine as envelope for another signal.

(
// mappings may need some tweaking
{ 
	var startFreq = 200;
	var endFreq = 1;
	var ctrl = MouseX.kr(0, 1);
	var power = ctrl.linlin(0, 0.5, 1, 1500).poll(label: \power);
	var freq = ctrl.explin(0.5, 1, startFreq, 1).poll(label: \freq);
	
	var sig = SelectX.ar(ctrl * 2, [
		SinOsc.ar(freq).range(0, 1) ** power,
		Impulse.ar(freq)
	]);	
	// for plotting of waveform changes you can drop LeakDC
	LeakDC.ar(Normalizer.ar(sig) * 0.1 ! 2)
}.play
)