Once I’ve gone through all the mode/menu code and made sure it works, I think I’m mostly done with the features I want to include in OS8. There may be some time to have the prop makers work out how to use the new features, but hopefully everything will be wrapped up and ready for an OS8 alpha in a month or two.
If there is something you think needs to be done before that, this thread would be an excellent place to let me know…
In terms of new features, I can’t remember if this was talked about or if it’s already been rejected/implemented - forgive me if it has - but does the NO REPEAT RANDOM feature get any changes? I saw the bit about making it default rather than needing a define which makes sense to me, but just wondering if functionality will be unchanged.
As I understand it, currently it remembers the last force effect/character quote played and so won’t play that one a second time. But as I understand it, it only remembers the last played effect and that’s all.
So for instance, if you have ten character quotes (force effect wavs) in your font folder, it could play, say, number 7 randomly, then the next press will guarantee a different wav, but the third press could be number 7 again. Have I got that right?
And if so, is there any interest in having it so that it never replays the same quote/force effect until ALL the other quotes in that folder have been played?
As always, I’m just bouncing ideas and I have no idea how easy or hard this would be to do or indeed if anyone else would want it.
Other than that, with all the discussions over the past few months, I can’t think of anything we would want that ProffieOS 8 can’t already do!
Ah, yeh, that makes sense. It hadn’t even occurred to me that it might be a memory eater, and I have no idea how it could be streamlined.
Interesting to see that someone else has thought along the same lines though.
I wonder also if it is truly random. I’ve had quote files that have dozens of quote files in them, but it sometimes feels like ProffieOS does seem to have its favourites that it keeps using. Maybe it’s just me imagining it, but if I get some time this week, I’ll do a few tests to see how random random really is. Not sure if it will help us, but you never know - maybe a pattern will emerge that can be tweaked without a memory penalty.
The two things I’ve spent the most time on are the modes (menu abstractions) and color displays. There are also some semi-large changes around better support for igniting blades individually.
Then there is all the small stuff, like more colors, a few new style templates, or the ability to to control if your computer can mount the SD card or not from a menu on the saber, plus a bunch of things I can’t remember right now…
#define MOUNT_SD_SETTING
This define will allow manual control of when to allow the SD to mount to the computer when Mass Storage is enabled.
First let’s review how Mass Storage works. Having the Arduino setting Tools>USB Type> Serial + Mass Storage selected allows the SD card to be accessed over USB (using the Proffieboard as a card reader).
The way it used to work before OS8 and this define was after the boot sound played, the SD card would immediately mount to the computer as an external USB drive. File transfers could take place then, and when finished, you would eject the SD from the computer. From then, the Proffieboard would use it as normal.
This meant that you always had to wait for the SD card to mount, and then eject it before uploading or using Serial Monitor. It also meant that to re-access the SD, you’d need to either reboot, or unplug and then re-plug the USB cable.
Now here’s how it can work in OS8 using #define MOUNT_SD_SETTING.
Even if Mass Storage is selected and uploaded, this define prevents the SD card from mounting until manually “allowed” by the user. At boot, the default permission is 0 (false).
To allow the SD to mount, send the command “set_allow_mount 1” in Serial Monitor. When you finish accessing the SD card and “eject” it from the computer, the Proffieboard will use it as normal and set the permission back to false.
If you want to access the SD again, you can just issue the “set_allow_mount 1” command again, and repeat as above.
Generally speaking, users aren’t expected to use “set_allow_mount” directly.
Most props are expected to support some sort of settings menu that lets you modify this setting. The command is means to be used by the workbench, but can also be used from the serial monitor of course.
ah. So in a menu have a “mount SD card” action that does it.
I think it will be clearer when you get a chance to document “how to use” the menus you’ve created.
Following on from the No Repeat Random thing, it seems I was imagining the fact that ProffieOS has its favourites. I loaded 20 force wavs into a font folder and hit play 130 times with the following results:
The only number it didn’t seem wild about was 13.
Is ProffieOS superstitious? LOL!
Anyway it looks like currently it is truly random, apart from the fact it will never play the same sound twice in a row. (which I can confirm it didn’t).
I know that my prop has a toggle of sequential or random quote playback.
Granted, sequential is strictly that, so it’s not exactly what you asked for (playing randomly through all without repeats) but close?
Now that I think about it, I wonder if there’s a relatively easy way to just play with the wav numbers without hogging memory. Something like:
Set sequential playback
get the number of files in the list
randomize the list numbers
iterate over the randomized list as the file selection
This is in fact exactly what the PR linked above tried to do.
The list of numbers takes up a fair amount of space though.
It should be possible to do in a more clever way though.
We can use an algorithm similar to RSA encryption to generate random sequences.
Basically, we would need two numbers, P and Q which are co-prime, then:
class GetNextRandom {
int next() {
return powm(n++, p, q);
}
private:
int powm(int n, int x, int m) }
int tmp = 1;
// ret = (tmp * n^x) % M
while (x) {
if (x & 1) {
tmp = (tmp * n) % m;
x--;
} else {
n = (n * n) % m;
x>>=1;
}
}
return tmp;
}
int n = 0;
int p;
int q;
};
This class will return numbers between 0 and q in a random order which depends on p.
Once ‘n’ is >= ‘q’, the sequence starts over.
The problem is that p and q most be co-prime, so not any numbers can be used.
So we would need another class which picks a new ‘p’ every now and then, and since “q” might
need to be larger than the number of actual files, the class would discard such return values and just try again.
This stuff is some very dark magic, feel free to recoil in terror.
std::bitset can still be arbitrarily large if you have lots and lots of files.
Also, it uses malloc(), which I try to avoid as much as possible.
The GetNextRandom class above currently uses 12 bytes, but n, p and q can all be made into short values, and q could probably be computed from files_found(), so that it doesn’t need to be stored at all, which would mean that it would use 4 bytes per Effect, regardless of how many files there are.
It could still cause some repetition when the sequence is re-initialized though… That’s a common problem with any kind of algorithm that re-shuffles the values at some point.
Hmm, probably the easy way to use powm() is to set the modulo (Q) to the closest higher power-of-two based on the number of files found. P can then be set to random(Q/2) * 2 + 1, which should always be co-prime with Q. (meaning that GCD(P, Q) = 1)
Alternatively, Q could be set to a prime number (larger than files_found), and P could be set to random(Q), that would also guarantee that GCD(P, Q) = 1.
Also, since the sequence is entirely predictable, it wouldn’t be too difficult to check if the next couple of numbers contain any of the same numbers as the last few numbers when a new P is chosen, and in that case chose a different P.
Yes we are.
There is one other option though, which is to ave a global (and finite) history of recently played files, and then just try to avoid those when selecting what to play next.
I dunno. that distribution looks fairly normal to me. If anything, it’s light on the high side. You need a lot more trials to validate a random generator.
That said, A 32bit integer could keep track of up to 31 unique quotes to ensure they all play before resetting and starting over–a simple loop using bitand, bitor. That shouldn’t take up too much memory–4 bytes for the tracker, 4 bytes for a comparator, plus a few lines of code for the simple loop.