Seed for Shuffle function

Writing software for systems that use VLSI Solution's devices as slave codecs to a host microcontroller.
Post Reply
Brek
Senior User
Posts: 60
Joined: Sun 2016-09-11 5:51

Seed for Shuffle function

Post by Brek » Mon 2017-02-13 16:21

Hi Guys :)
I have a shuffle function using a pseudo random number generator that wants a seed value (usually derived from system real time clock).
So far, I’m using a hardware timer on the microcontroller to count seconds and centi-seconds until the user pushes the first button.
That should really be a higher resolution raw timer value :D but anyway...

Is there a register in the VS1003b I could read in, that would be different most of the time?
Considering it’s clocked with it’s own free running oscillator, and faster than the microcontroller.
I have looked into the timer values, but assume something in it’s readable memory map would change faster than those.
Bearing in mind I’m only looking for a value for a seed generator, and not the random generator, uniformity and range don’t matter so much.
Cheers, Brek :)

Brek
Senior User
Posts: 60
Joined: Sun 2016-09-11 5:51

Re: Seed for Shuffle function

Post by Brek » Mon 2017-02-13 16:40

Oh, I forgot to mention, I don’t want the answer to be looking at the noise floor for the microphone ADC :D
It’s more respectable, I think, to rub a pair of free running oscillators together.

Here is a shuffle function to shuffle a list of a known quantity of MP3 files represented as their directory entry value
as a list of ordered integers in an array. Then iterating the array from zero to (total number of mp3 files),
for every number, swap the entry number with a random index in the array.
It leaves it’s child functions to the imagination, such as retrieving the shuffled entry number given input of the ordered entry number.

Pros: Don’t need a good random generator for good results. Guaranteed no repeated tracks, and all tracks are included in the result array.
Cons: needs an array of unsigned chars twice the size as the number of MP3 files. In this case 7050 bytes.

Code: Select all

void mpfileshuffle() {
unsigned int randa = 0;
unsigned int randb = 0; 
sp1 = 0; // clrbuffer counter
sp2 = 0;
WORD wordcount = 0;
unsigned long int nextr;                            // set random seed
nextr = sin_table[sinindex] + (count * 7);
nextr = nextr + (sinindex + (secondschanged*5));
nextr = nextr + 0xBFE001;
// clear screen
while (sp1 < 1024) {framebuffer[sp1] = 0; sp1++;}   // clear framebuffer
drawscreen();
drawshufflegraphic();

while (sp2 < (filecount*2) && sp2 < 7050) {         // populate shuffle array
voice[sp2+0] = (wordcount & 0b1111111100000000) >> 8;
voice[sp2+1] = wordcount & 0b0000000011111111;
sp2 = sp2 + 2; wordcount++;
} // sp2
// voice array should now be populated with incremented values
// sp2 should contain the number of files multiplied by two
//
sp3 = 0;                            // shuffle the array
if (mpshuffle != 0) {
while (sp3 < wordcount) {
randa = nextr % wordcount;
randb = sp3;
pl1 = voice[(randa*2)+0];           // swap a pair of 16 bit elements
pl2 = voice[(randa*2)+1];
voice[(randa*2)+0] = voice[(randb*2)+0];
voice[(randa*2)+1] = voice[(randb*2)+1];
voice[(randb*2)+0] = pl1;
voice[(randb*2)+1] = pl2;
sp3++;
nextr = nextr * 1103515245 + 12345;
}} // mpshuffle

sp1 = 0;
while (sp1 < 1024) {framebuffer[sp1] = 0; sp1++;}   // clear framebuffer
drawscreen();
}
//

User avatar
pasi
VLSI Staff
Posts: 1494
Joined: Thu 2010-07-15 16:04

Re: Seed for Shuffle function

Post by pasi » Mon 2017-02-13 17:36

How many bits do you need? You can start the VS1003 timer with 1x pre-divider and read the value, but because both clocks depend on temperature, the correlation between them should be pretty high, and you thus get only a couple of usable bits per read.

(for a timer interval of 256 : WRAMADDR=0xc030, WRAM=0, WRAM=1, WRAM=256, WRAM=0, WRAM=256, WRAM=0, WRAMADDR=0xc036, read WRAM)

