Dead Man's Catch modified firmware for Peaks


#301

Cool! Finally managed to explain it in terms that make sense to someone else…

The time-quantisation would be optional, but I think it has to loop, otherwise there’s no real advantage over interpolated seeded random sequence.

I don’t think you’d ever have to save anything in RAM, except the lookup table used to store the grid values used to lookup the perlin noise. This would be a constant though, and would never have to be written to at runtime.

Most implementations I’ve seen use a largish array (typically 256 or 512 random values).

My implementation wouldn’t ever need to pre-generate a sequence of values. It simply looks them up at each point, so the computational load is the same for every lookup. The downside of course, is that that load might be quite high, depending on the interpolation method used, so it might not be possible to run at audio rates. For me, that’s not a problem.

a|x


#302

I suspect the Sonic Potions module simply keeps a rolling buffer of seeded random numbers, then freezes the buffer and iterates over the values to loop them.

I may be wrong though.

a|x


#303

> I don’t think you’d ever have to save anything in RAM, except the lookup table used to store the grid values used to lookup the perlin noise

Yes that’s the map I was talking about (not the whole terrain of course). Actually there is I think an easy way to not even have to save this table, and generate it on the fly by a (deterministic) PRNG. What about for instance looking up into this 2D table by something like:

float lookup(int x, int y) {
Random::Seed(x + y * 32768);
return Random::GetFloat();
}

If you graph this 2D table (and if I’m correct) you’ll get uniform noise, but completely deterministic one, and the lookup time is constant.

> Most implementations I’ve seen […]

Could you point me to one?


#304

toneburst> the difference between a true 2D PN method and the one you describe is that moving the ‘scan-line’ (as above) a small distance along the opposite axis to the one being scanned across (in my example, the X axis), results in a kind of morph of the output pattern to a new set of values. The further you move from the initial position on the Y axis, the more the the values diverge.

Yes, that corresponds exactly to what I described above, using statistical terminology - so I get exactly what you mean. However, I’m interested in the use-case of having several vectors traversing the Perlin map, not necessarily in straight lines, so that their cross-correlation will vary.

BTW, more complete information about the Sonic Potions module is here - the use of an analogue noise source, substitutable with external signals, and read via an ADC, is interesting. It seems like there is adjustable auto-correlation in the signals at various octaves, although how that is achieved isn’t clear. And fractal mixing of octaves, but as it says, it is inspired by Perlin noise and doesn’t seem to be a precise implementation of it (but why should it be?). Interesting module - but I want more than a single correlated noise signal at a time.


#305

toneburst> Most implementations I’ve seen
mqtthiqs> Could you point me to one?

well, there’s always the one I linked to in a post in this thread yesterday: http://flafla2.github.io/2014/08/09/perlinnoise.html

Yes, the gradient vectors for the current point being evaluated just requires a deterministic random number for each of the vertices of the integer bounding box or bounding cube (or hypercube) for that point - so for the 2D map, you just need 4 deterministic random numbers read from an an integer grid. The implementation referred to above just uses a hash function based on a look-up table of 256 random integers to treat it as a 256x256 random grid (because a random hash look-up of a random array gives a different random array, right?) - so no large memory requirement. The rest is just the dot product or the vertex random vectors and the distance vector from the vertices to the point being evaluated, and a weighted average of those 4 dot products, where the weight is given by a polynomial easing curve and bingo! there’s your peril value for that point on the map. All computationally quite cheap - if you have hardware floating point support - and doesn’t use much memory at all. Doing it with integer maths shouldn’t be too hard, just not as easy as with FP support. There are, as @toneburst pointed out, integer maths implementations published for various Arduino platforms. Oh well, there goes my weekend…


#306

Have I managed to convince you both that my idea would likely produce musically useful output?
:wink:

a|x


#307

@BennelongBicyclist as I said, I’m not trained in mathematics or statistical terminology, so apologies for not fully understanding what you were saying.

