Control hardware and server synth with one Pbind?

Hi,

not on the wrong path, but it’s one of those pattern questions, that sound very easy, but are tricky in detail. But first, there are two problems in the posted code:

If you want to set the latency, you’d have to do it in a different way, otherwise latency isn’t set (check with m.latency after evaluating the above line). Also I wouldn’t set the latency to such a low value, because the server latency is still 0.2 (however you could set both to 0.05 or so). With my setup I need MIDIOut(0), but of course that can be different on yours, e.g.

MIDIClient.init;
m = MIDIOut(0);
m.latency = 0.05;
s.latency = 0.05;

The second thing is the doubled definition of SinOsc’s mul arg in the SynthDef, e.g. say

(
SynthDef(\tone, {|out=0, gate=1, freq=440|
	var env = EnvGen.ar(Env.adsr(releaseTime: 0.1), gate, doneAction:2);
	Out.ar(out, SinOsc.ar(freq!2, mul: env));
}).add;
)

Now the problem of “doubling” the event data - it’s (again) a matter of differentiating Streams and Patterns. Some possibilities:

(1) Data sharing

See the chapter in James’ pattern guide:
http://doc.sccode.org/Tutorials/A-Practical-Guide/PG_06g_Data_Sharing.html

I’d use a Ptpar and the lag key to adjust the correct latency, the delay in the Ptpar ensures correct order of evaluation, with lag (lagtime in seconds) you can compensate, this value (0.025) compensates fine on my Mac using SimpleSynth via midi and IAC.

(
a = Pbind(
	// _ is partial application syntax, you could also write:
	// collect { |x| ~degree = x }
	\degree, Prand([1, 2, 3], inf).collect(~degree = _),
	\dur, Prand([2, 1, 1]/5 , inf).collect(~dur = _),
	\lag, 0.025
);

b = Pbind(
	// takes over the values from other stream when played
	\degree, Pfunc { ~degree },
	\dur, Pfunc { ~dur },
	\amp, 0.5,
	\type, \midi,
	\midiout, m,
)
)

Ptpar([0, a, 0.001, b]).play

(2) Using Pchain with Streams

Maybe a surprising solution (at least for me, first time I’ve done it this way - or I had forgotten it … see Pchain help file, last examples). If you chain the Streams, define the source with a Pstutter, then each random value will be produced twice, for the both streams that need it. ‘lag’ is also taken over, so redefine it in the midi pattern to keep the difference.

(
a = Pbind(
	\degree, Pstutter(2, Pxrand([1, 2, 3], inf)),
	\dur, Pstutter(2, Prand([2, 1, 1]/5 , inf)),
	\lag, 0.025
).asStream;


b = Pbind(
	\lag, 0,
	\amp, 0.5,
	\type, \midi,
	\midiout, m
) <> a
)

Ptpar([0, a, 0.001, b]).play

(3) Using PSdup from miSCellaneous lib

PSx patterns behave like Streams, they remember last items (events), PSdup is just duplicating the data of another PSx pattern, here PS(p). This solution looks very similar to (2), but you don’t have to use Pstutter.

(
p = Pbind(
	\degree, Prand([1, 2, 3], inf),
	\dur, Prand([2, 1, 1]/5 , inf),
	\lag, 0.025
);

a = PS(p);

b = Pbind(
	\lag, 0,
	\amp, 0.5,
	\type, \midi,
	\midiout, m
) <> PSdup(a)
)

Ptpar([0, a, 0.001, b]).play

PSx patterns are admittedly strange - but especially in a case like this they provide a quite straight solution.