Jump to content

Photo

Possible to capture LPC code from Text-to-Speech "SPEAK" routine?


25 replies to this topic

#1 OLD CS1 OFFLINE  

OLD CS1

    Technomancer

  • 5,695 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Oct 6, 2016 1:03 PM

In my quest to add custom phrases to Extended BASIC programs, I found myself with a copy of the TI "Text to Speech" software.  It includes two important routines: XLAT and SPEAK, which convert English text to allophones and allpohones to LPC.

 

I have been wanting take a manually-constructed allophone string and convert to LPC data for inclusion in a program.  Since Extended BASIC's own speech routines are designed around LPC, it is this code I would need to include in programs for which I do not intend to require any expansions.  That is, with the Text-to-Seech software I could load the routine necessary to make Extended BASIC speak custom phrases, but that would require 32k and disk.  Even if the user has those expansions, it would be "simpler" to just include strings of LPC code to send to the Speech Synthesizer.  (As well, I am not even certain I would be allowed to distribute TI's software with my own.)

 

The nagging problem is I still have found no way to capture the LPC codes!

 

Is there some way in our repertoire to convert an allophone string into an LPC output without sending the LPC directly to the Speech Synthesizer, so I can include the LPC as DATA statements in a program??



#2 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,804 posts
  • Location:Silver Run, Maryland

Posted Thu Oct 6, 2016 2:10 PM

I don't know the answers to your other questions, but I am pretty sure the “Text to Speech” software was placed in the public domain by Texas Instruments.

 

...lee



#3 OLD CS1 OFFLINE  

OLD CS1

    Technomancer

  • Topic Starter
  • 5,695 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Oct 6, 2016 2:32 PM

I don't know the answers to your other questions, but I am pretty sure the “Text to Speech” software was placed in the public domain by Texas Instruments.

 

...lee

 

Would make sense, considering what it did with its other Home Computer software.

 

Reading the manual more, the SETUP subroutine calls for a DSK1.DATABASE file which apparently contains the allophone-to-LPC conversions.  I might do well investigating that file.



#4 Stuart OFFLINE  

Stuart

    Dragonstomper

  • 793 posts
  • Location:Southampton, UK

Posted Thu Oct 6, 2016 3:32 PM

OLD CS1, on 06 Oct 2016 - 8:03 PM, said:

 

Is there some way in our repertoire to convert an allophone string into an LPC output without sending the LPC directly to the Speech Synthesizer, so I can include the LPC as DATA statements in a program??

 

An idea ... if you load the "Text to Speech" software into Classic99 and run it, you should be able to find where it writes to the Speech Synth (at address >9400?). Then patch the code so it writes to a block of RAM instead, then dump that data.



#5 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,322 posts
  • HarmlessLion
  • Location:BUR

Posted Thu Oct 6, 2016 3:41 PM

Isn't the output of the XLAT function the allophone data you are looking for?

 

I have the XB Text to speech as well and last year I was about halfway through documenting them with an eye to getting a source code we could rebuild and use from cartridge programs. Getting the data out we can totally figure out. Whether it would work with CALL SAY, that I can't help with.



#6 OLD CS1 OFFLINE  

OLD CS1

    Technomancer

  • Topic Starter
  • 5,695 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Thu Oct 6, 2016 4:35 PM

An idea ... if you load the "Text to Speech" software into Classic99 and run it, you should be able to find where it writes to the Speech Synth (at address >9400?). Then patch the code so it writes to a block of RAM instead, then dump that data.

 
Crazy enough to work.
 

Isn't the output of the XLAT function the allophone data you are looking for?
 
I have the XB Text to speech as well and last year I was about halfway through documenting them with an eye to getting a source code we could rebuild and use from cartridge programs. Getting the data out we can totally figure out. Whether it would work with CALL SAY, that I can't help with.

 
XLAT converts text to allophones, but the allophones are the easy part.  Those are documented in the TE-II manual, as well as the Text to Speech manual.  The LPC data to which allophones translate, THAT is the part which eludes me.



#7 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,322 posts
  • HarmlessLion
  • Location:BUR

Posted Thu Oct 6, 2016 7:37 PM

XLAT converts text to allophones, but the allophones are the easy part.  Those are documented in the TE-II manual, as well as the Text to Speech manual.  The LPC data to which allophones translate, THAT is the part which eludes me.


Dumping from Classic99 may be simplest... but if it's helpful, I have all of SETUP and XLAT commented, and about half of SPEAK, plus the basic purpose of most of the database worked out. This is incomplete, but might have enough information in it for you to build a tool to pull out the data you want (or alternately, maybe hack up SPEAK ;) ).

Attached File  SpeechCart.zip   108.47KB   12 downloads

#8 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,322 posts
  • HarmlessLion
  • Location:BUR

Posted Thu Oct 6, 2016 7:39 PM

(Ah.. in re-reading it, I see that SPEAK is a little more complex than just saying a list of allophones, it seems to have a little scripting engine going. Dumping the bytes that reach the speech chip is probably simplest. ;) )

#9 --- Ω --- OFFLINE  

--- Ω ---

    HexaCoreRunner

  • 13,019 posts

Posted Thu Oct 6, 2016 7:46 PM

I'm waiting for the day when there is a PC program that will let me speak into the microphone and then the software will spit out XB code consisting of data statements that can be merged with a program.  Hey, I can dream!



#10 HOME AUTOMATION OFFLINE  

HOME AUTOMATION

    Chopper Commander

  • 144 posts

Posted Wed Oct 31, 2018 12:16 AM

Dumping from Classic99 may be simplest... but if it's helpful, I have all of SETUP and XLAT commented, and about half of SPEAK, plus the basic purpose of most of the database worked out. This is incomplete, but might have enough information in it for you to build a tool to pull out the data you want (or alternately, maybe hack up SPEAK ;) ).

attachicon.gifSpeechCart.zip

Was this issue solved here? I could never really determine... It seems like it just sort of fizzled out...

I never figured out what you meant by "Dumping"

 

I know there has been some interest in this topic, beyond this thread...

I have a solution in place for this. This solution works very much as stated. In order to achieve this though, I found it was necessary to swap out a line of code in the speak.obj on the E/A Text to Speech disk.

To solve this using TEII I had to make a similar edit to the TEII .bin file.
There is also a small external interactive data xfer program.
 
I would post the files... and description of how to use but I do not know if this is allowed as I suppose It could perhaps be considered some form of reverse engineering...

any thoughts???



#11 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,322 posts
  • HarmlessLion
  • Location:BUR

Posted Wed Oct 31, 2018 2:43 AM