Interestingly, I’ve just been working on a 16bit shift-register for Axoloti, that uses an external noise source to determine if a given bit should be flipped as it feeds back (Turing Machine style).

The noise source could also be an LFO, of course, and could be synced to a multiple of the clock feeding the bit-shifting, for non-random bit-flipping.

a|x


#308

@mqtthiqs what would the the advantage of generating the random number lookup table at boot-time, over hard-coding a static array?

a|x


#309

toneburst> Have I managed to convince you both that my idea would likely produce musically useful output?

No, you have just described a way of using 2D Perlin noise in a modular synth context that makes sense to me, and which can be implemented on a eurorack MPU. Whether it is musically useful remains to be seen, or rather, heard. Maybe it is, maybe it isn’t. There’s only one way to find out…


#310

Ok, let me rephrase that: “…is worth persuing”.

a|x


#311

Incidentally, there’s an integer-based linear interpolation function in the Grids firmware.

Might work adequately for generating notes or sample-and-hold-style LFO shapes, though you’d need something more sophisticated (cubic interpolation is commonly used, I think) for smooth LFO output.

a|x


#312

toneburst> what would the the advantage of generating the random number lookup table at boot-time, over hard-coding a static array?

A hard-coded random 2D array (or better, a random 1D array with a random hash look-up to generate a 2D array from it) will produce the same Perlin terrain map every time. You might want that, but the ability to generate different maps might be useful. However, for a 256 x 256 grid, you only need 256 values from a linear congruential PRNG, stored as a constant 1D array, which would take only a millisecond or two to generate. But if you provide the same seed, you get the same map, which is desirable.


#313

toneburst> Ok, let me rephrase that: “…is worth pursuing”.

There’s only one way to find out… implement it and see. I don’t think its musical utility can be evaluated as a thought experiment, at least not by any thoughts I might have.


#314

> the use of an analogue noise source, substitutable with external signals, and read via an ADC, is interesting

The analogue noise source is probably the hardware one built into the STM32F4 (if this module actually uses this MCU).

> It seems like there is adjustable auto-correlation in the signals at various octaves, although how that is achieved isn’t clear.

Low pass filtering of the random stream and adequate amplitude compensation.


#315

@BennelongBicyclist From my point of view, you’d lose one of the major reasons for implementing 2D Perlin if the lookup table wasn’t the same each time.

The lookup array would be 1D, as you say. Having said that, some GPU-accelerated implementations use a random noise image of eg 256x256 pixels as a 2-dimensional lookup table. GPUs are massively parallel, unlike MCUs, of course, so different methods are used.

a|x


#316

toneburst> From my point of view, you’d lose one of the major reasons for implementing 2D Perlin if the lookup table wasn’t the same each time

Yes, with the same seed and a deterministic PRNG, it will be the same every time. But you wouldn’t want to hard-code just one seed, or just one array, into firmware, otherwise everyone using that module will have the same map, and thus their modular music will all sound the same… no, wait!


#317

Hehe… well, you could say the same about a VCO. Or a sequencer…

With just 3 controls, you’d get a very large number of patterns anyway, even with a single static array/map (exact number would depend on the resolution of the controls, of course).

a|x


#318

The precomputed map is kind of silly because it has a limited resolution.

If the coordinates are modulated by a slow LFO, we’ll get a very smooth output because the only thing we can do is linearly interpolate between the pre-computed points. What if we want to go slowly, but still get small fractal details? For this to work we need to be able to add arbitrary harmonics between the points of the pre-computed map.


#319

Incidentally, going back to your idea of having multiple patterns at once; couldn’t you just scan across parallel lines, with different Y-axis offsets? You could have a ‘Spread’ control to create more of less closely-related patterns.

Of course, having more than one pattern multiplies the processor load (I don’t think there are any shortcuts here).

a|x


#320

The co-ordinates you evaluate are floating point values (or decimals to whatever resolution you want). Only the corners of the integer bounding boxes are, well, integers.