[question] - supercollider synthesis definition not working

how could i theoretically fix this?

    Server.local.makeWindow
    s.options.memSize = 2000000;
    s.reboot;
    
    (
    SynthDef(\mysynth, {
    	var bufferSize = 128;
    	~oscs = [SinOsc, Saw, Pulse, LFSaw];
    
    	~env = Mix.new([
    		EnvGen.kr(Env.asr(0.1, 0.5, 0.5), 1),
    		EnvGen.kr(Env.perc(0.1, 1), 1)
    	]);
    
    	~modOsc = SinOsc.kr(freq: 1);
    
    	~filters = [LPF, BPF, HPF];
    
    	Mix.fill(bufferSize, {
      
    		~a=~filters.choose.ar(~oscs.choose.ar(
    			freq: TRand.kr(30, 20000, Impulse.kr(
    				freq: 1/60)) + ~modOsc ,
    			mul: SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/60)))
    			* ~env*12 * SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/10))))*(1/bufferSize),
    		// Multiply the output of the oscillators by 0.5
    		freq: TRand.kr(30,20000,Impulse.kr(1/10)).abs);
          
    		~b=~filters.choose.ar(~oscs.choose.ar(
    			freq: TRand.kr(30, 20000, Impulse.kr(
    				freq: 1/60)) + ~modOsc,
    			mul: SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/60)))
    			* ~env*12 * SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/10))))*(1/bufferSize),
    		freq: TRand.kr(30,20000,Impulse.kr(1/10)).abs);
          
    		~reverb = FreeVerb.ar(Mix.new(~a+~b), 0.5, 0.5);
    		~delay  = DelayC.ar(~reverb, 0.5, 0.5);
          
    		~output = [~a+~b+~reverb+~delay]!2;
    		~output=Pan2.ar(~output, SinOsc.kr(TRand.kr(0.125,3.14,Impulse.kr(1/10)),mul:1),0.3);
          
    		Out.ar(0, ~output);
    	});
    }).add;
    )
    
    a = Synth(\mysynth);

thank you so much

i fixed the for loop as indicated by mr @Thor_Madsen

by the way, besides crediting @Thor_Madsen and the supercollider forum community, for helping me iterating this, i should do the same for openai chatgpt

by the way, thank you @semiquaver for the extra help as well as @jamshark70

so for, it’ts fixed fixed. at least for now. i may need some further iteration so don’t close this thread yet, which may lead to the necessity of getting some extra help

The for (…) statement is not valid - syntax error, and also semicolon after the statement needed. I am not sure exactly what you are trying to achieve, maybe you can do (1…3).collect{|i|…} instead. Also, you cannot use .wait outside a routine, so you should put everything inside a routine for this.

you have 3 dots instead of 2 - should be (1..3).collect - or better 3.collect

first of all: thank you so much for your kindness and thank you for pointing me to directions on how to fix this. i tried to improve the overall thing. but i am still getting some errors. if you could help me fixing those, by testing the code on your machine, debugging it trying to fix it. and trying to provide me on a fixed implementation i would be quite thankful.
kind regards
T.

The general structure you are using in your ~synth function is not allowed. You cannot use .choose in a SynthDef or a function playing sound. Instead you have to define all 4 Ugens, ie. SinOsc.ar(…), Saw.are etc and use the Select Ugen or similar to choose one of the other or you have to create a synth factory (ie. a function producing SynthDefs or any functions producing sound) which run before you call .play. It is not clear to me what result you are trying to obtain. Can you describe it in detail?

I can’t find the right places in the documentation regarding conditional logic on the server right now, maybe somebody else can find it?

Also, these are language-side operations which should never be written in a synthesis function.

Actually, in your first version, there isn’t even a synthesis function. You’ll need a SynthDef or {}.play structure.

Here’s a template. You can fill in the contents for yourself.

Task {
	SynthDef(\mysynth, {
		synthesis stuff
		and
		only synthesis stuff
		in here
		
		NO .wait
		NO Server.whatever
		do not write those in here
	}).add;
	
	s.sync;
	
	a = Synth(\mysynth, [...]);

	// note that this is OUTSIDE of the synthdef
	// but INSIDE the Routine/Task
	60.wait;
	a.free;
}

This line:

rectModM=Mix.fill(256, recMod);

This might be meaningful if recMod is a function (see Array.fill help). But it’s not. It’s just a UGen. So the result you get here is recMod + recMod + recMod + recMod + recMod + recMod + recMod + ... 256 times... + recMod which… if this is what you want, then why not just write recMod * 256? 1 UGen vs 255.

But then… you’re reducing the envelope volume by (1/256) * 6 – or why not just write 6/256? – and then * 256 with the Mix… is this being done for a concrete purpose?

