Scripting advanced random playback

By Hal MacLean

Occasionally there are times when a simple random playback is not enough – you might have a lot of clips to work with or you might want to extend the playback in different ways. You may not want to physically partition the DVDSP registers, for example, and in this case you need to use bit based maths. This tutorial will explore the concepts behind the bit based approach and assume that you have a high number of clips to play, needing several registers to store values in. Lets work with 40 clips. I must stress that this is a theoretical project – as yet it has not been built or proven, but presents the process. There may be bugs in the scripts which will need tracking down and solving, but if you are wanting to explore the ideas behind using bit based maths then this is a good place to start.

Throughout, we will avoid using pre-scripts, too – there are not enough good reasons to make use of them for this project.

The basic premise of a project like this is that you need to select a random number, check to see if it has been chosen before, and if not play an associated clip but make sure it can’t then get re-chosen.

To track what has played we will use a single bit slot in a register. With 40 clips we will need 40 bit slots, and this means that two and a half 16bit registers will be needed. We can probably use the other half register as a counter to keep track of how many clips get played and make sure we don’t try to play over 40. This leaves five to do everything else with, and that should be more than enough.

To start, we need to select a random number, so add a script to your project and call it ‘selector’; the script starts as follows:

ran GPRM0, 65535
mod GPRM0, 40
add GPRM0, 1

The addition in the third line is because with a mod of 40 the possible results are 0 through to 39. Adding 1 means we can then associate the random number directly with the clip number later.

The next part is to find out whether the number has been used previously. If it has then a corresponding bit slot in a GPRM will be turned on (have a value of ’1′). Otherwise the bit slot will show ’0′. For this project we can keep GPRM7, 6 and 5 as the ones tracking what has been used already. The random numbers below 17 will go in one register, 17 to 32 in a second and anything above 32 in the third.

So the next part of the script deals with that. You can easily do all of this in one script using a ‘goto’ command, but for now I want to use three different (but nearly identical) scripts to split this out a little bit. Each of the three scripts will target a particular GPRM. The main script needs the following lines added:

Jump Set1 if (GPRM0 < 17)
Jump Set2 if (GPRM0 < 33)
Jump Set3

You will now need three scripts called Set1, Set2 and Set3.

Set1 reads as follows:

mov GPRM1, GPRM0 //copy the random value to G1
mov GPRM2, 1 //use G2 for calculating the bit value
mul GPRM2, 2 // calculation begins
sub GPRM1, 1 // keep a loop going until the random number has decreased to 0
goto 3 if (GPRM1 > 0) // the loop for calculating
mov GPRM1, GPRM2 // Keep a copy of the value for later use (line 9)
and GPRM2, GPRM5 // compare G5 with G2 to see if the bit has been set before
Jump Selector If (GPRM2 > 0) // Go and get a new random value if this has already been used
add GPRM5, GPRM1 if (GPRM2 = 0) // if the 'and' shows '0', then fill the slot in G5

What this section is doing is taking the random number generated, multiplying it so that it will put a ’1′ in the corresponding bit slot of another GPRM (i.e. if random was 5, the fifth bit slot in GPRM5 will need to be checked) then comparing this with what is in GPRM5. The ‘and’ operation compares bits – if both GPRM5 and GPRM2 have got a ’1′ in the fifth bit slot (for example) then the bitslot in GPRM2 will get a ’1′. If either is a ’0′ then it gets a ’0′. Thus, we can tell if the number has been previously chosen and whether the film has already played. We can then take action from there. We also made a copy of the number we need since the ‘and’ operation *might* remove the data from GPRM2 to leave zero.

Before we go further, we now have to consider how we get to the correct clip as quickly and easily as we can. We might be tempted to write out sixteen jump statements to cover every possible eventuality for the values that are selected, however that is tedious. What we will do is use the internal values for the clips. If we assume that each clip lives in its own track then we can start to use the track values. If you have them in a single track, but have used stories to separate them, then this still works. What you need to know is that the first track, or the first story in DVDSP has a value of 49,280. The second track, or second story in the first track will be 128 more than that value, or 49,408. This continues in sequence, incrementing the value by 128 each time. We can use this information to help us get to the correct item to play back, simply by starting at 49280 and adding the correct number of 128s to this according to the random number. So if random 5 was selected, we need 49280 plus 4 lots of 128, or we can look at it a different way.

If we multiply 128 by 5 and add it on to 49280 we would be 128 too high. However, if we do the multiplication and add on 49152 it would be correct (49152 is exactly 128 less than the value for the first track or first story).

mov GPRM1, 128 // the base point of the next calculation - we can lose the earlier value
mul GPRM1, GPRM0 // multiply it by the number originally selected
add GPRM1, 49152 // add on the amount we need to start looking at tracks/stories to play
Jump Indirect GPRM1 // this jump will take us to the fifth track or story, if that was the random number chosen at the beginning.

