{ This is the second module for the speechtoy. See speechtoy.pas } MODULE dospeech( output ); INCLUDE 'speechtoy.inc'; {$L- Turn off listing for the external routines include files } INCLUDE 'devices/routines'; { For AbortIO, Translate } INCLUDE 'exec/io'; { For SendIO } INCLUDE 'intuition/gadgets'; { For Add/Remove/RefreshGadgets } INCLUDE 'intuition/menus'; { For SetMenuStrip } INCLUDE 'intuition/requests'; { For AutoRequest } INCLUDE 'intuition/screens'; { For DisplayBeep } INCLUDE 'intuition/windows'; { For Open/CloseWindow } INCLUDE 'graphics/rastport'; { For Draw, Move, RectFill, SetAPen } {$L+} PROCEDURE MyCleanup( code : INTEGER ); IMPORT; PROCEDURE MyNewList( mp : MsgPortPtrType ); EXTERNAL; { A MENUPICK has been received, this routine takes the appropriate action } PROCEDURE MenuMessage( code : WORD; w : WindowPtrType ); EXPORT; VAR brc : BOOLEAN; { Return code is ignored } BEGIN IF ((code & $X1F) = 0) AND (((code >> 5) & $X3F) = 0) THEN brc := AutoRequest( w, ReqText, NIL, OKText, 0, 0, 280, 47 ); END; { This calculates variables used to draw the mouth } { and eyes, as well as redrawing the face. } { Proportionality makes it a bit complex, but its } { more complicated if GimmeZeroZero window isn't } { used ! } PROCEDURE DrawFace; EXPORT; VAR w, h, EyesW, EyesH, halfw, jaw : INTEGER; BEGIN WITH FaceWindow^ DO BEGIN w := GZZWidth & $XFFFF; h := GZZHeight & $XFFFF; EyesW := w >> 3; EyesH := h >> 3; { Eye width and height } halfw := w >> 1; XMouthCentre := halfw; EyesLeft := w >> 2; { Set left edge of left eye } MouthWMult := w >> 6; { Multiplier for mouth width } EyesTop := (h >> 2) - (h >> 4); EyesBottom := EyesTop + EyesH + 1; jaw := h - EyesBottom; YMouthCentre := (jaw >> 1) + EyesBottom; MouthHMult := jaw >> 5; SetAPen( RPort, WHTP ); { Set pen to White and fill background } RectFill( RPort, 0, 0, w, h ); SetAPen( RPort, BLUP ); { Set pen to Blue and draw eyes } RectFill( RPort, EyesLeft, EyesTop, EyesLeft + EyesW, EyesTop + EyesH ); RectFill( RPort, halfw + EyesW, EyesTop, halfw + EyesW + EyesW, EyesTop + EyesH ); SetAPen( RPort, REDP ); { Set pen to Red and draw closed mouth } Move( RPort, XMouthCentre - EyesW, YMouthCentre ); Draw( RPort, XMouthCentre + EyesW, YMouthCentre ); END; END; { DrawFace } PROCEDURE XOR( VAR a : WORD; b : WORD ); EXPORT; BEGIN a := (a | b) & (~(a & b)) END; PROCEDURE DoFaceGadget; BEGIN { Tell the write that reads will be forthcomming } IF (FaceGadget^.Flags & SELECTED) <> 0 THEN BEGIN voice_io.mouths := 1; FaceWindow := OpenWindow( NewFaceWindow ); IF FaceWindow = NIL THEN BEGIN WRITELN( 'Couldn''t open face window.' ); MyCleanup( 0 ); END; SetMenuStrip( FaceWindow, MyMenu ); DrawFace; END ELSE BEGIN { FaceGadget de-SELECTed } voice_io.mouths := 0; WITH NewFaceWindow^ DO BEGIN LeftEdge := FaceWindow^.LeftEdge; TopEdge := FaceWindow^.TopEdge; Width := FaceWindow^.Width; Height := FaceWindow^.Height; END; CloseWindow( FaceWindow ); FaceWindow := NIL; END; END; { DoFaceGadget } PROCEDURE DoStopGadget; BEGIN AbortIO( ADDR( voice_io ) ); voice_io.message.io_Error := 0; mouth_io.voice.message.io_Error := 0; END; { DoStopGadget } { Since this program changes a flag that intuition expects } { only the user to change (SELECTED bit), this program has } { to remove, then change, then add this gadget. Then by } { passing the address of this gadget to RefreshGadgets, } { only the gadgets from here to the start of the list will } { be refreshed, which minimizes the visible flash that } { RefreshGadgets can introduce. } { If one of the two gadgets (female/male) is hit, toggle } { the selection of the other gadget (since the gadget hit } { was toggled by intuition when it was hit). } PROCEDURE DoFemaleGadget; BEGIN IF (FemaleGadget^.Flags & SELECTED) <> 0 THEN voice_io.sex := FEMALE ELSE voice_io.sex := MALE; pos := RemoveGadget( ControlWindow, MaleGadget ); WITH MaleGadget^ DO XOR( Flags, SELECTED ); pos := AddGadget( ControlWindow, MaleGadget, pos ); RefreshGadgets( MaleGadget, ControlWindow, NIL ); END; { DoFemaleGadget } { Since the program changes the contents of the string } { gadgets' buffer and it's size, which is something ELSE } { intuition doesn't expect a program (as opposed to the } { user) to do. The program must remove, then change, then } { add this gadget, and then by passing the address of this } { gadget to RefreshGadgets, only the gadgets from here } { to the start of the list will be refreshed, which } { minimizes the visible flash that RefreshGadgets can } { introduce. } PROCEDURE DoMaleGadget; BEGIN IF (MaleGadget^.Flags & SELECTED) <> 0 THEN voice_io.sex := MALE ELSE voice_io.sex := FEMALE; pos := RemoveGadget( ControlWindow, FemaleGadget ); WITH FemaleGadget^ DO XOR( Flags, SELECTED ); pos := AddGadget( ControlWindow, FemaleGadget, pos ); RefreshGadgets( MaleGadget, ControlWindow, NIL ); END; { DoMaleGadget } PROCEDURE DoTranslateGadget; BEGIN pos := RemoveGadget( ControlWindow, PhonStrGadget ); IF Translate( EnglInfo^.Buffer, EnglInfo^.NumChars, PhonInfo^.Buffer, PhonInfo^.MaxChars ) <> 0 THEN DisplayBeep( ControlWindow^.WScreen ); { Flash this screen } { Note : NumChars includes the terminating null. } WITH voice_io.message, PhonInfo^ DO BEGIN NumChars := io_Length + 1; IF DispPos > io_Length THEN DispPos := io_Length; END; pos := AddGadget( ControlWindow, PhonStrGadget, pos ); RefreshGadgets( PhonStrGadget, ControlWindow, NIL ); END; { DoTranslateGadget } PROCEDURE DoSpeakGadget; BEGIN WITH SpeakGadget^ DO XOR( Flags, GADGDISABLED ); WITH FaceGadget^ DO XOR( Flags, GADGDISABLED ); voice_io.message.io_Length := PhonInfo^.NumChars; SendIO( ADDR( voice_io ) ); IF voice_io.mouths = 1 THEN BEGIN mouth_io.voice.message.io_Error := 0; SendIO( ADDR( mouth_io ) ); END; END; { DoSpeakGadget } { A GADGETUP has been received, this routine takes the appropriate action } { The address of the relevant Gadget is passed as a parameter } PROCEDURE GadgetMessage( address : GadgetPtrType ); EXPORT; BEGIN IF address = ModeGadget THEN IF (ModeGadget^.Flags & SELECTED) <> 0 THEN voice_io.mode := ROBOTICF0 ELSE voice_io.mode := NATURALF0 ELSE IF address = FaceGadget THEN DoFaceGadget ELSE IF address = StopGadget THEN DoStopGadget ELSE IF address = FemaleGadget THEN DoFemaleGadget ELSE IF address = MaleGadget THEN DoMaleGadget ELSE IF address = TranslateGadget THEN DoTranslateGadget ELSE IF address = SpeakGadget THEN DoSpeakGadget ELSE IF address = EnglStrGadget THEN BEGIN END { do nothing } ELSE IF address = PhonStrGadget THEN BEGIN END { do nothing } ELSE WITH voice_io DO BEGIN IF address = Props[0] THEN sampfreq := (((PInfos[0]^.HorizPot >> 1) * RNGFREQ) >> 15) + MINFREQ ELSE IF address = Props[1] THEN rate := (((PInfos[1]^.HorizPot >> 1) * RNGRATE) >> 15) + MINRATE ELSE IF address = Props[2] THEN pitch := (((PInfos[2]^.HorizPot >> 1) * RNGPITCH) >> 15) + MINPITCH ELSE IF address = Props[3] THEN volume := (((PInfos[3]^.HorizPot >> 1) * RNGVOL) >> 15) + MINVOL END; { with voice_io } END; PROCEDURE DrawSpeechtoy; EXPORT; BEGIN { Fill background of window, draw gadgets and create menu bar } WITH ControlWindow^ DO BEGIN SetAPen( RPort, BLKP ); RectFill( RPort, 0, 0, GZZWidth, GZZHeight ); END; RefreshGadgets( Props[NUMPROPS], ControlWindow, NIL ); SetMenuStrip( ControlWindow, MyMenu ); END; { DrawSpeechtoy } BEGIN END.