Code: Select all

#define TIMER_CONFIG	0xC030
#define TIMER_ENABLE	0xC031
#define TIMER_T0L	0xC034
#define TIMER_T0H	0xC035
#define TIMER_T0CNTL	0xC036
#define TIMER_T0CNTH	0xC037
#define TIMER_T1L	0xC038
#define TIMER_T1H	0xC039
#define TIMER_T1CNTL	0xC03A
#define TIMER_T1CNTH	0xC03B
If the user presses buttons, you can also get random values determining the timing of those.

The vs1003 standalone player implements Shuflle using a PRNG as well without using additional memory. Something like the below...

Code: Select all

#include <stdlib.h>
#include <vstypes.h>
u_int16 shuffleSeeds[2] = {0, 0};
u_int16 Shuffle(register __c0 u_int16 files, register __c1 u_int16 old) {
    if (files > 1) {
        register __b0 u_int16 t;
        do {
            shuffleSeeds[0] = shuffleSeeds[0] * 16217 + 9043;
            t = shuffleSeeds[0] + shuffleSeeds[1];
            if (shuffleSeeds[0] == 0)
                shuffleSeeds[1] += files;
        } while (t >= files /*skip if not in range*/
                    || t == old /*same file - can only happen when shuffleSeeds[1] is changed*/);
        return t;
    }
    return old;
}
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

Brek
Senior User
Posts: 60
Joined: Sun 2016-09-11 5:51

Re: Seed for Shuffle function

Post by Brek » Wed 2017-02-15 7:11

It looks like you have random with a check for twice in a row?
Shuffle is different, like shuffling a deck of cards, as you deal them out, all cards must appear, and appear only once.
Admittedly, I don’t fully understand what your arrays are, but for shuffle, you shouldn't have to check for two in a row.

I haven’t got to using the timer yet, and really was hoping for something that moves faster with the chips execution itself,
There is a startup delay timer option for my micro, which is an RC clock, so that could add some variance.
Also, the micro, if not both, wait for PLL stability at startup, and I’m not sure about the nature of the oscillators with which that is achieved.

I have made a window to look at the X Y RAM area, and the main registers that start from zero.
Perhaps you could explain this. The last register, 0x587F, in the video, wasn’t written with 0xABCD due to an off by 1 error.
The missing clock value I can’t explain at all.

https://www.youtube.com/watch?v=_F394y1YtYg

User avatar
pasi
VLSI Staff
Posts: 1494
Joined: Thu 2010-07-15 16:04

Re: Seed for Shuffle function

Post by pasi » Wed 2017-02-15 11:47

No, the not-two-in-a-row is only between two full shuffle sequences. You're missing what the while loop does.

The PRNG never hits the same file twice, it provides a "shuffle function". The function skips all values that are not valid file numbers, so all files are selected exactly once per one cycle of the PRNG. After each cycle we add an 'offset' value, which causes the output to give a different sequence. Whenever we switch from one cycle to the next we check that we don't start the cycle with the one that ended the previous one. It is largely an unnecessary check.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

Brek
Senior User
Posts: 60
Joined: Sun 2016-09-11 5:51

Re: Seed for Shuffle function

Post by Brek » Fri 2017-02-24 9:21

I see... I think you have taken a file count, but have no cache, so you only have to find another value below the file count.
I’m keeping the shuffled array in memory to be able to skip back and forward in the shuffle sequence, and can’t quite work out if you’re doing that.
But even if not, I guess it would be possible to make the random generator work in reverse to look up the shuffled value for any number.

User avatar
pasi
VLSI Staff
Posts: 1494
Joined: Thu 2010-07-15 16:04

Re: Seed for Shuffle function

Post by pasi » Fri 2017-02-24 12:18

Yeah, I don't have backwards implemented, but there are two methods.
1) For only a few steps backwards allowed: It is easy to cache the seed of a few already played files.
2) Skip back N files --> cycle through the sequence 65535-N times (without adjusting the extra offset value). Each step takes 9 cycles, so with 3.0x clock it takes less than 20ms. Some can be shaved off by making a dedicated function.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

Brek
Senior User
Posts: 60
Joined: Sun 2016-09-11 5:51

