Jump to content
Sign in to follow this  
freewheel

IntyBASIC + Intellivoice

Recommended Posts

I have some questions that the IntyBASIC manual doesn't seem to address:

 

1. Is there a way to stop the Intellivoice, if it's mid-sentence? ie: if I run VOICE PLAY label, and it's halfway through the contents of <label> - can I stop it? I think I can call VOICE INIT to do this, but is that a good/safe method?

 

2. Is there a way to detect if the Intellivoice is still speaking?

 

3. I don't really understand what VOICE WAIT and VOICE PLAY WAIT are supposed to do. Do they literally pause the program until the voice queue is empty? Because just using VOICE PLAY label, it *always* waits until the queue is empty before playing <label>. In jzintv and on real hardware.

Share this post


Link to post
Share on other sites

I have some questions that the IntyBASIC manual doesn't seem to address:

 

1. Is there a way to stop the Intellivoice, if it's mid-sentence? ie: if I run VOICE PLAY label, and it's halfway through the contents of <label> - can I stop it? I think I can call VOICE INIT to do this, but is that a good/safe method?

There's no way currently.

 

2. Is there a way to detect if the Intellivoice is still speaking?

Now there is a VOICE.PLAYING expression.

 

3. I don't really understand what VOICE WAIT and VOICE PLAY WAIT are supposed to do. Do they literally pause the program until the voice queue is empty? Because just using VOICE PLAY label, it *always* waits until the queue is empty before playing <label>. In jzintv and on real hardware.

VOICE WAIT is to wait for voice to end playing.

 

VOICE PLAY WAIT is to play a voice and wait for it to end.

 

I'm pretty sure VOICE PLAY stops any other voice playing. I'll need to check about this because the trick to stop voice would be something like putting a VOICE PA4,0 and then VOICE PLAY that voice.

Share this post


Link to post
Share on other sites

I think I can call VOICE INIT to do this, but is that a good/safe method?

 

You should only call VOICE INIT once, at the start of time. Recall the fun we discovered w/ Crazybus? Also, there was some other game that had voice issues due to calling VOICE INIT more than once.

 