What I meant by dumping was logging every byte the emulator wrote to the speech synthesizer to a disk file. The debugger allows logging writes to disk (though man, I haven't tested THAT feature in a long time). Of course, what you DO with those bytes becomes a personal exercise.

 

I think reverse engineering is all we do here... I don't think the forum prohibits it??


  • RXB likes this

#12 HOME AUTOMATION OFFLINE  

HOME AUTOMATION

    Chopper Commander

  • 144 posts

Posted Wed Oct 31, 2018 3:18 AM

I didn't realize your debugger did that! Nice to know ...could substitute for more difficult electronic solutions.

I suppose I was being silly about the reverse engineering, considering all the modified .bin files for the FG99. :dunce:
I guess I wondered why no one else had done it. :ponder:

       Thanx. :cool:



#13 RXB OFFLINE  

RXB

    River Patroller

  • 3,367 posts
  • Location:Vancouver, Washington, USA

Posted Wed Oct 31, 2018 5:11 PM

What I meant by dumping was logging every byte the emulator wrote to the speech synthesizer to a disk file. The debugger allows logging writes to disk (though man, I haven't tested THAT feature in a long time). Of course, what you DO with those bytes becomes a personal exercise.

 

I think reverse engineering is all we do here... I don't think the forum prohibits it??

How about some FORWARD THINKING?

 

Extended Basic GPL SPEECH SOURCE CODE:

[2984]               ***********************************************************
[2985]               * CALL SAY(....................)
[2986]               *  Decode given parameter(s). Store all data first, then go
[2987]               *   speak it all at once.
[2988]               ***********************************************************
[2989] B1D0 D6,42,B7 SAY    CEQ  LPARZ,@CHAT       Must start with "("
[2990] B1D3 4D,BA           BR   ERRSYN
[2991] B1D5 BD,4C,6E        DST  @VSPTR,@FAC2      Save current top of stack on
[2992] B1D8 0F,77           XML  VPUSH              the stack
[2993] B1DA BF,0C,00        DST  255,@BYTES        255 bytes = 85 3 byte entires
       B1DD FF
[2994] B1DE 0F,71           XML  GETSTR            Get temp speech list string
[2995] B1E0 BF,4A,00        DST  >001C,@FAC        Indicate it is temp string (S
       B1E3 1C
[2996] B1E4 BF,4C,65        DST  >6500,@FAC2       Indicate it is string entry
       B1E7 00
[2997] B1E8 BD,4E,1C        DST  @SREF,@FAC4       Save pointer to temp string
[2998] B1EB BD,50,0C        DST  @BYTES,@FAC6      Length is 255
[2999] B1EE 0F,77           XML  VPUSH             Make it semi-permenant
[3000]               * Set up pointers into the speak list
[3001] B1F0 BD,00,4E        DST  @FAC4,@PTFBSL     Front points to begining
[3002] B1F3 BD,02,4E        DST  @FAC4,@PTLBSL     Last now points to beginning
[3003] B1F6 BD,04,00        DST  @PTFBSL,@PTEBSL
[3004] B1F9 A1,04,50        DADD @FAC6,@PTEBSL     End points to the end+1
[3005] B1FC 06,B6,1A        CALL SETRW             Set PHROM read/write address
[3006] B1FF 06,B6,0F        CALL WAIT              Wait till no one is speaking
[3007] B202 06,B3,E7 DIRSPK CALL GETPRM            Get next parameter
[3008] B205 72,79           BS   NEXT1             If non-null ASCII string
[3009] B207 BD,06,4E        DST  @FAC4,@PTFCIS     Set up pointer to first char
[3010] B20A BD,0A,50        DST  @FAC6,@PTLCIS     Set ptr-to-last-char-in-strin
[3011] B20D A1,0A,06        DADD @PTFCIS,@PTLCIS    by adding length-of-string
[3012] B210 93,0A           DDEC @PTLCIS            and subtracting 1
[3013]               * Make a speech list
[3014] B212 06,B6,1A        CALL SETRW             Set speech read/write addrs
[3015] B215 BD,08,06        DST  @PTFCIS,@PTCCIS   Start at beginning of string
[3016] B218 86,4C           CLR  @TOTTIM           Clear total time delay
[3017] B21A 06,B4,64        CALL GETTIM            Get first timing mark
[3018] B21D 06,B4,54        CALL TIMING            Get any subsequent marks
[3019]               * The total first time delay is in TOTTIM now
[3020] B220 C5,08,0A GB158  DCH  @PTLCIS,@PTCCIS   While more string
[3021] B223 72,6F           BS   GB1A7
[3022] B225 06,B3,FD        CALL PHRASE            Get next phrase
[3023]               * If spell flag is 0, try to look the phrase up. If it
[3024]               * can not be found, then set the spell flag, and it will be
[3025]               * spelled out. If found, save on speak list.
[3026] B228 8E,4B           CZ   @SPLFLG           There is a phrase
[3027] B22A 52,3B           BR   GB173
[3028] B22C 06,B4,F9        CALL LOOKUP            Try to look it up in the PHRO
[3029] B22F 8F,4D           DCZ  @DATAAD           If not found then
[3030] B231 52,38           BR   GB170
[3031] B233 BE,4B,01        ST   1,@SPLFLG         Set the spell flag
[3032] B236 52,3B           BR   GB173
[3033] B238 06,B5,FF GB170  CALL STDATA            Store data in list
[3034]               * If spell flag is 1, set time delay to >3C, and take the
[3035]               * phrase one character at a time (spell it). Look up each
[3036]               * character: if not found, use 'UHOH' data instead.
[3037]               * Regardless, store data on speak list.
[3038] B23B D6,4B,01 GB173  CEQ  1,@SPLFLG         Need to spell it out?
[3039] B23E 52,68           BR   GB1A0
[3040] B240 BD,4F,10        DST  @PTLCIP,@PTLCIL   Est last char to spell out
[3041] B243 BE,4C,3C        ST   >3C,@TOTTIM       >3C used because sounds good
[3042]               *                      Take each single character

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0053 
EQUATES EXEC-359
[3043]               * Skip over any embedded spaces encountered in a phrase
[3044] B246 D6,B0,0C GB17E  CEQ  SPACE,V*PTFCIP
       B249 20
[3045] B24A 52,50           BR   GB188
[3046] B24C 91,0C           DINC @PTFCIP
[3047] B24E 52,46           BR   GB17E
[3048]               * Set first and last pointers to same one character
[3049] B250 BD,10,0C GB188  DST  @PTFCIP,@PTLCIP
[3050] B253 06,B4,F9        CALL LOOKUP            Try to look it up
[3051]               * If not found, use data to 'UHOH'
[3052] B256 8F,4D           DCZ  @DATAAD
[3053] B258 52,5E           BR   GB196
[3054] B25A BF,4D,71        DST  >71F4,@DATAAD     Put addr of 'UHOH' in
       B25D F4
[3055] B25E 06,B5,FF GB196  CALL STDATA            Store data on speak list
[3056] B261 91,0C           DINC @PTFCIP           Go on to next character
[3057] B263 C5,0C,4F        DCH  @PTLCIL,@PTFCIP   Until done all
[3058] B266 52,46           BR   GB17E
[3059]               * At this point, get next timing group. The first timing
[3060]               * character has already been found, and it's value is still
[3061]               * in TIMLEN. Therefore, initiatory call to GETTIM not
[3062]               * needed. Simply clear TOTTIM and call TIMING.
[3063] B268 86,4C    GB1A0  CLR  @TOTTIM
[3064] B26A 06,B4,54        CALL TIMING
[3065] B26D 52,20           BR   GB158
[3066]               * At this point, finished all the phrases in this string.
[3067]               * TOTTIM should equal >FE, it indicate end of sting If it
[3068]               * doesn't equal >FE, it indicates that a timing group was
[3069]               * put on the end of the string. Therefore, save the timing
[3070]               * group with a null data address to show it is only timing.
[3071] B26F D6,4C,FE GB1A7  CEQ  >FE,@TOTTIM
[3072] B272 72,79           BS   NEXT1
[3073] B274 87,4D           DCLR @DATAAD
[3074] B276 06,B5,FF        CALL STDATA
[3075]               * Next item could be direct string.
[3076] B279 D6,42,B3 NEXT1  CEQ  COMMAZ,@CHAT      If direct string present
[3077] B27C 52,93           BR   SPEAK
[3078] B27E 06,B3,E7        CALL GETPRM            Get the next parameter
[3079] B281 72,8E           BS   NEXT2             If non-null direct string
[3080] B283 BE,4C,FF        ST   >FF,@TOTTIM       Mark TOTTIM as direct string
[3081] B286 0F,77           XML  VPUSH             Save direct string on stack
[3082] B288 BD,4D,6E        DST  @VSPTR,@DATAAD    Store stack addr on string
[3083] B28B 06,B5,FF        CALL STDATA            And add to the speak list
[3084]               * If the next character is a comma, loop thru it again
[3085] B28E D6,42,B3 NEXT2  CEQ  COMMAZ,@CHAT
[3086] B291 72,02           BS   DIRSPK
[3087]               * If end fall into SPEAK
[3088]               ***********************************************************
[3089]               * SPEAK will actually speak the speech list. It tests the
[3090]               * timing byte to see if it is an >FF. If it is, then the
[3091]               * data following it points to a direct speech data string
[3092]               * in VDP. If it is not, then the data following it points
[3093]               * to a PHROM speech data list. In the first case, this
[3094]               * routine will issue a speak external command to the PHROM
[3095]               * and then feed bytes out to the PHROM as it requests them.
[3096]               * In the second case, the address will be loaded out to the
[3097]               * PHROM, and then a speak command will be issued.
[3098]               ***********************************************************
[3099] B293 06,B6,1A SPEAK  CALL SETRW             Set read/write address
[3100] B296 C9,00,02 GB1CE  DCHE @PTLBSL,@PTFBSL   More speech list to go
[3101] B299 73,20           BS   GB258
[3102] B29B 06,B6,0F        CALL WAIT              Yes, wait until previous
[3103]               *                              speech is though
[3104] B29E D6,B0,00        CEQ  >FF,V*PTFBSL      External speech data

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0054 
EQUATES EXEC-359
       B2A1 FF
[3105] B2A2 72,C6           BS   GB1FE
[3106] B2A4 BC,79,B0        ST   V*PTFBSL,@TIMER   No, load timer
       B2A7 00
[3107] B2A8 82,79           NEG  @TIMER             and neg it to correct
[3108] B2AA BD,12,E0        DST  V@1(@PTFBSL),@PTFBPH   Put addr into PTFBPH
       B2AD 01,00
[3109] B2AF A3,00,00        DADD 3,@PTFBSL               and skip to next node
       B2B2 03
[3110] B2B3 D2,79,00 LOOP1  CGE  0,@TIMER          Wait for time delay
[3111] B2B6 52,B3           BR   LOOP1
[3112] B2B8 8E,12           CZ   @PTFBPH           If there is data
[3113] B2BA 72,C4           BS   GB1FC
[3114] B2BC 06,B5,B5        CALL LOADAD            Load the addr to PHROM
[3115] B2BF BE,C0,00        ST   >50,@VAR0(@WRITE)  and issue speak command
       B2C2 5A,50
[3116] B2C4 53,1D    GB1FC  BR   CONTIN
[3117] B2C6 91,00    GB1FE  DINC @PTFBSL           Speak external, skip over >FF
[3118] B2C8 BD,5E,B0        DST  V*PTFBSL,@PTCBED  Set up pointer to 1st byte
       B2CB 00
[3119] B2CC BD,5E,E0        DST  V@4(@PTCBED),@PTCBED    in external speech data
       B2CF 04,5E
[3120] B2D1 95,00           DINCT @PTFBSL          Skip addr bytes
[3121] B2D3 BC,62,EF        ST   V@-1(@PTCBED),@LENWST  Get Len of whole string
       B2D6 FF,FF,5E
[3122] B2D9 A6,62,03 DIRSPH SUB  3,@LENWST         Minus 3 bytes overhead
[3123]               * All external speech strings start with a >60
[3124] B2DC D6,B0,5E        CEQ  >60,V*PTCBED      Bad speech string
       B2DF 60
[3125] B2E0 4D,EE           BR   ERRBV
[3126] B2E2 06,B6,0F        CALL WAIT              Wait for go ahead
[3127] B2E5 95,5E           DINCT @PTCBED          Skip spk ext & 1st byte len
[3128] B2E7 BC,60,B0        ST   V*PTCBED,@LENCST  Get len of current string
       B2EA 5E
[3129] B2EB 91,5E           DINC @PTCBED           Skip len byte to 1st real byt
[3130] B2ED BE,56,10        ST   16,@TEMP2         Do 1st 16 bytes (fill buff)
[3131] B2F0 BE,C0,00        ST   >60,@VAR0(@WRITE) Start Speak External
       B2F3 5A,60
[3132] B2F5 BC,C0,00 LOOPR  ST   V*PTCBED,@VAR0(@WRITE) Write byte to PHROM
       B2F8 5A,B0,5E
[3133] B2FB 91,5E           DINC @PTCBED           Go to next byte
[3134] B2FD 92,62           DEC  @LENWST           1 less char in whole string
[3135] B2FF 73,1D           BS   CONTIN            Finished whole string?
[3136] B301 92,60           DEC  @LENCST           1 less char in curr string
[3137] B303 72,D9           BS   DIRSPH            Finished current string?
[3138] B305 92,56           DEC  @TEMP2            1 less char in this loop
[3139] B307 52,F5           BR   LOOPR             Not finished curr loop yet?
[3140] B309 BC,69,C0 GB241  ST   @VAR0(@READ),@SPKSTS Read status from PHROM
       B30C 00,58
[3141]                
[3142]               * If the next statement is true, it means that speak was
[3143]               * probably interupted and that it is shot at this point.
[3144]               * Therefore, we are going to quit now.
[3145] B30E DA,69,80        CLOG >80,@SPKSTS
[3146] B311 73,1D           BS   CONTIN
[3147] B313 DA,69,40        CLOG >40,@SPKSTS       Loop till buff below half
[3148] B316 73,09           BS   GB241
[3149] B318 BE,56,08        ST   8,@TEMP2          Put 8 more bytes to PHROM
[3150] B31B 52,F5           BR   LOOPR              and go do these
[3151] B31D 05,B2,96 CONTIN B    GB1CE             We've said it all!!
[3152]               * Now pop all entries off stack that we put on!
[3153] B320 0F,78    GB258  XML  VPOP              Free up a temporary string
[3154] B322 D5,6E,4C        DCEQ @FAC2,@VSPTR
[3155] B325 53,20           BR   GB258

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0055 
EQUATES EXEC-359
[3156] B327 51,BA           BR   GB0F2             And return to the caller
[3157]               ***********************************************************
[3158]               * SPGET subprogram. Load speech data from external device.
[3159]               *       Use standard file I/O
[3160]               ***********************************************************
[3161] B329 D6,42,B7 SPGET  CEQ  LPARZ,@CHAT       Must have left parenthesis
[3162] B32C 4D,BA           BR   ERRSYN
[3163] B32E 06,B6,1A        CALL SETRW             Set PHROM read/write address
[3164] B331 06,B6,0F        CALL WAIT              Wait till no one is speaking
[3165] B334 06,B3,E7 NXTPAR CALL GETPRM            Get the next parameter
[3166] B337 8F,50           DCZ  @FAC6             If non-null ASCII string
[3167] B339 73,E0           BS   GB318
[3168] B33B BD,06,4E        DST  @FAC4,@PTFCIS     Pointer to 1st char in string
[3169] B33E BD,0A,50        DST  @FAC6,@PTLCIS     Pointer to last-char-in-strin
[3170] B341 A1,0A,06        DADD @PTFCIS,@PTLCIS    by adding length-of-string
[3171] B344 93,0A           DDEC @PTLCIS             and subtracting 1
[3172] B346 06,B6,1A        CALL SETRW             Set the speech read/write add
[3173] B349 BD,08,06        DST  @PTFCIS,@PTCCIS   Set curr char to first char
[3174] B34C 86,4C           CLR  @TOTTIM           Clear total time delay
[3175] B34E 06,B4,64        CALL GETTIM            Get first timing mark
[3176] B351 06,B4,54        CALL TIMING            Get any subsquent marks
[3177]               * Get one phrase, and look it up. If the phrase is not foun
[3178]               * substitute in 'UHOH'.
[3179] B354 C5,08,0A        DCH  @PTLCIS,@PTCCIS   Possible phrase
[3180] B357 73,E0           BS   GB318
[3181] B359 06,B3,FD        CALL PHRASE            Yes, go get it
[3182] B35C D6,4B,01        CEQ  1,@SPLFLG         Spell flag set then set
[3183] B35F 53,64           BR   GB29C
[3184] B361 BD,10,0C        DST  @PTFCIP,@PTLCIP    last ptr to first (1 char)
[3185] B364 06,B4,F9 GB29C  CALL LOOKUP            Look up the phrase
[3186] B367 8F,4D           DCZ  @DATAAD           If not there,
[3187] B369 53,72           BR   GB2AA
[3188] B36B BF,4D,71        DST  >71F4,@DATAAD      use 'UHOH' data addr
       B36E F4
[3189] B36F BE,64,51        ST   >51,@STRLEN        'UHOH' data length
[3190]               * Data must be in PHRADD and PHLEN, so move it
[3191] B372 BD,01,4D GB2AA  DST  @DATAAD,@PHRADD
[3192] B375 BC,00,64        ST   @STRLEN,@PHLEN
[3193] B378 A2,00,03        ADD  3,@PHLEN          For overhead info
[3194]               * There must be a variable to put this data in. If not, err
[3195] B37B 0F,7E           XML  SPEED
[3196] B37D 00              BYTE SYNCHK
[3197] B37E B3              BYTE COMMAZ
[3198] B37F 0F,7A           XML  SYM               Find symbol in table
[3199] B381 0F,7B           XML  SMB               Evaluate andy subscripts
[3200] B383 0F,77           XML  VPUSH             Save for assignment
[3201] B385 86,0C           CLR  @BYTES            Two byte value
[3202] B387 BC,0D,00        ST   @PHLEN,@BYTES+1   Length of string needed
[3203] B38A 0F,71           XML  GETSTR            Get a string for the data
[3204] B38C 06,B6,1A        CALL SETRW             Set up speech read/write addr
[3205] B38F BF,4A,00        DST  >001C,@FAC        Now build string FAC entry
       B392 1C
[3206] B393 BF,4C,65        DST  >6500,@FAC2       String ID
       B396 00
[3207] B397 BD,4E,1C        DST  @SREF,@FAC4       Pointer to string
[3208] B39A BD,50,0C        DST  @BYTES,@FAC6      Length of string
[3209] B39D BF,B0,1C        DST  >6000,V*SREF      Mark string as speech data
       B3A0 60,00
[3210] B3A2 BC,E0,02        ST   @PHLEN,V@2(@SREF) Put in string length
       B3A5 1C,00
[3211] B3A7 A7,E0,01        DSUB 3,V@1(@SREF)       minus thei info
       B3AA 1C,00,03
[3212]               * LOADAD expects addr to be in PTFBPH, so move it.
[3213] B3AD BD,12,01        DST  @PHRADD,@PTFBPH

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0056 
EQUATES EXEC-359
[3214] B3B0 06,B5,B5        CALL LOADAD
[3215]               * Going to copy string from PHROM to VDP. The actual data
[3216]               * from PHROM is in bit-reversed order, so must reverse the
[3217]               * order after reading in the order. Remember that 3 bytes
[3218]               * PHLEN are our own overhead, so don't copy all
[3219] B3B3 C6,00,03 GB2EB  CH   3,@PHLEN
[3220] B3B6 53,DE           BR   GB316
[3221] B3B8 BE,C0,00        ST   >10,@VAR0(@WRITE) Issue read byte command
       B3BB 5A,10
[3222] B3BD BC,68,C0        ST   @VAR0(@READ),@BYTE3 Read the byte
       B3C0 00,58
[3223]               * the following code is somewhat tricky. It will bit
[3224]               * reverse the contents of BYTE3 into BYTE1 through
[3225]               * BYTE2 by means of word shifts. Note the definition of
[3226]               * BYTE1 , BYTE2, and BYTE3 in EQU's. You might try an
[3227]               * example if it isn't clear what is going on.
[3228] B3C2 86,67           CLR  @BYTE2
[3229] B3C4 BE,54,08        ST   >08,@TEMP1
[3230] B3C7 EB,67,00 RNDAG  DSRC 1,@BYTE2
       B3CA 01
[3231] B3CB E3,66,00        DSLL 1,@BYTE1
       B3CE 01
[3232] B3CF 92,54           DEC  @TEMP1
[3233] B3D1 53,C7           BR   RNDAG
[3234]               * Store the bit-corrected byte into the string & inc str pt
[3235] B3D3 BC,E0,03        ST   @BYTE1,V@3(@SREF)
       B3D6 1C,66
[3236] B3D8 91,1C           DINC @SREF
[3237] B3DA 92,00           DEC  @PHLEN            Dec the string length
[3238] B3DC 53,B3           BR   GB2EB             Go do next char if there is o
[3239] B3DE 0F,7C    GB316  XML  ASSGNV            Assign the string to variable
[3240] B3E0 D6,42,B3 GB318  CEQ  COMMAZ,@CHAT      If more go do
[3241] B3E3 73,34           BS   NXTPAR
[3242] B3E5 51,BA           BR   GB0F2
[3243]               ***********************************************************
[3244]               * GETPAM gets the next string paameter passed to the
[3245]               * routine. If that parameter is non-exist or null, then
[3246]               * condition bit is set. If the parameter is there then
[3247]               * condition bit is reset and the FAC entry describes the
[3248]               * string. In either case, return with condition is done.
[3249]               ***********************************************************
[3250] B3E7 0F,79    GETPRM XML  PGMCHR            Get next token
[3251] B3E9 D6,42,B3        CEQ  COMMAZ,@CHAT      Go set condition no parm
[3252] B3EC 73,F9           BS   SETCB
[3253] B3EE 0F,74           XML  PARSE
[3254] B3F0 B6              BYTE RPARZ
[3255] B3F1 D6,4C,65        CEQ  >65,@FAC2         If not string, error
[3256] B3F4 4D,BE           BR   ERRSNM
[3257] B3F6 8F,50           DCZ  @FAC6             Set cond if null string
[3258] B3F8 01              RTNC                   Else return
[3259] B3F9 D4,00,00 SETCB  CEQ  @VAR0,@VAR0       Set condition bit
[3260] B3FC 01              RTNC
[3261]               ***********************************************************
[3262]               * Get the next phrase out of the current string. The phrase
[3263]               * may begin with a #, which means it will continue to the
[3264]               * next #, or it many begin with an ordinary character, in
[3265]               * which case it will end with the character just before the
[3266]               * first timing character encountered. In either case, the
[3267]               * end of the string will indicate a legal end of phrase if
[3268]               * it occurs before the usual indicator!
[3269]               ***********************************************************
[3270] B3FD D6,4A,23 PHRASE CEQ  NUMBER,@CCHAR     Phrase start with #?
[3271] B400 54,38           BR   GB370
[3272] B402 91,08           DINC @PTCCIS           Yes, inc CC ptr past #

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0057 
EQUATES EXEC-359
[3273] B404 D6,B0,08 GB33C  CEQ  SPACE,V*PTCCIS    Skip spaces
       B407 20
[3274] B408 54,0E           BR   GB346
[3275] B40A 91,08           DINC @PTCCIS
[3276] B40C 54,04           BR   GB33C
[3277] B40E D6,B0,08 GB346  CEQ  NUMBER,V*PTCCIS   All spaces?
       B411 23
[3278] B412 54,17           BR   GB34F
[3279] B414 91,08           DINC @PTCCIS           Yes, skip this # too
[3280] B416 00              RTN                    And ignore this phrase
[3281] B417 BD,0C,08 GB34F  DST  @PTCCIS,@PTFCIP   Save 1st char in phrase
[3282] B41A 91,08    GB352  DINC @PTCCIS           Go on to next char
[3283]               * Got to watch for end of string. If encountered before a
[3284]               * #, act like char after string is #. Then last char will
[3285]               * be char before, or the last char in the string!!
[3286] B41C C5,08,0A        DCH  @PTLCIS,@PTCCIS
[3287] B41F 74,2A           BS   FNDNUM
[3288] B421 BC,4A,B0        ST   V*PTCCIS,@CCHAR   No, get char in CCHAR
       B424 08
[3289] B425 D6,4A,23        CEQ  NUMBER,@CCHAR     If not # continue looking
[3290] B428 54,1A           BR   GB352
[3291] B42A BD,10,08 FNDNUM DST  @PTCCIS,@PTLCIP   Last char in phrase is one
[3292] B42D 93,10           DDEC @PTLCIP            before the #
[3293] B42F 91,08           DINC @PTCCIS           Point to char after #
[3294] B431 06,B4,64        CALL GETTIM            Get 1st timing char after phr
[3295] B434 86,4B           CLR  @SPLFLG           Indicate don't spell
[3296] B436 54,53           BR   GB38B             No # as 1st char in phrase
[3297] B438 BD,0C,08 GB370  DST  @PTCCIS,@PTFCIP   Curr char is 1st char phrase
[3298] B43B 86,4B           CLR  @SPLFLG           Assume don't spell
[3299] B43D CA,4A,41        CHE  >41,@CCHAR        If not alphabetic   (>41="A")
[3300] B440 74,44           BS   GB37C
[3301] B442 90,4B           INC  @SPLFLG            set spell flag
[3302]               * Need to find end of phrase, which is char before next
[3303]               * timing char we find. Therefore, look for a timing char!
[3304] B444 91,08    GB37C  DINC @PTCCIS
[3305] B446 06,B4,64        CALL GETTIM
[3306] B449 D6,51,FF        CEQ  >FF,@TIMLEN       If not timing, loop
[3307] B44C 74,44           BS   GB37C
[3308] B44E BD,10,08        DST  @PTCCIS,@PTLCIP   Char before curr char is
[3309] B451 93,10           DDEC @PTLCIP            the last char in phrase
[3310] B453 00       GB38B  RTN
[3311]               ***********************************************************
[3312]               * TIMING will loop through chars in string until it finds
[3313]               * non-timing char. Non-timing chars have TIMLEN values of
[3314]               * >FE or >FF. GETTIM must be called before this routine to
[3315]               * establish a correct value of TIMLEN. Also, most likely
[3316]               * TOTTIM should have been cleared.
[3317]               ***********************************************************
[3318] B454 CA,51,FE TIMING CHE  >FE,@TIMLEN
[3319] B457 74,63           BS   GB39B
[3320] B459 A1,4C,51        DADD @TIMLEN,@TOTTIM
[3321] B45C 91,08           DINC @PTCCIS
[3322] B45E 06,B4,64        CALL GETTIM
[3323] B461 54,54           BR   TIMING
[3324] B463 00       GB39B  RTN
[3325]               ***********************************************************
[3326]               * GETTIM will examine the current char in the string and
[3327]               * set TIMLEN to the appropriate time delay value. TIMLEN
[3328]               * can take on the following values:
[3329]               *           >00 if char is timing '+'
[3330]               *           >06 if char is timing ' '
[3331]               *           >0C if char is timing '-'
[3332]               *           >12 if char is timing ','
[3333]               *           >1E if char is timing ';'

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0058 
EQUATES EXEC-359
[3334]               *           >30 if char is timing ':'
[3335]               *           >3C if char is timing '.'
[3336]               *           >FE if char is out of stirng bounds
[3337]               *           >FF if char is not timing
[3338]               * Note that to test timing, some manipulation of PTCCIS
[3339]               * would be neccesary, so it is stored and used in TEMP1
[3340]               ***********************************************************
[3341] B464 BC,4A,B0 GETTIM ST   V*PTCCIS,@CCHAR   Get the char
       B467 08
[3342] B468 BD,54,08        DST  @PTCCIS,@TEMP1     store curr ptr in TEMP1
[3343] B46B C5,54,0A        DCH  @PTLCIS,@TEMP1     out of string bounds?
[3344] B46E 54,74           BR   GB3AC
[3345] B470 BE,51,FE        ST   >FE,@TIMLEN       Yes, load value and return
[3346] B473 00              RTN
[3347] B474 C6,4A,3B GB3AC  CH   SEMICO,@CCHAR     Can not be timing
[3348] B477 74,DE           BS   NOTIME
[3349] B479 D6,4A,20        CEQ  SPACE,@CCHAR
[3350] B47C 54,8D           BR   GB3C5
[3351] B47E BE,51,06        ST   6,@TIMLEN
[3352] B481 D6,E0,01 GB3B9  CEQ  SPACE,V@1(@PTCCIS) While spaces
       B484 08,20
[3353] B486 54,8C           BR   GB3C4
[3354] B488 91,08           DINC @PTCCIS           Skip them
[3355] B48A 54,81           BR   GB3B9
[3356] B48C 00       GB3C4  RTN
[3357] B48D D6,4A,2B GB3C5  CEQ  PLUS,@CCHAR
[3358] B490 54,9C           BR   GB3D4
[3359] B492 91,54           DINC @TEMP1            Need to test the next char
[3360] B494 06,B4,E2        CALL NUMERC            Is it numeric
[3361] B497 74,DE           BS   NOTIME            Was numeric => not timing cha
[3362] B499 86,51           CLR  @TIMLEN           Not numeric => set as no timi
[3363] B49B 00              RTN
[3364] B49C D6,4A,2C GB3D4  CEQ  COMMAT,@CCHAR
[3365] B49F 54,A5           BR   GB3DD
[3366] B4A1 BE,51,12        ST   >12,@TIMLEN
[3367] B4A4 00              RTN
[3368] B4A5 D6,4A,2E GB3DD  CEQ  PERIOD,@CCHAR
[3369] B4A8 54,BC           BR   GB3F4
[3370] B4AA 93,54           DDEC @TEMP1            Go back to preceding char
[3371] B4AC 06,B4,E2        CALL NUMERC            Is it numeric?
[3372] B4AF 54,B8           BR   PTIME             No, so it is timing
[3373] B4B1 95,54           DINCT @TEMP1           Yes, on to following char
[3374] B4B3 06,B4,E2        CALL NUMERC            Is it numeric too?
[3375] B4B6 74,DE           BS   NOTIME            Yes, both numeric => not timi
[3376] B4B8 BE,51,3C PTIME  ST   >3C,@TIMLEN       Both not numeric  => timing
[3377] B4BB 00              RTN
[3378] B4BC D6,4A,2D GB3F4  CEQ  HYPEN,@CCHAR
[3379] B4BF 54,CC           BR   GB404
[3380] B4C1 91,54           DINC @TEMP1            Check next char
[3381] B4C3 06,B4,E2        CALL NUMERC            Is it numeric?
[3382] B4C6 74,DE           BS   NOTIME            Was numeric => not a timing c
[3383] B4C8 BE,51,0C        ST   >0C,@TIMLEN       Was not numeric => set as tim
[3384] B4CB 00              RTN
[3385] B4CC D6,4A,3A GB404  CEQ  COLON,@CCHAR
[3386] B4CF 54,D5           BR   GB40D
[3387] B4D1 BE,51,30        ST   >30,@TIMLEN
[3388] B4D4 00              RTN
[3389] B4D5 D6,4A,3B GB40D  CEQ  SEMICO,@CCHAR
[3390] B4D8 54,DE           BR   NOTIME
[3391] B4DA BE,51,1E        ST   >1E,@TIMLEN
[3392] B4DD 00              RTN
[3393] B4DE BE,51,FF NOTIME ST   >FF,@TIMLEN       Set as no timing char present
[3394] B4E1 00              RTN
[3395]               ***********************************************************

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0059 
EQUATES EXEC-359
[3396]               * NUMERC tests the char pointed to by PTCCIS and verifies
[3397]               * the following:
[3398]               *  1 - it is within the current string boundaries
[3399]               *  2 - it is numeric (i.e. between '0' and '9')
[3400]               * If both of the above conditions are true, COND is set
[3401]               * upon return, otherwise COND is reset
[3402]               ***********************************************************
[3403] B4E2 C5,54,0A NUMERC DCH  @PTLCIS,@TEMP1
[3404] B4E5 74,F8           BS   GB430
[3405] B4E7 C5,06,54        DCH  @TEMP1,@PTFCIS
[3406] B4EA 74,F8           BS   GB430
[3407] B4EC CA,B0,54        CHE  >30,V*TEMP1
       B4EF 30
[3408] B4F0 54,F8           BR   GB430
[3409] B4F2 C6,B0,54        CH   >39,V*TEMP1
       B4F5 39
[3410] B4F6 53,F9           BR   SETCB
[3411] B4F8 01       GB430  RTNC
[3412]               ***********************************************************
[3413]               * LOOKUP is a prolong routine to SEARCH. In each PHROM,
[3414]               * there may be 2 trees, one starting at >0000 and the other
[3415]               * at >8000. Either may or may not be present. Presences is
[3416]               * determined if a >AA byte is at the starting location.
[3417]               * LOOKUP determines if the tree at >0000 is in, and if so,
[3418]               * calls SEARCH with that addr. If that tree is not present
[3419]               * or the phrase couldn't be found in it, LOOKUP then checks
[3420]               * if the tree at >8000 is present, and again, if so, calls
[3421]               * SEARCH with that tree address. If the word was found in
[3422]               * the first tree, or after searching the second tree, the
[3423]               * routine will return.
[3424]               ***********************************************************
[3425] B4F9 87,66    LOOKUP DCLR @BYTE1            BYTE1 contains addr of curr t
[3426] B4FB BD,12,66 TRYAGN DST  @BYTE1,@PTFBPH    Look for >AA tree header
[3427] B4FE 06,B5,B5        CALL LOADAD            LOADAD expects addr in PTFBPH
[3428] B501 BE,C0,00        ST   >10,@VAR0(@WRITE) Put out read byte command
       B504 5A,10
[3429] B506 D6,C0,00        CEQ  >AA,@VAR0(@READ)  Tree out there?
       B509 58,AA
[3430] B50B 55,16           BR   GB44E
[3431] B50D 91,12           DINC @PTFBPH           Skip the tree header
[3432] B50F 06,B5,21        CALL SEARCH            Go search this PHROM tree
[3433] B512 8F,4D           DCZ  @DATAAD           Phrase found => exit
[3434] B514 55,20           BR   FOUND
[3435] B516 A3,66,80 GB44E  DADD >8000,@BYTE1      Go to start of next PHROM tre
       B519 00
[3436]               * Note >8000 + >8000 = >0000 => tried both trees
[3437] B51A 8F,66           DCZ  @BYTE1
[3438] B51C 54,FB           BR   TRYAGN
[3439] B51E 87,4D           DCLR @DATAAD           Didnt find phrase in either t
[3440] B520 00       FOUND  RTN
[3441]               ***********************************************************
[3442]               * SEARCH actually searches the PHROM tree for the phrase.
[3443]               * The PHROM tree organization is as follows:
[3444]               *        (i.e. this is one phrase node)
[3445]               *              phrase ASCII length      1 byte
[3446]               *              actual ASCII characters  n bytes
[3447]               *              less then pointer        2 bytes
[3448]               *              greater then pointer     2 bytes
[3449]               *              speech data pointer      3 bytes
[3450]               *              speech data length       1 byte
[3451]               * The comparison of two words proceeds on a char by char
[3452]               * basis, where length is secondary to char values, i.e.
[3453]               * move > answer; number < we; eight < eighty; etc...
[3454]               ***********************************************************

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0060 
EQUATES EXEC-359
[3455] B521 06,B5,B5 SEARCH CALL LOADAD            Set PHROM to start phrase nod
[3456] B524 BE,C0,00        ST   >10,@VAR0(@WRITE) Issue read byte command
       B527 5A,10
[3457] B529 86,16           CLR  @PTLCPH           Length of phrase => PTLCPH
[3458] B52B BC,17,C0        ST   @VAR0(@READ),@PTLCPH+1 (stored as 2 byte value
       B52E 00,58
[3459] B530 A1,16,12        DADD @PTFBPH,@PTLCPH   Add front ptr giving end ptr
[3460] B533 BD,14,12        DST  @PTFBPH,@PTCCPH   Set up curr char as 1 beyond
[3461] B536 91,14           DINC @PTCCPH            length byte
[3462] B538 BD,0E,0C        DST  @PTFCIP,@PTCCIP   Reset current ptr into phrase
[3463]               * Compare two characters
[3464] B53B BE,C0,00 NEXT   ST   >10,@VAR0(@WRITE) Issue read byte command
       B53E 5A,10
[3465] B540 BC,5D,C0        ST   @VAR0(@READ),@PHDATA Get char in from PHROM
       B543 00,58
[3466] B545 D4,5D,B0        CEQ  V*PTCCIP,@PHDATA  Compare the char
       B548 0E
[3467] B549 55,99           BR   GB4D1
[3468] B54B 91,14           DINC @PTCCPH           Equal, advance both pointers
[3469] B54D 91,0E           DINC @PTCCIP
[3470] B54F D6,B0,0E        CEQ  SPACE,V*PTCCIP    Skip extra spaces
       B552 20
[3471] B553 55,69           BR   GB4A1
[3472] B555 D6,E0,01 GB48D  CEQ  SPACE,V@1(@PTCCIP) While spaces
       B558 0E,20
[3473] B55A 55,60           BR   GB498
[3474] B55C 91,0E           DINC @PTCCIP           Skip them
[3475] B55E 55,55           BR   GB48D
[3476]               * By skipping extra spaces, might have reached end of phras
[3477]               * If this is true, next char in phrase = #. If so, advance
[3478]               * the pointer to be beyond end of phrase.
[3479] B560 D6,E0,01 GB498  CEQ  NUMBER,V@1(@PTCCIP)
       B563 0E,23
[3480] B565 55,69           BR   GB4A1
[3481] B567 91,0E           DINC @PTCCIP
[3482] B569 C5,14,16 GB4A1  DCH  @PTLCPH,@PTCCPH   End of PHROM word?
[3483] B56C 55,8E           BR   GB4C6
[3484] B56E C5,0E,10        DCH  @PTLCIP,@PTCCIP   Yes, end of phrase
[3485] B571 55,88           BR   GB4C0
[3486] B573 BD,12,16        DST  @PTLCPH,@PTFBPH   Yes, word found
[3487]               * Skip 5 bytes down from last char to data pointer
[3488] B576 A3,12,00        DADD 6,@PTFBPH
       B579 06
[3489] B57A 06,B5,E7        CALL READAD            Set data addr => DATAAD
[3490] B57D BE,C0,00        ST   >10,@VAR0(@WRITE) Issue read byte command
       B580 5A,10
[3491] B582 BC,64,C0        ST   @VAR0(@READ),@STRLEN Get length of speech data
       B585 00,58
[3492] B587 00              RTN
[3493] B588 BF,12,00 GB4C0  DST  3,@PTFBPH         Move 3 bytes past PTLCPH
       B58B 03
[3494] B58C 55,A5           BR   NXTPHR
[3495] B58E C5,0E,10 GB4C6  DCH  @PTLCIP,@PTCCIP   2 characters
[3496] B591 55,3B           BR   NEXT
[3497] B593 BF,12,00        DST  1,@PTFBPH         Phrase linger: use LT ptr
       B596 01
[3498] B597 55,A5           BR   NXTPHR
[3499]               * Two characters compared were not equal
[3500] B599 BF,12,00 GB4D1  DST  3,@PTFBPH         3 bytes past last to GT
       B59C 03
[3501] B59D C4,5D,B0        CH   V*PTCCIP,@PHDATA  After phrase
       B5A0 0E
[3502] B5A1 55,A5           BR   NXTPHR
[3503] B5A3 97,12           DDECT @PTFBPH          Back up 2 bytes to LT link

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0061 
EQUATES EXEC-359
[3504]               * Go get next phrase out of the PHROM to compare
[3505] B5A5 A1,12,16 NXTPHR DADD @PTLCPH,@PTFBPH   Add displacement to last char
[3506] B5A8 06,B5,E7        CALL READAD             and get the new address
[3507] B5AB 8F,4D           DCZ  @DATAAD           More leaves on this tree
[3508] B5AD 55,B0           BR   GB4E8
[3509] B5AF 00              RTN                    No, return empty handed
[3510] B5B0 BD,12,4D GB4E8  DST  @DATAAD,@PTFBPH   Store new addr in PTFBPH
[3511] B5B3 55,21           BR   SEARCH            Go compare this new word!
[3512]               * The program should never reach this point!! It should
[3513]               * return somewhere up above.
[3514]               ***********************************************************
[3515]               * LOADAD will set the addr out in the PHROM to the addr
[3516]               * found in PTFBPH. Note that the PHROM is expecting five
[3517]               * nybbles to be written out as the address.
[3518]               ***********************************************************
[3519] B5B5 BD,54,12 LOADAD DST  @PTFBPH,@TEMP1    This is destructive, so copy
[3520] B5B8 BD,56,12        DST  @PTFBPH,@TEMP2     address into temporary areas
[3521] B5BB E6,54,04        SRL  4,@TEMP1          Isolate the MSN of the MSB
[3522] B5BE E6,55,04        SRL  4,@TEMP1+1        Isolate the MSN of the LSB
[3523] B5C1 B3,56,0F        DAND >0F0F,@TEMP2      Isolate the LSN of the MSB, L
       B5C4 0F
[3524] B5C5 B7,54,40        DOR  >4040,@TEMP1      Include a 4 as MSN of all 4 n
       B5C8 40
[3525] B5C9 B7,56,40        DOR  >4040,@TEMP2       to indicate a Load Address C
       B5CC 40
[3526] B5CD BC,C0,00        ST   @TEMP2+1,@VAR0(@WRITE) Write out the LSN of th
       B5D0 5A,57
[3527] B5D2 BC,C0,00        ST   @TEMP1+1,@VAR0(@WRITE) Write out the LSN of th
       B5D5 5A,55
[3528] B5D7 BC,C0,00        ST   @TEMP2,@VAR0(@WRITE)   Write out the MSN of th
       B5DA 5A,56
[3529] B5DC BC,C0,00        ST   @TEMP1,@VAR0(@WRITE)   Write out the MSN of th
       B5DF 5A,54
[3530] B5E1 BE,C0,00        ST   >40,@VAR0(@WRITE)      Write out 0 as fifth ny
       B5E4 5A,40
[3531] B5E6 00              RTN
[3532]               ***********************************************************
[3533]               * READAD will read an address from the PHROM and store it
[3534]               * in DATAAD. Note that PTFBPH should contain the addr of
[3535]               * the PHROM location to be read so LOADAD will work.
[3536]               ***********************************************************
[3537] B5E7 06,B5,B5 READAD CALL LOADAD            Set the addr of the PHROM
[3538] B5EA BE,C0,00        ST   >10,@VAR0(@WRITE) Get high byte of addr
       B5ED 5A,10
[3539] B5EF BC,4D,C0        ST   @VAR0(@READ),@DATAAD Stroe it in DATAAD
       B5F2 00,58
[3540] B5F4 BE,C0,00        ST   >10,@VAR0(@WRITE) Get low byte of addr
       B5F7 5A,10
[3541] B5F9 BC,4E,C0        ST   @VAR0(@READ),@DATAAD+1 Store it in DATAAD+1
       B5FC 00,58
[3542] B5FE 00              RTN
[3543]               ***********************************************************
[3544]               * STDATA will store the data in DATAAD and TOTTIM onto the
[3545]               * speech list. It will also check that there is room on the
[3546]               * speech list for this entry, and abort with error if not.
[3547]               ***********************************************************
[3548] B5FF D5,02,04 STDATA DCEQ @PTEBSL,@PTLBSL   Is there room?
[3549] B602 76,21           BS   ERRSSL
[3550] B604 35,00,03        MOVE 3,@TOTTIM,V*PTLBSL   Put data in list
       B607 B0,02,4C
[3551] B60A A3,02,00        DADD 3,@PTLBSL              and inc top of list
       B60D 03
[3552] B60E 00              RTN
[3553]               ***********************************************************

99/4 GPL-ASSEMBLER (Pass 3) correct                                   PAGE 0062 
EQUATES EXEC-359
[3554]               * WAIT loops until the speech peripheral goes idle.
[3555]               ***********************************************************
[3556]               *    ( Loop until nobody is talking)
[3557] B60F BC,69,C0 WAIT   ST   @VAR0(@READ),@SPKSTS  Read status from PHROM
       B612 00,58
[3558] B614 DA,69,80        CLOG >80,@SPKSTS
[3559] B617 56,0F           BR   WAIT
[3560] B619 00              RTN
[3561]               ***********************************************************
[3562]               * SETRW moves addrs of speech read/write from GROM to VDP
[3563]               ***********************************************************
[3564] B61A 31,00,04 SETRW  MOVE 4,G@>0046,@READ
       B61D 58,00,46
[3565] B620 00              RTN
[3566]               ***********************************************************
[3567]               *                    ERROR MESSAGES
[3568]               ***********************************************************
[3569]               *      The following calls are in EXECS file.
[3570]               * ERRSYN CALL ERRZZ           * SYNTAX ERROR
[3571]               *        BYTE 3
[3572]               * ERRSNM CALL ERRZZ           * STRING-NUMBER MISMATCH
[3573]               *        BYTE 7
[3574]               * ERRBV  CALL ERRZZ           * BAD VALUE
[3575]               *        BYTE 30
[3576]               * ERRIAL CALL ERRZZ           * INCORRECT ARGUMENT LIST
[3577]               *        BYTE 31
[3578]               ***********************************************************
[3579] B621 06,6A,84 ERRSSL  CALL ERRZZ          * SPEECH STRING TOO LONG
[3580] B624 15               BYTE 21


#14 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,322 posts
  • HarmlessLion
  • Location:BUR

Posted Wed Oct 31, 2018 5:38 PM

They want to capture the LPC strings for the TE2 SPEECH device, Rich. Do you have that source? :)


  • RXB likes this

#15 OLD CS1 OFFLINE  

OLD CS1

    Technomancer

  • Topic Starter
  • 5,695 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Wed Oct 31, 2018 9:03 PM

I would be happy with a table of allophone to LPC.  Otherwise, I moved on from the project which needed that information.



#16 BeeryMiller OFFLINE  

BeeryMiller

    Dragonstomper

  • 688 posts
  • Location:Campbellsburg, KY

Posted Thu Nov 1, 2018 5:25 AM

Hey,

 

I just want to throw this out there.  Barry Boone wrote a program, Sound F/X, that allows one to play sound files through the sound chip.  The source code is out there someone.  I disassembled his program years ago and wrote a player for MDOS for the Geneve.  Basically, it is load a sound file into memory, then play.  You could do something very similar without using the TE2 cartridge "IF" you wanted to go that route.  The actual source code was not all that long.  It should not be too difficult to convert it into a CALL LINK routine and pass parameters to it to load a file.  It does take up a fair amount of memory, but if you are doing something with a SAMS card, it may be an option to consider.

 

I'm guessing you would need a PC/Windows computer to record audio that could then be played back that would need to be compatible with the supported formats of the program.

 

Food for thought.

 

Beery



#17 mizapf OFFLINE  

mizapf

    River Patroller

  • 3,398 posts
  • Location:Germany

Posted Thu Nov 1, 2018 6:12 AM

It should be possible to get the allophone table by disassembling TE-II. Not a project for one week-end, though.

 

Also, to get the LPC data within MAME, we would have to set a debug flag in the speech synthesizer emulation and recompile. I could do that if this is desired. The data would then be output on the console or saved to a file.



#18 arcadeshopper OFFLINE  

arcadeshopper

    River Patroller

  • 3,837 posts
  • Location:Portland, Oregon USA

Posted Thu Nov 1, 2018 6:34 PM

Hey,

 

I just want to throw this out there.  Barry Boone wrote a program, Sound F/X, that allows one to play sound files through the sound chip.  The source code is out there someone.  I disassembled his program years ago and wrote a player for MDOS for the Geneve.  Basically, it is load a sound file into memory, then play.  You could do something very similar without using the TE2 cartridge "IF" you wanted to go that route.  The actual source code was not all that long.  It should not be too difficult to convert it into a CALL LINK routine and pass parameters to it to load a file.  It does take up a fair amount of memory, but if you are doing something with a SAMS card, it may be an option to consider.

 

I'm guessing you would need a PC/Windows computer to record audio that could then be played back that would need to be compatible with the supported formats of the program.

 

Food for thought.

 

Beery

 

Beery,

 

sometime we need to discuss your geneve player and some suggestions for it ;)

 

Greg



#19 RXB OFFLINE  

RXB

    River Patroller

  • 3,367 posts
  • Location:Vancouver, Washington, USA

Posted Thu Nov 1, 2018 10:54 PM

They want to capture the LPC strings for the TE2 SPEECH device, Rich. Do you have that source? :)

Sorry never GPL disassembled TE2 yet.

 

Did start a project to do so, but other projects got in way. 

 

People just were not that into Speech that much back then, LPC considered archaic compared to PC or Mac speech.



#20 HOME AUTOMATION OFFLINE  

HOME AUTOMATION

    Chopper Commander

  • 144 posts

Posted Thu Nov 1, 2018 11:47 PM

I almost have this ready, Rich's code got me to thinking... maybe >60 was what was needed to make my program's output compatible with CALL SAY's expectations. Sure enough I had been looking for the solution in the wrong place. I'm checking the length accuracy now. I intend to add enable/disable routines, so the whole system doesn't need to be reset between dumps.

Hopefully it will be ready tonight or tomorrow. :party:



#21 BeeryMiller OFFLINE  

BeeryMiller

    Dragonstomper

  • 688 posts
  • Location:Campbellsburg, KY

Posted Fri Nov 2, 2018 9:01 AM

 

Beery,

 

sometime we need to discuss your geneve player and some suggestions for it ;)

 

