Range Adjustment Function on Server

I have a very simple function that takes an input number and scales it, if it gets below or above a certain value.
I would like to have access to it in a SynthDef and was hoping maybe turning it into a method would be a kind of workaround. Is there any way to make this function on the server-side? Maybe there is already something that works like this?

Thanks!

	roughFix {
		var dur;
		dur = this;
					case
		{dur < 0.125} {dur = dur * 8}
		{((dur < 0.25) && (dur > 0.125))} {dur = dur * 4}
		{((dur < 0.5) && (dur > 0.25))} {dur = dur * 2}
		{((dur < 2) && (dur > 0.5))} {dur = dur * 1}
		{((dur > 2) && (dur < 4))} {dur = dur * 0.5}
		{((dur > 4) && (dur < 8))} {dur = dur * 0.25}
		{(dur > 8)} {dur = dur * 0.125};
		^dur;
		}

Yes, if you use a logarithm to remove the conditionals.

First a correction – try 4.roughFix and you’ll see why.

roughFix {
		var dur;
		dur = this;
		case
		{dur <= 0.125} {dur = dur * 8}
		{((dur <= 0.25) && (dur > 0.125))} {dur = dur * 4}
		{((dur <= 0.5) && (dur > 0.25))} {dur = dur * 2}
		{((dur < 2) && (dur > 0.5))} {dur = dur * 1}
		{((dur >= 2) && (dur < 4))} {dur = dur * 0.5}
		{((dur >= 4) && (dur < 8))} {dur = dur * 0.25}
		{(dur >= 8)} {dur = dur * 0.125};
		^dur;
		}

Then:

Input range Log_2 range Factor Log_2(factor)
x <= 0.125 log <= -3 8 3
0.125 < x <= 0.25 -3 < log <= -2 4 2
… … … …
x >= 8 log >= 3 0.125 -3

So your function is implicitly taking the base-2 log, truncating off the fractional part, negating, and then multiplying by 2 to that power.

roughFix { ^this * (2 ** log2(this).clip(-3, 3).trunc.neg) }

The cool thing about writing it this way is that you can extend it for an infinite number of octaves just by deleting the clip :grin:

roughFix { ^this * (2 ** log2(this).trunc.neg) }

Haven’t tested but I think this should do it.

EDIT: Oops! I had guessed that trunc() would always pull toward 0, but it doesn’t. So the real solution needs another couple steps:

f = { |x|
	var log = log2(x);
	x * (2 ** (log.abs.trunc * log.sign.neg))
};

roughFix {
	var log = log2(this);
	this * (2 ** (log.abs.trunc * log.sign.neg))
}

hjh

1 Like

I wouldn’t have figured this out in a million years. Thank you for this beautiful solution.

It works as a fine non-linear “waveshaping” function:

{
    var a = LFSaw.ar(51 + LFNoise1.kr(0.5!2));
    var b = MouseX.kr(0.1, 2.0, 1); 
    var c = a * (2 ** ((log2(a.abs + 0.0001) * b).round / b * a.sign.neg));
    SinOsc.ar(c.range(340, 770), 0, 0.1)
}.play;

{
    var a = LFNoise1.ar(51!2);
    var b = MouseX.kr(0.01, 2.0, 1); 
    var c = a * (2 ** ((log2(a.abs + 0.000001) * b).round / b * a.sign.neg));
    SinOsc.ar(c.range(340, 770), 0, 0.1)
}.play;
1 Like