Re: Seed for Shuffle function

Post by Brek » Sat 2018-01-13 9:35

I didn’t want to sample the ADC there, probably because I don’t have a hardware reset if anything goes wrong.
My player only allows MP3 files, and needing to reset the chip, even only the software reset mode bit has not been needed.

I thought I’d test a function to read some samples of the audio noise floor, and add samples to a u16_int for output to add to a random seed value,
for MP3 playlist shuffle function.
This is the first thing that worked, and not messed up the MP3 player after it runs. I just call it once at startup.
If anything obvious is wrong I’d like to know. I know I should probably read back the mode register at the end,
to verify, and write again if the values don’t match.
Cheers, Brek.

Code: Select all

// sample audio background noise for random number seed
// sets the vs1003b chip to recording mode and retrieves
// input sample data from the audio line input whether
// anything is connected to the audio line input or not
unsigned int noiseforrandom() { // update for version 1.0.192
unsigned char vsvala = 0;
unsigned char vsvalb = 0;
unsigned int sambuff = 0;
unsigned int ranbuff = 0;
unsigned int numword = 0;
unsigned int exetime = 0;
SD_CS = 1;            // deselect sd card
SPISTAT  = 0;         //
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0; // select vs1003 instruction
WriteSPIManual(0x02); // write
WriteSPIManual(0x0C); // register
WriteSPIManual(0x00); // default divider value
WriteSPIManual(0x00); // is used for zero
VSXCS = 1; // deselect vs1003 instruction
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0; // select vs1003 instruction
WriteSPIManual(0x02); // write
WriteSPIManual(0x0D); // register
WriteSPIManual(0x04); // set gain
WriteSPIManual(0x00); // to one
VSXCS = 1; // deselect vs1003 instruction
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0; // select vs1003 instruction
WriteSPIManual(0x02); // write
WriteSPIManual(0x00); // mode register
WriteSPIManual(0x58); // enable
WriteSPIManual(0x04); // input sampling
VSXCS = 1; // deselect vs1003 instruction
// get sample noise floor data
while (exetime < 8) { // stay in loop timer
numword = 0; // reset number of words ready
while (numword == 0) { // wait for data ready
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0;   
WriteSPIManual(0x03); // read
WriteSPIManual(0x09); // hdat1
vsvala = ReadSPIManual(); // read ready status
vsvalb = ReadSPIManual(); //
VSXCS = 1;
numword = vsvala;
numword = numword << 8;
numword = numword + vsvalb;
} // numword
while (numword > 0) { // read sample data
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0;    
WriteSPIManual(0x03); // read
WriteSPIManual(0x08); // hdat0
vsvala = ReadSPIManual(); // read sample data
vsvalb = ReadSPIManual(); //
VSXCS = 1;
sambuff = vsvala;
sambuff = sambuff << 8;
sambuff = sambuff + vsvalb;
ranbuff = ranbuff + sambuff; // add to random
numword--;
} // numword
exetime++; // increment loop counter
} // exetime
// restore registers and software reset
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0; // select vs1003 instruction
WriteSPIManual(0x02); // write
WriteSPIManual(0x0D); // register
WriteSPIManual(0x00); // reset
WriteSPIManual(0x00); // to zero
VSXCS = 1; // deselect vs1003 instruction
while (VSDREQ == 0) {delay_gen(0);}
VSXCS = 0; // select vs1003 instruction
WriteSPIManual(0x02); // write
WriteSPIManual(0x00); // mode register
WriteSPIManual(0x08); // software reset
WriteSPIManual(0x04); //
VSXCS = 1; // deselect vs1003 instruction
while (VSDREQ == 0) {delay_gen(10);}
VSXCS = 0; // select vs1003 instruction
WriteSPIManual(0x02); // write
WriteSPIManual(0x00); // mode register
WriteSPIManual(0x08); // set to
WriteSPIManual(0x00); // normal operation
VSXCS = 1; // deselect vs1003 instruction
while (VSDREQ == 0) {delay_gen(8);}
SPISTAT = 0x8000;     // select sd card
SD_CS = 0;            //
delay_gen(2);         // safety delay
return (ranbuff);     // return value
}
//

Post Reply