Quantizing the Output of an Ugen

I have a LFO “LFNoise1.kr(16,1,2)” that goes between 1 and 3. I’d like to quantize it’s output according to an array “[1,1.2,1.3,1.6,1.9,3]” how can I do this? I only found round etc. but nothing that follows an array.

cheers, Bernhard

See IndexInBetween.

  • Put the array data into a Buffer.
  • Use IndexInBetween to get a fractional index.
  • Round the index to the nearest integer.
  • Index.kr to get the quantized value.


1 Like

Thanks James, I made it: A little test with a LFNoise quantized to some intervalls playing a Saw. But isn’t there a easier way for doing this? It seems a quiet obvious thing to do - quark anyone?

    var index, intv, lfo, buffer = [1,9/7,7/5,5/3,9/5,15/7,7/3,25/9,3].as(LocalBuf);
	lfo = LFNoise0.kr(1,1,2);
    index = IndexInBetween.kr(buffer, lfo).round;
    intv = Index.kr(buffer, index).poll;

1 Like

Tbh, I think this already is fairly easy. The hard part is finding the right array element, for which we have a built-in UGen (and Array method in the language). (By comparison, Pure Data vanilla definitely doesn’t have this operation built in, and I don’t readily see an external for it, so, build it yourself, takes more time… pretty sure Pd can’t do it in just 3 UGens.)

It’s idiomatic for modular synths. Because I “think in SC” much more than I “think in modular,” this wouldn’t have been my first thought, in fact. I would tend to think first of a list of the probability of each interval, and then wchoose / Pwrand (in the language side control domain) or TWChoose / Dwrand (in the server side signal domain) to get the intervals.

Another approach, though maybe not easier, is to convert the array of intervals into a transfer function, store that in a wavetable buffer, and use Shaper.

Those solutions are meant to preserve the probabilities of each interval in your list. If you don’t care about the precise probabilities, then it gets even easier.

You could make a quark :+1:


To illustrate what I mean by “this already is fairly easy,” here’s what I came up with in Pure Data. The “xfer” subpatch at left took maybe 20-30 minutes to sketch out and another 15 to debug and simplify. Compare that to the 3 lines of code in SC.

Just for some perspective (about how easy we have it in SC-land).


Hi James, thanks for the inputs,

I often use Prand, choose, etc. for that kind of tasks. Adding the modular-style gives me another flavour. But it’s true that my brain still works in a modular way. I started coding not even 2 years ago and my mind starts slowly to think different :slight_smile: I never made a quark, I’ll give it a try.

The transfer function wave shaper idea seems very interesting. I always wanted to build a trigger generator with floating groove/swing factor in a similar way. So many things to do…

cheers, Bernhard

There is also IEnvGen which can do this, if you provide the right array.

As a challenge, I written a function to generate the env from the quant array. The code is not less verbose, but it’s fun ^^ I am not 100% sure my code is reproducing the same behavior, but here it is:

~quant_to_env = { arg arr;
	var times = arr.collect({ arg a, idx;
		arr[idx+1] ? 0 - a / 2 + a
	times = [ times.differentiate.abs, 0!arr.size ].flop.flat;
	Env(arr.stutter(2), times)

    var index, intv, lfo, buffer = ~quant_to_env.([1,9/7,7/5,5/3,9/5,15/7,7/3,25/9,3]);
	lfo = LFNoise0.kr(1,1,2);
	intv = IEnvGen.kr( buffer, lfo );

	Splay.ar( {MoogLadder.ar(Saw.ar(intv.lag(0.3)*30*LFNoise2.kr(12,0.02,1), LFNoise2.kr(4,0.4,0.6)**2), LFNoise2.kr(1,1700,2200),0.3)}!8);