; --------------------
; Speak de time by CJD
; --------------------

	imbed c:\masm\saldef.sal
	include c:\masm\stdlib.mac

; ----- Define locations of interest in the vector table
Abs0	segment at 0

	org 0F1H*4+2			; Speech segment address
SpPtr	label word

	org 0F3H*4			; Code to call Speech (INT F2)
Speech	label far

Abs0	ends

; ----- Define a dummy Speech code segment for code verification
SpeechSeg  segment at 0 		 ; Don't really know where, but...
	   org 100H
SpeechCode label byte
SpeechSeg  ends


; ----- Finally our real code segment
code	segment
assume	cs:code,ds:code,es:code

	org 100H			; Start of .COM code
main proc far
	jmp start

; Table of number words.  Entries are number, word length, word.
NumTab	label byte
N0	db 0,  N1-N0-2,     'oh-oh'
N1	db 1,  N2-N1-2,     'w-uh-n'
N2	db 2,  N3-N2-2,     't-oo-oo'
N3	db 3,  N4-N3-2,     'th-r-ee'
N4	db 4,  N5-N4-2,     'f-oh-r'
N5	db 5,  N6-N5-2,     'f-i-v'
N6	db 6,  N7-N6-2,     's-ih-k-s'
N7	db 7,  N8-N7-2,     's-eh-v-eh-n'
N8	db 8,  N9-N8-2,     'a-a-t'
N9	db 9,  N10-N9-2,    'n-i-n'
N10	db 10, N11-N10-2,   't-eh-n'
N11	db 11, N12-N11-2,   'eh-l-eh-v-uh-n'
N12	db 12, N13-N12-2,   't-w-eh-l-v'
N13	db 13, N14-N13-2,   'th-ih-r-t-ee-n'
N14	db 14, N15-N14-2,   'f-oh-r-t-ee-n'
N15	db 15, N16-N15-2,   'f-ih-f-t-ee-n'
N16	db 16, N17-N16-2,   's-ih-k-s-t-ee-n'
N17	db 17, N18-N17-2,   's-eh-v-eh-n-t-ee-n'
N18	db 18, N19-N18-2,   'a-a-t-ee-n'
N19	db 19, N20-N19-2,   'n-i-n-t-ee-n'
N20	db 20, N30-N20-2,   't-w-eh-n-t-ee'
N30	db 30, N40-N30-2,   'th-ih-r-t-ee'
N40	db 40, N50-N40-2,   'f-oh-r-t-ee'
N50	db 50, N99-N50-2,   'f-ih-f-t-ee'
N99	db 99				; EOT mark

SpeechParms	db 'th-uh t-i-m ih-z'
SP2		db 255 dup (?)

StringLen	db SP2-SpeechParms
		dw SpeechParms

ErrMsg$ 	db 'saytime internal error',13,10,10,'$'


Start:
	call Init			; Find SPEECH
	If carry Then			; SPEECH not installed
	    al := 1			; Return errorlevel 1
	Else				; SPEECH installed
	    call Build			; Build the time string
	    call Speak			; Say the time
	    al := 0			; Return errorlevel 0
	Endif
	@doscall 4CH			; Back to DOS, AL=errorlevel
main endp

; -----------------------------------------------
; Build the time string and set length for SPEECH
; -----------------------------------------------
Build proc near
	@doscall 2CH			; Get time (CH=hr, CL=min, DH=sec)
	di -> SP2

	ah := ch			; Add hour
	call AddTime
	al := ' '			; Add extra pause between
	stosb
	++ StringLen

	ah := cl			; Add minute
	call AddTime
	al := ' '			; Add extra pause between
	stosb
	++ StringLen

	ah := dh			; Add second
	call AddTime
	ret

; ----- Add time component in AH to string
AddTime:
	push ax
	push bx

	If ah < 10 Then 		; Prefix with "oh"
	    al := 0
	    call AddWord
	Endif

	If ah <= 20 Then
	    al := ah
	    call AddWord
	Else
	    bl := 10
	    al := ah
	    cbw
	    div bl			; AH = low digit; AL = high digit
	    bh := ah			; BH = low digit
	    mul bl			; AL = 10*high digit = tens word
	    call AddWord		; Add tens
	    If bh <> 0 Then
		al := bh		    ; Add ones
		call AddWord
	    Endif
	Endif

	pop bx
	pop ax
	ret

; ----- Add word for number in AL to string
AddWord:
	push ax
	push cx
	push dx

	ah := al			; Move number to AH
	ch := 0
	si -> NumTab

	Repeat
	    lodsb			; Get the number from the table
	    cl := [si]			; CX = length
	    ++ si			; SI => word for this number

	    If ah = al Then		; Found the right entry
		StringLen += cl 	; Add length of word to total
		++ StringLen		; + 1 for space
		al := ' '		; Insert a space
		stosb
		rep movsb		; Add word to string
		Leave			; Exit loop
	    ElseIf al <> 99 Then	; Not right entry, but not end of table
		add si,cx		; Skip number word
	    Else			; End of table--internal error
		dx -> ErrMsg$
		@doscall 9
	    Endif
	Until Leave
	pop dx
	pop cx
	pop ax
	ret
Build endp


; ---------------------------------
; Call SPEECH to say the time string
; ---------------------------------
Speak proc near
	mov ax,offset StringLen 	; AX = ptr to parm len
	push ax 			; Put on stack
	call Speech			; Call Speech program
	ret
Speak endp


; -----------------------------------------
; Make sure SPEECH is installed.  If not,
; return CF=1 and message displayed.
; -----------------------------------------
Dumb$	db 'SPEECH not installed',13,10,10,'$'
Init proc near
	push ds
	push es

	mov ax,Abs0			; Get Speech seg addr to DS
	mov es,ax
	assume es:Abs0
	mov ax,word ptr SpPtr
	mov ds,ax
	assume ds:SpeechSeg

	cmp SpeechCode,090H		; Verify 1st three bytes of Speech code
	jne Dumb
	cmp SpeechCode+1,1EH
	jne Dumb
	cmp SpeechCode+2,0B8H
	jnz Dumb

	pop es
	pop ds
	clc
Init9:
	ret


Dumb:
	pop es
	pop ds
	dx -> Dumb$
	@doscall 9
	stc
	jmp Init9
Init endp
code ends
end main
