ttl 'QT2 - approximate time display (version 87/10/05)' sys macro ;Call a system routine. ifnd _LVO\1 xref _LVO\1 endc jsr _LVO\1(a6) endm code * * Equates * lf equ $0A ;Line feed cr equ $0D ;Carriage return pr_MsgPort equ $5C pr_CLI equ $AC CMD_WRITE equ 3 ;Write command * * External references (most are taken care of by the SYS macro) * xref _AbsExecBase xref _CreatePort xref _DeletePort xdef _SysBase xdef _DOSBase * * Initialization * start: move.l sp,savesp ;Save the stack pointer. clr.l _DOSBase ;Clear library pointers. clr.l intbase clr.l trnbase clr.l voice_port * Open dos.library move.l _AbsExecBase,a6 ;Find library move.l a6,_SysBase lea dosname,a1 ;'dos.library' moveq #0,d0 ;Any version sys OpenLibrary ;Open dos.library. move.l d0,_DOSBase ;Save it for future reference. beq quitprg ;Couldn't get pointer. * Find out whether we were called from a CLI. suba.l a1,a1 move.l _SysBase,a6 sys FindTask ;Find our task control block. move.l d0,a4 move.l pr_CLI(a4),prcli ;Save pointer to CLI. beq.s openwb ;We were called from Workbench. * Get file handles for stdin and stdout. move.l _DOSBase,a6 ;Pointer to dos.library sys Input ;Get file handle for keyboard. move.l d0,stdin ;Save it here. beq quitprg ;Couldn't get keyboard handle. sys Output ;Get file handle for screen. move.l d0,stdout ;Save it here. beq quitprg ;Couldn't get screen handle. bra.s openint * Special Workbench startup stuff openwb lea pr_MsgPort(a4),a0 move.l _SysBase,a6 sys WaitPort ;Wait for startup message from Workbench. lea pr_MsgPort(a4),a0 sys GetMsg ;Get the message. move.l d0,retmsg ;Save it so we can return it when we're done. * Open intuition.library openint move.l _SysBase,a6 lea intname,a1 moveq #0,d0 sys OpenLibrary move.l d0,intbase bne.s opened ;We got it opened. lea interr,a0 bsr pstring ;Indicate open failure. bra quitprg ;Exit. opened: * * Get the time and convert it to cute notation. * * Get the time - put hour in D6 and minute in D7. move.l _DOSBase,a6 move.l #dtstamp,d1 sys DateStamp ;Get the time. move.l dtstamp+4,d7 ;Work with the time here. divu #60,d7 ;Convert to hours and minutes. moveq #0,d6 move.w d7,d6 ;Work with hours here. clr.w d7 swap d7 ;Get minutes in low-order word. lea timemsg,a2 ;A2 loads the final message. lea its,a0 bsr copy ;"It's " * Adjust for minutes "to" the next hour if it's after (approximately) half past. cmpi.w #33,d7 ;33 minutes or more past the hour? bcs.s adjhr ;No. addq.l #1,d6 ;It's time "to" the next hour. adjhr cmpi.w #13,d6 ;Is it in the afternoon? bcs.s adj12 ;No. subi.w #12,d6 ;Keep it in the range 1..12 adj12 tst.w d6 ;Is hour zero? bne.s adj5 ;No. moveq #12,d6 ;Set hour to 12. * Look up nearness to a 5-minute interval. adj5 addq.l #2,d7 ;Adjust for 5-minute rounding cmpi.w #60,d7 bcs.s near sub.w #60,d7 ;Adjust for carry into the next hour. * Express how near we are to the 5-minute interval. near divu #5,d7 ;Divide adjusted minute by 5. swap d7 ;Get the remainder move.w d7,d0 asl.w #2,d0 ;Multiply by 4 for longword displacement lea nearptr,a0 move.l 0(a0,d0.w),a0 ;Pointer to appropriate "near" phrase bsr copy ;Copy phrase to string. * Now put in the appropriate 5-minute phrase itself. swap d7 ;(minute+2)/5 asl.w #2,d7 lea minptr,a0 move.l 0(a0,d7.w),a0 ;Pointer to appropriate minute phrase bsr copy * Say whether it's past the previous hour or approaching the next hour. tst.b d7 ;Is it around the hour? beq.s hrname ;Yes - don't say anything here. lea past,a0 ;Assume it's past the hour cmpi.w #28,d7 ;Is it approaching the next hour? bcs.s pastto ;No. lea to,a0 pastto bsr copy * Now add the hour name. hrname subq.l #1,d6 ;Convert 1..12 to 0..11 asl.w #2,d6 lea hrptr,a0 move.l 0(a0,d6.w),a0 bsr copy * Finish off the string and display it. tst.w d7 ;Is it around the hour? bne.s moveper ;No. lea oclock,a0 bsr copy ;Add " o'clock". moveper lea period,a0 bsr copy ;Finish off the message. move.l a2,d0 ;Save ending address. subq.l #1,d0 ;Back over the terminating null. lea timemsg,a0 sub.l a0,d0 ;Length of string move.l d0,timelen tst.l prcli ;Were we called from a CLI? beq.s saytime ;No - just say the time. bsr pstring ;Display the time. * * Now say the time (if we can!). * saytime * Translate the string to phonemes. move.l _SysBase,a6 lea trnname,a1 moveq #0,d0 sys OpenLibrary ;Open translator.library. move.l d0,trnbase beq notalk ;The open failed - forget it. lea timemsg,a0 ;Address of original string move.l timelen,d0 ;Length of original string lea tranmsg,a1 ;Address of translated string moveq #tranmax,d1 ;Maximum length move.l trnbase,a6 sys Translate ;Translate the string. * Open a reply port for the narrator. clr.l -(sp) clr.l -(sp) jsr _CreatePort ;voice_port = CreatePort (0L, 0L); add.l #8,sp move.l d0,voice_port move.l d0,mn_ReplyPort beq notalk ;Couldn't create the port! * Set up the write channel information. move.l #audio_chan,ch_masks move.w #audio_chan_len,nm_masks clr.b mouths move.w #CMD_WRITE,io_Command clr.l io_Offset move.l #voice_io_len,mn_Length lea tranmsg,a0 move.l a0,io_Data tranlen tst.b (a0)+ bne.s tranlen ;Determine length of phoneme string. suba.l #1,a0 sub.l io_Data,a0 move.l a0,io_Length * Open the device and say the time. lea narname,a0 moveq #0,d0 lea voice_io,a1 moveq #0,d1 move.l _SysBase,a6 sys OpenDevice tst.l d0 ;Were we successful? bne notalk ;No. lea voice_io,a1 move.l _SysBase,a6 sys DoIO ;Say the time. lea voice_io,a1 move.l _SysBase,a6 sys CloseDevice ;Close narrator.device. bra.s quitprg ;We made it! * We were unable to talk - display a requester saying so. notalk suba.l a0,a0 lea notalki,a1 suba.l a2,a2 lea foritxt,a3 moveq #0,d0 moveq #0,d1 move.l #200,d2 moveq #50,d3 move.l intbase,a6 sys AutoRequest ;Display the requester. * * End of program, one way or another * quitprg move.l savesp,sp ;Restore stack pointer. move.l voice_port,d0 beq.s clostrn move.l d0,-(sp) jsr _DeletePort ;Delete the narrator message port. add.l #4,sp clostrn move.l _SysBase,a6 move.l trnbase,d0 ;Close translator.library. beq.s closint ;It wasn't opened. move.l d0,a1 sys CloseLibrary closint move.l intbase,d0 ;Close intuition.library. beq.s closdos move.l d0,a1 sys CloseLibrary closdos move.l _DOSBase,d0 ;Close dos.library. beq.s endwb move.l d0,a1 sys CloseLibrary endwb tst.l prcli ;Were we called from a CLI? bne.s exit0 ;Yes. move.l _SysBase,a6 sys Forbid ;Don't let Workbench UnLoadSeg() us. move.l retmsg,a1 sys ReplyMsg ;Return the startup message to Workbench. exit0 moveq #0,d0 ;Return with no error. rts ;All done * * Copy the null-terminated string pointed to by A0 to (A2). * On exit, A2 points to the last byte copied (i.e. the null). * copy move.b (a0)+,(a2)+ ;Move one character. bne.s copy ;Get the next character. suba.l #1,a2 ;Back over the null. rts * * Display the null-terminated string pointed to by A0. * pstring movem.l d2-d3/a6,-(sp) move.l a0,d2 ;AmigaDOS wants the address here. pstrl tst.b (a0)+ ;Scan for end of string. bne.s pstrl move.l a0,d3 ;AmigaDOS wants the length here. sub.l d2,d3 ;Length plus one subq.l #1,d3 ;Reduce to proper length. move.l stdout,d1 move.l _DOSBase,a6 sys Write ;Write the string. movem.l (sp)+,d2-d3/a6 rts page ************************************************************************* * * * Constants * * * ************************************************************************* section Constants,data dosname dc.b 'dos.library',0 intname dc.b 'intuition.library',0 trnname dc.b 'translator.library',0 interr dc.b 'Unable to open intuition.library',cr,lf,0 narname dc.b 'narrator.device',0 notalkm dc.b 'I can''t talk!',0 fortext dc.b 'Forget it',0 its dc.b 'It''s ',0 nearptr dc.l almost,nearly,null,justaft,justpas almost dc.b 'almost ',0 nearly dc.b 'nearly ',0 null dc.l 0 justaft dc.b 'just after ',0 justpas dc.b 'just past ',0 minptr dc.l null,five,ten,quarter,twenty,twenfiv,half dc.l twenfiv,twenty,quarter,ten,five quarter dc.b 'a quarter',0 half dc.b 'half',0 hrptr dc.l one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve one dc.b 'one',0 two dc.b 'two',0 three dc.b 'three',0 four dc.b 'four',0 five dc.b 'five',0 six dc.b 'six',0 seven dc.b 'seven',0 eight dc.b 'eight',0 nine dc.b 'nine',0 ten dc.b 'ten',0 eleven dc.b 'eleven',0 twelve dc.b 'twelve',0 twenty dc.b 'twenty',0 twenfiv dc.b 'twenty-five',0 to dc.b ' to ',0 past dc.b ' past ',0 oclock dc.b ' o''clock',0 period dc.b '.',cr,lf,0 audio_chan dc.b 3,5,10,12 ;Which audio channels to use audio_chan_len equ *-audio_chan * IntuiText structures for "can't-talk" requester cnop 0,4 notalki ;BodyText dc.b 0,1,0,0 dc.w 10,5 dc.l 0,notalkm,0 foritxt ;NegativeText dc.b 0,1,0,0 dc.w 4,3 dc.l 0,fortext,0 page ************************************************************************* * * * Storage areas * * * ************************************************************************* section Storage,bss savesp ds.l 1 ;Stack pointer save area retmsg ds.l 1 ;Pointer to Workbench startup message _SysBase ds.l 1 ;Copy of _AbsExecBase _DOSBase ds.l 1 ;Pointer to dos.library intbase ds.l 1 ;Pointer to intuition.library trnbase ds.l 1 ;Pointer to translator.library prcli ds.l 1 ;Pointer to CLI or zero stdin ds.l 1 ;stdin file handle stdout ds.l 1 ;stdout file handle dtstamp ds.l 3 ;Date stamp (days, minutes, ticks) timemsg ds.b 41 ;Time message is built here. timelen ds.l 1 ;Actual length of time message tranmsg ds.b 80 ;"timemsg" translated to phonemes tranmax equ *-tranmsg voice_port ds.l 1 ;Pointer to message port for narrator.device * * Narrator write request * voice_io ;struct narrator_rb message ;struct IOStdReq io_Message ;struct Message mn_Node ;struct Node ln_Succ ds.l 1 ;Pointer to successor Node ln_Pred ds.l 1 ;Pointer to predecessor Node ln_Type ds.b 1 ln_Pri ds.b 1 ln_Name ds.l 1 ;Pointer ; End of struct Node mn_ReplyPort ds.l 1 ;Pointer to MsgPort (message reply port) mn_Length ds.w 1 ;Message length in bytes ; End of struct Message io_Device ds.l 1 ;Pointer to device node io_Unit ds.l 1 ;Pointer to Unit (driver private) io_Command ds.w 1 ;Device command io_Flags ds.b 1 io_Error ds.b 1 ;Error or warning number ; End of struct IOReq - IOStdReq continues... io_Actual ds.l 1 ;Actual number of bytes transferred io_Length ds.l 1 ;Requested number of bytes transferred io_Data ds.l 1 ;Points to data area. io_Offset ds.l 1 ;Offset for block-structured devices ; End of struct IOStdReq rate ds.w 1 ;Speaking rate (words per minute) pitch ds.w 1 ;Baseline pitch in Hertz mode ds.w 1 ;Pitch mode sex ds.w 1 ;Sex of voice ch_masks ds.l 1 ;Pointer to audio allocation maps nm_masks ds.w 1 ;Number of audio allocation maps volume ds.w 1 ;Volume: 0 (off) thru 64 (maximum) sampfreq ds.w 1 ;Audio sampling frequency mouths ds.b 1 ;If non-zero, generate mouths. chanmask ds.b 1 ;Which channel mask used (internal) numchan ds.b 1 ;Number of channel masks used (internal) ds.b 1 ;For alignment voice_io_len equ *-voice_io ; End of struct narrator_rb end