sc-grids icon indicating copy to clipboard operation
sc-grids copied to clipboard

Pkey on Pseq does not work for density

Open capital-G opened this issue 4 years ago • 4 comments

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;
)

capital-G avatar Jun 08 '21 23:06 capital-G

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.

capital-G avatar Jun 08 '21 23:06 capital-G

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;
)

capital-G avatar Jun 08 '21 23:06 capital-G

@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?

capital-G avatar Jun 09 '21 10:06 capital-G

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

telephon avatar Jun 09 '21 14:06 telephon