Pkey on Pseq does not work for density
Minimal example
s.boot;
(
SynthDef(\hh, {|out|
var sig = WhiteNoise.ar*EnvGen.kr(Env.perc(releaseTime: \release.kr(0.2)), doneAction: Done.freeSelf)*\amp.kr(0.5);
Out.ar(out, sig!2);
}).add;
)
// works
Synth(\hh);
// does not yield anything
// => density is always 0
(
Pdef(\foo, Pbind(
\instrument, \hh,
\density, Pseq([0.0, 0.9], inf),
\dur, Pgrids(\hihat, density: Pkey(\density, inf)),
)).play;
)
but the more easier example works. Is this a bug by Pkey?
(
Pdef(\foo, Pbind(
\instrument, \hh,
\dur, Pgrids(\hihat, density: Pseq([0.0, 0.6], inf)),
)).play;
)
Strangely using Pwhite on density works, see
(
Pdef(\foo, Pbind(
\instrument, \hh,
\density, Pwhite(0.0, 1.0),
\dur, Pgrids(\hihat, density: Pkey(\density)),
)).play;
)
This is probably a bug in the code as the toy example
(
Pdef(\bar, Pbind(
\instrument, \default,
\foo, Pseq([400, 600], inf),
\freq, Pkey(\foo, inf),
)).play;
)
works as expected.
Is this maybe caused by the fact that in case of density==0 we yield Rest().yield which maybe does some hickup?
Because this other toy example, omitting density=0 works
(
Pdef(\foobar, Pbind(
\instrument, \hh,
\dur, Pgrids(\hihat, density: Pseq([0.1, 1.0], inf)),
)).play;
)
@telephon do you have a clue what the problem could be here? Is this a bug or a feature of the Pkey/Rest class?
(
x = Pbind(
\instrument, \hh,
\dur, Pgrids(\hihat, density: Pseq([0.0, 0.9], 1)),
);
a = x.asStream;
)
a.next(());
yields
-> ( 'instrument': hh, 'dur': Rest(1) )
-> ( 'instrument': hh, 'dur': 0.125 )
-> ( 'instrument': hh, 'dur': 0.125 )
-> ( 'instrument': hh, 'dur': 0.125 )
-> ( 'instrument': hh, 'dur': 0.125 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.0625 )
-> ( 'instrument': hh, 'dur': 0.0625 )
-> ( 'instrument': hh, 'dur': 0.0625 )
-> ( 'instrument': hh, 'dur': 0.0625 )
-> nil
as expected
on the other hand
(
y = Pbind(
\instrument, \hh,
\density, Pseq([0.0, 0.9], 1),
\dur, Pgrids(\hihat, density: Pkey(\density)),
);
b = y.asStream;
)
b.next(())
yields
-> ( 'instrument': hh, 'dur': Rest(1), 'density': 0.0 )
-> ( 'instrument': hh, 'dur': Rest(1), 'density': 0.9 )
-> nil
It seems the hand off between Pkey does something to our pattern, compare this "working" example
(
y = Pbind(
\instrument, \hh,
\density, Pseq([0.1, 0.4], 1),
\dur, Pgrids(\hihat, density: Pkey(\density)),
);
b = y.asStream;
)
b.next(())
yields
-> ( 'instrument': hh, 'dur': 2.0, 'density': 0.1 )
-> ( 'instrument': hh, 'dur': 0.25, 'density': 0.4 )
-> nil
but the same w/o Pkey
(
x = Pbind(
\instrument, \hh,
\dur, Pgrids(\hihat, density: Pseq([0.1, 0.4], 1)),
);
a = x.asStream;
)
a.next(());
yields
-> ( 'instrument': hh, 'dur': 2.0 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.5 )
-> ( 'instrument': hh, 'dur': 0.25 )
-> ( 'instrument': hh, 'dur': 0.75 )
-> nil
It seems when using Pkey our patterns are non-exhausive by our Pattern generator but by Pkey?
But if this would be the case than why two times Rest(1) gets yielded which does not make any sense on this theory?
I think you might not be passing the inevent upstream correctly.
There are a number of comments on the code, Pattern code is a little hard to get right in the beginning.
if(xVal.notNil and: {yVal.notNil and: {instrumentVal.notNil and: {densityVal.notNil and: {biasVal.notNil}}}},
{
levels = 32.collect({|i|
ScGrids.calculateLevel(instrumentVal.asSymbol, curBeat: i, x: xVal, y: yVal, bias: biasVal);
});
// why not asSymbol only once (move above)?
indices = levels.selectIndices({|level| level>(1-densityVal)});
//this I don't understand yet, I need some explanation what is happening here.
if(indices.isEmpty, {
Rest().yield;
}, {
values = indices.collect({|i| levels[i]});
// this can be written as: values = levels[indices];
b = Pseq(values).asStream;
// better: values.do { |x| inval = x.yield }
// or you can directly embed a Pseq:
// inval = Pseq(values).embedInStream(inval)
while({outval = b.next; outval.notNil}, {
inval = outval.yield;
});
});
}, {
// if you want to end the stream here you can either use a while loop above
// or add here:
// nil.alwaysYield;
inval=nil.yield
});
In *calculateLevel:
x.div(0.25) // why not just * 4