; --------------------
; Speak de time by CJD
; --------------------

;	imbed c:\masm\saldef.sal
; ----- SAT definitions

;        saljmp short
;        salcmp unsigned

;        salmac := mov &-,&+
;        salmac ==> lea &-,&+
;        salmac =& mov &-,offset &+
;        salmac -> mov &-,offset &+

;        salmac -- dec &+
;        salmac ++ inc &+

;        salmac += add &-,&+
;        salmac -= sub &-,&+
;        salmac /= div &+
;        salmac *= mul &+

;        salmac |= or &-,&+
;        salmac &= and &-,&+
;        salmac ^= xor &-,&+

;        salmac >= shr &-,&+
;        salmac >> shr &-,&+
;        salmac <= shl &-,&+
;        salmac << shl &-,&+

;        salmac clear xor &+,&+

;        salmac <- push &+ ^ pop &-
;        saldef jmps jmp short
;        saldef (b) byte ptr
;        saldef (w) word ptr
;        saldef (si) byte ptr [si]
;        saldef (di) byte ptr [di]
;        saldef {si} word ptr [si]
;        saldef {di} word ptr [di]

	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
	JNC	SAAA_AA
	mov	al,1			; Return errorlevel 1
;	Else				; SPEECH installed
	JMP	SHORT	SAAA_AB
SAAA_AA:
	call Build			; Build the time string
	call Speak			; Say the time
	mov	al,0			; Return errorlevel 0
;	Endif
SAAA_AB:
	@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)
	mov	di,offset	SP2

	mov	ah,ch			; Add hour
	call AddTime
	mov	al,' '			; Add extra pause between
	stosb
	inc	StringLen

	mov	ah,cl			; Add minute
	call AddTime
	mov	al,' '			; Add extra pause between
	stosb
	inc	StringLen

	mov	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"
	CMP	ah,10
	JAE	SAAB_AA
	mov	al,0
	call AddWord
;	Endif
SAAB_AA:

;	If ah <= 20 Then
	CMP	ah,20
	JA	SAAC_AA
	mov	al,ah
	call AddWord
;	Else
	JMP	SHORT	SAAC_AB
SAAC_AA:
	mov	bl,10
	mov	al,ah
	cbw
	div bl			; AH = low digit; AL = high digit
	mov	bh,ah			; BH = low digit
	mul bl			; AL = 10*high digit = tens word
	call AddWord		; Add tens
;	    If bh <> 0 Then
	OR	bh,bh
	JE	SAAD_AA
	mov	al,bh			; Add ones
	call AddWord
;	    Endif
SAAD_AA:
;	Endif
SAAC_AB:

	pop bx
	pop ax
	ret

; ----- Add word for number in AL to string
AddWord:
	push ax
	push cx
	push dx

	mov	ah,al			; Move number to AH
	mov	ch,0
	mov	si,offset	NumTab

;	Repeat
SAAE_@R:
	lodsb			; Get the number from the table
	mov	cl,[si]			; CX = length
	inc	si			; SI => word for this number

;	    If ah = al Then		; Found the right entry
	CMP	ah,al
	JNE	SAAF_AA
	add	StringLen,cl		; Add length of word to total
	inc	StringLen		; + 1 for space
	mov	al,' '			; Insert a space
	stosb
	rep movsb		; Add word to string
;		Leave			; Exit loop
	JMP	SHORT	SAAE_@L
;	    ElseIf al <> 99 Then	; Not right entry, but not end of table
	JMP	SHORT	SAAF_@Z
SAAF_AA:
	CMP	al,99
	JE	SAAG_AA
	add si,cx		; Skip number word
;	    Else			; End of table--internal error
	JMP	SHORT	SAAF_@Z
SAAG_AA:
	mov	dx,offset	ErrMsg$
	@doscall 9
;	    Endif
SAAF_@Z:
;	Until Leave
	JMP	SHORT	SAAE_@R
SAAE_@L:
	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
	mov	dx,offset	Dumb$
	@doscall 9
	stc
	jmp Init9
Init endp
code ends
end main
