home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 1.2 / amidev_cd_12.iso / reference_library / devices / dev_examples / full_narrator.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-20  |  16.6 KB  |  568 lines

  1. /*
  2.  * Full_Narrator.c
  3.  *
  4.  * This example program sends a string of phonetic text to the narrator
  5.  * device and, while it is speaking, highlights, word-by-word, a
  6.  * corresponding English string.  In addition, mouth movements are drawn
  7.  * in a separate window.
  8.  *
  9.  * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
  10.  *
  11.  * Requires Kickstart V37 or greater.
  12.  */
  13.  
  14. #include <exec/types.h>
  15. #include <exec/memory.h>
  16. #include <dos/dos.h>
  17. #include <intuition/intuition.h>
  18. #include <ctype.h>
  19. #include <exec/exec.h>
  20. #include <fcntl.h>
  21. #include <devices/narrator.h>
  22.  
  23. #include <clib/exec_protos.h>
  24. #include <clib/alib_protos.h>
  25. #include <clib/intuition_protos.h>
  26. #include <clib/graphics_protos.h>
  27. #include <clib/dos_protos.h>
  28.  
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <stdio.h>
  32.  
  33. #ifdef LATTICE
  34. int CXBRK(void) { return(0); }     /* Disable SAS CTRL/C handling */
  35. int chkabort(void) { return(0); }  /* really */
  36. #endif
  37.  
  38.  
  39. /*
  40.  *  Due to an omission, the sync field defines were not included in older
  41.  *  versions of the narrator device include files.  So, if they haven't
  42.  *  already been defined, do so now.
  43.  */
  44.  
  45. #ifndef NDF_READMOUTH                        /* Already defined ? */
  46. #define NDF_READMOUTH   0x01                 /* No, define here   */
  47. #define NDF_READWORD    0x02
  48. #define NDF_READSYL     0x04
  49. #endif
  50.  
  51. #define PEN3    3                            /* Drawing pens */
  52. #define PEN2    2
  53. #define PEN1    1
  54. #define PEN0    0
  55.  
  56.  
  57. BOOL FromCLI = TRUE;
  58. BYTE chans[4] = {3, 5, 10, 12};
  59.  
  60.  
  61. LONG EyesLeft;                               /* Left edge of left eye     */
  62. LONG EyesTop;                                /* Top of eyes box           */
  63. LONG EyesBottom;                             /* Bottom of eyes box        */
  64. LONG YMouthCenter;                           /* Pixels from top edge      */
  65. LONG XMouthCenter;                           /* Pixels from left edge     */
  66. LONG LipWidth, LipHeight;                    /* Width and height of mouth */
  67.  
  68.  
  69. struct TextAttr MyFont = {"topaz.font", TOPAZ_SIXTY, FS_NORMAL, FPF_ROMFONT,};
  70.  
  71. struct  IntuitionBase   *IntuitionBase = NULL;
  72. struct  GfxBase         *GfxBase = NULL;
  73.  
  74. struct  MsgPort         *VoicePort = NULL;
  75. struct  MsgPort         *MouthPort = NULL;
  76.  
  77. struct  narrator_rb     *VoiceIO = NULL;
  78. struct  mouth_rb        *MouthIO = NULL;
  79.  
  80. struct  IntuiText  HighLight;
  81. struct  NewWindow  NewWindow;
  82. struct  Window    *TextWindow;
  83. struct  Window    *FaceWindow;
  84. struct  RastPort  *FaceRast;
  85.  
  86.  
  87. void main(int argc, char **argv)
  88. {
  89. LONG     i;
  90. LONG     sentence;
  91. LONG     Offset;
  92. LONG     CharsLeft;
  93. LONG     ScreenPos;
  94. LONG     WordLength;
  95. LONG     LineNum;
  96. UBYTE    *Tempptr;
  97. UBYTE    *English;
  98. UBYTE    *OldEnglish;
  99. UBYTE     c;
  100.  
  101. UBYTE    *PhonPtr;              /* Pointer to phonetic text     */
  102. LONG     PhonSize;              /* Size of phonetic text        */
  103. UBYTE    *PhonStart[100];       /* Start of phonetic sentences  */
  104. LONG     NumPhonStarts;         /* Number of phonetic sentences */
  105.  
  106. UBYTE    *EngPtr;               /* Pointer to English text      */
  107. LONG     EngSize;               /* Size of English text         */
  108. UBYTE    *EngStart[100];        /* Start of English sentences   */
  109. LONG     NumEngStarts;          /* Number of English sentences  */
  110.  
  111. UBYTE    *EngLine[24];          /* Start of line on screen      */
  112. LONG     EngBytes[24];          /* Bytes per line on screen     */
  113. LONG     NumEngLines;           /* Number of lines on screen    */
  114.  
  115.  
  116. extern  void  Cleanup(UBYTE *errmsg);
  117. extern  void  ClearWindow(struct Window *TextWindow);
  118. extern  void  DrawFace(void);
  119. extern  void  UpdateFace(void);
  120.  
  121.  
  122. /*
  123.  *  (0)   Note whether the program was started from the CLI or from
  124.  *        Workbench.
  125.  */
  126.  
  127. if (argc == 0)
  128.     FromCLI = FALSE;
  129.  
  130. /*
  131.  *  (1)   Setup the phonetic text to be spoken.  If there are any non-
  132.  *        alphabetic characters in the text (such as NEWLINES or TABS)
  133.  *        replace them with spaces.  Then break up the text into sentences,
  134.  *        storing the start of each sentence in PhonStart array elements.
  135.  */
  136.  
  137. PhonPtr = "KAA1RDIYOWMAYAA5PAXTHIY.  AY /HAED NEH1VER /HER4D AXV IHT "
  138.           "BIXFOH5R, BAHT DHEH5R IHT WAHZ - LIH4STIXD AEZ (DHAX FOH5RM "
  139.           "AXV /HAA5RT DIHZIY5Z) DHAET FEH4LD (NAAT WAH5N OHR TUW5) - "
  140.           "BAHT (AO7L THRIY5 AXV DHAX AA5RTAXFIHSHUL /HAA5RTQ "
  141.           "RIXSIH5PIYINTS).  (AH LIH5TUL RIXSER5CH) PROHDUW5ST (SAHM "
  142.           "IH5NTRIHSTIHNX RIXZAH5LTS). AHKOH5RDIHNX TUW (AEN AA5RTIHKUL "
  143.           "IHN DHAX NOWVEH5MBER EY2THQX NAY5NTIYNEYTIYFOH1R NUW IY5NXGLIND "
  144.           "JER5NUL AXV MEH5DIXSIN), (SIH5GEREHT SMOW5KIHNX) KAO4ZIHZ "
  145.           "(DHIHS LIY5THUL DIHZIY5Z) DHAET WIY4KINZ (DHAX /HAA5RTS "
  146.           "PAH4MPIHNX PAW2ER).  WAYL (DHIY IHGZAE5KT MEH5KINIXZUM) IHZ "
  147.           "NAAT KLIY5R, DAA5KTER AA5RTHER JEY2 /HAARTS SPEH5KYULEYTIHD "
  148.           "DHAET NIH4KAXTIY2N- OHR KAA5RBIN MUNAA5KSAYD IHN DHAX SMOW5K- "
  149.           "SAH5M/HAW1 POY4ZINZ DHAX /HAA5RT, AEND LIY4DZ TUW (/HAA5RT "
  150.           "FEY5LYER).";
  151.  
  152. PhonSize = strlen(PhonPtr);
  153. NumPhonStarts = 0;
  154. PhonStart[NumPhonStarts++] = PhonPtr;
  155. for (i = 0;  i < PhonSize;  ++i)
  156.      {
  157.      if (isspace((int)(c = *PhonPtr++)))
  158.          *(PhonPtr-1) = ' ';
  159.      if ((c == '.') || (c == '?'))
  160.          {
  161.          *PhonPtr = '\0';
  162.          PhonStart[NumPhonStarts++] = ++PhonPtr;
  163.          }
  164.      }
  165.  
  166. /*
  167.  *  (2)  Create the English text corresponding to the phonetic text above.
  168.  *       As before, insure that there are no TABS or NEWLINES in the text.
  169.  *       Break the text up into sentences and store the start of each
  170.  *       sentence in EngStart array elements.
  171.  */
  172. EngPtr = "Cardiomyopathy. I had never heard of it before, but there it was "
  173.          "listed as the form of heart disease that felled not one or two but "
  174.          "all three of the artificial heart recipients. A little research "
  175.          "produced some interesting results. According to an article in the "
  176.          "November 8, 1984, New England Journal of Medicine, cigarette smoking "
  177.          "causes this lethal disease that weakens the heart's pumping power.   "
  178.          "While the exact mechanism is not clear, Doctor Arthur J Hartz "
  179.          "speculated that nicotine or carbon monoxide in the smoke somehow "
  180.          "poisons the heart and leads to heart failure.";
  181.  
  182. EngSize = strlen(EngPtr);
  183. NumEngStarts = 0;
  184. EngStart[NumEngStarts++] = EngPtr;
  185. for (i = 0;  i < EngSize;  ++i)
  186.      {
  187.      if (isspace((int)(c = *EngPtr++)))
  188.          *(EngPtr-1) = ' ';
  189.      if ((c == '.') || (c == '?'))
  190.          {
  191.          *EngPtr = '\0';
  192.          EngStart[NumEngStarts++] = ++EngPtr;
  193.          }
  194.      }
  195.  
  196. /*
  197.  *  (3)   Open Intuition and Graphics libraries.
  198.  */
  199.  
  200. if (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0)))
  201.     Cleanup("can't open intuition");
  202.  
  203. if ((GfxBase=(struct GfxBase *)OpenLibrary("graphics.library", 0)) == NULL)
  204.     Cleanup("can't open graphics");
  205.  
  206. /*
  207.  *  (4)   Setup the NewWindow structure for the text display and
  208.  *        open the text window.
  209.  */
  210. NewWindow.LeftEdge    = 20;
  211. NewWindow.TopEdge     = 100;
  212. NewWindow.Width       = 600;
  213. NewWindow.Height      = 80;
  214. NewWindow.DetailPen   = 0;
  215. NewWindow.BlockPen    = 1;
  216. NewWindow.Title       = " Narrator Demo ";
  217. NewWindow.Flags       = SMART_REFRESH | ACTIVATE | WINDOWDEPTH | WINDOWDRAG;
  218. NewWindow.IDCMPFlags  = NULL;
  219. NewWindow.Type        = WBENCHSCREEN;
  220. NewWindow.FirstGadget = NULL;
  221. NewWindow.CheckMark   = NULL;
  222. NewWindow.Screen      = NULL;
  223. NewWindow.BitMap      = NULL;
  224. NewWindow.MinWidth    = 600;
  225. NewWindow.MinHeight   = 80;
  226. NewWindow.MaxWidth    = 600;
  227. NewWindow.MaxHeight   = 80;
  228.  
  229. if ((TextWindow = (struct Window *)OpenWindow(&NewWindow)) == NULL)
  230.     Cleanup("Text window could not be opened");
  231.  
  232. /*
  233.  *  (4)   Setup the NewWindow structure for the face display, open the
  234.  *        window, cache the RastPort pointer, and draw the initial face.
  235.  */
  236.  
  237. NewWindow.LeftEdge    = 20;
  238. NewWindow.TopEdge     = 12;
  239. NewWindow.Width       = 120;
  240. NewWindow.Height      = 80;
  241. NewWindow.DetailPen   = 0;
  242. NewWindow.BlockPen    = 1;
  243. NewWindow.Title       = " Face ";
  244. NewWindow.Flags       = SMART_REFRESH | WINDOWDEPTH | WINDOWDRAG;
  245. NewWindow.IDCMPFlags  = NULL;
  246. NewWindow.Type        = WBENCHSCREEN;
  247. NewWindow.FirstGadget = NULL;
  248. NewWindow.CheckMark   = NULL;
  249. NewWindow.Screen      = NULL;
  250. NewWindow.BitMap      = NULL;
  251. NewWindow.MinWidth    = 120;
  252. NewWindow.MinHeight   = 80;
  253. NewWindow.MaxWidth    = 120;
  254. NewWindow.MaxHeight   = 80;
  255.  
  256. if ((FaceWindow = (struct Window *)OpenWindow(&NewWindow)) == NULL)
  257.     Cleanup("Face window could not be opened");
  258.  
  259. FaceRast = FaceWindow->RPort;
  260.  
  261. DrawFace();
  262.  
  263. /*
  264.  *  (5)   Create read and write msg ports.
  265.  */
  266.  
  267. if ((MouthPort = CreatePort(NULL,0)) == NULL)
  268.     Cleanup("Can't get read port");
  269. if ((VoicePort = CreatePort(NULL,0)) == NULL)
  270.     Cleanup("Can't get write port");
  271.  
  272. /*
  273.  *  (6)   Create read and write I/O request blocks.
  274.  */
  275.  
  276. if (!(MouthIO = (struct mouth_rb *)
  277.                   CreateExtIO(MouthPort,sizeof(struct mouth_rb))))
  278.     Cleanup("Can't get read IORB");
  279.  
  280. if (!(VoiceIO = (struct narrator_rb *)
  281.                    CreateExtIO(VoicePort,sizeof(struct narrator_rb))))
  282.     Cleanup("Can't get write IORB");
  283.  
  284. /*
  285.  *  (7)   Set up the write I/O request block and open the device.
  286.  */
  287.  
  288. VoiceIO->ch_masks            = &chans[0];
  289. VoiceIO->nm_masks            = sizeof(chans);
  290. VoiceIO->message.io_Command = CMD_WRITE;
  291. VoiceIO->flags               = NDF_NEWIORB;
  292.  
  293. if (OpenDevice("narrator.device", 0, VoiceIO, 0) != NULL)
  294.     Cleanup("OpenDevice failed");
  295.  
  296. /*
  297.  *  (8)   Set up the read I/O request block.
  298.  */
  299.  
  300. MouthIO->voice.message.io_Device = VoiceIO->message.io_Device;
  301. MouthIO->voice.message.io_Unit   = VoiceIO->message.io_Unit;
  302. MouthIO->voice.message.io_Message.mn_ReplyPort = MouthPort;
  303. MouthIO->voice.message.io_Command = CMD_READ;
  304.  
  305. /*
  306.  *  (9)   Initialize highlighting IntuiText structure.
  307.  */
  308.  
  309. HighLight.FrontPen  = 1;
  310. HighLight.BackPen   = 0;
  311. HighLight.DrawMode  = JAM1;
  312. HighLight.ITextFont = &MyFont;
  313. HighLight.NextText  = NULL;
  314.  
  315. /*
  316.  *  (10)   For each sentence, put up the English text in BLACK.  As
  317.  *         Narrator says each word, highlight that word in BLUE.  Also
  318.  *         continuously draw mouth shapes as Narrator speaks.
  319.  */
  320.  
  321. for (sentence = 0; sentence < NumPhonStarts; ++sentence)
  322.      {
  323.      /*
  324.       *  (11)  Begin by breaking the English sentence up into lines of
  325.       *        text in the window.  EngLine is an array containing a
  326.       *        pointer to the start of each English text line.
  327.       */
  328.  
  329.      English = EngStart[sentence] + strspn((UBYTE *)EngStart[sentence], " ");
  330.      NumEngLines = 0;
  331.      EngLine[NumEngLines++] = English;
  332.      CharsLeft = strlen(English);
  333.      while (CharsLeft > 51)
  334.            {
  335.            for (Offset = 51; *(English+Offset) != ' '; --Offset) ;
  336.            EngBytes[NumEngLines-1] = Offset;
  337.            English                += Offset + 1;
  338.            *(English-1)            = '\0';
  339.            EngLine[NumEngLines++]  = English;
  340.            CharsLeft              -= Offset + 1;
  341.            }
  342.      EngBytes[NumEngLines-1] = CharsLeft;
  343.  
  344.      /*
  345.       *  (12)   Clear the window and draw in the unhighlighted English text.
  346.       */
  347.  
  348.      ClearWindow(TextWindow);
  349.  
  350.      HighLight.FrontPen = 1;
  351.      HighLight.LeftEdge = 10;
  352.      HighLight.TopEdge  = 20;
  353.  
  354.      for (i = 0; i < NumEngLines; ++i)
  355.           {
  356.           HighLight.IText = EngLine[i];
  357.           PrintIText(TextWindow->RPort, &HighLight, 0, 0);
  358.           HighLight.TopEdge += 10;
  359.           }
  360.  
  361.      HighLight.TopEdge  = 20;
  362.      HighLight.FrontPen = 3;
  363.      HighLight.IText    = EngLine[0];
  364.  
  365.      /*
  366.       *  (13)   Set up the write request with the address and length of
  367.       *         the phonetic text to be spoken.  Also tell device to
  368.       *         generate mouth shape changes and word sync events.
  369.       */
  370.  
  371.      VoiceIO->message.io_Data   = PhonStart[sentence];
  372.      VoiceIO->message.io_Length = strlen(VoiceIO->message.io_Data);
  373.      VoiceIO->flags             = NDF_NEWIORB | NDF_WORDSYNC;
  374.      VoiceIO->mouths            = 1;
  375.  
  376.     /*
  377.      *  (14)   Send the write request to the device.  This is an
  378.      *         asynchronous write, the device will return immediately.
  379.      */
  380.  
  381.      SendIO(VoiceIO);
  382.  
  383.     /*
  384.      *  (15)   Initialize some variables.
  385.      */
  386.  
  387.      ScreenPos  = 0;
  388.      LineNum    = 0;
  389.      English    = EngLine[LineNum];
  390.      OldEnglish = English;
  391.      MouthIO->voice.message.io_Error = 0;
  392.  
  393.     /*
  394.      *  (16)   Issue synchronous read requests.  For each request we
  395.      *         check the sync field to see if the read returned a mouth
  396.      *         shape change, a start of word sync event, or both.  We
  397.      *         continue issuing read requests until we get a return code
  398.      *         of ND_NoWrite, which indicates that the write has finished.
  399.      */
  400.  
  401.      for (DoIO(MouthIO);MouthIO->voice.message.io_Error != ND_NoWrite;DoIO(MouthIO))
  402.           {
  403.  
  404.           /*
  405.            *  (17)   If bit 1 of the sync field is on, this is a start
  406.            *         of word sync event.  In that case we highlight the
  407.            *         next word.
  408.            */
  409.  
  410.           if (MouthIO->sync & NDF_READWORD)
  411.               {
  412.               if ((Tempptr = strchr(English, ' ')) != NULL)
  413.                   {
  414.                   English = Tempptr + 1;
  415.                   *(English-1) = '\0';
  416.                   }
  417.               PrintIText(TextWindow->RPort, &HighLight, 0, 0);
  418.               WordLength      = strlen(OldEnglish) + 1;
  419.               HighLight.IText = English;
  420.               OldEnglish      = English;
  421.               ScreenPos      += WordLength;
  422.  
  423.               if (ScreenPos >= EngBytes[LineNum])
  424.                   {
  425.                   HighLight.LeftEdge   = 10;
  426.                   HighLight.TopEdge   += 10;
  427.                   ScreenPos            = 0;
  428.                   English = OldEnglish = EngLine[++LineNum];
  429.                   HighLight.IText      = English;
  430.                   }
  431.               else
  432.                   HighLight.LeftEdge += 10*WordLength;
  433.               }
  434.  
  435.           /*
  436.            *  (18)   If bit 0 of the sync field is on, this is a mouth
  437.            *         shape change event.  In that case we update the face.
  438.            */
  439.  
  440.           if (MouthIO->sync & NDF_READMOUTH)
  441.               UpdateFace();
  442.  
  443.  
  444.           }
  445.  
  446.  
  447.      /*
  448.       *  (19)   The write has finished (return code from last read equals
  449.       *         ND_NoWrite).  We must wait on the write I/O request to
  450.       *         remove it from the message port.
  451.       */
  452.  
  453.      WaitIO(VoiceIO);
  454.  
  455.      }
  456.  
  457.  
  458. /*
  459.  *  (20)   Program completed, cleanup and return.
  460.  */
  461.  
  462. Cleanup("Normal completion");
  463.  
  464. }
  465.  
  466.  
  467. void Cleanup(UBYTE *errmsg)
  468. {
  469.  
  470.  
  471. /*
  472.  *  (1)   Cleanup and go away.  This routine does not return but EXITs.
  473.  *        Everything it does is pretty self explanatory.
  474.  */
  475.  
  476. if (FromCLI)
  477.     printf("%s\n\r", errmsg);
  478. if (TextWindow)
  479.     CloseWindow(TextWindow);
  480. if (FaceWindow)
  481.     CloseWindow(FaceWindow);
  482. if (VoiceIO && VoiceIO->message.io_Device)
  483.     CloseDevice(VoiceIO);
  484. if (VoiceIO)
  485.     DeleteExtIO(VoiceIO);
  486. if (VoicePort)
  487.     DeletePort(VoicePort);
  488. if (MouthIO)
  489.     DeleteExtIO(MouthIO);
  490. if (MouthPort)
  491.     DeletePort(MouthPort);
  492. if (GfxBase)
  493.     CloseLibrary(GfxBase);
  494. if (IntuitionBase)
  495.     CloseLibrary(IntuitionBase);
  496.  
  497. exit(RETURN_OK);
  498. }
  499.  
  500.  
  501. void ClearWindow(struct Window *TextWindow)
  502. {
  503. LONG    OldPen;
  504.  
  505. /*
  506.  *  (1)   Clears a window.
  507.  */
  508.  
  509. OldPen = (LONG)TextWindow->RPort->FgPen;
  510. SetAPen(TextWindow->RPort, 0);
  511. SetDrMd(TextWindow->RPort, JAM1);
  512. RectFill(TextWindow->RPort, 3, 12, TextWindow->Width-3, TextWindow->Height-2);
  513. SetAPen(TextWindow->RPort, OldPen);
  514. }
  515.  
  516.  
  517. void DrawFace()
  518. {
  519.  
  520. /*
  521.  *  (1)   Draws the initial face.  The variables defined here are used in
  522.  *        UpdateFace() to redraw the mouth shape.
  523.  */
  524.  
  525. EyesLeft = 15;
  526. EyesTop = 20;
  527. EyesBottom = 35;
  528.  
  529. XMouthCenter = FaceWindow->Width >> 1;
  530. YMouthCenter = FaceWindow->Height - 25;
  531.  
  532. SetAPen(FaceWindow->RPort, PEN1);
  533. RectFill(FaceWindow->RPort, 3, 10, FaceWindow->Width-3, FaceWindow->Height-2);
  534.  
  535. SetAPen(FaceWindow->RPort, PEN0);
  536. RectFill(FaceWindow->RPort, EyesLeft, EyesTop, EyesLeft+25, EyesTop+15);
  537. RectFill(FaceWindow->RPort, EyesLeft+65, EyesTop, EyesLeft+90, EyesTop+15);
  538.  
  539. SetAPen(FaceWindow->RPort, PEN3);
  540. Move(FaceWindow->RPort, XMouthCenter-(FaceWindow->Width >> 3), YMouthCenter);
  541. Draw(FaceWindow->RPort, XMouthCenter+(FaceWindow->Width >> 3), YMouthCenter);
  542. }
  543.  
  544.  
  545. void UpdateFace()
  546. {
  547.  
  548. /*
  549.  *  (1)   Redraws mouth shape in response to a mouth shape change message
  550.  *        from the device.  Its all pretty self explanatory.
  551.  */
  552.  
  553. WaitBOVP(&FaceWindow->WScreen->ViewPort);
  554. SetAPen(FaceRast, PEN1);
  555. RectFill(FaceRast, 3, EyesBottom, FaceWindow->Width-3, FaceWindow->Height-2);
  556.  
  557. LipWidth  = MouthIO->width*3;
  558. LipHeight = MouthIO->height*2/3;
  559.  
  560. SetAPen(FaceRast, PEN3);
  561. Move(FaceRast, XMouthCenter - LipWidth, YMouthCenter);
  562. Draw(FaceRast, XMouthCenter           , YMouthCenter - LipHeight);
  563. Draw(FaceRast, XMouthCenter + LipWidth, YMouthCenter);
  564. Draw(FaceRast, XMouthCenter,            YMouthCenter + LipHeight);
  565. Draw(FaceRast, XMouthCenter - LipWidth, YMouthCenter);
  566. }
  567.  
  568.