Server-Side Seeded Randomness Question

Hey there,

I’m currently trying to rewrite some functions I was using on the language side to use on the server. Here’s two versions of a function that gives back a semi-random number and I can call it as many times as I want, it would always give back the same number for the same (floating point) input:

(
~functions = ();
// https://en.wikipedia.org/wiki/Linear_congruential_generator
~functions[\rand] = {|phase, min = 0.0, max = 1.0, chn=7|
	var a = 2**31 - chn.nthPrime;
	var c = 2**31 - (chn.nthPrime+3);
	var m = 2**31 - 1;
	phase = phase.hash;
	(((a * phase + c) % m) / (2**31) * (max-min)) + min
};
)
(
~functions[\rand] = {|phase, min = 0.0, max = 1.0|
	phase = phase.hash;
	phase = phase.bitXor( (phase << 13) & 0xFFFFFFFF);
	phase = phase.bitXor( (phase >> 17) & 0xFFFFFFFF);
	phase = phase.bitXor( (phase << 05) & 0xFFFFFFFF);
	phase = (phase + (2**31)) / (2**32);
	(phase * (max-min)) + min
};
)
~functions[\rand].(123.4)

Using these functions on the server is not possible because I cant use .hash() there. Does anybody have an idea how I could construct a function that accomplishes what I need? :slight_smile:
Using RandSeed and RandID UGens seems not really suitable for me as I would like to provide the “seed” anew with every function call.

Greetings,
moritz

How about Hasher.ar?

2 Likes

On the language side, you could use spatial noise, which will always return the same value for the same input, and similar values for “nearby” inputs. You can also use it to generate periodic nose. A little plug fo ther SimplexNoise-SC Quark (Announce: New SimplexNoise-SC Quark)… However, it seems you already have a solution you’re happy about on the language side. :wink:

Since you’re asking about the Server, I wonder if you’ve tried some tricks often used in (e.g. GLSL) shader programming. One common one is to get pseudo-noise using a scaled-large sine function. Something like this would work on the Server:

n = { arg x; frac(sin(x) * 43758.5453123) };

// Test it on Server:
{ var x = Line.ar(0, 100, 1, doneAction: Done freeSelf); f.(x) }.play;

Unlike spatial noise, calling it for values that are very close (0.01 and 0.02, for example) will produce pretty unrelated outputs, similar to hashing. It’s obviously not white noise, but if the values are far enough apart it sounds like it, as in my example above. In that case, it’s just a question of scaling the input to get what you want.

A good reference about noise in shader programming: GLSL Noise Algorithms · GitHub

1 Like

Nice, @jordan , I didn’t know about Hasher, it’s probably a better choice than the hack I suggested, it seems to produce pretty uncorrelated output (as expected), even for very close numbers.

In my example above, replace the 0-100 range by 0-1 (more closely-spaced inputs), and you’ll hear a big difference between my f.(x) and Hasher.ar(x). At 0-100 range (played over one second) they sound much more similar, more like white noise.

Thanks very much you two! :~) I had a misconception about Hasher.ar, it fits my needs exactly!