Jump to content
IGNORED

General Turbo Forth questions


Vorticon

Recommended Posts

You can do what @Tursi suggested by using TF's SOUND for each channel and devising a VDP-interrupt counting mechanism for the duration times.

 

...lee

 

Yes that may actually work quite well since duration is not specified as a parameter and is left to the programmer to do it manually. There are also supplementary sound words, namely Volume, Tone and Noise which provide an even finer level of control. Definitely worth a look as there is no point in reinventing the wheel here :) The question will be how fast will these execute...

Link to comment
Share on other sites

Considering some of the regularity of the sounds we are creating, and the fact that the sounds generated by the Spectrum have tones with a higher resolution than 1/60s, I postulated on the idea of a custom sound routine which would just throw the requisite data at the 9919. It looks like resolution used for Jetpac on the Spectrum is somewhere between 1/90s and 1/120s. As a result the sounds from the game are more complex than can be easily recreated in an interrupt-driven player.

 

What can TF do toward this end?

Link to comment
Share on other sites

Considering some of the regularity of the sounds we are creating, and the fact that the sounds generated by the Spectrum have tones with a higher resolution than 1/60s, I postulated on the idea of a custom sound routine which would just throw the requisite data at the 9919. It looks like resolution used for Jetpac on the Spectrum is somewhere between 1/90s and 1/120s. As a result the sounds from the game are more complex than can be easily recreated in an interrupt-driven player.

 

What can TF do toward this end?

 

According to the source code, TF services sound every other frame (1/30 sec). I couldn't figure out how it does it, however. @Willsy will shed some light on it ere long.

 

...lee

Link to comment
Share on other sites

Considering some of the regularity of the sounds we are creating, and the fact that the sounds generated by the Spectrum have tones with a higher resolution than 1/60s, I postulated on the idea of a custom sound routine which would just throw the requisite data at the 9919. It looks like resolution used for Jetpac on the Spectrum is somewhere between 1/90s and 1/120s. As a result the sounds from the game are more complex than can be easily recreated in an interrupt-driven player.

 

What can TF do toward this end?

 

It's a bit of an un-known quantity really.

 

I decided to bite the bullet and write my own sound list processor/driver. Here it is:

 

 

