What's an efficient way of getting a random number to apply to a pitch drift algorithm?

I’m looking at a doing a pitch drift algorithm and for that I think I need a random float between 0 and 1.

I’ve seen an example of rand() based on the current date and time, which I suspect might be expensive.
What would be your approach to efficiently getting a random number for a pitch drift ?
For a subtle pitch drift I might have to clamp that number between 0 and 0.2 , or something like that - I’ll have to experiment. Being relatively new to this, I’m guessing.

The code from this Stack Overflow answer works, with the added benefit that the seeding values (m_w/m_z) can be initialized with known seeds (meaning all subsequent random calls are reproducible) or you can seed them with something like curerent system time in milliseconds, for ‘pure’ randomity.

#include <stdio.h>
#include <stdint.h>

unsigned int m_w = 0xdead;    /* must not be zero */
unsigned int m_z = 0xbeef;    /* must not be zero */

unsigned int get_random()
{
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;  /* 32-bit result */
}


int main(int argc, char *argv[])
{
    printf("random 1: %d\n", get_random());
    printf("random 2: %d\n", get_random());
    printf("random 3: %d\n", get_random());
    printf("random 4: %d\n", get_random());
}

EDIT: This one is pretty good too:

static unsigned long x=123456789, y=362436069, z=521288629;

unsigned long xorshf96(void) {          //period 2^96-1
unsigned long t;
    x ^= x << 16;
    x ^= x >> 5;
    x ^= x << 1;

   t = x;
   x = y;
   y = z;
   z = t ^ x ^ y;

  return z;
}

These have the benefit of being pretty fast, even if not entirely as random as one might need for crypto - maybe the reproducibility (based on seed value) is actually useful in the pitch-drift context…

2 Likes

I would imagine that the main challenge is going to be smothing the random numbers so that they stay within a useful range but also make use of the whole range.
I doubt a simple Lowpass would acheive that.

I started looking up 1d Perlin noise, but that might be overkill. This post seems to contain some useful ideas including the non-periodic combinations of sine waves: c# - Perlin Noise for 1D? - Stack Overflow

1 Like

Maybe this is of interest:

https://people.sc.fsu.edu/~jburkardt/c_src/normal/normal.html

1 Like

that is exactly what my first plugin release is all about. a vibrato plugin with lots of modulators, some of which contain randomization (perlin, dropout).

for the perlin noise one i use a mersienne twister, which is expensive, but i buffered the noise anyway, so it’s cool. for the dropout one i just used juce::Random. good enough.

just like dave elton already said, more interesting than how the numbers are generated is what you are doing with the numbers. a 1pole lowpass filter is actually a good start i think. better can be a steeper lowpass and a whole other approach would be interpolating, for example with cubic hermite spline. it’s important that the interpolation type you use never overshoots the delay’s size, but most interpolation types that don’t have overshoot are not wiggly and fun, so you have to find a compromise there that is safe and still sounds good to you

3 Likes

JUCE Random works well as a light weight shift based general purpose PRNG, that’s seedable:

int Random::nextInt() noexcept
{
    seed = (int64) (((((uint64) seed) * 0x5deece66dLL) + 11) & 0xffffffffffffLL);

    return (int) (seed >> 16);
}

For pitch modulation, keep in mind that you should probably apply modulation on a logarithmic scale (as opposed to simply adding to an existing pitch factor/frequency/wavelength). -1 to +1 octave is a factor between 0.5 and 2, with 1 in the center.

PRNGs in general: Did anyone here ever observe perceivable benefits when using any of the more fancy PRNGs (like Mersenne Twister) when it comes to noise oscillators or noise modulation? Are there any experiences with alternative noise distributions?

1 Like