[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [sc-dev] In and Out



On Thursday, July 18, 2002, at 05:15 AM, Julian Rohrhuber wrote:

should instruments in sc3 make use of an Out ugen?

my current working design says 'no'.

if i want to patch instruments...

for that reason.

this is what I'm doing right now:

Instr-asSynthDef { arg outClass = \Out,xfader;
		outClass = outClass.asClass;

		// should only happen if you are ar or kr out
^SynthDef.newList(this.defName ++ "." ++ outClass.name.asString.at(0).toLower,{ arg inputs;
			var outIndex;
			outIndex = inputs.removeAt(0);
			inputs = inputs.collect({arg in,i;
						var spec;
						spec = specs.at(i);
						if(spec.rate == \audio,{
							In.ar(in,spec.numChannels)
						},{
							if(spec.rate == \scalar,{
								in
							},{// control
								//In.kr(in,spec.numChannels)
								in // no support of variable channel .kr
							})
						})
					});
			// todo: support kr
			if(outClass !== XOut,{
				outClass.ar(outIndex,this.func.valueArray(inputs))
			},{
				outClass.ar(outIndex,xfader.value,this.func.valueArray(inputs))
			});
		},
			[[\outIndex,\control,0]] ++ specs.collect({ arg spec,i;
										[this.argNameAt(i),spec.rate,this.defArgAt(i)]
									})
		);
	}



issues:
	i built a new constructor for SynthDef

	Out vs ReplaceOut vs XOut
so far I am letting the user of the function decide how it wants to use it.
			Patch RPatch XPatch ?

		I write different synthDef files on demand:
			defName.o.scsyndef,defName.r.scsyndef,defName.x.scsyndef
			depending on which style Out is requested.

so that a client that needs one of these is likely to find it already compiled and reuse it.


note that i found that In.kr was not necessary, as you should just hand in the initial float value and then once the Synth has been created, map it to the control bus of the input.
i guess if multi channel .kr is needed, then this will not work.
i might be wrong about this.

i added .rate and .numChannels to Spec/ControlSpec/StaticSpec



is not very handy, although:
	- we could give each a bus, asign an In.ar
	to the input and patch them on the server
	- Out.ar could accept -1 as bus number to stay disabled.
	then Out should have an output.

a = Instrument(\a, { ... });
b = Instrument(\b, { a.ar * oscx });

there is no other way of patching Instruments when building the definition like
this when using Out in this way, because Out has no
output. This limits the use of Instruments to representation
of SynthDefs only.

i agree.  many of my Instruments use other instruments.ar inside of them
to reuse code.  this should build to a single synthDefFile



there is a similar issue when using an input:

 	a = Instrument(\name, { arg gate=1, zin=0, out=0;
			var snd;
			snd = In.ar(zin) * gate;
			Out.ar(out, snd);
			out
	})
	a.ar(1, SinOsc.ar, 0);//this will not work.


i solved this with Patch.
any object responds to
.play
and
.mapToControlNode



// this will all be refactored
Patch-play { arg out,server;
		var inputs;
		
// if your outSpec is not ar or kr, then .value your function and return that
		
		// do super ensure playing stuff
		// if you are playing already (really playing) return
		// ensure def file is written, loaded
		
		// if out is an Integer it should be taken as the output channel.
		// the default ar buss allocation is the main out.
		// default kr buss allocation should be the first unused control buss.
out = out ?? {BusAllocation.new(instr.outSpec.rate,0,instr.outSpec.numChannels,server)}
;

		// get the children playing
		// playAntecedents
		inputs = this.args.collect({ arg argh,i;
			var sp,buss;
			sp = instr.specs.at(i);
			/*
				play of an .ar
					starts itself playing, allocating a (non-audible-output) bus
				 	returns the buss index
				play of a .kr
					starts itself playing
					returns its initial float value (see below for buss mapping)
				play of a step sequencer/process
				 	returns its initial value (see below for starting the process)
					 	
				play of any scalar returns
					itself

				play of a Sample
					loads/allocates the buffer and returns the buffer index
			
			*/
			if(sp.rate == \audio,{
				// get a non-audible bus allocation
[ i, argh.play(BussAllocation.next(sp.rate,sp.numChannels,server).index, server) ]
			},{
				[ i,argh.play(nil,server)]
			})
		}).flatten(1); // 0,value,1,value... etc.

		// play yourself
		mySynth = Synth(nil,nil, out.server); // groupID ?
mySynth.playSynthDef(this.defName,[out.index] ++ inputs); // index is wrong actually

		// activate each input to do buss mapping etc.
		inputs.do({ arg inputProxy,i;
			inputProxy.mapToControlNode(NodeControl(mySynth,i));
			/*
				.ar
					nothing to do
				.kr	we are already playing so mySynth exists
					nodeControl.readFromBus(mySynth.out)
				.ir scalar etc.
					nothing to do
				sequencer, number patterns, etc.
					start AppClock driven updater that does this
					nodeControl.value = nextValue;
				midi, wacom etc. inputs
					set up updater or control bus mapping
		});
		
		// .ar version
		^myOut = out.index
			// if you are the final ar  audio object in the play chain
			// you will not pay any attention to this return value.
			// i have already defaulted to play out of your main out.
			// if this patch leads to further stuff, the out index will
			// be used, passed through to the function.

		// .kr should return initial float value
	}


what all of this accomplishes:
	Instrument remains a simple reusable function.
	anything can be patched to anything via Patch.
	children are started before the parent.
	automatic bus allocation (destruction, recycling to come).
		on a per server basis

	it works already !

yourPatch.play;
otherPatch.play;
yourPatch.stop;
otherPatch.stop;
yourPatch.play(server: australia);



____________________
http://crucial-systems.com