Greg

 

Greg, what suggestions?

 

Beery



#22 HOME AUTOMATION OFFLINE  

HOME AUTOMATION

    Chopper Commander

  • 144 posts

Posted Fri Nov 2, 2018 11:23 AM

I would be happy with a table of allophone to LPC.  Otherwise, I moved on from the project which needed that information.

Should the LPC data in the table be pure LPC or start with a length byte or word(MSByte would always be zero for short data) or should the entries begin with 96(>60) so as to be directly compatible with CALL SAY? I suppose pure would be the easiest to concatenate, though you would have to determine the final length. :ponder:



#23 RXB OFFLINE  

RXB

    River Patroller

  • 3,367 posts
  • Location:Vancouver, Washington, USA

Posted Fri Nov 2, 2018 6:29 PM

Both XB and TE2 put the LPC from Disk into VDP and then use it, our problem is amount of LPC Library VDP space is limited to that GPL Cart.

XB has much less available space then TE2 does.

 

But ad in a TI Basic program and Speech to the TE2 and XB comes out oddly with more space as XB has 24K program space and 8K assembly.

Thus TE2 has more RAM but that does nothing for VDP used.



#24 OLD CS1 OFFLINE  

OLD CS1

    Technomancer

  • Topic Starter
  • 5,695 posts
  • Technology Samurai
  • Location:Tallahassee, FL