Technically, you can, but the choice will be made at the time of building the SynthDef and it will not change per Synth. If you do want it to change per Synth, you can use Select as noted, or create a separate SynthDef per oscillator type and choose the SynthDef name.

hjh

@tmm881 - just out of curiosity, was this code generated by some ai algo or by you?

the code was created by me, and iterated with the help of ai

greetings
i tried to merge my two previous examples.

    Server.local.makeWindow
    s.options.memSize = 2000000;
    s.reboot;
    
    (
    SynthDef(\mysynth, {
    	var bufferSize = 128;
    	~oscs = [SinOsc, Saw, Pulse, LFSaw];
    
    	~env = Mix.new([
    		EnvGen.kr(Env.asr(0.1, 0.5, 0.5), 1),
    		EnvGen.kr(Env.perc(0.1, 1), 1)
    	]);
    
    	~modOsc = SinOsc.kr(freq: 1);
    
    	~filters = [LPF, BPF, HPF];
    
    	Mix.fill(bufferSize, {
      
    		~a=~filters.choose.ar(~oscs.choose.ar(
    			freq: TRand.kr(30, 20000, Impulse.kr(
    				freq: 1/60)) + ~modOsc ,
    			mul: SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/60)))
    			* ~env*12 * SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/10))))*(1/bufferSize),
    		// Multiply the output of the oscillators by 0.5
    		freq: TRand.kr(30,20000,Impulse.kr(1/10)).abs);
          
    		~b=~filters.choose.ar(~oscs.choose.ar(
    			freq: TRand.kr(30, 20000, Impulse.kr(
    				freq: 1/60)) + ~modOsc,
    			mul: SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/60)))
    			* ~env*12 * SinOsc.kr(TRand.kr(0.125,8,Impulse.kr(1/10))))*(1/bufferSize),
    		freq: TRand.kr(30,20000,Impulse.kr(1/10)).abs);
          
    		~reverb = FreeVerb.ar(Mix.new(~a+~b), 0.5, 0.5);
    		~delay  = DelayC.ar(~reverb, 0.5, 0.5);
          
    		~output = [~a+~b+~reverb+~delay]!2;
    		~output=Pan2.ar(~output, SinOsc.kr(TRand.kr(0.125,3.14,Impulse.kr(1/10)),mul:1),0.3);
          
    		Out.ar(0, ~output);
    	});
    }).add;
    )
    
    a = Synth(\mysynth);

Which 2 previous examples? Are those working? Is still not clear to me what you are trying to achieve. Getting help fixing non-working code without a description of what you want to achieve is close to impossible :wink:

i am trying to make a cloud of about 256 procedural voices, that instantiate themselves on a different way everytime they run, and change freequancy, and have built in frequency modulation, ringmodular, reverb, chorus, delay, and distortion, and filtering. by the way the freequencies are not changing

Ok, we are getting there but still a very broad and general description. Before putting 256 of these voices and adding fx, how would one voices look? I still did not see any working examples of anything so far:)

Also:

  • What is the frequency relation between the 256 voices
  • Why 256 voices?
  • Should the fx be added per voice or to the sum of the voices (either mono or stereo)? Adding 256 instances of a reverb might not be a way forward as the total cpu load will be huge. On the other hand, FM modulation, ringmodulation and distortion are cheaper processes cpu-wise and could be done per voice.

Ok so I looked some more at you code and I think I understand what you are trying to achieve now. Below are two different ways you can approach it. It does not do everything you asked, but you can see a general method for accomplishing what you are after. In this version I am calling the changes from the language instead of using triggers on the server. As you can see, when using 256 instances, the cpu load is quite heavy so in any case you will have to be careful about cpu resources.

// Define 3 osc synthdefs, 3 filter synthdefs and 1 mod synthdef