asm: soundListPlayer ( -- )
    \ re-entrant. Uses r0 to remember state:
    \ 0 = doing nothing. Waiting for a sound list to be loaded
    \ 1 = loading sound bytes to sound chip
    \ 2 = counting off duration counter
    $2000 lwpi,
    r0 r0 mov,              \ have a sound list to process?
    ne if,
        r0 1 ci,            \ loading sound bytes?
        eq if,              \ yes
            r1 *+ r2 movb,  \ get number of bytes to send to sound chip
            r2 8 srl,       \ move to low byte
            eq if,
                r0 clr,     \ if 0 then we're finished
            else,   
                begin,
                    r1 *+ $8400 @@ movb,    \ send a byte to the sound chip
                    r2 dec,                 \ decrement counter
                eq until,       \ loop until finished
                r1 *+ r3 movb,  \ get duration byte
                r3 8 srl,       \ move to low byte
                eq if,          \ processed everything?
                    r0 clr,     \ reset state to 0 (idle)
                else,
                    r0 2 li,    \ set state flag to counting
                endif,
            endif,
        else,
            \ we're counting off duration
            r3 dec,         \ decrement duration`
            eq if,          \ hit zero?
                r0 1 li,    \ set state to load sound bytes
            endif,
        endif,
    endif,
    $83e0 lwpi,             \ restore GPL's workspace
    r11 ** b,               \ return via R11
;asm

 

It occupies a whopping ( :grin: ) 86 bytes. How cool is that. It plays regular sound lists in the TI format.

 

'Yall probably don't know, but TF has built into it a user ISR hook. When an interrupt fires, it first checks to see if there's any data to pipe out to the speech synth. After that, it checks CPU ram location >A008 for an address. If there is an address in there (i.e. it's non-zero) it branches to the code at that address, hence you can run your own machine code on the VDP interrupt.

 

So, the little sound driver above is pretty cool. It's re-entrant, and stateful. It manages it's own state. You can analyse the code to see how it works, but very briefly, the driver has 3 states:

 

0 - idle - nothing happening

1 - loading sound bytes into the sound chip

2 - counting off duration ticks

 

To play a sound, put an address of a sound list on the stack, and call playSoundList - as long as there is some vdp access going on, it'll play the sounds.

 

 

: playSoundList ( address -- )
    $2000 @ 0= if       \ if r0 of ISR=0 (not playing a sound list)
        $2002 !         \ set R1 of user ISR workspace with sound list address
        1 $2000 !       \ kick off sound processing
    then
;

 

 

Note: As you can see, playSoundList as written will only play a sound list if it's idle.

 

You can query the driver with soundBusy? to see if it's idle. You might want to do this before initiating a sound.

 

 

: soundBusy? ( -- flag )
    $2000 @             \ load R0 of user ISR workspace
;

 

 

So, boot TF, load the assembler from the blocks file (9 LOAD) and paste the text in the attached text file in, and then try:

 

airBurstSnd playSoundList

 

and

 

groundBurstSnd playSoundList

 

and

 

inFlightSnd playSoundList

 

I cannot take credit for the example sound list data. I took it from The Art Of Assembly, from the chapters on sound lists, which is a lot easier to understand than TI's load of old cock. The code is my own though.

 

Oh, one thing to note: The driver above does NOT require the sound list to be placed in VDP ram. It reads it directly out of the compiled data list. Much more efficient.

 

I've tried it from the command line and it's perfect. However, when you enter something on the command line TF just sits there flashing the cursor. That is quite a short loop, and interrupts are enabled and disabled in that loop. I would expect it to be more jittery in running code.

 

Walid, I was thinking, wrt to Jetpac: Do you call the delay routine in the main loop of your game anywhere? If so, it would be a great place to do some dummy vdp access to fire the vdp interrupts. So, instead of:

 

: delay ( n -- ) 0 do loop ;

 

You could have:

 

: delay ( n -- ) 0 do 0 v@ drop loop ;

 

You would have to shorten your delay loops in your code, but interrupts would fire the delay loop without a doubt. That might be all you need to remove the jitter.

 

Note that JOYST also fires the interrupts.

 

Entire source code attached. I have't produced a CODE: version of the assembler code, but 'yall know how to do that.

 

Rock on. Time for bed! :)

 

sound list driver.txt

  • Like 3
Link to comment
Share on other sites

  • 1 month later...

I was able to get TurboForth running on my Geneve, just had to add GramKracker headers to the bin files. Cool... I noted that there is a KDEL setting to deal with keyboard repeat rates, which makes me wonder how well my USB keyboard works in TurboForth. So my TurboForth question is: Can the roms be used on a 512k red board if I flood it with the first 8k page, and then put the 2nd 8k page in the right spot on the 512k eprom? Why, cause I have 512k uv eproms...

 

-M@

Link to comment
Share on other sites

... my TurboForth question is: Can the roms be used on a 512k red board if I flood it with the first 8k page, and then put the 2nd 8k page in the right spot on the 512k eprom?

 

You can copy either or both ROMs in any order to flood the unused ROM space; but, you must get the first two in the correct order, which, for TF, is backwards for the red board. That is, you want TF bank 0 in the second 8KiB and TF bank 1 in the first 8KiB.

 

...lee

Link to comment
Share on other sites

 

You can copy either or both ROMs in any order to flood the unused ROM space; but, you must get the first two in the correct order, which, for TF, is backwards for the red board. That is, you want TF bank 0 in the second 8KiB and TF bank 1 in the first 8KiB.

 

...lee

 

Yep, that worked... I skipped splitting the .eprom and used the two bank files that are in the classic99 folder of the distribution. My red board always powers on at the last bank, so I loaded TurboForthC.bin at 00000, TurboForthD.bin at 02000, and TurboForthC.bin again at 7E000 in the minipro eprom programmer.

 

Double negatives like non-inverted cause brain freeze :)

 

Thanks!

Link to comment
Share on other sites

So, I'm looking at getting the DSK1/BLOCKS file out of the TurboForth.net download onto DSSD80 disks, but I don't recognize the 3.2meg file size... and TI99DIR nor TiImageTool think it is a disk image. Looking inside, it looks like the actual blocks file, just way to big.

 

-M@

 

It should not be that large, for sure. Mark will have to weigh in on this. However, it looks like mostly spaces after the first 80KiB—except for a few hundred bytes at the very end, which were actually duplicated from much earlier in the file. In a hex editor, I clipped the TIFILES header (128 bytes) and all of the tail end except for 80KiB (81920 bytes)—I assumed that was the size it should be. I then converted it in TI99Dir from PC to TI file (DF128, with no data conversion), which produced a V9T9 file. Though I have not tested it, here it is in a ZIP file: BLOCKS.zip

 

...lee

Link to comment
Share on other sites

 

It should not be that large, for sure. Mark will have to weigh in on this. However, it looks like mostly spaces after the first 80KiB—except for a few hundred bytes at the very end, which were actually duplicated from much earlier in the file. In a hex editor, I clipped the TIFILES header (128 bytes) and all of the tail end except for 80KiB (81920 bytes)—I assumed that was the size it should be. I then converted it in TI99Dir from PC to TI file (DF128, with no data conversion), which produced a V9T9 file. Though I have not tested it, here it is in a ZIP file: attachicon.gifBLOCKS.zip

 

...lee

 

 

Thanks, that blocks file worked. And the turboforth.net site does say it should be an 80 block file. So that is probably good. Things seemed to load fine.

Mark, you probably want to fix the archive on your website.

 

-M@

Link to comment
Share on other sites

  • 1 month later...
  • 1 month later...

I thought I would play around with the SAMS bank switching library in Turboforth.

 

I have found one gotcha: the data and enhanced data ( data[ ]data ) words

 

They don't return the address of the data when compiling into a paged bank.

 

: testdata data[ 1 2 3 4 ]data ;

: test testdata 0 do CR @++ . loop drop ;

 

Running test prints out the expected 1 2 3 4

 

But if you do these first:

 

2 banks

0 setbank

 

Then it prints out entirely different values. I suspect values I get are the machine code leading up to jumping into the bank.

 

-M@

Link to comment
Share on other sites

  • 1 year later...

 

It's a bit of an un-known quantity really.

 

I decided to bite the bullet and write my own sound list processor/driver. Here it is:

 

 

asm: soundListPlayer ( -- )
    \ re-entrant. Uses r0 to remember state:
    \ 0 = doing nothing. Waiting for a sound list to be loaded
    \ 1 = loading sound bytes to sound chip
    \ 2 = counting off duration counter
    $2000 lwpi,
    r0 r0 mov,              \ have a sound list to process?
    ne if,
        r0 1 ci,            \ loading sound bytes?
        eq if,              \ yes
            r1 *+ r2 movb,  \ get number of bytes to send to sound chip
            r2 8 srl,       \ move to low byte
            eq if,
                r0 clr,     \ if 0 then we're finished
            else,   
                begin,
                    r1 *+ $8400 @@ movb,    \ send a byte to the sound chip
                    r2 dec,                 \ decrement counter
                eq until,       \ loop until finished
                r1 *+ r3 movb,  \ get duration byte
                r3 8 srl,       \ move to low byte
                eq if,          \ processed everything?
                    r0 clr,     \ reset state to 0 (idle)
                else,
                    r0 2 li,    \ set state flag to counting
                endif,
            endif,
        else,
            \ we're counting off duration
            r3 dec,         \ decrement duration`
            eq if,          \ hit zero?
                r0 1 li,    \ set state to load sound bytes
            endif,
        endif,
    endif,
    $83e0 lwpi,             \ restore GPL's workspace
    r11 ** b,               \ return via R11
;asm

 

It occupies a whopping ( :grin: ) 86 bytes. How cool is that. It plays regular sound lists in the TI format.

<SNIP>

 

While looking for stories about sound I found this one. 86 Bytes is pretty small for sure.

This one in Forth adds only 124 bytes to the system and that includes about 31 bytes of names and linked-list stuff.

So not too shabby.

HEX
: SILENT ( --)  9F SND!  BF SND!  DF SND! FF SND! ;  \ turn off all sounds

: PLAY$ ( sound_string -- ) \ play 1 sound string
       COUNT                \ -- addr len
       2DUP + C@  >R        \ get duration at end of string, Rpush
       BOUNDS               \ convert addr/len to end-addr. start-addr.
       DO  I C@ SND! LOOP   \ feed bytes to sound chip
       R> JIFFS ;           \ use the delay from Rstack (JIFF=1/60)

: PLAYLIST   ( addr -- )    \ play a TI sound list
         BEGIN DUP C@ WHILE \ while the length is not 0
            PAUSE           \ give somebody else some time
            DUP PLAY$       \ play a single string
            COUNT + 1+      \ advance to the next sound string
         REPEAT
         SILENT
         DROP ;             \ mom said always clean up after yourself
Edited by TheBF
  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...