Article View: comp.sys.amiga.tech
Article #8406A small ARexx example, and other useful tidbits . . .
From: Kim DeVaughn
Date: Fri, 01 Apr 1988 23:11
Date: Fri, 01 Apr 1988 23:11
311 lines
14680 bytes
14680 bytes
[ "A car is just a big purse on wheels." --Johanna Reynolds ]
In a recent posting concerning ARexx and IPC, as an example of ARexx's
scripting/macro capabilities, I made reference to an amicron initiated,
talking alarm clock program that one of my co-workers whipped off.
I hadn't really thought about posting it, until Peter da Silva catagorized
the REXX language as being "PL/I like". Bunk.
So, in the interest of education, and with Bob Rethemeyer's permission
(he's the author), here's "cuckoo", along with a crontab file.
Also included is a 336-byte, "bare-bones", assembly language substitute
for the "say" command. It's valuable in it's own right as an assembly
language example of using the translator.library and narrator.device.
[ Coincidentally, I just saw a posting requesting assembly language examples
for inclusion into a freely redistributable library, similar in concept to
the Fish Disks. Feel free to include "mumble". ]
Bear in mind that the REXX language has many more features, and power than
are used in "cuckoo". It should, however, give you a "feel" for what the
language is like. Note too, that this example makes implicit use of IPC
to communicate to AmigaDOS (where it invokes the "say" command [line 19],
and also where it invokes whatever is equated to "speak" [lines 8, 59, 60,
and 62], which in this case is "mumble").
Hope some of you find this example useful!
/kim
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file". (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# cuckoo.rexx timeto.rexx sample.crontab mumble.asm mumble.uue
echo x - cuckoo.rexx
cat > "cuckoo.rexx" << '//E*O*F cuckoo.rexx//'
/* CUCKOO: ANNOUNCES THE CURRENT TIME. R. Rethemeyer 03-88 *
* Cuckoo is useful with AmiCron to announce times for events. *
* The "MUMBLE" program is used for the voice output. *
* If that is not available, change 'speak' to "sys:system/say".*
* Usage: "RX CUCKOO [ALARM]" *
* The ALARM option produces an obnoxious noise and message. */
/*--------------------------------------------------------------------*/
speak="Mumble" /* PROGRAM FOR VOICE OUTPUT */
nice="Excuse me sir, the time iz now" /* NORMAL MESSAGE */
nasty="All right u bum, get up. Nouw. The time iz" /* ALARM MESSAGE */
dingaling="gggggggggggggggggggggggggggg" /* OBNOXIOUS ALARM NOISE */
/*--------------------------------------------------------------------*/
arg opt
if opt="ALARM" then intro=nasty ; else intro=nice
zhour = time('h')
xmin = time('m')
xmin = xmin-((xmin%60)*60)
xhour = zhour
say "Cuckoo at" zhour||":"||xmin
mnite = " "
if zhour > 12 then xhour = zhour-12
select
when xhour=0 then do; xhour="twelve"; if xmin=0 then mnite="midnite"; end
when xhour=11 then xhour = "elaven"
when xhour=12 then do; xhour="twelve"; if xmin=0 then mnite="noon"; end
otherwise nop
end
smin=" "
if xmin=0 then tmin = "o clock"
else do
tmin=xmin%10
if tmin=1 then do;
select
when xmin=10 then tmin = "ten"
when xmin=11 then tmin = "elaven"
when xmin=12 then tmin = "twelve"
when xmin=13 then tmin = "thirt teen"
when xmin=14 then tmin = "fourt teen"
when xmin=15 then tmin = "fif teen"
when xmin=16 then tmin = "six teen"
when xmin=17 then tmin = "seven teen"
when xmin=18 then tmin = "eight teen"
when xmin=19 then tmin = "nine teen"
end
end
else do
smin=xmin
if xmin>9 then smin=xmin-(tmin*10)
if smin=0 then smin=" "
select
when tmin=0 then tmin = "oh"
when tmin=2 then tmin = "twenty"
when tmin=3 then tmin = "thirty"
when tmin=4 then tmin = "forty"
when tmin=5 then tmin = "fifty"
end
end
end
if opt="ALARM" then address COMMAND speak dingaling
address COMMAND speak intro xhour tmin smin mnite "."
if tmin="o clock" & opt="ALARM" then ,
address COMMAND speak "I repeat," xhour tmin "."
exit
//E*O*F cuckoo.rexx//
echo x - timeto.rexx
cat > "timeto.rexx" << '//E*O*F timeto.rexx//'
/* speak a sentence prefixed by time */
parse arg sentence
cuckoo /* announce the time first */
address command "mumble Its time to " sentence "."
exit
//E*O*F timeto.rexx//
echo x - sample.crontab
cat > "sample.crontab" << '//E*O*F sample.crontab//'
0,15,30,45 * * * * rx cuckoo
0,10,20,30,40,50 7 * * 1-5 rx cuckoo alarm
30 7,18 * * * rx timeto feed the cat
//E*O*F sample.crontab//
echo x - mumble.asm
cat > "mumble.asm" << '//E*O*F mumble.asm//'
PLEN 60
**********************************************************************
* Program: MUMBLE - bare-bones CLI substitute for SAY command *
* Author: Robert Rethemeyer, Sunnyvale, CA (@BBS-HT or BBS-JC) *
* Revision: 0.1 03/30/88 initial release *
* Status: RELEASED TO THE PUBLIC DOMAIN, "AS-IS" *
**********************************************************************
* MUMBLE is a very small CLI program which speaks the text on the *
* command line using the Amiga's translator/narrator voice output. *
* It is convenient for use in CLI or ARexx scripts. *
* Command usage: MUMBLE <text> *
**********************************************************************
* MUMBLE provides a function similar to the command line usage of *
* the SAY command, but takes much less memory and disk space *
* (300 bytes vs. 9K+). It is not, however, as versatile as SAY. *
* There are no -options; the voice parameters are fixed, and the *
* program will not run in window mode or read from a file. *
**********************************************************************
* Mumble return codes:
* 0= success
* 1-9,20-26= narrator IO error
* 11= could not allocate memory
* 12= could not open translator.library
* 13= could not open narrator.device
**********************************************************************
NOLIST
INCLUDE "exec/types.i"
INCLUDE "exec/io.i"
INCLUDE "exec/ports.i"
INCLUDE "exec/memory.i"
INCLUDE "devices/narrator.i"
LIST
XREF _LVOOpenLibrary
XREF _LVOCloseLibrary
XREF _LVOAllocMem
XREF _LVOFreeMem
XREF _LVOOpenDevice
XREF _LVOCloseDevice
XREF _LVOTranslate
XREF _LVOFindTask
XREF _LVOAddPort
XREF _LVORemPort
XREF _LVODoIO
ExecBase EQU 4
execptr EQUR A6
**********************************************************************
* Voice parameters can be changed here, to user's liking:
VSEX EQU MALE MALE/FEMALE/DEFSEX
VMODE EQU NATURALF0 NATURALF0/ROBOTICF0/DEFMODE
VRATE EQU 180 40-400/DEFRATE
VFREQ EQU DEFFREQ 5000-28000/DEFFREQ
VPITCH EQU DEFPITCH 65-320/DEFPITCH
VVOL EQU DEFVOL 0-64/DEFVOL
**********************************************************************
Mumble:
MOVEQ #0,d5 return code if parmlen=0
MOVE.L d0,d4 SAVE EXECUTION PARMS parmlen
BEQ endprog do nothing if parmlen=0
MOVE.L a0,d3 save parmaddr
MOVE.L ExecBase,execptr a6=exec lib pointer
* ALLOCATE SCRATCH MEMOR%
MOVEQ #11,d5 return code if this fails
ASL.L #2,d0 size of TRarea = parmlen*4
ADD.L #scratchlen,d0 add to size of scratch area
MOVE.L d0,d6 remember for deallocate later
MOVE.L #MEMF_PUBLIC+MEMF_CLEAR,d1 mem flags
JSR _LVOAllocMem(execptr) ask for the storage
MOVE.L d0,a3 a3=scratch area ptr
BEQ broke1 abort if request failed
* OPEN TRANSLATOR LIBRARY
MOVEQ #12,d5 return code if this fails
LEA tranlib(pc),a1 addr of library name
MOVEQ #0,d0 any version will do
JSR _LVOOpenLibrary(execptr) get library pointer
MOVE.L d0,a5 a5=tran lib pointer
BEQ broke2 back out if no lib
* TRANSLATE COMMAND LINE PARAMETER
MOVE.L d3,a0 retrieve parmaddr
MOVE.L d4,d0 and parmlen
LEA TRarea(a3),a1 point to xlat out buff
ASL.L #2,d4 figure out buff length again
MOVE.L d4,d1 for func (and save for later)
JSR _LVOTranslate(a5) translate to phonemes
MOVE.L a5,a1 :
JSR _LVOCloseLibrary(execptr) close trans lib
* INIT NARRATOR DEVICE PORT
MOVE.L #0,a1 :
JSR _LVOFindTask(execptr) identify this task
MOVE.L d0,Narport+MP_SIGTASK(a3) let narrator find it
LEA Narport(a3),a1 point to the port area
JSR _LVOAddPort(execptr) install narrator port
* INIT NARRATOR DEVICE
MOVEQ #13,d5 return code if this fails
LEA Narname(pc),a0 point to device name
MOVEQ #0,d0 unit 0
LEA Nardev(a3),a1 point to device structure
MOVEQ #0,d1 no flags
JSR _LVOOpenDevice(execptr) open narrator device
TST.L d0 if device open failed
BNE.S broke3 then back out
* INIT DEVICE STUFF
LEA Nardev(a3),a1 a1=device structure
LEA Narport(a3),a0 a0=port address
MOVE.L a0,MN_REPLYPORT(a1) give port addr to device
LEA audmaps(pc),a0 audio maps
MOVE.L a0,NDI_CHMASKS(a1) addr of maps
MOVE.W #4,NDI_NUMMASKS(a1) number of masks
MOVE.W #VPITCH,NDI_PITCH(a1) init pitch
MOVE.W #VRATE,NDI_RATE(a1) init rate
MOVE.W #VVOL,NDI_VOLUME(a1) init volume
MOVE.W #VFREQ,NDI_SAMPFREQ(a1) init sample freq
MOVE.W #VSEX,NDI_SEX(a1) init sex
MOVE.W #VMODE,NDI_MODE(a1) init mode
MOVE.W #CMD_WRITE,IO_COMMAND(a1) init device command
MOVE.L d4,IO_LENGTH(a1) length of buffer
LEA TRarea(a3),a0 addr of buffer
MOVE.L a0,IO_DATA(a1) :
* THE MOMENT OF TRUTH
JSR _LVODoIO(execptr) do i/o, wait for reply
MOVE.L d0,d5 save return code
NEG.L d5 convert rc to positive
* CLEAN UP AND RETURN
LEA Nardev(a3),a1 point to device structure
JSR _LVOCloseDevice(execptr) release device
broke3 LEA Narport(a3),a1 point to port
JSR _LVORemPort(execptr) delete the port
broke2 MOVE.L d6,d0 length of scratch area
MOVE.L a3,a1 addr of scratch area
JSR _LVOFreeMem(execptr) free scratch mem
broke1 MOVE.L d5,d0 set return code
endprog RTS ALL DONE!
************************************************************
CNOP 0,2
tranlib DC.B 'translator.library',0
CNOP 0,2
narname DC.B 'narrator.device',0
CNOP 0,2
audmaps DC.B 3,5,10,12 Audio device maps
*************************************************************
version DC.B 'MUMBLE V0.1 RAR' Imbedded version info
*************************************************************
STRUCTURE Scratch,0 Format of allocated scratch mem
STRUCT Narport,MP_SIZE Message reply port for narrator
STRUCT Nardev,NDI_SIZE Narrator IO block
LABEL scratchlen Length of scratch area less TRarea
STRUCT TRarea,0 xlat out buff (size computed dynamically)
END and there ain't no more
//E*O*F mumble.asm//
echo x - mumble.uue
cat > "mumble.uue" << '//E*O*F mumble.uue//'
begin 755 mumble
M```#\P`````````!``````````````!+```#Z0```$MZ`"@`9P``ZB8(+'@`^
M!'H+Y8`&@````&@L`"(\``$``4ZN_SHF0&<``,9Z#$/Z`,1P`$ZN_=@J0&<`)
M`*P@0R`$0^L`:.6$(@1.K?_B(DU.KOYB(GP`````3J[^VB=``!!#ZP``3J[^0
MGGH-0?H`FG``0^L`(G(`3J[^1$J`9F!#ZP`B0>L``"-(``Y!^@"*(T@`.#-\&
M``0`/#-\`&X`,C-\`+0`,#-\`$``/C-\5K@`0#-\````-C-\````-#-\``,`&
M'"-$`"1!ZP!H(T@`*$ZN_C@J`$2%0^L`(DZN_CY#ZP``3J[^F"`&(DM.KO\NW
M(`5.=71R86YS;&%T;W(N;&EB<F%R>0``;F%R<F%T;W(N9&5V:6-E``,%"@Q-'
554U"3$4@5C`N,2!205(```````/RT
``
end
size 336
//E*O*F mumble.uue//
echo Possible errors detected by \'wc\' [hopefully none]:
temp=/tmp/shar$$
trap "rm -f $temp; exit" 0 1 2 3 15
cat > $temp <<\!!!
63 331 2294 cuckoo.rexx
5 28 152 timeto.rexx
3 25 109 sample.crontab
147 730 8084 mumble.asm
13 15 506 mumble.uue
231 1129 11145 total
!!!
wc cuckoo.rexx timeto.rexx sample.crontab mumble.asm mumble.uue | sed 's=[^ ]*/==' | diff -b $temp -
exit 0
--
UUCP: kim@amdahl.amdahl.com
or: {sun,decwrl,hplabs,pyramid,ihnp4,uunet,oliveb,cbosgd,ames}!amdahl!kim
DDD: 408-746-8462
USPS: Amdahl Corp. M/S 249, 1250 E. Arques Av, Sunnyvale, CA 94086
CIS: 76535,25
Technical Details
Message-ID:
<26223@amdahl.uts.amdahl.com>Path:
arc1-ca.pugleaf.net!utzoo!mnetor!uunet!lll-winken!lll-lcc!ames!oliveb!amdahl!kimShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!mnetor!uunet!lll-winken!lll-lcc!ames!oliveb!amdahl!kim From: kim@amdahl.uts.amdahl.com (Kim DeVaughn) Newsgroups: comp.sys.amiga.tech,comp.sys.amiga Subject: A small ARexx example, and other useful tidbits . . . Message-ID: <26223@amdahl.uts.amdahl.com> Date: 1 Apr 88 23:11:35 GMT Organization: Amdahl Corporation, Sunnyvale, CA 94086 Lines: 310 Keywords: Warning: also contains a small assembly language example!