home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel
/
CAROUSEL.cdr
/
mactosh
/
da
/
talkmoos.sit
/
MooseUnit.p
< prev
next >
Wrap
Text File
|
1987-04-01
|
16KB
|
285 lines
{ This file (unit) contains Pascal code to control the Talking Moose. }
{ Slight modification is necessary for the various Pascal environments. }
{ }
{ The Talking Moose Desk Accessory uses the "MacinTalk" speech driver. }
{ Of course, Pascal programmers could use MacinTalk commands to get speech, }
{ but the Talking Moose provides all of MacinTalk's commands, plus some }
{ extra features, so I believe it's an improvement. If the Talking Moose }
{ desk accessory is available, (and MacinTalk and Moose Phrases are present), }
{ then Pascal programs with added Moose code will work. }
{ Pascal Commands are described below: }
{ }
{ FUNCTION StartMoose(hide: boolean) : integer; }
{ This function installs the Talking Moose. Call it at the beginning }
{ of your program. (If the Moose was already installed before your }
{ program, no harm done.) If "hide" is TRUE, the Desk Accessory window }
{ won't be opened. The integer results returned are: 0=Installed OK, }
{ -1=Moose already installed, 1=No MacinTalk, 2=No Moose Phrases, }
{ 3=No SysHeap space, 4=other D.A. errors. }
{ Note: Although the Moose's internal tasks get installed, these tasks }
{ wait until the 1st NULL event in your main event loop before finishing }
{ the "SpeechOn" process: ie opening ResFiles and the .SPEECH driver. }
{ }
{ FUNCTION CallReader( s : Str255; h : Handle) : integer; }
{ This function provides the equivalent of MacinTalk's "Reader". The }
{ "s" input text is translated into Phonemes, and placed into the "h" }
{ output handle. The handle is resized to the proper size, and }
{ thus should be created previously with MyPhonemes := NewHandle( 0 ); }
{ The function result is 0 if no error occurred. }
{ Note: The Moose must be "fully" installed, thus if you want to call this }
{ function during initialization, a prior "CallMooseToSpeak" is necesary. }
{ }
{ FUNCTION GetMoose( VAR m: MoosePtr) : boolean; }
{ This function returns TRUE if the Moose is installed. If TRUE, the }
{ MoosePtr is returned as a pointer to the Moose's global variables. (See }
{ the definition of a "MooseRec" below) Changing the Moose's variables is }
{ how you: Make the Moose talk, Change Pitch,Rate, etc. Plus lots more... }
{ }
{ Consider these code fragments showing how to use that MoosePtr. }
{ IF GetMoose( MyMoosePtr ) THEN }
{ BEGIN }
{ MyMoosePtr^.Rate := 160; "Change the Rate. 85 thru 425" }
{ MyMoosePtr^.Pitch := 130; "Change Pitch. 65 thru 500" }
{ MyMoosePtr^.Delay := 6000; "Increase speaking delay" }
{ MyMoosePtr^.Animate := 0; "Turn OFF animation. 1=ON." }
{ MyMoosePtr^.MoosFlags := MyMoosePtr^.MoosFlags - PauseMask; }
{ END; }
{ Notes: You should change the Rate,Pitch,Robotic settings only in the }
{ the initialization part of your program, after StartMoose but before }
{ the main event loop. The Delay, Animate,Inter,MoosFlags,Enable settings }
{ can be changed anytime. MoosFlags are bits allowing you to selectively }
{ turn off Moose functions. (If you turn flags OFF, turn them back ON when }
{ your program exits.) }
{ }
{ IF GetMoose( MyMoosePtr ) THEN }
{ BEGIN }
{ MyMoosePtr^.NowHandle := MyPhonemes; "Handle holding phonemes" }
{ MyMoosePtr^.NowID := 1988; "Res ID of 'STR#' with phrases" }
{ MyMoosePtr^.NowNum := 2; "Use 2nd string from above 'STR#'" }
{ MyMoosePtr^.SayCode := 1; "1=Speak Time, 2=Say GoodBye," }
{ "3=Say Switch Disks, 4=Say Hello" }
{ END; }
{ Notes: This section shows 3 possible ways to make the Moose speak. You }
{ can give it a handle holding phonemes, OR, you can give it a 'STR#' ID }
{ and number, OR, you can give it a "Code". Then, your program should }
{ just return to it's main event loop, because the Moose will wait until }
{ there are no more events before speaking what you told it. If there }
{ was a previous "NowHandle" there, your program should _DisposHandle }
{ it before storing a new handle there. (Or it could add the new phonemes }
{ onto the end of the old.) The Moose will dispose of the handle once }
{ it's finished speaking it. }
{ }
{ PROCEDURE CallMooseToSpeak; }
{ After you have stored a "NowHandle","SayCode", or NowID&Num, there }
{ may be situations where you want the Moose to speak it right away, }
{ instead of waiting for the main event loop. This routine gives the }
{ Moose a chance to talk right away, by convincing the Moose that there }
{ are only NULL events occurring. Another place to use this procedure is }
{ after "StartMoose", (before the main event loop) to force the Moose }
{ to fully prepare for speaking. }
{ }
{ A good convenient way to add optional speech into your programs is to use }
{ a sample procedure like this: (referencing strings in a STR# resource) }
{ PROCEDURE SpeakPhrase( sID: integer; sNum: integer ); }
{ VAR }
{ m : MoosePtr; }
{ BEGIN }
{ IF GetMoose(m) THEN "If the Moose is installed" }
{ IF (m^.Enable=1) THEN "and if the Moose is enabled" }
{ BEGIN "then tell it to speak a string" }
{ m^.NowNum := sNum; "from a STR# resource." }
{ m^.NowID := sID; }
{ END; }
{ END; }
UNIT MooseUnit;
INTERFACE
{ Different USES are needed for different implementations. }
{ Needed to define things like "Str255","Handle","Ptr", etc }
{ plus defines Toolbox Traps and parameters. }
{ USES macintf (I think...?) Uses for TML }
{ No USES needed for LightSpeed, but the Moose competes for memory }
USES Memtypes, Quickdraw, OSIntf, ToolIntf; { Uses for MPW }
CONST
VblQueue = $0160; { Vertical Retrace tasks Queue header. }
ApplScratch = $0A78; { Location of temporary global storage. }
PauseMask = $00000001; { Flag turns on Pause messages. }
DSMask = $00000002; { Flag turns on Disk-Switch messages. }
ErrorMask = $00000004; { Flag turns on Error messages. }
AlarmMask = $00000008; { Flag turns on Alarm clock checking. }
GZMask = $00000010; { Flag turns on GrowZone shut-off Moose. }
{ Initially, all flags are 1 = ON. }
TYPE
SigType = PACKED ARRAY [1..4] OF CHAR;
MoosePtr = ^MooseRec;
MooseRec = RECORD { This record is an extension of a }
qLink : MoosePtr; { VBL queue element, with stuff added }
qType : Integer; { onto the end. The Moose stores its }
vblAddr : Ptr; { globals in a VBL queue element. }
vblCount : Integer; { Most of these shouldn't be changed. }
vblPhase : Integer;
Sig : SigType; { Signature of Moose VBL. 'TALK' }
Rate : integer; { MacinTalk speaking rate. }
Pitch : integer; { MacinTalk speaking pitch. }
Delay : integer; { Ticks between Pause messages. }
Robot : integer; { Robotic setting. 1=ON, 0=OFF. }
Enable : integer; { Talking Mac 1=ON, 0=OFF. }
Animate : integer; { Animation 1=ON, 0=OFF. }
TheSpeech : Handle; { MacinTalk's theSpeech data. }
Error : integer; { Error code. }
mRect1 : longint; { Rectangle of D.A. window. 1st half }
mRect2 : longint; { Rectangle of D.A. window. 2nd half }
NowID : integer; { STR# ID holding phrase to be spoken.}
NowNum : integer; { STR# phrase number to be spoken. }
TurnOnNum : integer; { Current "Please turn on" message. }
TurnOnMax : integer; { Max "TurnOn" messages available. }
TurnOffNum : integer; { Current "Please turn off" message. }
TurnOffMax : integer; { Max "TurnOff" messages available. }
NowHandle : handle; { Handle to phonemes to be spoken. }
SayCode : integer; { Code for internal phrases. }
PauseNum : integer; { Current "Pause" message. }
PauseMax : integer; { Max "Pause" messages available. }
Inter : integer; { Quick Stop 1=ON, 0=OFF. }
ByeNum : integer; { Current "Goodbye" message. }
ByeMax : integer; { Max "GoodBye" messages available. }
SwtchNum : integer; { Current "Switch disks" message. }
SwtchMax : integer; { Max "switch" messages available. }
HelloNum : integer; { Current "Hello" message. }
HelloMax : integer; { Max "Hello" messages available. }
DoReader : Ptr; { Ptr to routine to translate text. }
PhonemeErr : integer; { Character where phoneme error found.}
DoMoose : Ptr; { Ptr to routine to wait to speak. }
SpeechErr : integer; { MacinTalk error code. }
MoosFlags : longint; { Flags (bits) controlling Moose. }
BuryFlag : integer; { Flag to not bury files for Switcher }
SpOnFlag : integer; { Flag if internal "SpeechOn" needed. }
END;
FUNCTION StartMoose (hide : boolean) : integer;
FUNCTION GetMoose (VAR m : MoosePtr): boolean;
FUNCTION CallReader (s : Str255; h : Handle) : integer;
FUNCTION CallReader1(s : Str255; h : Handle; m : MoosePtr) : integer;
PROCEDURE CallMooseToSpeak;
PROCEDURE CallMoose1 (m : MoosePtr);
IMPLEMENTATION
{ These INLINE routines jump directly into Moose code... }
PROCEDURE Jump1 (addr : ProcPtr);
INLINE
$205F, { MOVE.L (SP)+,A0 }
$4E90; { JSR (A0) }
FUNCTION Jump2(h1:handle;t:Ptr;i:longint;h2:handle;addr:ProcPtr):INTEGER;
INLINE
$205F, { MOVE.L (SP)+,A0 }
$4E90; { JSR (A0) }
{ This routine searches the VBL queue until it finds an entry that has the }
{ Moose's signature, and returns a pointer to that entry. That VBL entry }
{ contains all the important Moose globals. }
FUNCTION GetMoose;
VAR
flag : boolean;
BEGIN
m := pointer(Ord4(VblQueue + 2)); { This tricky line gets the 1st }
m := m^.qLink; { entry in the VBL queue. }
flag := FALSE;
WHILE (m <> NIL) AND (flag = FALSE) DO
BEGIN
IF m^.Sig = 'TALK' THEN flag := TRUE
ELSE m := m^.qLink;
END;
GetMoose := flag;
END;
{ This routine will install the Talking Moose. If "hide" is TRUE, then the }
{ Desk Accessory window will not be opened. }
{ Returned values are: 0=ok, -1=Also ok, Moose was previously installed. }
{ 1=No MacinTalk, 2=No Moose Phrases, 3=No Sys Space, 4=Cant open D.A. }
FUNCTION StartMoose;
VAR
i : integer; { OpenDeskAcc return code, ignored. }
name : Str255;
newApplScratchPtr : ^SigType;
origApplScratch : SigType; { Save original ApplScratch value. }
codeApplScratch : longint; { Recover Moose return codes. }
AmoosPtr : MoosePtr;
BEGIN
StartMoose := -1; { Default return code. Moose already installed }
name := concat(' ','Talking Moose'); { Put a leading NULL }
name[1] := chr(0); { in front of the name.}
newApplScratchPtr := pointer(ord4(ApplScratch));
origApplScratch := newApplScratchPtr^;
newApplScratchPtr^ := 'Norm';
IF NOT GetMoose(AmoosPtr) THEN StartMoose := 0;
IF hide = TRUE THEN
BEGIN
newApplScratchPtr^ := 'Hide';
CloseDeskAcc(OpenDeskAcc(name));
END
ELSE i := OpenDeskAcc(name);
codeApplScratch := longint(ord4(ApplScratch));
IF ((SigType(codeApplScratch) = 'Norm')
OR ( SigType(codeApplScratch) = 'Hide')) THEN
StartMoose := 5
ELSE IF (LoWord(codeApplScratch) <> 0) THEN
StartMoose := HiWord(codeApplScratch);
newApplScratchPtr^ := origApplScratch;
END;
{ Arrive with s = Str255 holding string to convert. Put it in h=Handle. }
FUNCTION CallReader; { Routine to convert English into phonemes. }
VAR
m : MoosePtr;
BEGIN
IF GetMoose(m) THEN
CallReader := CallReader1(s, h, m);
END;
FUNCTION CallReader1;
VAR
t : Ptr;
i : longint;
BEGIN
t := pointer(ord4(@s) + 1); { t = Point past the length byte. }
i := length(s); { i = length of string to convert. }
CallReader1 := Jump2(m^.TheSpeech, t, i, h, m^.DoReader);
END;
{ Routine to force the Moose to speak immediately . }
PROCEDURE CallMooseToSpeak;
VAR
m : MoosePtr;
BEGIN
IF GetMoose(m) THEN CallMoose1(m);
END;
PROCEDURE CallMoose1;
BEGIN
Jump1(m^.DoMoose);
END;
END.