Posted Fri Nov 2, 2018 6:39 PM

Should the LPC data in the table be pure LPC or start with a length byte or word(MSByte would always be zero for short data) or should the entries begin with 96(>60) so as to be directly compatible with CALL SAY? I suppose pure would be the easiest to concatenate, though you would have to determine the final length. :ponder:

 

Either way is fine.  My intention at the time was to use the data in an XB program and I was building my own phrases.



#25 HOME AUTOMATION OFFLINE  

HOME AUTOMATION

    Chopper Commander

  • 144 posts

Posted Fri Nov 2, 2018 9:28 PM

LPC EXTRACTOR VERSION of XB TTS ENGLISH disk

Easy and familiar to use.
The buffer can handle >2497bytes.
Buffer can be disabled while testing data.
Dual output: C$=length byte&LPC data
Output from D$ is directly compatible with CALL SAY.
Long data can be accessed directly from buffer @>3700.
Gets good mileage.

Two examples of how to use:
PHRASE decodes short strings.
TABLE creates an ARRAY containing LPC of all ALLOPHONES.

Use CALL LINK("ON") to activate or reset the buffer.

Use CALL LINK("OFF") to deactivate the buffer.

Use CALL LINK("LPC",x$) to access data (from within XB)

Use "y$=CHR$(96)&CHR$(0)&x$ to create y$"(compatible with CALL SAY)

sorry so little support...

 

 


Attached File  TTS2LPC.dsk   90KB   6 downloads






metadata(don't look...)text to speech lpc solution






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users