The *really* no repeat random thread

In the Gearing up for OS8 thread, there has been a good deal of discussion around improving the NO_REPEAT_RANDOM in some way. It’s also been suggested that this topic deserves it’s own thread. This is that thread.

The ghost of random past

Mostly, this is applies to quotes, but any effect that is selected randomly sounds kind of flat if you choose the same effect twice in a row. In the past, ProffieOS simply used random to choose which effect (or quote) to play, so repeats happened with a probability of 1/N (where N is the number of files for that particular effect)

The ghost of random present

With NO_REPEAT_RANDOM, which is going to be the default in OS8, ProffieOS remembers the last file played, and avoids playing that one again. However, it will still happily play that file again the next time, which can still be kind of boring.

The many ghosts of random futures

Ok, so what can we do about it? Many suggestions have been made. Most of them revolve around the idea of playing all the files before starting over. Several suggestions have been made for how that can be implemented, but it still leaves the chance of repetition when we start over. The last file played might be the first one played next time. Ideally we would want to avoid that, but if we just keep track of the last file played, we’re sort of back in the present. (Although it would happen less often.)

On a theoretical level, it’s not actually very well defined what it means to avoid repetition. Does it mean avoiding the last N files played? Does it mean reducing the chance that the last files played play again?

Then there is the problem of memory. Some algorithms, requires that we keep track of each file individually, which could take a fairly large amount of memory if there are lots of files. Also, the memory would need to be allocated dynamically, which is something that we try to avoid in ProffieOS.

There doesn’t seem to be any well-established algorithms for this stuff (besides Fisher-Yates) so it kind of seems that something new would have to be implemented.


So I did some thinking about the RSA algorithm yesterday, and it seems like it won’t work. The problem is that setting the modulo to a fairly small number (number of files) also limits the number of permutations to a fairly low number.

However, I did have another idea…

// This returns a hash of the file number with 3 bits in it.
uint32_t hash3bits(uint32 file) {
    uint32_t tmp = file * 2987239873;
    uint32_t b1 = tmp & 0x1f;
    tmp >>= 5;
    uint32_t b2 = tmp & 0x1f;
    tmp >>= 5;
    uint32_t b3 = tmp & 0x1f;
    tmp = 1 << b1;
    tmp |= tmp + (1 << b2);
    tmp |= tmp + (1 << b3);
    return tmp;
int rnd() {
   while (true) {
       int file = random(files_found());
       uint32_t bits = hash3bits(file);
       if (bitset_ & bits) {
            // Remove one bit randomly
            bitset_ &=~ (1 << random(32));
       } else {
           bitsset_ |= bits;
           return file;

I need to do some testing on this to see if it works well though.

If you’ve already passed file by value (makes sense cause a reference/pointer would be the same size anyway and have to deal with indirection), why not *= and use it instead of tmp?

I’m probably reading way too far into this, but wanted to know if there was a reason or if it was just quickly written.

I prefer not to re-use arguments for something different, because it makes the code harder to read. Most of the time, the compiler will generate the same code regardless how you arrange your temporary variables anyways.

1 Like

My vote would be to leave the current NO_REPEAT_RANDOM in place underneath any new “RANDOM_ONCE_THROUGH” so no matter what, the same file is never back to back.

I think the current conversation really revolves around quotes primarily. I feel like the current NO_REPEAT_RANDOM is pretty much sufficient for blst, clsh and other actual SFX since they’re relatively similar sounds anyway. I feel the temptation as well to want to apply some new global feature, but maybe the the complete “play all before repeating” is more suited just for distinct sounds that would be really obvious, like quotes .

That is an option. However, if we do come up with a new algorithm, and that new algorithm is a superset of the old one, then the old one will be removed/disabled. Redundant code is bad and makes it harder to find problems when they occur.

I think that is mostly true. Some fonts have people talking in other effects, like blast sounds, and that really blurs the line I think. However, if we do feel like we need something that takes up more than a few bytes of memory, then only applying it to some effects (like quotes) might be a good way to do it without eating up too much memory.

I think don’t play prev wav, unless there’s only 1 file is good for SFX

I think Quotes are the only thing that needs to “cycle randomly before not, and on cycle never repeat last”.

Also, side Q about quotes: Are they only random? Or is there a setting currently to make it just cycle them in order, if desired?

Depends on the prop, my prop plays quotes sequentially by default or you can randomize with a define.

BC prop has toggle sequential or random quotes on a button action.
Fett263 prop has the toggle on a define.
The actual code is pretty small and straightforward so you could always do something a different way for yourself with a little editing.

Technically, with Special Abilities and my OS7 library you can set up Quotes as Sequential, Random, select specific quotes or set up a mini micom with specific randomized quotes independently with unique controls to trigger in each preset, so each preset can have it’s own independent set up for quotes as needed.

1 Like