home *** CD-ROM | disk | FTP | other *** search
/ Carousel / CAROUSEL.cdr / mactosh / da / talkmoos.sit / MooseUnit.p < prev    next >
Text File  |  1987-04-01  |  16KB  |  285 lines

  1. { This file (unit) contains Pascal code to control the Talking Moose.         }
  2. { Slight modification is necessary for the various Pascal environments.       }
  3. {                                                                             }
  4. {      The Talking Moose Desk Accessory uses the "MacinTalk" speech driver.   }
  5. { Of course, Pascal programmers could use MacinTalk commands to get speech,   }
  6. { but the Talking Moose provides all of MacinTalk's commands,  plus some      }
  7. { extra features, so I believe it's an improvement.  If the Talking Moose     }
  8. { desk accessory is available, (and MacinTalk and Moose Phrases are present), }
  9. { then Pascal programs with added Moose code will work.                       }
  10. { Pascal Commands are described below:                                        }
  11. {                                                                             }
  12. {  FUNCTION StartMoose(hide: boolean) : integer;                              }
  13. {    This function installs the Talking Moose.  Call it at the beginning      }
  14. {    of your program.  (If the Moose was already installed before your        }
  15. {    program, no harm done.)   If "hide" is TRUE, the Desk Accessory window   }
  16. {    won't be opened.  The integer results returned are: 0=Installed OK,      }
  17. {    -1=Moose already installed, 1=No MacinTalk, 2=No Moose Phrases,          }
  18. {    3=No SysHeap space,  4=other D.A. errors.                                }
  19. {    Note:  Although the Moose's internal tasks get installed, these tasks    }
  20. {    wait until the 1st NULL event in your main event loop before finishing   }
  21. {    the "SpeechOn" process: ie opening ResFiles and the .SPEECH driver.      }
  22. {                                                                             }
  23. {  FUNCTION CallReader( s : Str255; h : Handle) : integer;                    }
  24. {    This function provides the equivalent of MacinTalk's "Reader".  The      }
  25. {    "s" input text is translated into Phonemes, and placed into the "h"      }
  26. {    output handle.  The handle is resized to the proper size,  and           }
  27. {    thus should be created previously with MyPhonemes := NewHandle( 0 );     }
  28. {    The function result is 0 if no error occurred.                           }
  29. {    Note: The Moose must be "fully" installed, thus if you want to call this }
  30. {    function during initialization, a prior "CallMooseToSpeak" is necesary.  }
  31. {                                                                             }
  32. {  FUNCTION GetMoose( VAR m: MoosePtr) : boolean;                             }
  33. {    This function returns TRUE if the Moose is installed.  If TRUE, the      }
  34. {    MoosePtr is returned as a pointer to the Moose's global variables. (See  }
  35. {    the definition of a "MooseRec" below)  Changing the Moose's variables is }
  36. {    how you: Make the Moose talk, Change Pitch,Rate, etc.  Plus lots more... }
  37. {                                                                             }
  38. {    Consider these code fragments showing how to use that MoosePtr.          }
  39. {    IF GetMoose( MyMoosePtr ) THEN                                           }
  40. {        BEGIN                                                                }
  41. {            MyMoosePtr^.Rate  :=  160;     "Change the Rate.   85 thru 425"  }
  42. {            MyMoosePtr^.Pitch :=  130;     "Change Pitch.  65 thru 500"      }
  43. {            MyMoosePtr^.Delay := 6000;     "Increase speaking delay"         }
  44. {            MyMoosePtr^.Animate := 0;      "Turn OFF animation.  1=ON."      }
  45. {            MyMoosePtr^.MoosFlags := MyMoosePtr^.MoosFlags - PauseMask;      }
  46. {        END;                                                                 }
  47. {    Notes:   You should change the Rate,Pitch,Robotic settings only in the   }
  48. {    the initialization part of your program, after StartMoose but before     }
  49. {    the main event loop.  The Delay, Animate,Inter,MoosFlags,Enable settings }
  50. {    can be changed anytime.  MoosFlags are bits allowing you to selectively  }
  51. {    turn off Moose functions. (If you turn flags OFF, turn them back ON when }
  52. {    your program exits.)                                                     }
  53. {                                                                             }
  54. {    IF GetMoose( MyMoosePtr ) THEN                                           }
  55. {        BEGIN                                                                }
  56. {            MyMoosePtr^.NowHandle := MyPhonemes;  "Handle holding phonemes"  }
  57. {            MyMoosePtr^.NowID  := 1988;     "Res ID of 'STR#' with phrases"  }
  58. {            MyMoosePtr^.NowNum := 2;     "Use 2nd string from above 'STR#'"  }
  59. {            MyMoosePtr^.SayCode  := 1;     "1=Speak Time,   2=Say GoodBye,"  }
  60. {                                         "3=Say Switch Disks,  4=Say Hello"  }
  61. {        END;                                                                 }
  62. {    Notes:  This section shows 3 possible ways to make the Moose speak. You  }
  63. {    can give it a handle holding phonemes, OR,  you can give it a 'STR#' ID  }
  64. {    and number,   OR,  you can give it a "Code".  Then, your program should  }
  65. {    just return to it's main event loop,  because the Moose will wait until  }
  66. {    there are no more events before speaking what you told it.   If there    }
  67. {    was a previous "NowHandle" there,  your program should _DisposHandle     }
  68. {    it before storing a new handle there. (Or it could add the new phonemes  }
  69. {    onto the end of the old.)  The Moose will dispose of the handle once     }
  70. {    it's finished speaking it.                                               }
  71. {                                                                             }
  72. {  PROCEDURE CallMooseToSpeak;                                                }
  73. {     After you have stored a "NowHandle","SayCode", or NowID&Num,  there     }
  74. {     may be situations where you want the Moose to speak it right away,      }
  75. {     instead of waiting for the main event loop.  This routine gives the     }
  76. {     Moose a chance to talk right away, by convincing the Moose that there   }
  77. {     are only NULL events occurring.  Another place to use this procedure is }
  78. {     after "StartMoose", (before the main event loop) to force the Moose     }
  79. {     to fully prepare for speaking.                                          }
  80. {                                                                             }
  81. {  A good convenient way to add optional speech into your programs is to use  }
  82. {  a sample procedure like this:   (referencing strings in a STR# resource)   }
  83. {  PROCEDURE SpeakPhrase( sID: integer; sNum: integer );                      }
  84. {     VAR                                                                     }
  85. {          m : MoosePtr;                                                      }
  86. {  BEGIN                                                                      }
  87. {       IF GetMoose(m) THEN             "If the Moose is installed"           }
  88. {           IF (m^.Enable=1) THEN       "and if the Moose is enabled"         }
  89. {               BEGIN                   "then tell it to speak a string"      }
  90. {                   m^.NowNum := sNum;  "from a STR# resource."               }
  91. {                   m^.NowID  := sID;                                         }
  92. {               END;                                                          }
  93. {  END;                                                                       }
  94.  
  95.  
  96.  
  97. UNIT MooseUnit;
  98.  
  99. INTERFACE
  100.  
  101.   {  Different USES are needed for different implementations.         }
  102.   {  Needed to define things like "Str255","Handle","Ptr", etc        }
  103.   {  plus defines Toolbox Traps and parameters.                       }
  104.   {  USES macintf      (I think...?)            Uses for TML          }
  105.   {  No USES needed for LightSpeed, but the Moose competes for memory }
  106.  USES Memtypes, Quickdraw, OSIntf, ToolIntf;  { Uses for MPW          }
  107.  
  108.     CONST
  109.         VblQueue    = $0160;      { Vertical Retrace tasks Queue header.   }
  110.         ApplScratch = $0A78;      { Location of temporary global storage.  }
  111.         PauseMask   = $00000001;  { Flag turns on Pause messages.          }
  112.         DSMask      = $00000002;  { Flag turns on Disk-Switch messages.    }
  113.         ErrorMask   = $00000004;  { Flag turns on Error messages.          }
  114.         AlarmMask   = $00000008;  { Flag turns on Alarm clock checking.    }
  115.         GZMask      = $00000010;  { Flag turns on GrowZone shut-off Moose. }
  116.                                      { Initially, all flags are 1 = ON.       }
  117.  
  118.  
  119.     TYPE
  120.         SigType = PACKED ARRAY [1..4] OF CHAR;
  121.         MoosePtr = ^MooseRec;
  122.         MooseRec = RECORD               { This record is an extension of a    }
  123.                 qLink : MoosePtr;       { VBL queue element, with stuff added }
  124.                 qType : Integer;        { onto the end.  The Moose stores its }
  125.                 vblAddr : Ptr;          { globals in a VBL queue element.     }
  126.                 vblCount : Integer;     { Most of these shouldn't be changed. }
  127.                 vblPhase : Integer;
  128.                 Sig : SigType;          { Signature of Moose VBL. 'TALK'      }
  129.                 Rate : integer;         { MacinTalk speaking rate.            }
  130.                 Pitch : integer;        { MacinTalk speaking pitch.           }
  131.                 Delay : integer;        { Ticks between Pause messages.       }
  132.                 Robot : integer;        { Robotic setting. 1=ON, 0=OFF.       }
  133.                 Enable : integer;       { Talking Mac      1=ON, 0=OFF.       }
  134.                 Animate : integer;      { Animation        1=ON, 0=OFF.       }
  135.                 TheSpeech : Handle;     { MacinTalk's theSpeech data.         }
  136.                 Error : integer;        { Error code.                         }
  137.                 mRect1 : longint;       { Rectangle of D.A. window. 1st half  }
  138.                 mRect2 : longint;       { Rectangle of D.A. window. 2nd half  }
  139.                 NowID : integer;        { STR# ID holding phrase to be spoken.}
  140.                 NowNum : integer;       { STR# phrase number to be spoken.    }
  141.                 TurnOnNum : integer;    { Current "Please turn on" message.   }
  142.                 TurnOnMax : integer;    { Max "TurnOn" messages available.    }
  143.                 TurnOffNum : integer;   { Current "Please turn off" message.  }
  144.                 TurnOffMax : integer;   { Max "TurnOff" messages available.   }
  145.                 NowHandle : handle;     { Handle to phonemes to be spoken.    }
  146.                 SayCode : integer;      { Code for internal phrases.          }
  147.                 PauseNum : integer;     { Current "Pause" message.            }
  148.                 PauseMax : integer;     { Max "Pause" messages available.     }
  149.                 Inter : integer;        { Quick Stop       1=ON, 0=OFF.       }
  150.                 ByeNum : integer;       { Current "Goodbye" message.          }
  151.                 ByeMax : integer;       { Max "GoodBye" messages available.   }
  152.                 SwtchNum : integer;     { Current "Switch disks" message.     }
  153.                 SwtchMax : integer;     { Max "switch" messages available.    }
  154.                 HelloNum : integer;     { Current "Hello" message.            }
  155.                 HelloMax : integer;     { Max "Hello" messages available.     }
  156.                 DoReader : Ptr;         { Ptr to routine to translate text.   }
  157.                 PhonemeErr : integer;   { Character where phoneme error found.}
  158.                 DoMoose : Ptr;          { Ptr to routine to wait to speak.    }
  159.                 SpeechErr : integer;    { MacinTalk error code.               }
  160.                 MoosFlags : longint;    { Flags (bits) controlling Moose.     }
  161.                 BuryFlag : integer;     { Flag to not bury files for Switcher }
  162.                 SpOnFlag : integer;     { Flag if internal "SpeechOn" needed. }
  163.            END;
  164.  
  165.     FUNCTION  StartMoose (hide : boolean) : integer;
  166.     FUNCTION  GetMoose (VAR m : MoosePtr): boolean;
  167.     FUNCTION  CallReader (s : Str255; h : Handle) : integer;
  168.     FUNCTION  CallReader1(s : Str255; h : Handle; m : MoosePtr) : integer;
  169.     PROCEDURE CallMooseToSpeak;
  170.     PROCEDURE CallMoose1 (m : MoosePtr);
  171.  
  172.  
  173. IMPLEMENTATION
  174.  
  175.     { These INLINE routines jump directly into Moose code... }
  176.     PROCEDURE Jump1 (addr : ProcPtr);
  177.     INLINE
  178.         $205F,  { MOVE.L (SP)+,A0 }
  179.         $4E90;  { JSR    (A0)     }
  180.  
  181.     FUNCTION Jump2(h1:handle;t:Ptr;i:longint;h2:handle;addr:ProcPtr):INTEGER;
  182.     INLINE
  183.         $205F,  { MOVE.L (SP)+,A0 }
  184.         $4E90;  { JSR    (A0)     }
  185.  
  186.  
  187.  
  188.  
  189. { This routine searches the VBL queue until it finds an entry that has the }
  190. { Moose's signature, and returns a pointer to that entry.  That VBL entry  }
  191. { contains all the important Moose globals.                                }
  192.     FUNCTION GetMoose;
  193.         VAR
  194.              flag : boolean;
  195.     BEGIN
  196.         m := pointer(Ord4(VblQueue + 2)); { This tricky line gets the 1st }
  197.         m := m^.qLink;                    { entry in the VBL queue.       }
  198.  
  199.         flag := FALSE;
  200.         WHILE (m <> NIL) AND (flag = FALSE) DO
  201.             BEGIN
  202.                 IF m^.Sig = 'TALK' THEN  flag := TRUE
  203.                 ELSE m := m^.qLink;
  204.             END;
  205.         GetMoose := flag;
  206.     END;
  207.  
  208.  
  209.  
  210.  
  211. { This routine will install the Talking Moose.  If "hide" is TRUE, then the }
  212. { Desk Accessory window will not be opened.                                 }
  213. { Returned values are: 0=ok,  -1=Also ok, Moose was previously installed.   }
  214. {  1=No MacinTalk,  2=No Moose Phrases,  3=No Sys Space,  4=Cant open D.A.  }
  215.    FUNCTION StartMoose;
  216.         VAR
  217.             i : integer;                { OpenDeskAcc return code, ignored. }
  218.             name : Str255;
  219.             newApplScratchPtr : ^SigType;
  220.             origApplScratch : SigType;   { Save original ApplScratch value. }
  221.             codeApplScratch : longint;   { Recover Moose return codes.      }
  222.             AmoosPtr : MoosePtr;
  223.     BEGIN
  224.         StartMoose := -1;      { Default return code. Moose already installed }
  225.         name := concat(' ','Talking Moose');           { Put a leading NULL   }
  226.         name[1] := chr(0);                             { in front of the name.}
  227.         newApplScratchPtr := pointer(ord4(ApplScratch));
  228.         origApplScratch := newApplScratchPtr^;
  229.         newApplScratchPtr^ := 'Norm';
  230.  
  231.         IF NOT GetMoose(AmoosPtr) THEN StartMoose := 0;
  232.  
  233.         IF hide = TRUE THEN
  234.             BEGIN
  235.                 newApplScratchPtr^ := 'Hide';
  236.                 CloseDeskAcc(OpenDeskAcc(name));
  237.             END
  238.         ELSE i := OpenDeskAcc(name);
  239.  
  240.         codeApplScratch := longint(ord4(ApplScratch));
  241.         IF ((SigType(codeApplScratch) = 'Norm') 
  242.         OR ( SigType(codeApplScratch) = 'Hide')) THEN
  243.             StartMoose := 5
  244.         ELSE IF (LoWord(codeApplScratch) <> 0) THEN
  245.             StartMoose := HiWord(codeApplScratch);
  246.  
  247.         newApplScratchPtr^ := origApplScratch;
  248.     END;
  249.  
  250.  
  251. { Arrive with s = Str255 holding string to convert. Put it in h=Handle.  }
  252.     FUNCTION CallReader; { Routine to convert English into phonemes. }
  253.         VAR
  254.              m : MoosePtr;
  255.     BEGIN
  256.         IF GetMoose(m) THEN
  257.             CallReader := CallReader1(s, h, m);
  258.     END;
  259.  
  260.     FUNCTION CallReader1;
  261.         VAR
  262.             t : Ptr;
  263.             i : longint;
  264.     BEGIN
  265.         t := pointer(ord4(@s) + 1);  { t = Point past the length byte.  }
  266.         i := length(s);              { i = length of string to convert. }
  267.         CallReader1 := Jump2(m^.TheSpeech, t, i, h, m^.DoReader);
  268.     END;
  269.  
  270.  
  271.  
  272. { Routine to force the Moose to speak immediately . }
  273.     PROCEDURE CallMooseToSpeak;
  274.         VAR
  275.             m : MoosePtr;
  276.     BEGIN
  277.         IF GetMoose(m) THEN CallMoose1(m);
  278.     END;
  279.  
  280.     PROCEDURE CallMoose1;
  281.     BEGIN
  282.         Jump1(m^.DoMoose);
  283.     END;
  284.  
  285. END.