Urgent help needed to condense code for VGA (buffer?) and counting display code
WBA Consulting
Posts: 2,938
I have a project that I am working on that is due Saturday morning for a Christmas play this weekend. My code is going very well, but I have run into a snag with running out of memory and I still need to add code for the xBee module that will receive triggers from a remote for each particular event. There are a couple places that I think I can reduce my code usage to save some small bits, but I have realized that the VGA code I am using is taking up a significant amount of space.
I am using BIG VGA Font from this thread, and in the VAR section, a LONG array called BITMAP is being declared that consumes 3072+64 longs. I don't fully understand how this bitmap buffer is utilized, so I am uncertain, but can this be reduced? It appears that this is my biggest memory killer.
Also, there is a LONG array called colors being specified at 64 longs. Do I need this variable that large when I am only using 4 colors?
One section I am going to condense is for my counting display sequence. Currently, I have each year-to-year sequence separately coded, but I know I can condense them by using one routine that uses variables for the differences so the code can be the same. With that, however, I need to figure out how to make the code count from one year to the next in a specific amount of time when the difference between the years varies (one jump is 2013 to 1978 (35 years) , but the next jump is only 1978 to 1985 (7 years). The sound effect that plays while the time machine is counting is 24 seconds long. The counting display needs to last 18 seconds. Below is my current code sequence for jumping from 2013 to 1978. It times out perfectly by use of the delay while counting, but I have to change this delay for each jump.
Also, it is hardcoded to count down, but the next jump needs to count up. There are a total of 8 separate years to travel to: Start at 2013, then 1978, 1985, 1959, 1998, 1944, 0, 1944,and finally back to 2013. I will probably need to have a special routine for jumping between 1944 and 0 due to the high number of years to count.
Here is the code for my version 008 demo that works for a keypad entry sequence, two time jumps with the sound file, and then displays "the end". Only the time jump for 1978 routine is commented fully.
I am using BIG VGA Font from this thread, and in the VAR section, a LONG array called BITMAP is being declared that consumes 3072+64 longs. I don't fully understand how this bitmap buffer is utilized, so I am uncertain, but can this be reduced? It appears that this is my biggest memory killer.
VAR long bitmap[3072+64] ' Must be aligned on 32 byte boundary long colors[64] word screen[x_tiles * y_tiles] long bitmapAddr byte numStr[5]
Also, there is a LONG array called colors being specified at 64 longs. Do I need this variable that large when I am only using 4 colors?
One section I am going to condense is for my counting display sequence. Currently, I have each year-to-year sequence separately coded, but I know I can condense them by using one routine that uses variables for the differences so the code can be the same. With that, however, I need to figure out how to make the code count from one year to the next in a specific amount of time when the difference between the years varies (one jump is 2013 to 1978 (35 years) , but the next jump is only 1978 to 1985 (7 years). The sound effect that plays while the time machine is counting is 24 seconds long. The counting display needs to last 18 seconds. Below is my current code sequence for jumping from 2013 to 1978. It times out perfectly by use of the delay while counting, but I have to change this delay for each jump.
PUB JUMP1978 | i
wav.play(string("SFX.wav")) ' Play 24 second long "time jump" sound effect
waitcnt(cnt+clkfreq*2) ' Let SFX volume fade up
JUMPSTANDBY ' Show time machine activation/standby display
waitcnt(cnt+clkfreq*2) ' and leave up for 2 seconds before counting
' Count from present year to jump year
i:=2013
' this repeat loop must complete in ~18 seconds to match sound file!
repeat until i == 1977 ' stop at 1978
num2str(i)
gr.textmode(9,9,6,5)
gr.colorwidth(1,3)
gr.text(0,10,@numStr)
waitcnt(cnt+clkfreq/3) ' delay between years during counting
i-=1 ' increment year down (how to handle both directions?????)
gr.colorwidth(0,8)
gr.box(-120,-30,240,81)
' WAV sound effect fades out about here
' Flash current year ' done counting, flash year of arrival 8 times
repeat 8
gr.colorwidth(0,8)
gr.box(-120,-30,240,81) ' draw black box to clear year
waitcnt(cnt+clkfreq/4)
gr.textmode(9,9,6,5)
gr.colorwidth(1,8)
gr.text(0,10,@numStr) ' draw year
waitcnt(cnt+clkfreq)
Also, it is hardcoded to count down, but the next jump needs to count up. There are a total of 8 separate years to travel to: Start at 2013, then 1978, 1985, 1959, 1998, 1944, 0, 1944,and finally back to 2013. I will probably need to have a special routine for jumping between 1944 and 0 due to the high number of years to count.
Here is the code for my version 008 demo that works for a keypad entry sequence, two time jumps with the sound file, and then displays "the end". Only the time jump for 1978 routine is commented fully.
' TIME MACHINE
' WBA Consulting
' Andrew Williams
' (c)2013
'
' Code emulates a Time Machine Prop for a Church Christmas Kids Play.
' Uses WAV files for sound effects, drives a VGA display, and lights some LEDs
'
' Version Info:
' 007 Working code for demo of display setup and sound files
' 008 Cleaned Structure, fixed formatting discrepancies
' 009 ***Need to add other years***
'
CON
_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000
x_tiles = 16
y_tiles = 12
'WAV Player
lPin = 26
rPin = 27
doPin = 22
clkPin = 23
diPin = 24
csPin = 25
wpPin = -1
cdPin = -1
VAR
long bitmap[3072+64] ' Must be aligned on 32 byte boundary
long colors[64]
word screen[x_tiles * y_tiles]
long bitmapAddr
byte numStr[5]
OBJ
vga : "vga"
gr : "graphics"
wav : "V2-WAV_DACEngine.spin"
PUB start '| i
'VGA Initilization
StartVGA
'WAV Player Initilization
wav.begin(lPin, rPin, doPin, clkPin, diPin, csPin, wpPin, cdPin)
waitcnt(cnt+clkfreq*2)
'Code
SYSBOOT
repeat 6
gr.textmode(4,4,6,0)
gr.colorwidth(1,3)
gr.text(-70,10,string("#>_"))
waitcnt(cnt+clkfreq/3)
gr.colorwidth(0,3)
gr.text(-70,10,string(" _"))
waitcnt(cnt+clkfreq/4)
DATAENTRY
waitcnt(cnt+clkfreq*4)
JUMP1978
waitcnt(cnt+clkfreq*4)
JUMP1985
' the end
waitcnt(cnt+clkfreq*8)
gr.clear
gr.colorwidth(1,4)
gr.box(-120,-30,240,81)
gr.textmode(4,4,6,5)
gr.colorwidth(2,3)
gr.text(0,10,string("the end"))
PUB SYSBOOT
gr.textmode(3,3,6,5)
gr.colorwidth(1,3)
gr.text(-40,80,string("SYS READY"))
gr.textmode(2,2,6,5)
gr.colorwidth(2,2)
gr.text(-70,-70,string("HO-2000"))
gr.textmode(2,2,6,5)
gr.colorwidth(2, 2)
gr.text(50, -70, string("DEPART"))
PUB SYSREADY
gr.textmode(3,3,6,5)
gr.colorwidth(1,3)
gr.text(-40,80,string("SYS READY"))
gr.textmode(2,2,6,5)
gr.colorwidth(2,2)
gr.text(-70,-70,string("HO-2000"))
PUB JUMPSTANDBY
gr.clear
gr.textmode(3,3,6,5)
gr.colorwidth(1,3)
gr.text(0,75,string("12 / 24"))
gr.textmode(9,9,6,5)
gr.colorwidth(1,3)
gr.text(0,10,string("2013"))
gr.textmode(2,2,6,5)
gr.colorwidth(2,2)
gr.text(-70,-70,string("HO-2000"))
gr.textmode(2,2,6,5)
gr.colorwidth(3, 2)
gr.text(50, -70, string("12/24/----"))
PUB DATAENTRY
gr.clear
SYSREADY
wav.play(string("keys.wav"))
gr.textmode(4,4,6,0)
gr.colorwidth(1,3)
gr.text(-70,10,string("#>1"))
waitcnt(cnt+clkfreq/4*3)
gr.text(-70,10,string("#>12"))
waitcnt(cnt+clkfreq/4*3)
gr.clear
SYSREADY
gr.textmode(2,2,6,5)
gr.colorwidth(3, 2)
gr.text(50, -70, string("12/--/----"))
gr.colorwidth(1,3)
gr.textmode(4,4,6,0)
waitcnt(cnt+clkfreq/4)
gr.text(-70,10,string("#>2"))
waitcnt(cnt+clkfreq/4)
gr.text(-70,10,string("#>24"))
waitcnt(cnt+clkfreq/4*3)
gr.clear
SYSREADY
gr.textmode(2,2,6,5)
gr.colorwidth(3, 2)
gr.text(50, -70, string("12/24/----"))
gr.textmode(4,4,6,0)
gr.colorwidth(1,3)
gr.text(-70,10,string("#> "))
PUB JUMP1978 | i
wav.play(string("SFX.wav")) ' Play 24 second long "time jump" sound effect
waitcnt(cnt+clkfreq*2) ' Let SFX get going
JUMPSTANDBY ' Show time machine activation/standby display
waitcnt(cnt+clkfreq*2) ' and leave up for 2 seconds before counting
' Count from present year to jump year
i:=2013
' this repeat loop must complete in ~18 seconds
repeat until i == 1977 ' stop at 1978
num2str(i)
gr.textmode(9,9,6,5)
gr.colorwidth(1,3)
gr.text(0,10,@numStr)
waitcnt(cnt+clkfreq/3) ' delay between years during counting
i-=1
gr.colorwidth(0,8)
gr.box(-120,-30,240,81)
' WAV sound effect fades out about here
' Flash current year ' done counting, flash year of arrival 8 times
repeat 8
gr.colorwidth(0,8)
gr.box(-120,-30,240,81) ' draw black box to clear year
waitcnt(cnt+clkfreq/4)
gr.textmode(9,9,6,5)
gr.colorwidth(1,8)
gr.text(0,10,@numStr) ' draw year
waitcnt(cnt+clkfreq)
PUB JUMP1985 | i
wav.play(string("SFX.wav"))
gr.colorwidth(0,8) ' clear bolded year
gr.box(-120,-30,240,81)
' Count from present year to jump year
i:=1978 ' current year
repeat until i == 1986
num2str(i)
gr.textmode(9,9,6,5)
gr.colorwidth(1,3)
gr.text(0,10,@numStr)
if i == 1978
waitcnt(cnt+clkfreq*9)
else
waitcnt(cnt+clkfreq)
i+=1
gr.colorwidth(0,8)
gr.box(-120,-30,240,81)
' Flash current year
repeat 8
gr.colorwidth(0,8)
gr.box(-120,-30,240,81)
waitcnt(cnt+clkfreq/4)
gr.textmode(9,9,6,5)
gr.colorwidth(1,8)
gr.text(0,10,@numStr)
waitcnt(cnt+clkfreq)
PUB num2str(value) | given ' For numbers from 100 to 9999
given := value
if value < 1000
value *= 10
numStr[0] := value / 1000 + "0"
value //= 1000
numStr[1] := value / 100 + "0"
value //= 100
numStr[2] := value / 10 + "0"
value //= 10
numStr[3] := value + "0"
numStr[4] := 0
if given < 1000
numStr[3] := 0
PUB StartVGA | i, dx, dy, c
bitmapAddr := (@bitmap + $3F) & $FFFF_FFC0 ' Bitmap address must start on a 32 byte boundary
'start vga
vga_videobase := @screen
vga_colorbase := @colors
vga.start(@vgaparams)
'init colors
repeat i from 0 to 63
colors[i] := $28_48_FF_00 ' teal, purple, white, black
'init tile screen
repeat dx from 0 to vga_hc - 1
repeat dy from 0 to vga_vc - 1
screen[dy * vga_hc + dx] := bitmapAddr >> 6 + dy + dx * vga_vc '+ ((dy & $3F) << 10)
'start and setup graphics
gr.start
gr.setup(16, 12, 128, 96, bitmapAddr)
DAT
vgaparams long 0 'status
long 1 'enable
long 1_111 'pins
long 11 'mode
vga_videobase long 0 'videobase
vga_colorbase long 0 'colorbase
vga_hc long x_tiles 'hc
vga_vc long y_tiles 'vc
long 2 'hx //RJA increased from 1X to 2X
long 2 'vx //RJA increased from 1X to 2X
long 0 'ho
long 0 'vo
long 512 'hd
long 16 'hf
long 96 'hs
long 48 'hb
long 380+16 'vd //RJA added 16
long 11 'vf
long 2 'vs
long 31+16 'vb //RJA subtracted 16
long 20_000_000 'rate

Comments
Thanks for the BST tip! Compiling in BST with the two options you mention increases the free longs from 220 to 654, so it definitely does help. I might be able to make that work. I have a lot of code to finish out to know what I truly need, but adding simple serial for the XB and two more time jumps wiped me out originally.
I think my next hurdle is figuring out how to re-use the jump loop code or finish off the XB code to see where I stand. I am worried that I may end up in a memory crunch again though....
Just something to keep in mind if you can't squeeze everything you need/want into the remaining memory.
Also, try creating a single method for the waitcnts like this, see if this saves a few longs:
PUB W(dv) waitcnt(cnt+clkfreq/dv)Duane, Yeah, I had thought of that. I could use my Prop Activity Board for the audio and XB then use the PropBOE for the video. I hope I don't have to go that route as that adds more time, more testing, etc. I may try to complete everything but the video display to get it "done" then try to add the video.
You don't need all the colors array longs. If you are only using 4 screen colors, then you can cut that array down to just one long, if you want to. How it works is each tile gets a 4 color palette. The 64 longs represent 64 possible 4 color palettes for the tiles. Maybe keep two longs, and you could use 8 colors, if you want to, etc...
In my signature, I've got a link there "Parallax Colors Simplified" and it applies to this tile type driver you are using. There are methods in there to set the screen colors, show how the color array is used, etc...
This code sets all the palette entries to the same 4 colors.
BTW, once you have done this, you can then change those 4 colors dynamically and the entire screen changes. You can set one to black, or your background color for example. Say color 00 = black. Say color 01 = red, but you want to draw a lot of stuff, then have it pop onto the screen. Set color 01 = black, draw it all, then set it to red. Everything will appear all at once.
'init colors repeat i from 0 to 63 colors[i] := $28_48_FF_00 ' teal, purple, white, blackYou want:
'init colors colors[0] := $28_48_FF_00 ' teal, purple, white, blackThen you want all the tiles assigned to the same palette entry!
(more in a minute)
I'm having trouble pasting into a code window on this Mac.
Just know that this code:
'init tile screen repeat dx from 0 to vga_hc - 1 repeat dy from 0 to vga_vc - 1 screen[dy * vga_hc + dx] := bitmapAddr >> 6 + dy + dx * vga_vc '+ ((dy & $3F) << 10)Initializes all the tiles. Each tile points to a little region of HUB RAM, and each tile references one of those color palettes. That complex bit of code assigns lots of color palettes. This is undesirable when using a 4 color screen.
Use the methods in the programs you find in my signature to see how the tile address and color palette get defined and then define all your tiles to the same screen layout, but make sure they all point to just one color entry and you save those longs. If you change the variable names and color definitions, they should work with this driver you are using.
Edit: Looks like you are already running single buffer on that one.
That means the 3072 longs are needed for the 256x192 screen. If you want some savings, you could get rid of a row or two of tiles in the "X" direction. Each tile is 16 pixels wide, and each row removed will recover 768 bytes for you.
Remove one row, and you've got a 240 pixel display. Compensate by increasing the vgaparams to better center the tiles on the display. I can't run this right now, or I would.
These also can't be in the upper 64K. The VGA driver needs them in the HUB.
Between those two things, you should be able to cram things in next to the video.
More savings is possible. If you need it, let me know, but the next thing to do is play tricks with the tiles. Say you have blank areas on the screen. Those can be mapped to the SAME HUB RAM bytes allowing for creative screen arrangements using less HUB RAM. It's possible to make little regions too. The techniques are in the commented graphics_demo.spin in my signature.
http://rayslogic.com/Propeller/Products/VgaGraphics/VgaGraphics.htm
'init tile screen repeat dx from 0 to vga_hc - 1 repeat dy from 0 to vga_vc - 1 screen[dy * vga_hc + dx] := bitmapAddr >> 6 + dy + dx * vga_vcFor 3 drivers eating up a good amount of COG-RAM this saves up to 6kB.
A quick and dirty solution would be to move the PASM code of all 3 drivers into one big SPIN-file. Having the PASM code in a row allows to reuse this DAT sections a screen-buffer after loading into COGs.
The reason is both the color palette array index number, and the HUB memory address for the pixel data in that tile are encoded into the screen word associated with each tile.
The lower 10 bits for each tile in the screen array point to a 64 byte aligned HUB memory address. That is where the actual pixels are. The upper 6 bits point to an entry in the colors array, and that is where the colors of those pixels are.
You want those to be zero and that equals "colors[0]"
'init tile screen "The Screen Array" { This bit of code, writes the hub screen memory address pointers for each tile on the screen. Each tile = 64 bytes, or 16 longs. Tiles are 16 pixels, 2 bits per pixel for a total of 1 long wide, and 16 pixels high. Tiles are numbered (0,0) at the upper right, incrementing horizontally, then down to reach the limits of x_tiles and y tiles as given above. The lower 10 bits of each screen address entry contain the address where the pixels for that tile are contained in the HUB. The upper 6 bits of each screen address entry contain the pointer to the color palette for that tile. Again, these lists are used by the TV driver to know where in the hub the picture is, and what colors it has. } repeat dx from 0 to tv_hc - 1 repeat dy from 0 to tv_vc - 1 screen[dy * tv_hc + dx] := display_base >> 6 + dy + dx * tv_vc '+ ((dy & $3F) << 10) 'I've commented out the original Parallax color scheme, which means all tiles are referencing 'Color Palette entry 0, which is black, dark green, light green background, and white, just to 'show how the tile color palettes work.Reading...
In your original post:
'init tile screen repeat dx from 0 to vga_hc - 1 repeat dy from 0 to vga_vc - 1 screen[dy * vga_hc + dx] := bitmapAddr >> 6 + dy + dx * vga_vc [B]'+ ((dy & $3F) << 10)[/B]You've got it commented out already! All tiles should point to colors[0] now.
This is the piece that does the funky palette assignments:
'+ ((dy & $3F) << 10)
So you should be able to cut the colors array back and have it work. Is that not the case?
Assuming it is, we can move on to shaving some pixels off in the X direction, if you need another 700-1400 bytes.
I also started looking into the WAV code out of curiosity. It's quite a bit over my head, but I see a lot of error handling for unsupported files that I won't need. At a quick swipe at removing the error handling in that code, I freed up 154 longs. I think I am learning some tricks to get where I need to be!
What does your display look like? Do the numbers and such consume all of it, or just some of it? I'm thinking we can take a strip off the X at a minimum. 240 pixels is very similar to the 256 pixels you have now. That's good for 700 bytes, if needed.
I'm going to check out here in a minute, but here is what you do:
First, subtract one from the number of tiles in the X direction:
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 x_tiles = 16-1 ' = 15 = 240 pixels now y_tiles = 12Then resize your bitmap:
Then in your StartVGA, adjust the graphics setup so that the graphics commands do the right thing in the right place.
You might adjust where you put things. I don't know, didn't check.
Finally, you might want to fiddle with the offsets and scale factors found in:
vgaparams long 0 'status long 1 'enable long 1_111 'pins long 11 'mode vga_videobase long 0 'videobase vga_colorbase long 0 'colorbase vga_hc long x_tiles 'hc vga_vc long y_tiles 'vc long 2 'hx //RJA increased from 1X to 2X long 2 'vx //RJA increased from 1X to 2X long 0 'ho long 0 'vo long 512 'hd long 16 'hf long 96 'hs long 48 'hb long 380+16 'vd //RJA added 16 long 11 'vf long 2 'vs long 31+16 'vb //RJA subtracted 16 long 20_000_000 'rateSadly, it's been a while since I ran this driver. I think you want the xo, yo parameters to offset the display somewhere acceptable, but I'm not sure. Maybe others are needed too. If I were you, I would draw a big rectangle around the outside edge, see where it all is and fiddle with those, until it's somewhere in the center of your display. Then remove those commands.
Repeat with another strip off the X direction, if you really need to.
If you need more beyond that, we are going to have to exchange info about what your display looks like, or maybe I can run it, or something. If there are blank areas, we can shave off 64 bytes per blank area that is never drawn into, by assigning the tiles in creative ways and then running gr.setup multiple times... Hopefully, it won't go there.
Since my laptop just went to sleep due to the battery, I guess I should call it a night as well. Had to plug it in so I could resume windows to finish typing this post, lol. I will keep working on this tomorrow at lunchtime.
Open all 3 driver files and copy all the code into one new file.
Tweaks needed are:
Rename SPIN-functions and variables which have the same name - probably start and stop. Simply make it startVGA, startGraph & startDAC...
Make sure that you put all PASM DAT sections in a row to give you a continuous block of bytes which then can be reused by VGA as a bitmap- and screen-buffer.
Tweak here is to start VGA as the last driver and to clean the DAT section to avoid seeing too much garbage on the screen.
Being optimistic means that this is all you have to do. It has to be checked weather the graphics driver is fine when started after the VGA driver, but in theory I don't see a reason why not.
Then you use the startcog label mod 64 + 64 as your start of bitmap screen.
But, I see you've already done that. Actually, I see my initials in there on that change...
You could maybe go 4X and further reduce the pixel count, but then it might get too pixelated...
I'd try replacing the wav code with FSRW and my wav player...
Might not have as many features as Kye's code, but I think it's much smaller...
Rayman, You are right. Using your WAV player for 16 bit mono, I will gain another 507 longs. I don't need stereo as long as the mono output to be left and right. The WAV player only needs to be able to play the WAV file. No other options needed at all. (IE: volume, error handling, etc)
PUB Jumpyear(depyear, arryear, j, delayadj) | i, TimeBase, OneMS, jumptime wav.play(string("SFX.wav")) ' Play 24 second long "time jump" sound effect WAITL(2) 'waitcnt(cnt+clkfreq*2) ' Let SFX get going JUMPSTANDBY ' Show time machine activation/standby display WAITL(2) 'waitcnt(cnt+clkfreq*2) ' and leave up for 2 seconds before counting ' Count from present year to jump year OneMS := clkfreq / 1000 'Calculate cycles per 1 millisecond jumptime := ||depyear - arryear ' get difference in years jumptime := 20000//jumptime ' determine steps needed for inside 20 seconds jumptime := jumptime**OneMs ' convert steps into miliseconds TimeBase := cnt 'Get current count Repeat i from depyear to arryear step j num2str(i) gr.textmode(9,9,6,5) gr.colorwidth(1,3) gr.text(0,10,@numStr) waitcnt(TimeBase += jumptime) ' Wait to start of next timeframe gr.colorwidth(0,8) gr.box(-120,-30,240,81) ' Flash current year repeat 8 gr.colorwidth(0,8) gr.box(-120,-30,240,81) WAITS(4) 'waitcnt(cnt+clkfreq/4) gr.textmode(9,9,6,5) gr.colorwidth(1,8) gr.text(0,10,@numStr) WAITL(1) 'waitcnt(cnt+clkfreq)If I convert my delays to mS, I can use a single method, so I may do that before my code gets too far out of hand. I also starting noticing that much of my calls to the Graphics object account to less than 10 different types. I can probably convert those to method calls instead of individual code segments to clean up the code structure.
Still have a lot of work to do before Saturday morning. I am sure that I will be out of midnight oil over the next couple nights.
As for the questions about the display, here is what it looks like when at a particular year. There is some black space, but not at the top or bottom edges (my widescreen monitor at my desk makes it appear otherwise however). I think with all my other code condensing, I will not need to cut back the VGA code anymore. BST has made a big difference in compiling for size.
PUB Jumpyear(depyear, arryear, j, delayadj) | i, TimeBase, OneMS, jumptime OneMS := clkfreq / 1000 'Calculate cycles per 1 millisecond wav.play(string("SFX.wav")) ' Play 24 second long "time jump" sound effect WAITL(2) 'waitcnt(cnt+clkfreq*2) ' Let SFX get going JUMPSTANDBY ' Show time machine activation/standby display WAITL(2) 'waitcnt(cnt+clkfreq*2) ' and leave up for 2 seconds before counting ' Count from present year to jump year Repeat i from depyear to arryear step j num2str(i) gr.textmode(9,9,6,5) gr.colorwidth(1,3) gr.text(0,10,@numStr) ' WAITL(delayadj*OneMS) WAITMS(delayadj) gr.colorwidth(0,8) gr.box(-120,-30,240,81) ' Flash current year repeat 8 gr.colorwidth(0,8) gr.box(-120,-30,240,81) WAITS(4) 'waitcnt(cnt+clkfreq/4) gr.textmode(9,9,6,5) gr.colorwidth(1,8) num2str(arryear) gr.text(0,10,@numStr) WAITL(1) 'waitcnt(cnt+clkfreq)To jump from 2013 to 1978 I call this:
The 300 ms delay between counting years makes it last 12 seconds which finishes at the loud whoosh sound in the sound effect (like coming to a stop in a time machine, lol)