(
SynthDef(\sin, {
	var sig = SinOsc.ar((\freq.kr(110) * \mod.kr(0)).max(30).min(10000), 0, \amp.kr(0.1));
	var env = Env.asr(\atk.kr(2), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.ar(\out.kr(0), sig * env)
}).add;

SynthDef(\saw, {
	var sig = Saw.ar((\freq.kr(110) * \mod.kr(0)).max(30).min(10000), \amp.kr(0.1));
	var env = Env.asr(\atk.kr(2), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.ar(\out.kr(0), sig * env)
}).add;

SynthDef(\pulse, {
	var sig = Pulse.ar(\freq.kr(110) * \mod.kr(0), 0.5, \amp.kr(0.1));
	var env = Env.asr(\atk.kr(2), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.ar(\out.kr(0), sig * env)
}).add;

SynthDef(\lpf, { 
	var sig = Pan2.ar(LPF.ar(In.ar(\in.kr(0)), \freq.kr(300)), 0);
	var env = Env.asr(\atk.kr(0.1), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.ar(\out.kr(0), sig * env) 
}).add;

SynthDef(\hpf, { 
	var sig = Pan2.ar(HPF.ar(In.ar(\in.kr(0)), \freq.kr(300)), 0);
	var env = Env.asr(\atk.kr(0.1), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.ar(\out.kr(0), sig * env) 
}).add;

SynthDef(\bpf, { 
	var sig = Pan2.ar( BPF.ar(In.ar(\in.kr(0)), \freq.kr(300)));
	var env = Env.asr(\atk.kr(0.1), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.ar(\out.kr(0), sig * env) 
}).add;

SynthDef(\mod, {
	var sig = SinOsc.kr(\freq.kr(1), 0, \mul.kr(1)).midiratio;
	var env = Env.asr(\atk.kr(0.1), 1, \rel.kr(1)).kr(2, \gate.kr(1));
	Out.kr(\out.kr(0), sig * env)
}).add;
)

// busses in b for passing osc to filter, c for modulating freq of b
(
s.newBusAllocators;
b = { Bus.audio(s) }!256;
c = { Bus.control(s) }!256;
)

// function to play all the types of synth, audio chain is syn -> filter. mod modulates freq of syn.
(
~f = {|num = 256|
	num.collect{|i|
		var syn = Synth([\sin, \saw, \pulse].choose, [freq:rrand(30, 5000), amp:num.lincurve(1, 256, 0.5, 0.01, -30), out:b[i]]);
		var filt = Synth.tail(nil, [\lpf, \hpf, \bpf].choose, [freq:rrand(30, 5000), in:b[i], out:0]);
		var mod = Synth(\mod, [out:c[i], freq:rrand(0.3, 5), mul:rrand(1, 10)]);
		syn.set(\mod, c[i].asMap);
		[syn, filt, mod]
	};
};
)

~sig = nil;
( // evaluate this everytime you want to change, wait 1.1 seconds for start )
{
	if (~sig.notNil) { ~sig.flat.do{|n|n !? { n.set(\gate, 0, \rel, 1) } } };
	s.sync;
	~sig = nil;
	1.1.wait;
	~sig = ~f.(256);
}.fork
)

/// Pattern version

/// Define groups to ensure order-of-execution, ie. filter is after synth. If you hit cmd+period you must re-evaluate
(
~synGrp = Group.new;
~filtGrp = Group.after(~synGrp);
s.latency = 0.2
)


(
var dur = 10;
var num = 100; // if set to 256 i get error messages
var amp = num.lincurve(1, 256, 0.5, 0.01, -30);
Pdef(\test,
	Ppar([
		Ppar(num.collect{|i|		
			Pbind(
				\instrument, Pfunc{ [\sin, \saw, \pulse].choose },
				\dur, dur,
				\amp, amp,
				\freq, Pwhite(300, 1000),
				\out, b[i],
				\mod, c[i].asMap,
				\group, ~synGrp
			)
		}),
		Ppar(num.collect{|i|
			Pbind(
				\dur, dur,
				\instrument, \mod,
				\out, c[i],
				\freq, Pwhite(1, 5),
				\mul, Pwhite(1, 5),
			)
		}),				
		Ppar(num.collect{|i|		
			Pbind(
				\instrument, Pfunc{ [\lpf, \hpf, \bpf].choose },
				\freq, Pwhite(300, 1000),
				\dur, dur,
				\in, b[i],
				\out, 0,
				\group, ~filtGrp
			)
		})
	])
).play
)

Pdef(\test).clear

This could be optimized in various ways. You wouldn’t need envelopes on all the synths, you could free them in a routine and save on the amount of Ugens. Also, the SynthDef could be done by iteration rather than writing everything out, but for clarity it is probably good for now.

Here is a much quicker way but, and this is the big BUT here: all the Ugens are running all the time (3 oscs and 3 filters, no modulation yet) so the cpu hit is much higher:

(
{
	256.collect{
		var freq = rrand(30, 5000);
		var sig = Select.ar(LFNoise0.kr(1).range(0, 2).round, [SinOsc.ar(freq, 0, 0.1), Saw.ar(freq, 0.1), Pulse.ar(freq, 0, 0.1)]);
		var filtFreq = rrand(30, 5000);
		var filt = Select.ar(LFNoise0.kr(1).range(0, 2).round, [LPF.ar(sig, filtFreq), HPF.ar(sig, filtFreq), BPF.ar(sig, filtFreq)]);
		filt;
	}.sum * 2/256 ! 2
}.play
)
2 Likes

Here is a decked out version, still with the easy but wasteful approach of using Select.ar. Pretty cool textures though.

(
// s.options.memSize_(2 ** 20)
{
	var num = 100;
	// var num = 256; // very cpu heavy, maybe not sonically more interesting?
	// var num = 10; // really cool!
	var dur = 1/60;
	// var dur = 1/6; // more action
	var sig = num.collect{
		var freq = rrand(30, 5000) * SinOsc.kr(LFNoise1.kr(dur/6).range(30, 1000), 0, LFNoise1.kr(dur).range(0.01, 8)).midiratio;
		var sig = Select.ar(LFNoise0.kr(dur).range(0, 2).round, [SinOsc.ar(freq, 0, 0.1), Saw.ar(freq, 0.1), Pulse.ar(freq, 0, 0.1)]);
		var filtFreq = rrand(30, 1000) * LFNoise1.kr(dur).range(1.0, 5.0);
		var filt = Select.ar(LFNoise0.kr(dur).range(0, 2).round, [LPF.ar(sig, filtFreq), HPF.ar(sig, filtFreq), BPF.ar(sig, filtFreq)]);
		var dly = CombL.ar(sig, 0.5, LFNoise1.kr(dur/6).range(0.02, 0.5), rrand(0.3, 2)); 
		dly
	};
	sig = Splay.ar(sig); // nb! levelComp: true, so if removed signal will be extremely loud!
	sig = FreeVerb2.ar(sig[0], sig[1], LFNoise1.kr(dur).range(0, 1.0), LFNoise1.kr(dur * 3).range(0.2, 2));
	sig
}.play
)

i will keep this version

			(
			// s.options.memSize_(2 ** 20)
			{
				~num = 100;
				// var num = 256; // very cpu heavy, maybe not sonically more interesting?
				// var num = 10; // really cool!
				~dur = 1/60;
				// var dur = 1/6; // more action
				~sig = ~num.collect{
					~freq = rrand(30, 5000) * SinOsc.kr(LFNoise1.kr(~dur/6).range(30, 1000), 0, LFNoise1.kr(~dur).range(0.01, 8)).midiratio;
					~sig = Select.ar(LFNoise0.kr(~dur).range(0, 2).round, [SinOsc.ar(~freq, 0, 0.1), Saw.ar(~freq, 0.1), Pulse.ar(~freq, 0, 0.1)]);
					~filtFreq = rrand(30, 1000) * LFNoise1.kr(~dur).range(1.0, 5.0);
					~filt = Select.ar(LFNoise0.kr(~dur).range(0, 2).round, [LPF.ar(~sig, ~filtFreq), HPF.ar(~sig, ~filtFreq), BPF.ar(~sig, ~filtFreq)]);
					~dly = CombL.ar(~sig, 0.5, LFNoise1.kr(~dur/6).range(0.02, 0.5), rrand(0.3, 2)); 
					~dly
				};
				~sig = Splay.ar(~sig); // nb! levelComp: true, so if removed signal will be extremely loud!
				~sig = FreeVerb2.ar(~sig[0], ~sig[1], LFNoise1.kr(~dur).range(0, 1.0), LFNoise1.kr(~dur * 3).range(0.2, 2));
				~sig
			}.play
			)

sounding terrific. thanks @Thor_Madsen

by the way, how can i turn this into a class?

TMM88 : StandingWaves {
	*ar {
		^this.multiNew('audio')
	}
	*kr {
		^this.multiNew('control')
	}
}

StandingWaves1 : StandingWaves {
	*ar {
	~num = 100;
	// var num = 256; // very cpu heavy, maybe not sonically more interesting?
	// var num = 10; // really cool!
	~dur = 1/60;
	// var dur = 1/6; // more action
	~sig = ~num.collect{
		~freq = rrand(30, 5000) * SinOsc.kr(LFNoise1.kr(~dur/6).range(30, 1000), 0, LFNoise1.kr(~dur).range(0.01, 8)).midiratio;
		~sig = Select.ar(LFNoise0.kr(~dur).range(0, 2).round, [SinOsc.ar(~freq, 0, 0.1), Saw.ar(~freq, 0.1), Pulse.ar(~freq, 0, 0.1)]);
		~filtFreq = rrand(30, 1000) * LFNoise1.kr(~dur).range(1.0, 5.0);
		~filt = Select.ar(LFNoise0.kr(~dur).range(0, 2).round, [LPF.ar(~sig, ~filtFreq), HPF.ar(~sig, ~filtFreq), BPF.ar(~sig, ~filtFreq)]);
		~dly = CombL.ar(~sig, 0.5, LFNoise1.kr(~dur/6).range(0.02, 0.5), rrand(0.3, 2));
		~dly
	};
	~sig = Splay.ar(~sig); // nb! levelComp: true, so if removed signal will be extremely loud!
	~sig = FreeVerb2.ar(~sig[0], ~sig[1], LFNoise1.kr(~dur).range(0, 1.0), LFNoise1.kr(~dur * 3).range(0.2, 2));
	~sig
	^this.multiNew('audio')
	}
}

here is my attempt at doing a class implementation. I am getting some errors at the level of class discrepancy number. how can i possibly fix this?

thanks
T.