(IMHO, VOICE INIT should be removed from the language, and IntyBASIC should just initialize the Intellivoice automatically, if any VOICE keywords are used. But, that's a different topic.)

 

 

I'm pretty sure VOICE PLAY stops any other voice playing. I'll need to check about this because the trick to stop voice would be something like putting a VOICE PA4,0 and then VOICE PLAY that voice.

 

Just be sure that IntyBASIC cuts over on phoneme boundaries. We don't want to get our poor SP0256 confused. :-) If it gets confused enough, it'll need to be reset via the hardware reset button.

  • Like 2

Share this post


Link to post
Share on other sites

VOICE WAIT is to wait for voice to end playing.

 

VOICE PLAY WAIT is to play a voice and wait for it to end.

 

I'm pretty sure VOICE PLAY stops any other voice playing. I'll need to check about this because the trick to stop voice would be something like putting a VOICE PA4,0 and then VOICE PLAY that voice.

 

I still don't understand - what waits? I've played around a bit, and VOICE WAIT doesn't seem to do anything. The program continues even if a voice is playing. VOICE PLAY and VOICE PLAY WAIT seem to do the exact same thing.

 

VOICE PLAY does *not* stop another voice that's playing. It seems to queue up a PLAY command, and then when the current one is finished, plays the next one. Watching the actual value of VOICE.PLAYING, it seems to change by 1 every time I queue up another VOICE PLAY - and then change by 1 as it de-queues and plays the next one.

 

I'm just using a simple program - 2 VOICE PLAY statements, called when you press keypad 1 or 2. I can play one at a time, but it always plays until the end. And the others queue up (subject to a limit of 10 in the queue, including the one currently playing).

 

Observation: VOICE.PLAYING isn't totally accurate. It resets back to 0 while it's saying the second-to-last phrase/phoneme for a given VOICE PLAY statement. Not a big deal, but I figured I'd mention it as I look at the exact behaviour of these commands :) Easy test for this - use the MATTEL phrase. VOICE.PLAYING very quickly changes value, and then back to 0. The Intellivoice keeps talking for a bit.

 

Edit: OK, I can "fix" the issue with VOICE.PLAYING. Adding a pause (PA*) at the end of any label, means that it resets to 0 right before the pause. So in effect, it goes to 0 when the Intellivoice stops talking. A simple enough solution.

  • Like 2

Share this post


Link to post
Share on other sites

 

I still don't understand - what waits? I've played around a bit, and VOICE WAIT doesn't seem to do anything. The program continues even if a voice is playing. VOICE PLAY and VOICE PLAY WAIT seem to do the exact same thing.

 

 

Hehehe. I thought exactly the same thing: "X waits until play ends; Y plays until the end." :lol: LOL!

 

However, I think that what it means is that "VOICE WAIT" will wait for the already playing voice string to finish, while "VOICE PLAY WAIT" will accept a voice string and start playing it, and wait until it ends.

 

In other words, "VOICE PLAY WAIT" is the same as "VOICE PLAY" (start playing) followed by "VOICE WAIT" (wait until active voice ends).

 

I could be wrong, but that's my interpretation of the description. Perhaps others would like to chime in.

 

-dZ.

  • Like 1

Share this post


Link to post
Share on other sites

I could be wrong, but that's my interpretation of the description. Perhaps others would like to chime in.

 

-dZ.

That's exactly what it does.

 

I remind testing it throughly.

 

I'll need to check again in case something slip. Not a great deal of time available these days :ponder:

Share this post


Link to post
Share on other sites

 

Edit: OK, I can "fix" the issue with VOICE.PLAYING. Adding a pause (PA*) at the end of any label, means that it resets to 0 right before the pause. So in effect, it goes to 0 when the Intellivoice stops talking. A simple enough solution.

 

Interestingly enough, I put a note to that effect in my Intellivoice driver, about 15 years ago:

;; ======================================================================== ;;
;;  NAME                                                                    ;;
;;      IV_WAIT     Wait for voice queue to empty.                          ;;
;;                                                                          ;;
;;  AUTHOR                                                                  ;;
;;      Joseph Zbiciak <intvnut AT gmail.com>                               ;;
;;                                                                          ;;
;;  REVISION HISTORY                                                        ;;
;;      15-Sep-2002 Initial revision . . . . . . . . . . .  J. Zbiciak      ;;
;;                                                                          ;;
;;  INPUTS for IV_WAIT                                                      ;;
;;      R5      Return address                                              ;;
;;                                                                          ;;
;;  OUTPUTS                                                                 ;;
;;      R0      trashed.                                                    ;;
;;                                                                          ;;
;;  NOTES                                                                   ;;
;;      This waits until the Intellivoice is nearly completely quiescent.   ;;
;;      Some voice data may still be spoken from the last triggered         ;;
;;      phrase.  To truly wait for *that* to be spoken, speak a 'pause'     ;;
;;      (eg. RESROM.pa1) and then call IV_WAIT.                             ;;
;; ------------------------------------------------------------------------ ;;
;;                   Copyright (c) 2002, Joseph Zbiciak                     ;;
;; ======================================================================== ;;

The SP0256 doesn't report whether it's still making noise. It only reports whether it can accept new speech data. So, you do have to speak a little bit of silence to know you're done making noise.

Share this post


Link to post
Share on other sites

As promised a couple days ago: I've modified intybasic_prologue.asm and intybasic_epilogue.asm such that:

  1. You never need to call VOICE INIT. If you use any voice functions in your game, VOICE INIT gets called automagically before your program starts. Zero overhead for games that don't use voice.
  2. Calling VOICE INIT is always safe; it really does a VOICE HUSH: Stop speaking the current sample, queue up a PA1 sample, and wait for PA1 to start.

You can adopt these changes into IntyBASIC 1.2.9 as-is just by dropping these files in over your existing files. If you're already using modified intybasic_prologue.asm and intybasic_epilogue.asm, here's the diff, should you want to apply the change:

.

--- ../intybasic-1.2.9b/intybasic_prologue.asm    2016-10-21 11:40:17.000000000 -0700
+++ intybasic_prologue.asm    2018-02-02 23:58:26.000000000 -0800
@@ -148,7 +148,8 @@
         MVII #$038,R0
         MVO R0,$01F8            ; Configures sound
         MVO R0,$00F8            ; Configures sound (ECS)
-        CALL _wait
+
+        CALL _bottom_half
 
 ;* ======================================================================== *;
 ;*  These routines are placed into the public domain by their author.  All  *;


--- ../intybasic-1.2.9b/intybasic_epilogue.asm	2016-10-21 11:40:21.000000000 -0700
+++ intybasic_epilogue.asm	2018-02-03 00:36:33.000000000 -0800
@@ -1980,7 +1980,7 @@
 ;;                   Copyright (c) 2002, Joseph Zbiciak                     ;;
 ;; ======================================================================== ;;
 
-IV_INIT     PROC
+IV_INIT_1   PROC
             MVII    #$0400, R0          ;
             MVO     R0,     $0081       ; Reset the Intellivoice
 
@@ -2002,9 +2002,11 @@
             DECR    R0
             MVO     R0,     IV.QH       ; Set queue to -1 ("No Intellivoice")
             MVO     R0,     IV.QT       ; Set queue to -1 ("No Intellivoice")
-            JR      R5                  ; Done!
+;           JR      R5                  ; Done!
+            B       _wait               ; Special for IntyBASIC!
             ENDP
 
+
 ;; ======================================================================== ;;
 ;;  NAME                                                                    ;;
 ;;      IV_ISR      Interrupt service routine to feed Intellivoice          ;;
@@ -2272,6 +2274,67 @@
 
 ;; ======================================================================== ;;
 ;;  NAME                                                                    ;;
+;;      IV_HUSH     Flush the speech queue, and hush the Intellivoice.      ;;
+;;                                                                          ;;
+;;  AUTHOR                                                                  ;;
+;;      Joseph Zbiciak <intvnut AT gmail.com>                               ;;
+;;                                                                          ;;
+;;  REVISION HISTORY                                                        ;;
+;;      02-Feb-2018 Initial revision . . . . . . . . . . .  J. Zbiciak      ;;
+;;                                                                          ;;
+;;  INPUTS for IV_HUSH                                                      ;;
+;;      None.                                                               ;;
+;;                                                                          ;;
+;;  OUTPUTS                                                                 ;;
+;;      R0 trashed.                                                         ;;
+;;                                                                          ;;
+;;  NOTES                                                                   ;;
+;;      Returns via IV_WAIT.                                                ;;
+;;                                                                          ;;
+;; ======================================================================== ;;
+IV_INIT:    ; In IntyBASIC, "VOICE INIT" turns into "VOICE HUSH" now.
+IV_HUSH     PROC
+            MVI     IV.QH,  R0
+            SWAP    R0,     2
+            BMI     IV_WAIT.leave
+
+            DIS
+            ;; We can't stop a phrase segment that's being FIFOed down.
+            ;; We need to remember if we've committed to pushing ALD.
+            ;; We _can_ stop new phrase segments from going down, and _can_
+            ;; stop new phrases from being started.
+
+            ;; Set head pointer to indicate we've inserted one item.
+            ;; Do this first, as we already have IV.QH in R0.
+            ANDI    #$F0,   R0
+            INCR    R0
+            MVO     R0,     IV.QH
+
+            ;; Reset tail pointer, keeping "need ALD" bit and other flags.
+            MVI     IV.QT,  R0
+            ANDI    #$F0,   R0
+            MVO     R0,     IV.QT
+
+            ;; Reset the phrase pointer, to stop a long phrase.
+            CLRR    R0
+            MVO     R0,     IV.PPTR
+
+            ;; Queue a PA1 in the queue.  Since we're can't guarantee the user
+            ;; has included resrom.asm, let's just use the raw number (5).
+            MVII    #5,     R0
+            MVO     R0,     IV.Q
+
+            ;; Re-enable interrupts and wait for Intellivoice to shut up.
+            ;;
+            ;; We can't just jump to IV_WAIT.q_loop, as we need to reload
+            ;; IV.QH into R0, and I'm really committed to only using R0.
+;           JE      IV_WAIT
+            EIS
+            ; fallthrough into IV_WAIT
+            ENDP
+
+;; ======================================================================== ;;
+;;  NAME                                                                    ;;
 ;;      IV_WAIT     Wait for voice queue to empty.                          ;;
 ;;                                                                          ;;
 ;;  AUTHOR                                                                  ;;
@@ -2279,6 +2342,7 @@
 ;;                                                                          ;;
 ;;  REVISION HISTORY                                                        ;;
 ;;      15-Sep-2002 Initial revision . . . . . . . . . . .  J. Zbiciak      ;;
+;;      02-Feb-2018 Shave cycles on presence detect  . . .  J. Zbiciak      ;;
 ;;                                                                          ;;
 ;;  INPUTS for IV_WAIT                                                      ;;
 ;;      R5      Return address                                              ;;
@@ -2296,9 +2360,8 @@
 ;; ======================================================================== ;;
 IV_WAIT     PROC
             MVI     IV.QH,  R0
-            SWAP    R0                  ;\___ test bit 7, leave if set.
-            SWAP    R0                  ;/    (SWAP2 corrupts upper byte.)
-            BMI     @@leave
+            CMPI    #$80,   R0
+            BC      @@leave
 
             ; Wait for queue to drain.
 @@q_loop:   CMP     IV.QT,  R0
@@ -2334,7 +2397,7 @@
 ;;  REVISION HISTORY                                                        ;;
 ;;      16-Sep-2002 Initial revision . . . . . . . . . . .  J. Zbiciak      ;;
 ;;                                                                          ;;
-;;  INPUTS for IV_INIT                                                      ;;
+;;  INPUTS for IV_SAYNUM16                                                  ;;
 ;;      R0      Number to "speak"                                           ;;
 ;;      R5      Return address                                              ;;
 ;;                                                                          ;;
@@ -2431,6 +2494,9 @@
 ;; ======================================================================== ;;
 ;;  End of File:  saynum16.asm                                              ;;
 ;; ======================================================================== ;;
+_bottom_half:   EQU    IV_INIT_1
+    ELSE
+_bottom_half:   EQU    _wait               ; No voice init; just WAIT.
 
     ENDI
 

intybasic_prologue.asm

intybasic_epilogue.asm

voice.diff.txt

Edited by intvnut
  • Like 1

Share this post


Link to post
Share on other sites

Note: I had had a minor error in my previous post; I've updated it to have the corrected code. Specifically, IV_HUSH should start like this:

+IV_INIT:    ; In IntyBASIC, "VOICE INIT" turns into "VOICE HUSH" now.
+IV_HUSH     PROC
+            MVI     IV.QH,  R0
+            SWAP    R0,     2
+            BMI     IV_WAIT.leave

I had accidentally had "BC" there instead of BMI. Should really be harmless, but worth fixing.

 

.....

 

EDIT: Aaaand I forgot the diff hunk for intybasic_prologue.asm. It's in the previously posted intybasic_prologue.asm, but it's missing from the "voice.diff.txt" file. The missing hunk looks like this:

--- ../intybasic-1.2.9b/intybasic_prologue.asm	2016-10-21 11:40:17.000000000 -0700
+++ intybasic_prologue.asm	2018-02-02 23:58:26.000000000 -0800
@@ -148,7 +148,8 @@
         MVII #$038,R0
         MVO R0,$01F8            ; Configures sound
         MVO R0,$00F8            ; Configures sound (ECS)
-        CALL _wait
+
+        CALL _bottom_half

This is how I transparently hook in the voice initialization, without taking any code size. The _bottom_half label gets defined in intybasic_epilogue.asm. If voice is being used, that label corresponds to IV_INIT_1, which then chains to _wait. If voice is not being used, that label corresponds to _wait directly.

 

I updated the diff accordingly in my previous post. That's what I get for posting in the weeee hours of the night. :-P

Edited by intvnut

Share this post


Link to post
Share on other sites

Random observation: VOICE.PLAYING will very briefly reset to 0 a few times, during something like this. I had to come up with a clever trick to determine if it's ACTUALLY done playing even if we see VOICE.PLAYING = 0.

VOICE PLAY voice_sample_long

voice_sample_long:
    VOICE ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN,ELEVEN,TWELVE,THIRTEEN,FOURTEEN,FIFTEEN,SIXTEEN,SEVENTEEN,EIGHTEEN,NINETEEN,TWENTY,PA4,0
  • Like 1

Share this post


Link to post
Share on other sites

 

Random observation: VOICE.PLAYING will very briefly reset to 0 a few times, during something like this. I had to come up with a clever trick to determine if it's ACTUALLY done playing even if we see VOICE.PLAYING = 0.

VOICE PLAY voice_sample_long

voice_sample_long:
    VOICE ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN,ELEVEN,TWELVE,THIRTEEN,FOURTEEN,FIFTEEN,SIXTEEN,SEVENTEEN,EIGHTEEN,NINETEEN,TWENTY,PA4,0

 

 

What's interesting about that sequence is that it's all RESROM samples. It appears VOICE.PLAYING doesn't check that the phrase pointer is null, only the FIFO loading pointer:

.

    MVI IV.QT,R0
    ANDI #7,R0
    SUB IV.QH,R0
    BNE $+15
    MVI IV.FPTR,R0
    TSTR R0
    BNE $+10
    MVI 129,R0
    COMR R0
    AND 128,R0
    COMR R0
    ANDI #32768,R0
    MVO R0,V1

.

Here's the problem:

  • IV.QH and IV.QT will be equal once the phrase starts playing, because there's only one phrase queued.
  • IV.FPTR will be zero, because there's no data to load into the FIFO. That's used for allophones, but not for RESROM.
  • Location $81 will always report "FIFO ready for data" as there's nothing in it.

So then we're left with the question of how big a window we will see LRQ go high ($80 bit 15) between RESROM samples. Note that IV_WAIT will do the wrong thing here too.

 

If you queue a second phrase with PA4, then the right thing will happen, as QH != QT. That's my long-standing suggestion anyway for handling the "still speaking" problem. Adding PA4 to the end of a phrase doesn't help because of the gaps in LRQ.

 

That probably should be fixed. This requires fixes in two places:

 

  1. VOICE.PLAYING should check for IV.PPTR = 0.
  2. IV_WAIT should also check for IV.PPTR = 0.

For IV_WAIT, I'd suggest something like this in intybasic_epilogue.asm:

;; ======================================================================== ;;
;;  NAME                                                                    ;;
;;      IV_WAIT     Wait for voice queue to empty.                          ;;
;;                                                                          ;;
;;  AUTHOR                                                                  ;;
;;      Joseph Zbiciak <intvnut AT gmail.com>                               ;;
;;                                                                          ;;
;;  REVISION HISTORY                                                        ;;
;;      15-Sep-2002 Initial revision . . . . . . . . . . .  J. Zbiciak      ;;
;;      02-Feb-2018 Shave cycles on presence detect  . . .  J. Zbiciak      ;;
;;      02-Aug-2018 Wait for last phrase to complete . . .  J. Zbiciak      ;;
;;                                                                          ;;
;;  INPUTS for IV_WAIT                                                      ;;
;;      R5      Return address                                              ;;
;;                                                                          ;;
;;  OUTPUTS                                                                 ;;
;;      R0      trashed.                                                    ;;
;;                                                                          ;;
;;  NOTES                                                                   ;;
;;      This waits until the Intellivoice is nearly completely quiescent.   ;;
;;      Some voice data may still be spoken from the last triggered         ;;
;;      phrase.  To truly wait for *that* to be spoken, speak a 'pause'     ;;
;;      (eg. RESROM.pa1) and then call IV_WAIT.                             ;;
;; ------------------------------------------------------------------------ ;;
;;                   Copyright (c) 2002, Joseph Zbiciak                     ;;
;; ======================================================================== ;;
IV_WAIT     PROC
            MVI     IV.QH,  R0
            CMPI    #$80,   R0
            BC      @@leave

            ; Wait for queue to drain.
@@q_loop:   CMP     IV.QT,  R0
            BNEQ    @@q_loop

            ; Wait for last phrase to complete.
            CLRR    R0
@@f_loop:   CMP     IV.PPTR,R0
            BNEQ    @@f_loop

            ; Wait for FIFO and LRQ to say ready.
@@s_loop:   MVI     $81,    R0          ; Read FIFO status.  0 == ready.
            COMR    R0
            AND     $80,    R0          ; Merge w/ LRQ status.  1 == ready
            TSTR    R0
            BPL     @@s_loop            ; if bit 15 == 0, not ready.

@@leave:    JR      R5
            ENDP

.

As for VOICE.PLAYING: Rather than open-code like that, it feels like it should just call a library function to save a bit of code-size. Is it really that performance critical to be so bloaty? If it calls a library function, then IV_WAIT could be rewritten in terms of that library function. Something like:

.

; Return R0 != 0 if voice is playing
_voice_playing      PROC
                    MVI     IV.QH,  R0
                    XOR     IV.QT,  R0
                    ANDI    #7,     R0
                    BNEQ    @@busy

                    MVI     IV.PPTR,R0
                    TSTR    R0
                    BNEQ    @@busy

                    MVI     $81,    R0
                    COMR    R0
                    AND     $80,    R0
                    COMR    R0
                    ANDI    #$8000, R0
@@busy:             JR      R5
                    ENDP

IV_WAIT             PROC
                    PSHR    R5
@@loop:             CALL    _voice_playing
                    TSTR    R0
                    BNEQ    @@loop
                    PULR    PC
                    ENDP

.

Thoughts?

  • Like 1

Share this post


Link to post
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...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...