So, instead of 16 different sets of code to check if a clip has played before, possibly taking three lines per set, we can do the same in only 13 lines of code, using two other GPRMs as a calculating space to move the numbers around in. The entire script looks like this:

mov GPRM1, GPRM0 //copy the random value to G1
mov GPRM2, 1 //use G2 for calculating the bit value
mul GPRM2, 2 // calculation begins
sub GPRM1, 1 // keep a loop going until the random number has decreased to 0
goto 3 if (GPRM1 > 0) // the loop for calculating
mov GPRM1, GPRM2 // Keep a copy of the value for later use (line 9)
and GPRM2, GPRM5 // compare G5 with G2 to see if the bit has been set before
Jump Selector If (GPRM2 > 0) // Go and get a new random value if this has already been used
add GPRM5, GPRM1 if (GPRM2 = 0) // if the 'and' shows '0', then fill the slot in G5
mov GPRM1, 128 // the base point of the next calculation - we can lose the earlier value
mul GPRM1, GPRM0 // multiply it by the random number originally selected
add GPRM1, 49152 // add on the amount we need to start looking at tracks/stories to play
Jump Indirect GPRM1 // this jump will take us to the fifth track or story, if that was the random number chosen at the beginning.

Now, we need to copy this for Set2 and make a slight change – we need to first of all take off 16 to be able to do the right calculations (since we are in the second set of of numbers, we don’t want to confuse ourselves by including the first set of 16). This introduces a new line and thus the ‘goto’ must allow for this. In line 8 we compare against a different GPRM, and in line 9 we will add to a different GPRM since we will be working with a random number between 16 and 32… I suggest GPRM6. The script for Set2 should be:

mov GPRM1, GPRM0 //copy the random value to G1
sub GPRM1, 16 // to not skew the next calculation
mov GPRM2, 1 //use G2 for calculating the bit value
mul GPRM2, 2 // calculation begins
sub GPRM1, 1 // keep a loop going until the random number has decreased to 0
goto 4 if (GPRM1 > 0) // the loop for calculating
mov GPRM1, GPRM2 // Keep a copy of the value for later use (line 9)
and GPRM2, GPRM6 // compare G6 with G2 to see if the bit has been set before
Jump Selector If (GPRM2 > 0) // Go and get a new random value if this has already been used
add GPRM6, GPRM1 if (GPRM2 = 0) // if the 'and' shows '0', then fill the slot in G6
mov GPRM1, 128 // the base point of the next calculation - we can lose the earlier value
mul GPRM1, GPRM0 // multiply it by the random number originally selected
add GPRM1, 49152 // add on the amount we need to start looking at tracks/stories to play
Jump Indirect GPRM1

Now we need to repeat this again for Set3, remembering this time to subtract 32 in line 2 and change the GPRM in the final line:

mov GPRM1, GPRM0 //copy the random value to G1
sub GPRM1, 32 // to not skew the next calculation
mov GPRM2, 1 //use G2 for calculating the bit value
mul GPRM2, 2 // calculation begins
sub GPRM1, 1 // keep a loop going until the random number has decreased to 0
goto 4 if (GPRM1 > 0) // the loop for calculating
mov GPRM1, GPRM2 // Keep a copy of the value for later use (line 9)
and GPRM2, GPRM7 // compare G7 with G2 to see if the bit has been set before
Jump Selector If (GPRM2 = 1) // Go and get a new random value if this has already been used
add GPRM7, GPRM1 if (GPRM2 = 0) // if the 'and' shows '0', then fill the slot in G7
mov GPRM1, 128 // the base point of the next calculation - we can lose the earlier value
mul GPRM1, GPRM0 // multiply it by the random number originally selected
add GPRM1, 49152 // add on the amount we need to start looking at tracks/stories to play
Jump Indirect GPRM1

There is no reason why these three scripts cannot be combined – there are so many similarities that we need only sort which GPRM to add to according to the random selection. Some slight changes will add a few lines of code to one of these scripts and deal with all three GPRMs in one instead of having three different scripts.

What we have achieved here is a random selection engine that checks to see whether a value has been used before, and if so it goes and generates a new one. If not, it sets the value in place so it can’t be used again and then calculates the value of the ‘item’ that needs to be played. It achieves this by using the internal project values and the knowledge that tracks and stories are represented by values starting at 49,280. With this we can jump to an item just by calculating the value.

The end jump for your track or story must be set to go back to the ‘selector’ script if you want to have a continuous playback, or to a menu where the user can use a button to choose another random clip each time. If using a menu then set the button target go to the selector script. As long as no registers are cleared in between time then the registers will retain their values and the random playback will remain reliable. If the registers are cleared in between then playback may repeat.