www.pudn.com > TAPIOfControl.rar > AdSapiEn.pas


(***** BEGIN LICENSE BLOCK ***** 
 * Version: MPL 1.1 
 * 
 * The contents of this file are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this file except in compliance with 
 * the License. You may obtain a copy of the License at 
 * http://www.mozilla.org/MPL/ 
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the 
 * License. 
 * 
 * The Original Code is TurboPower Async Professional 
 * 
 * The Initial Developer of the Original Code is 
 * TurboPower Software 
 * 
 * Portions created by the Initial Developer are Copyright (C) 1991-2002 
 * the Initial Developer. All Rights Reserved. 
 * 
 * Contributor(s): 
 * 
 * ***** END LICENSE BLOCK ***** *) 
 
{*********************************************************} 
{*                   ADSAPIEN.PAS 4.06                   *} 
{*********************************************************} 
{* TApdSAPIEngine component                              *} 
{*********************************************************} 
 
{ 
  provides Text-to-Speech and Speech-to-Text using SAPI 4. SAPI 4 is available 
  for Win9x/ME/2K/XP.  SAPI 5 is a newer, more flexible API, but it was not 
  functional when APRO 4 was released. You'll probably need to install SAPI 4 
  since it is not installed by default. 
    The SAPI4 SDK can be downloaded from 
    http://www.microsoft.com/downloads/release.asp?ReleaseID=26299. The 
    Spchapi.exe download from that site is 848K, and contains just the 
    supporting API, it does not contain any speech recognition or synthesis 
    engines.  The SAPI4SDK.exe (8,023k) and SAPI4SDKSuite.exe (40,001K) 
    downloads contain the API binaries as well as recognition/systhesis engines 
    and the SDK examples and help.  The MS-supplied speech recognition and 
    speech synthesis engines only support English, but other third-party 
    providers have engines tailored for different languages. There are several 
    third-party speech engine providers that can be used with the Speech API, 
    here are a few links: 
    http://www.lhsl.com/default2.htm 
    http://www.att.com/aspg/ 
    http://www.lucent.com/products/solution/0,,CTID+2002-STID+10054-SOID+851-LOCL+1,00.html 
    http://www.dragonsys.com/products/dev_main.html 
    http://www-4.ibm.com/software/speech/ 
 
    A www.google.com search for "speech engine" came up with a bunch of 
    other sources also. 
} 
 
{Global defines potentially affecting this unit} 
{$I AWDEFINE.INC} 
 
unit AdSapiEn; 
 
interface 
 
uses                                    
  Windows, 
  ActiveX, 
  Classes, 
  Graphics, 
  {$IFDEF Delphi5} 
  OleServer, 
  {$ENDIF} 
  OleCtrls, 
  StdVCL, 
  SysUtils, 
  Controls, 
  OoMisc, 
  AdISapi, 
  AdSapiGr, 
  {$IFDEF Delphi5} 
  Contnrs, 
  {$ENDIF} 
  Messages, 
  Forms, 
  Dialogs,   
  AdExcept, 
  ComObj; 
 
const 
 
  { Constants from the Speech API } 
 
  { TTS Character Sets } 
 
  ApdCHARSET_TEXT                  = $00; 
  ApdCHARSET_IPAPHONETIC           = $01; 
  ApdCHARSET_ENGINEPHONETIC        = $02; 
 
  { TTS Options } 
 
  ApdTTSDATAFLAG_TAGGED            = $01; 
 
  { TTS Ages } 
 
  ApdTTSAGE_BABY                   = 1; 
  ApdTTSAGE_TODDLER                = 3; 
  ApdTTSAGE_CHILD                  = 6; 
  ApdTTSAGE_ADOLESCENT             = 14; 
  ApdTTSAGE_ADULT                  = 30; 
  ApdTTSAGE_ELDERLY                = 70; 
 
  { TTS Features } 
 
  ApdTTSFEATURE_ANYWORD            = $00001; 
  ApdTTSFEATURE_VOLUME             = $00002; 
  ApdTTSFEATURE_SPEED              = $00004; 
  ApdTTSFEATURE_PITCH              = $00008; 
  ApdTTSFEATURE_TAGGED             = $00010; 
  ApdTTSFEATURE_IPAUNICODE         = $00020; 
  ApdTTSFEATURE_VISUAL             = $00040; 
  ApdTTSFEATURE_WORDPOSITION       = $00080; 
  ApdTTSFEATURE_PCOPTIMIZED        = $00100; 
  ApdTTSFEATURE_PHONEOPTIMIZED     = $00200; 
  ApdTTSFEATURE_FIXEDAUDIO         = $00400; 
  ApdTTSFEATURE_SINGLEINSTANCE     = $00800; 
  ApdTTSFEATURE_THREADSAFE         = $01000; 
  ApdTTSFEATURE_IPATEXTDATA        = $02000; 
  ApdTTSFEATURE_PREFERRED          = $04000; 
  ApdTTSFEATURE_TRANSPLANTED       = $08000; 
  ApdTTSFEATURE_SAPI4              = $10000; 
 
  { TTS Genders } 
 
  ApdGENDER_NEUTRAL                = 0; 
  ApdGENDER_FEMALE                 = 1; 
  ApdGENDER_MALE                   = 2; 
 
  { TTS Interfaces } 
 
  ApdTTSI_ILEXPRONOUNCE            = $01; 
  ApdTTSI_ITTSATTRIBUTES           = $02; 
  ApdTTSI_ITTSCENTRAL              = $04; 
  ApdTTSI_ITTSDIALOGS              = $08; 
  ApdTTSI_ATTRIBUTES               = $10; 
  ApdTTSI_IATTRIBUTES              = $10; 
  ApdTTSI_ILEXPRONOUNCE2           = $20; 
 
  { SR Features } 
 
  ApdSRFEATURE_INDEPSPEAKER        = $00001; 
  ApdSRFEATURE_INDEPMICROPHONE     = $00002; 
  ApdSRFEATURE_TRAINWORD           = $00004; 
  ApdSRFEATURE_TRAINPHONETIC       = $00008; 
  ApdSRFEATURE_WILDCARD            = $00010; 
  ApdSRFEATURE_ANYWORD             = $00020; 
  ApdSRFEATURE_PCOPTIMIZED         = $00040; 
  ApdSRFEATURE_PHONEOPTIMIZED      = $00080; 
  ApdSRFEATURE_GRAMLIST            = $00100; 
  ApdSRFEATURE_GRAMLINK            = $00200; 
  ApdSRFEATURE_MULTILINGUAL        = $00400; 
  ApdSRFEATURE_GRAMRECURSIVE       = $00800; 
  ApdSRFEATURE_IPAUNICODE          = $01000; 
  ApdSRFEATURE_SINGLEINSTANCE      = $02000; 
  ApdSRFEATURE_THREADSAFE          = $04000; 
  ApdSRFEATURE_FIXEDAUDIO          = $08000;  
  ApdSRFEATURE_IPAWORD             = $10000; 
  ApdSRFEATURE_SAPI4               = $20000; 
 
  { SR Supported grammar types } 
 
  ApdSRGRAM_CFG                    = $1; 
  ApdSRGRAM_DICTATION              = $2; 
  ApdSRGRAM_LIMITEDDOMAIN          = $4; 
 
  { SR Interfaces } 
 
  ApdSRI_ILEXPRONOUNCE             = $0000001; 
  ApdSRI_ISRATTRIBUTES             = $0000002; 
  ApdSRI_ISRCENTRAL                = $0000004; 
  ApdSRI_ISRDIALOGS                = $0000008; 
  ApdSRI_ISRGRAMCOMMON             = $0000010; 
  ApdSRI_ISRGRAMCFG                = $0000020; 
  ApdSRI_ISRGRAMDICTATION          = $0000040; 
  ApdSRI_ISRGRAMINSERTIONGUI       = $0000080; 
  ApdSRI_ISRESBASIC                = $0000100; 
  ApdSRI_ISRESMERGE                = $0000200; 
  ApdSRI_ISRESAUDIO                = $0000400; 
  ApdSRI_ISRESCORRECTION           = $0000800; 
  ApdSRI_ISRESEVAL                 = $0001000; 
  ApdSRI_ISRESGRAPH                = $0002000; 
  ApdSRI_ISRESMEMORY               = $0004000; 
  ApdSRI_ISRESMODIFYGUI            = $0008000; 
  ApdSRI_ISRESSPEAKER              = $0010000; 
  ApdSRI_ISRSPEAKER                = $0020000; 
  ApdSRI_ISRESSCORES               = $0040000; 
  ApdSRI_ISRESAUDIOEX              = $0080000; 
  ApdSRI_ISRGRAMLEXPRON            = $0100000; 
  ApdSRI_ISRRESGRAPHEX             = $0200000; 
  ApdSRI_ILEXPRONOUNCE2            = $0400000; 
  ApdSRI_IATTRIBUTES               = $0800000; 
  ApdSRI_ISRSPEAKER2               = $1000000; 
  ApdSRI_ISRDIALOGS2               = $2000000; 
 
  { SR Sequences } 
 
  ApdSRSEQUENCE_DISCRETE           = 0; 
  ApdSRSEQUENCE_CONTINUOUS         = 1; 
  ApdSRSEQUENCE_WORDSPOT           = 2; 
  ApdSRSEQUENCE_CONTCFGDISCDICT    = 3; 
 
  { SR Interference Types } 
 
  ApdSRMSGINT_NOISE                = $0001; 
  ApdSRMSGINT_NOSIGNAL             = $0002; 
  ApdSRMSGINT_TOOLOUD              = $0003; 
  ApdSRMSGINT_TOOQUIET             = $0004; 
  ApdSRMSGINT_AUDIODATA_STOPPED    = $0005; 
  ApdSRMSGINT_AUDIODATA_STARTED    = $0006; 
  ApdSRMSGINT_IAUDIO_STARTED       = $0007; 
  ApdSRMSGINT_IAUDIO_STOPPED       = $0008; 
 
  { SR Training Requests } 
 
  ApdSRGNSTRAIN_GENERAL            =  $01; 
  ApdSRGNSTRAIN_GRAMMAR            =  $02; 
  ApdSRGNSTRAIN_MICROPHONE         =  $04; 
 
  { SS Error codes } 
 
  ApdTTSERR_NONE                   = $00000000; 
  ApdTTSERR_INVALIDINTERFACE       = $80004002; 
  ApdTTSERR_OUTOFDISK              = $80040205; 
  ApdTTSERR_NOTSUPPORTED           = $80004001; 
  ApdTTSERR_VALUEOUTOFRANGE        = $8000FFFF; 
  ApdTTSERR_INVALIDWINDOW          = $8004000F; 
  ApdTTSERR_INVALIDPARAM           = $80070057; 
  ApdTTSERR_INVALIDMODE            = $80040206; 
  ApdTTSERR_INVALIDKEY             = $80040209; 
  ApdTTSERR_WAVEFORMATNOTSUPPORTED = $80040202; 
  ApdTTSERR_INVALIDCHAR            = $80040208; 
  ApdTTSERR_QUEUEFULL              = $8004020A; 
  ApdTTSERR_WAVEDEVICEBUSY         = $80040203; 
  ApdTTSERR_NOTPAUSED              = $80040501; 
  ApdTTSERR_ALREADYPAUSED          = $80040502; 
 
  { SR Error Codes } 
 
  ApdSRERR_NONE                    = $00000000; 
  ApdSRERR_OUTOFDISK               = $80040205; 
  ApdSRERR_NOTSUPPORTED            = $80004001; 
  ApdSRERR_NOTENOUGHDATA           = $80040201; 
  ApdSRERR_VALUEOUTOFRANGE         = $8000FFFF; 
  ApdSRERR_GRAMMARTOOCOMPLEX       = $80040406; 
  ApdSRERR_GRAMMARWRONGTYPE        = $80040407; 
  ApdSRERR_INVALIDWINDOW           = $8004000F; 
  ApdSRERR_INVALIDPARAM            = $80070057; 
  ApdSRERR_INVALIDMODE             = $80040206; 
  ApdSRERR_TOOMANYGRAMMARS         = $8004040B; 
  ApdSRERR_INVALIDLIST             = $80040207; 
  ApdSRERR_WAVEDEVICEBUSY          = $80040203; 
  ApdSRERR_WAVEFORMATNOTSUPPORTED  = $80040202; 
  ApdSRERR_INVALIDCHAR             = $80040208; 
  ApdSRERR_GRAMTOOCOMPLEX          = $80040406; 
  ApdSRERR_GRAMTOOLARGE            = $80040411; 
  ApdSRERR_INVALIDINTERFACE        = $80004002; 
  ApdSRERR_INVALIDKEY              = $80040209; 
  ApdSRERR_INVALIDFLAG             = $80040204; 
  ApdSRERR_GRAMMARERROR            = $80040416; 
  ApdSRERR_INVALIDRULE             = $80040417; 
  ApdSRERR_RULEALREADYACTIVE       = $80040418; 
  ApdSRERR_RULENOTACTIVE           = $80040419; 
  ApdSRERR_NOUSERSELECTED          = $8004041A; 
  ApdSRERR_BAD_PRONUNCIATION       = $8004041B; 
  ApdSRERR_DATAFILEERROR           = $8004041C; 
  ApdSRERR_GRAMMARALREADYACTIVE    = $8004041D; 
  ApdSRERR_GRAMMARNOTACTIVE        = $8004041E; 
  ApdSRERR_GLOBALGRAMMARALREADYACTIVE = $8004041F; 
  ApdSRERR_LANGUAGEMISMATCH        = $80040420; 
  ApdSRERR_MULTIPLELANG            = $80040421; 
  ApdSRERR_LDGRAMMARNOWORDS        = $80040422; 
  ApdSRERR_NOLEXICON               = $80040423; 
  ApdSRERR_SPEAKEREXISTS           = $80040424; 
  ApdSRERR_GRAMMARENGINEMISMATCH   = $80040425; 
  ApdSRERR_BOOKMARKEXISTS          = $80040426; 
  ApdSRERR_BOOKMARKDOESNOTEXIST    = $80040427; 
  ApdSRERR_MICWIZARDCANCELED       = $80040428; 
  ApdSRERR_WORDTOOLONG             = $80040429; 
  ApdSRERR_BAD_WORD                = $8004042A; 
  ApdE_WRONGTYPE                   = $8004020C; 
  ApdE_BUFFERTOOSMALL              = $8004020D; 
 
type 
 
  TApdSapiDuplex = (sdFull, sdHalf, sdHalfDelayed); 
  TApdSapiWaitMode = (wmNone, wmWaitSpeaking, wmWaitListening, 
                      wmRestoreListen); 
  TApdCharacterSet = (csText, csIPAPhonetic, csEnginePhonetic); 
  TApdTTSOptions = set of (toTagged); 
  TApdTTSAge = (tsBaby, tsToddler, tsChild, tsAdolescent, tsAdult, tsElderly, 
                tsUnknown); 
  TApdTTSFeatures = set of (tfAnyWord, tfVolume, tfSpeed, tfPitch, tfTagged, 
                            tfIPAUnicode, tfVisual, tfWordPosition, 
                            tfPCOptimized, tfPhoneOptimized, tfFixedAudio, 
                            tfSingleInstance, tfThreadSafe, tfIPATextData, 
                            tfPreferred, tfTransplanted, tfSAPI4); 
  TApdTTSGender = (tgNeutral, tgFemale, tgMale, tgUnknown); 
  TApdTTSInterfaces = set of (tiLexPronounce, tiTTSAttributes, tiTTSCentral, 
                              tiTTSDialogs, tiAttributes, tiIAttributes, 
                              tiLexPronounce2); 
 
  TApdSRFeatures = set of (sfIndepSpeaker, sfIndepMicrophone, sfTrainWord, 
                           sfTrainPhonetic, sfWildcard, sfAnyWord, 
                           sfPCOptimized, sfPhoneOptimized, sfGramList, 
                           sfGramLink, sfMultiLingual, sfGramRecursive, 
                           sfIPAUnicode, sfSingleInstance, sfThreadSafe, 
                           sfFixedAudio, sfIPAWord, sfSAPI4); 
  TApdSRGrammars = set of (sgCFG, sgDictation, sgLimitedDomain); 
  TApdSRInterfaces = set of (siLexPronounce, siSRAttributes, siSRCentral, 
                             siSRGramCommon, siSRDialogs, siSRGramCFG, 
                             siSRGramDictation, siSRGramInsertionGui, 
                             siSREsBasic, siSREsMerge, siSREsAudio, 
                             siSREsCorrection, siSREsEval, siSREsGraph, 
                             siSREsMemory, siSREsModifyGui, siSREsSpeaker, 
                             siSRSpeaker, siSREsScores, siSREsAudioEx, 
                             siSRGramLexPron, siSREsGraphEx, siLexPronounce2, 
                             siAttributes, siSRSpeaker2, siSRDialogs2); 
  TApdSRSequences = (ssDiscrete, ssContinuous, ssWordSpot, ssContCFGDiscDict, 
                     ssUnknown); 
  TApdSRInterferenceType = (itAudioStarted, itAudioStopped, itDeviceOpened, 
                            itDeviceClosed, itNoise, itTooLoud, itTooQuiet, 
                            itUnknown); 
  TApdSRTrainingType = set of (ttCurrentMic, ttCurrentGrammar, ttGeneral); 
 
  { Event types } 
 
  TApdOnSapiError = 
      procedure (Sender : TObject; Error : LongWord; 
                 const Details : string; const Message : string) of object; 
  TApdSapiNotifyEvent = 
      procedure (Sender : TObject) of object; 
  TApdSRInterferenceEvent = 
      procedure (Sender : TObject; 
                 InterferenceType : TApdSRInterferenceType) of object; 
  TApdSRPhraseFinishEvent = 
      procedure (Sender : TObject; const Phrase : string) of object; 
  TApdSRPhraseHypothesisEvent = 
      procedure (Sender : TObject; const Phrase : string) of object; 
  TApdSRTrainingRequestedEvent = 
      procedure (Sender : TObject; Training : TApdSRTrainingType) of object; 
  TApdSRVUMeterEvent = 
      procedure (Sender : TObject; Level : Integer) of object; 
  TApdSSAttributeChanged = 
      procedure (Sender : TObject; Attribute: Integer) of object; 
 
  { Hook methods } 
 
  TApdPhraseFinishMethod = 
    procedure (Sender : TObject; Phrase : string; Results : Integer) of object; 
  PApdPhraseFinishMethod = ^TApdPhraseFinishMethod; 
 
  TApdRegisteredEventTypes = (etPhraseFinish); 
  PApdRegisteredEvent = ^TApdRegisteredEvent; 
  TApdRegisteredEvent = record 
    CallBack : TApdPhraseFinishMethod; 
    EventType : TApdRegisteredEventTypes; 
    Active : Boolean; 
  end; 
 
  { Exceptions } 
 
  EApdSapiEngineException = class (Exception) 
    private 
      FErrorCode : Integer; 
 
    public 
      constructor Create (const ErrCode : Integer; const Msg : string); 
      { Note: ErrCode is before the string to prevent problems in compiling 
              with C++ Builder } 
 
    published 
      property ErrorCode : Integer read FErrorCode; 
  end; 
 
  { TApdSSVoices } 
   
  TApdSSVoices = class (TObject) 
    private 
      FCurrentVoice : Integer; 
      FiDirectSS    : TDirectSS; 
 
    protected 
      function CheckIndex (x : Integer) : Boolean; 
      function GetAge (x : Integer) : TApdTTSAge; 
      function GetCount : Integer; 
      function GetCurrentVoice : Integer; 
      function GetDialect (x : Integer) : string; 
      function GetEngineFeatures (x : Integer) : Integer; 
      function GetEngineID (x : Integer) : string; 
      function GetFeatures (x : Integer) : TApdTTSFeatures; 
      function GetGender (x : Integer) : TApdTTSGender; 
      function GetInterfaces (x : Integer) : TApdTTSInterfaces; 
      function GetLanguageID (x : Integer) : Integer; 
      function GetMfgName (x : Integer) : string; 
      function GetModeID (x : Integer) : string; 
      function GetModeName (x : Integer) : string; 
      function GetProductName (x : Integer) : string; 
      function GetSpeaker (x : Integer) : string; 
      function GetStyle (x : Integer) : string; 
      procedure SetCurrentVoice (v : Integer); 
 
    public 
      function Find (Criteria : string) : Integer; 
 
      property Age[x : Integer] : TApdTTSAge read GetAge; 
      property Dialect[x : Integer] : string read GetDialect; 
      property EngineFeatures[x : Integer] : Integer read GetEngineFeatures; 
      property EngineID[x : Integer] : string read GetEngineID; 
      property Features[x : Integer] : TApdTTSFeatures read GetFeatures; 
      property Gender[x : Integer] : TApdTTSGender read GetGender; 
      property Interfaces[x : Integer] : TApdTTSInterfaces read GetInterfaces; 
      property LanguageID[x : Integer] : Integer read GetLanguageID; 
      property MfgName[x : Integer] : string read GetMfgName; 
      property ModeID[x : Integer] : string read GetModeID; 
      property ModeName[x : Integer] : string read GetModeName; default; 
      property ProductName[x : Integer] : string read GetProductName; 
      property Speaker[x : Integer] : string read GetSpeaker; 
      property Style[x : Integer] : string read GetStyle; 
 
    published 
      property Count : Integer read GetCount; 
      property CurrentVoice : Integer 
               read GetCurrentVoice write SetCurrentVoice; 
  end; 
 
  { TApdSREngines } 
   
  TApdSREngines = class (TObject) 
    private 
      FCurrentEngine : Integer; 
      FiDirectSR     : TDirectSR; 
 
    protected 
      function  CheckIndex (x : Integer) : Boolean; 
 
      function  GetCount : Integer; 
      function  GetCurrentEngine : Integer; 
      function  GetDialect (x : Integer) : string; 
      function  GetEngineFeatures (x : Integer) : Integer; 
      function  GetEngineId (x : Integer) : string; 
      function  GetFeatures (x : Integer) : TApdSRFeatures; 
      function  GetGrammars (x : Integer) : TApdSRGrammars; 
      function  GetInterfaces (x : Integer) : TApdSRInterfaces; 
      function  GetLanguageID (x : Integer) : Integer; 
      function  GetMaxWordsState (x : Integer) : Integer; 
      function  GetMaxWordsVocab (x : Integer) : Integer; 
      function  GetMfgName (x : Integer) : string; 
      function  GetModeID (x : Integer) : string; 
      function  GetModeName (x : Integer) : string; 
      function  GetProductName (x : Integer) : string; 
      function  GetSequencing (x : Integer) : TApdSRSequences; 
      procedure SetCurrentEngine (v : Integer); 
 
    public 
      property Dialect[x : Integer] : string read GetDialect; 
      property EngineFeatures[x : Integer] : Integer read GetEngineFeatures; 
      property EngineID[x : Integer] : string read GetEngineID; 
      property Features[x : Integer] : TApdSRFeatures read GetFeatures; 
      property Grammars[x : Integer] : TApdSRGrammars read GetGrammars; 
      property Interfaces[x : Integer] : TApdSRInterfaces read GetInterfaces; 
      property LanguageID[x : Integer] : Integer read GetLanguageID; 
      property MaxWordsState[x : Integer] : Integer read GetMaxWordsState; 
      property MaxWordsVocab[x : Integer] : Integer read GetMaxWordsVocab; 
      property MfgName[x : Integer] : string read GetMfgName; 
      property ModeID[x : Integer] : string read GetModeID; 
      property ModeName[x : Integer] : string read GetModeName; default; 
      property ProductName[x : Integer] : string read GetProductName; 
      property Sequencing[x : Integer] : TApdSRSequences read GetSequencing; 
 
    published 
      property Count : Integer read GetCount; 
      property CurrentEngine : Integer 
               read GetCurrentEngine write SetCurrentEngine; 
 
  end; 
 
  { TApdCustomSapiEngine } 
 
  TApdCustomSapiEngine = class (TApdBaseComponent)  
    private 
      FiDirectSR                : TDirectSR; 
      FiDirectSS                : TDirectSS; 
      FCharSet                  : TApdCharacterSet; 
      FDictation                : Boolean; 
      FSpeaking                 : Boolean; 
      FListening                : Boolean; 
      FSRAmplitude              : Word; 
      FSRAutoGain               : Integer; 
      FTTSOptions               : TApdTTSOptions; 
      FWordList                 : TStringList; 
      FSREngines                : TApdSREngines; 
      FSSVoices                 : TApdSSVoices; 
      FPhraseFinishClients      : TList; 
      FHandle                   : HWnd; 
      FAutoTrain                : Boolean; 
      FDuplex                   : TApdSapiDuplex; 
      FWaitMode                 : TApdSapiWaitMode; 
      FInitSR                   : Boolean;                               {!!.04} 
      FInitSS                   : Boolean;                               {!!.04} 
 
      FOnInterference           : TApdSRInterferenceEvent; 
      FOnPhraseFinish           : TApdSRPhraseFinishEvent; 
      FOnPhraseHypothesis       : TApdSRPhraseHypothesisEvent; 
      FOnSpeakStart             : TApdSapiNotifyEvent; 
      FOnSpeakStop              : TApdSapiNotifyEvent; 
      FOnSRError                : TApdOnSapiError; 
      FOnSRWarning              : TApdOnSapiError; 
      FOnSSAttributeChanged     : TApdSSAttributeChanged; 
      FOnSSError                : TApdOnSapiError; 
      FOnSSWarning              : TApdOnSapiError; 
      FOnTrainingRequested      : TApdSRTrainingRequestedEvent; 
      FOnVUMeter                : TApdSRVUMeterEvent; 
 
    protected 
      function GetSRAmplitude : Word; 
      function GetSRAutoGain : Integer; 
      procedure InitializeSpeaking (var CSet : Integer; 
                                    var Options : Integer); 
      procedure Loaded; override; 
      procedure SetAutoTrain (v : Boolean); 
      procedure SetCharSet (v : TApdCharacterSet); 
      procedure SetDictation (v : Boolean); 
      procedure SetDuplex (v : TApdSapiDuplex); 
      procedure SetInitSR (const v : Boolean);                           {!!.04} 
      procedure SetInitSS (const v : Boolean);                           {!!.04}                                   
      procedure SetListening (v : Boolean); 
      procedure SetSpeaking (v : Boolean); 
      procedure SetSRAutoGain (Value: Integer); 
      procedure SetTTSOptions (v : TApdTTSOptions); 
      procedure SetWordList (v : TStringList); 
 
      procedure TriggerAudioStart (Sender : TObject; hi : Integer; 
                                   lo : Integer); 
      procedure TriggerAudioStop (Sender : TObject; hi : Integer; 
                                  lo : Integer); 
      procedure TriggerInterference (Sender : TObject; beginhi : Integer; 
                                     beginlo : Integer; endhi : Integer; 
                                     endlo : Integer; type_ : Integer); 
      procedure TriggerPhraseFinish (Sender : TObject; flags : Integer; 
                                     beginhi : Integer; beginlo : Integer; 
                                     endhi : Integer; endlo : Integer; 
                                     const Phrase : WideString; 
                                     const parsed : WideString; 
                                     results : Integer); 
      procedure TriggerPhraseFinishClients (Phrase : string; Results : Integer); 
      procedure TriggerPhraseHypothesis (Sender : TObject; flags : Integer; 
                                         beginhi : Integer; beginlo : Integer; 
                                         endhi : Integer; endlo : Integer; 
                                         const Phrase : WideString; 
                                         results : Integer); 
      procedure TriggerSpeakStart (Sender : TObject; beginhi : Integer; 
                                   beginlo : Integer); 
      procedure TriggerSpeakStop (Sender : TObject; beginhi : Integer; 
                                  beginlo : Integer; endhi : Integer; 
                                  endlo : Integer); 
      procedure TriggerSRError (Sender : TObject; Error : LongWord; 
                                const Details : WideString; 
                                const Message : WideString); 
      procedure TriggerSRWarning (Sender : TObject; Error : LongWord; 
                                  const Details : WideString; 
                                  const Message : WideString); 
      procedure TriggerSSAttribChanged (Sender : TObject; Attribute: Integer); 
      procedure TriggerSSError (Sender : TObject; Error : LongWord; 
                                const Details : WideString; 
                                const Message : WideString); 
      procedure TriggerSSWarning (Sender : TObject; Error : LongWord; 
                                  const Details : WideString; 
                                  const Message : WideString); 
      procedure TriggerTrainingRequested (Sender : TObject; train : Integer); 
      procedure TriggerVUMeter (Sender : TObject; beginhi : Integer; 
                                beginlo : Integer; level : Integer); 
      procedure WndProc (var Message : TMessage); 
 
    public 
      constructor Create (AOwner : TComponent); override; 
      destructor Destroy; override; 
 
      procedure CheckError (ErrorCode : DWORD); 
      procedure DeRegisterPhraseFinishHook ( 
                                 PhraseFinishMethod : TApdPhraseFinishMethod); 
      procedure InitializeSapi;                                        {!!.01} 
      procedure InitializeSR;                                          {!!.04} 
      procedure InitializeSS;                                          {!!.04} 
      function IsSapi4Installed : Boolean; 
      procedure Listen; 
      procedure PauseListening; 
      procedure PauseSpeaking; 
      procedure RegisterPhraseFinishHook ( 
                                 PhraseFinishMethod : TApdPhraseFinishMethod); 
      procedure ResumeListening; 
      procedure ResumeSpeaking; 
      procedure ShowAboutDlg (const Caption : string); 
      procedure ShowGeneralDlg (const Caption : string); 
      procedure ShowLexiconDlg (const Caption : string); 
      procedure ShowSRAboutDlg (const Caption : string); 
      procedure ShowSRGeneralDlg (const Caption : string); 
      procedure ShowSRLexiconDlg (const Caption : string); 
      procedure ShowSSAboutDlg (const Caption : string); 
      procedure ShowSSGeneralDlg (const Caption : string); 
      procedure ShowSSLexiconDlg (const Caption : string); 
      procedure ShowTrainGeneralDlg (const Caption : string); 
      procedure ShowTrainMicDlg (const Caption : string); 
      procedure ShowTranslateDlg (const Caption : string); 
      procedure Speak (Text : string); 
      procedure SpeakFile (FileName : string); 
      procedure SpeakFileToFile (const InFile, OutFile : string); 
      procedure SpeakStream (Stream : TStream; FileName : string); 
      procedure SpeakToFile (const Text, FileName : string); 
      procedure StopListening; 
      procedure StopSpeaking; 
      procedure WaitUntilDoneSpeaking; 
 
      property DirectSR : TDirectSR read FiDirectSR write FiDirectSR; 
      property DirectSS : TDirectSS read FiDirectSS write FiDirectSS; 
      property InitSR : Boolean read FInitSR write SetInitSR             {!!.04} 
               default True;                                             {!!.04} 
      property InitSS : Boolean read FInitSS write SetInitSS             {!!.04} 
               default True;                                             {!!.04} 
      property Listening : Boolean read FListening write SetListening; 
      property Speaking : Boolean read FSpeaking write SetSpeaking; 
      property SREngines: TApdSREngines 
               read FSREngines write FSREngines; 
      property SSVoices : TApdSSVoices 
               read FSSVoices write FSSVoices; 
 
    published 
      property AutoTrain : Boolean read FAutoTrain write SetAutoTrain 
               default False; 
      property CharSet : TApdCharacterSet read FCharSet write SetCharSet; 
      property Dictation : Boolean read FDictation write SetDictation; 
      property Duplex : TApdSapiDuplex 
               read FDuplex write SetDuplex default sdHalfDelayed; 
      property SRAmplitude : Word read GetSRAmplitude; 
      property SRAutoGain : Integer read GetSRAutoGain write SetSRAutoGain; 
      property TTSOptions : TApdTTSOptions 
               read FTTSOptions write SetTTSOptions; 
      property WordList : TStringLIst read FWordList write SetWordList; 
 
      property OnInterference : TApdSRInterferenceEvent 
               read FOnInterference write FOnInterference; 
      property OnPhraseFinish : TApdSRPhraseFinishEvent 
               read FOnPhraseFinish write FOnPhraseFinish; 
      property OnPhraseHypothesis : TApdSRPhraseHypothesisEvent 
               read FOnPhraseHypothesis write FOnPhraseHypothesis; 
      property OnSpeakStart : TApdSapiNotifyEvent 
               read FOnSpeakStart write FOnSpeakStart; 
      property OnSpeakStop : TApdSapiNotifyEvent 
               read FOnSpeakStop write FOnSpeakStop; 
      property OnSRError : TApdOnSapiError read FOnSRError write FOnSRError; 
      property OnSRWarning : TApdOnSapiError 
               read FOnSRWarning write FOnSRWarning; 
      property OnSSAttributeChanged : TApdSSAttributeChanged 
               read FOnSSAttributeChanged write FOnSSAttributeChanged; 
      property OnSSError : TApdOnSapiError read FOnSSError write FOnSSError; 
      property OnSSWarning : TApdOnSapiError 
               read FOnSSWarning write FOnSSWarning; 
      property OnTrainingRequested : TApdSRTrainingRequestedEvent 
               read FOnTrainingRequested write FOnTrainingRequested; 
      property OnVUMeter : TApdSRVUMeterEvent 
               read FOnVUMeter write FOnVUMeter; 
  end; 
 
  TApdSapiEngine = class (TApdCustomSapiEngine) 
    published 
      property CharSet; 
      property Dictation; 
      property SRAmplitude; 
      property SRAutoGain; 
      property TTSOptions; 
      property WordList; 
 
      property OnInterference; 
      property OnPhraseFinish; 
      property OnPhraseHypothesis; 
      property OnSpeakStart; 
      property OnSpeakStop; 
      property OnSRError; 
      property OnSRWarning; 
      property OnSSAttributeChanged; 
      property OnSSError; 
      property OnSSWarning; 
      property OnTrainingRequested; 
      property OnVUMeter; 
  end; 
 
{.Z+} 
function SearchSapiEngine (const C : TComponent) : TApdCustomSapiEngine; 
{.Z-} 
 
implementation 
 
{Miscellaneous procedures} 
 
function SearchSapiEngine (const C : TComponent) : TApdCustomSapiEngine; 
{-Search for a sapi engine in the same form as TComponent} 
 
  function FindSapiEngine (const C : TComponent) : TApdCustomSapiEngine; 
  var 
    I  : Integer; 
  begin 
    Result := nil; 
    if not Assigned (C) then 
      Exit; 
 
    {Look through all of the owned components} 
    for I := 0 to C.ComponentCount - 1 do begin 
      if C.Components[I] is TApdCustomSapiEngine then begin 
        Result := TApdCustomSapiEngine (C.Components[I]); 
        Exit; 
      end; 
 
      {If this isn't one, see if it owns other components} 
      Result := FindSapiEngine (C.Components[I]); 
    end; 
  end; 
 
begin 
  {Search the entire form} 
  Result := FindSapiEngine (C); 
end; 
 
{ EApdSapiEngineException } 
 
constructor EApdSapiEngineException.Create (const ErrCode : Integer; 
                                            const Msg : string); 
begin 
  inherited Create (Msg); 
 
  FErrorCode := ErrCode; 
end; 
 
{ TApdSSVoices } 
 
function TApdSSVoices.CheckIndex (x : Integer) : Boolean; 
begin 
  if not Assigned (FiDirectSS) then 
    raise EApdSapiEngineException.CreateFmt (ecApdNOSS, [0]); 
  if (x < 0) or (x >= FiDirectSS.CountEngines) then 
    raise EApdSapiEngineException.CreateFmt (ecApdBadIndex, [0]); 
  Result := True; 
end; 
 
function TApdSSVoices.Find (Criteria : string) : Integer; 
begin 
  Result := FiDirectSS.Find (Criteria); 
end; 
 
function TApdSSVoices.GetAge (x : Integer) : TApdTTSAge; 
 
  function ConvertAge (v : Integer) : TApdTTSAge; 
  begin 
    case v of 
      ApdTTSAGE_BABY       : Result := tsBaby; 
      ApdTTSAGE_TODDLER    : Result := tsToddler; 
      ApdTTSAGE_CHILD      : Result := tsChild; 
      ApdTTSAGE_ADOLESCENT : Result := tsAdolescent; 
      ApdTTSAGE_ADULT      : Result := tsAdult; 
      ApdTTSAGE_ELDERLY    : Result := tsElderly; 
    else 
      Result := tsUnknown; 
    end; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertAge (FiDirectSS.Age (x + 1)); 
end; 
 
function TApdSSVoices.GetCount : Integer; 
begin 
  Result := FiDirectSS.CountEngines; 
end; 
 
function TApdSSVoices.GetCurrentVoice : Integer; 
begin 
  result := FCurrentVoice; 
end; 
 
function TApdSSVoices.GetDialect (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.Dialect (x + 1); 
end; 
 
function TApdSSVoices.GetEngineFeatures (x : Integer) : Integer; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.EngineFeatures (x + 1); 
end; 
 
function TApdSSVoices.GetEngineID (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.EngineID (x + 1); 
end; 
 
function TApdSSVoices.GetFeatures (x : Integer) : TApdTTSFeatures; 
 
  function ConvertFeatures (v : Integer) :  TApdTTSFeatures; 
  begin 
    Result := []; 
    if (v and ApdTTSFEATURE_ANYWORD) <> 0 then 
      Result := Result + [tfAnyWord]; 
    if (v and ApdTTSFEATURE_VOLUME) <> 0 then 
      Result := Result + [tfVolume]; 
    if (v and ApdTTSFEATURE_SPEED) <> 0 then 
      Result := Result + [tfSpeed]; 
    if (v and ApdTTSFEATURE_PITCH) <> 0 then 
      Result := Result + [tfPitch]; 
    if (v and ApdTTSFEATURE_TAGGED) <> 0 then 
      Result := Result + [tfTagged]; 
    if (v and ApdTTSFEATURE_IPAUNICODE) <> 0 then 
      Result := Result + [tfIPAUnicode]; 
    if (v and ApdTTSFEATURE_VISUAL) <> 0 then 
      Result := Result + [tfVisual]; 
    if (v and ApdTTSFEATURE_WORDPOSITION) <> 0 then 
      Result := Result + [tfWordPosition]; 
    if (v and ApdTTSFEATURE_PCOPTIMIZED) <> 0 then 
      Result := Result + [tfPCOptimized]; 
    if (v and ApdTTSFEATURE_PHONEOPTIMIZED) <> 0 then 
      Result := Result + [tfPhoneOptimized]; 
    if (v and ApdTTSFEATURE_FIXEDAUDIO) <> 0 then 
      Result := Result + [tfFixedAudio]; 
    if (v and ApdTTSFEATURE_SINGLEINSTANCE) <> 0 then 
      Result := Result + [tfSingleInstance]; 
    if (v and ApdTTSFEATURE_THREADSAFE) <> 0 then 
      Result := Result + [tfThreadSafe]; 
    if (v and ApdTTSFEATURE_IPATEXTDATA) <> 0 then 
      Result := Result + [tfIPATextData]; 
    if (v and ApdTTSFEATURE_PREFERRED) <> 0 then 
      Result := Result + [tfPreferred]; 
    if (v and ApdTTSFEATURE_TRANSPLANTED) <> 0 then 
      Result := Result + [tfTransplanted]; 
    if (v and ApdTTSFEATURE_SAPI4) <> 0 then 
      Result := Result + [tfSAPI4]; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertFeatures (FiDirectSS.Features (x + 1)); 
end; 
 
function TApdSSVoices.GetGender (x : Integer) : TApdTTSGender; 
 
  function ConvertGender (v : Integer) : TApdTTSGender; 
  begin 
    case v of 
      ApdGENDER_NEUTRAL : Result := tgNeutral; 
      ApdGENDER_FEMALE  : Result := tgFemale; 
      ApdGENDER_MALE    : Result := tgMale; 
    else 
       Result := tgUnknown; 
    end; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertGender (FiDirectSS.Gender (x + 1)); 
end; 
 
function TApdSSVoices.GetInterfaces (x : Integer) : TApdTTSInterfaces; 
 
  function ConvertInterfaces (v : Integer) : TApdTTSInterfaces; 
  begin 
    Result := []; 
    if (v and ApdTTSI_ILEXPRONOUNCE) <> 0 then 
      Result := Result + [tiLexPronounce]; 
    if (v and ApdTTSI_ITTSATTRIBUTES) <> 0 then 
      Result := Result + [tiTTSAttributes]; 
    if (v and ApdTTSI_ITTSCENTRAL) <> 0 then 
      Result := Result + [tiTTSCentral]; 
    if (v and ApdTTSI_ITTSDIALOGS) <> 0 then 
      Result := Result + [tiTTSDialogs]; 
    if (v and ApdTTSI_ATTRIBUTES) <> 0 then 
      Result := Result + [tiAttributes]; 
    if (v and ApdTTSI_IATTRIBUTES) <> 0 then 
      Result := Result + [tiIAttributes]; 
    if (v and ApdTTSI_ILEXPRONOUNCE2) <> 0 then 
      Result := Result + [tiLexPronounce2]; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertInterfaces (FiDirectSS.Interfaces (x + 1)); 
end; 
 
function TApdSSVoices.GetLanguageID (x : Integer) : Integer; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.LanguageID (x + 1); 
end; 
 
function TApdSSVoices.GetMfgName (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.MfgName (x + 1); 
end; 
 
function TApdSSVoices.GetModeID (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.ModeID (x + 1); 
end; 
 
function TApdSSVoices.GetModeName (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.ModeName (x + 1); 
end; 
 
function TApdSSVoices.GetProductName (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.ProductName (x + 1); 
end; 
 
function TApdSSVoices.GetSpeaker (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.Speaker (x + 1); 
end; 
 
function TApdSSVoices.GetStyle (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSS.Style (x + 1); 
end; 
 
procedure TApdSSVoices.SetCurrentVoice (v : Integer); 
begin 
  if v <> FCurrentVoice then begin 
    CheckIndex (v); 
    FiDirectSS.Select (v + 1); 
    FCurrentVoice := v; 
  end; 
end; 
 
{ TApdSREngines } 
 
function TApdSREngines.CheckIndex (x : Integer) : Boolean; 
begin 
  if not Assigned (FiDirectSR) then 
    raise EApdSapiEngineException.CreateFmt (ecApdNoSR, [0]); 
  if (x < 0) or (x >= FiDirectSR.CountEngines) then 
    raise EApdSapiEngineException.CreateFmt (ecApdBadIndex, [0]); 
  Result := True; 
end; 
 
function TApdSREngines.GetCount : Integer; 
begin 
  Result := FiDirectSR.CountEngines; 
end; 
 
function TApdSREngines.GetCurrentEngine : Integer; 
begin 
  Result := FCurrentEngine; 
end; 
 
function TApdSREngines.GetDialect (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.Dialect (x + 1); 
end; 
 
function TApdSREngines.GetEngineFeatures (x : Integer) : Integer; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.EngineFeatures (x + 1); 
end; 
 
function TApdSREngines.GetEngineId (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.EngineId (x + 1); 
end; 
 
function TApdSREngines.GetFeatures (x : Integer) : TApdSRFeatures; 
 
  function ConvertFeatures (v : Integer) : TApdSRFeatures; 
  begin 
    Result := []; 
    if (v and ApdSRFEATURE_INDEPSPEAKER) <> 0 then 
      Result := Result + [sfIndepSpeaker]; 
    if (v and ApdSRFEATURE_INDEPMICROPHONE) <> 0 then 
      Result := Result + [sfIndepMicrophone]; 
    if (v and ApdSRFEATURE_TRAINWORD) <> 0 then 
      Result := Result + [sfTrainWord]; 
    if (v and ApdSRFEATURE_TRAINPHONETIC) <> 0 then 
      Result := Result + [sfTrainPhonetic]; 
    if (v and ApdSRFEATURE_WILDCARD) <> 0 then 
      Result := Result + [sfWildcard]; 
    if (v and ApdSRFEATURE_ANYWORD) <> 0 then 
      Result := Result + [sfAnyWord]; 
    if (v and ApdSRFEATURE_PCOPTIMIZED) <> 0 then 
      Result := Result + [sfPCOptimized]; 
    if (v and ApdSRFEATURE_PHONEOPTIMIZED) <> 0 then 
      Result := Result + [sfPhoneOptimized]; 
    if (v and ApdSRFEATURE_GRAMLIST) <> 0 then 
      Result := Result + [sfGramList]; 
    if (v and ApdSRFEATURE_GRAMLINK) <> 0 then 
      Result := Result + [sfGramLink]; 
    if (v and ApdSRFEATURE_MULTILINGUAL) <> 0 then 
      Result := Result + [sfMultiLingual]; 
    if (v and ApdSRFEATURE_GRAMRECURSIVE) <> 0 then 
      Result := Result + [sfGramRecursive]; 
    if (v and ApdSRFEATURE_IPAUNICODE) <> 0 then 
      Result := Result + [sfIPAUnicode]; 
    if (v and ApdSRFEATURE_SINGLEINSTANCE) <> 0 then 
      Result := Result + [sfSingleInstance]; 
    if (v and ApdSRFEATURE_THREADSAFE) <> 0 then 
      Result := Result + [sfThreadSafe]; 
    if (v and ApdSRFEATURE_FIXEDAUDIO) <> 0 then 
      Result := Result + [sfFixedAudio]; 
    if (v and ApdSRFEATURE_IPAWORD) <> 0 then 
      Result := Result + [sfIPAWord]; 
    if (v and ApdSRFEATURE_SAPI4) <> 0 then 
      Result := Result + [sfSAPI4]; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertFeatures (FiDirectSR.Features (x + 1)); 
end; 
 
function TApdSREngines.GetGrammars (x : Integer) : TApdSRGrammars; 
 
  function ConvertGrammars (v : Integer) : TApdSRGrammars; 
  begin 
    Result := []; 
    if (v and ApdSRGRAM_CFG) <> 0 then 
      Result := Result + [sgCFG]; 
    if (v and ApdSRGRAM_DICTATION) <> 0 then 
      Result := Result + [sgDictation]; 
    if (v and ApdSRGRAM_LIMITEDDOMAIN) <> 0 then 
      Result := Result + [sgLimitedDomain]; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertGrammars (FiDirectSR.Grammars (x + 1)); 
end; 
 
function TApdSREngines.GetInterfaces (x : Integer) : TApdSRInterfaces; 
 
  function ConvertInterfaces (v : Integer) : TApdSRInterfaces; 
  begin 
    Result := []; 
    if (v and ApdSRI_ILEXPRONOUNCE) <> 0 then 
      Result := Result + [siLexPronounce]; 
    if (v and ApdSRI_ISRATTRIBUTES) <> 0 then 
      Result := Result + [siSRAttributes]; 
    if (v and ApdSRI_ISRCENTRAL) <> 0 then 
      Result := Result + [siSRCentral]; 
    if (v and ApdSRI_ISRDIALOGS) <> 0 then 
      Result := Result + [siSRDialogs]; 
    if (v and ApdSRI_ISRGRAMCOMMON) <> 0 then 
      Result := Result + [siSRGramCommon]; 
    if (v and ApdSRI_ISRGRAMCFG) <> 0 then 
      Result := Result + [siSRGramCFG]; 
    if (v and ApdSRI_ISRGRAMDICTATION) <> 0 then 
      Result := Result + [siSRGramDictation]; 
    if (v and ApdSRI_ISRGRAMINSERTIONGUI) <> 0 then 
      Result := Result + [siSRGramInsertionGui]; 
    if (v and ApdSRI_ISRESBASIC) <> 0 then 
      Result := Result + [siSREsBasic]; 
    if (v and ApdSRI_ISRESMERGE) <> 0 then 
      Result := Result + [siSREsMerge]; 
    if (v and ApdSRI_ISRESAUDIO) <> 0 then 
      Result := Result + [siSREsAudio]; 
    if (v and ApdSRI_ISRESCORRECTION) <> 0 then 
      Result := Result + [siSREsCorrection]; 
    if (v and ApdSRI_ISRESEVAL) <> 0 then 
      Result := Result + [siSREsEval]; 
    if (v and ApdSRI_ISRESGRAPH) <> 0 then 
      Result := Result + [siSREsGraph]; 
    if (v and ApdSRI_ISRESMEMORY) <> 0 then 
      Result := Result + [siSREsMemory]; 
    if (v and ApdSRI_ISRESMODIFYGUI) <> 0 then 
      Result := Result + [siSREsModifyGui]; 
    if (v and ApdSRI_ISRESSPEAKER) <> 0 then 
      Result := Result + [siSREsSpeaker]; 
    if (v and ApdSRI_ISRSPEAKER) <> 0 then 
      Result := Result + [siSRSpeaker]; 
    if (v and ApdSRI_ISRESSCORES) <> 0 then 
      Result := Result + [siSREsScores]; 
    if (v and ApdSRI_ISRESAUDIOEX) <> 0 then 
      Result := Result + [siSREsAudioEx]; 
    if (v and ApdSRI_ISRGRAMLEXPRON) <> 0 then 
      Result := Result + [siSRGramLexPron]; 
    if (v and ApdSRI_ISRRESGRAPHEX) <> 0 then 
      Result := Result + [siSREsGraphEx]; 
    if (v and ApdSRI_ILEXPRONOUNCE2) <> 0 then 
      Result := Result + [siLexPronounce2]; 
    if (v and ApdSRI_IATTRIBUTES) <> 0 then 
      Result := Result + [siAttributes]; 
    if (v and ApdSRI_ISRSPEAKER2) <> 0 then 
      Result := Result + [siSRSpeaker2]; 
    if (v and ApdSRI_ISRDIALOGS2) <> 0 then 
      Result := Result + [siSRDialogs2]; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertInterfaces (FiDirectSR.Interfaces (x + 1)); 
end; 
 
function TApdSREngines.GetLanguageID (x : Integer) : Integer; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.LanguageID (x + 1); 
end; 
 
function TApdSREngines.GetMaxWordsState (x : Integer) : Integer; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.MaxWordsState (x + 1); 
end; 
 
function TApdSREngines.GetMaxWordsVocab (x : Integer) : Integer; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.MaxWordsVocab (x + 1); 
end; 
 
function TApdSREngines.GetMfgName (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.MfgName (x + 1); 
end; 
 
function TApdSREngines.GetModeID (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.ModeID (x + 1); 
end; 
 
function TApdSREngines.GetModeName (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.ModeName (x + 1); 
end; 
 
function TApdSREngines.GetProductName (x : Integer) : string; 
begin 
  CheckIndex (x); 
  Result := FiDirectSR.ProductName (x + 1); 
end; 
 
function TApdSREngines.GetSequencing (x : Integer) : TApdSRSequences; 
 
  function ConvertSequencing (v : Integer) : TApdSRSequences; 
  begin 
    case v of 
      ApdSRSEQUENCE_DISCRETE        : Result := ssDiscrete; 
      ApdSRSEQUENCE_CONTINUOUS      : Result := ssContinuous; 
      ApdSRSEQUENCE_WORDSPOT        : Result := ssWordSpot; 
      ApdSRSEQUENCE_CONTCFGDISCDICT : Result := ssContCFGDiscDict; 
    else 
      Result := ssUnknown; 
    end; 
  end; 
 
begin 
  CheckIndex (x); 
  Result := ConvertSequencing (FiDirectSR.Sequencing (x + 1)); 
end; 
 
procedure TApdSREngines.SetCurrentEngine (v : Integer); 
begin 
  if v <> FCurrentEngine then begin 
    CheckIndex (v); 
    FiDirectSR.Select (v + 1); 
    FCurrentEngine := v; 
  end; 
end; 
 
{ TApdCustomSapiEngine }                      
 
constructor TApdCustomSapiEngine.Create (AOwner : TComponent); 
begin 
  inherited Create (AOwner); 
 
  FInitSR := True;                                                     {!!.04} 
  FInitSS := True;                                                     {!!.04} 
 
  FHandle := AllocateHWnd (WndProc); 
 
  (*if not IsSapi4Installed then begin                                 {!!.04} 
    if Assigned (FOnSRError) then                                      {!!.04} 
      FOnSRError (Self, 0, '', ApdStrE_NOSAPI4);                       {!!.04} 
    if Assigned (FOnSSError) then                                      {!!.04} 
      FOnSSError (Self, 0, '', ApdStrE_NOSAPI4);                       {!!.04} 
  end; *)                                                              {!!.04} 
 
  FSpeaking := False; 
  FListening := False; 
  FDuplex := sdHalfDelayed; 
  FWaitMode := wmNone; 
 
  { Create needed classes } 
 
  FWordList := TStringList.Create; 
  FSSVoices := TApdSSVoices.Create; 
  FSREngines := TApdSREngines.Create; 
 
  { Create Registers } 
 
  FPhraseFinishClients := TList.Create; 
 
  FiDirectSS := nil; 
  FiDirectSR := nil; 
 
  FAutoTrain := False; 
end; 
 
destructor TApdCustomSapiEngine.Destroy; 
var 
  i : Integer; 
   
begin 
  FWordList.Free; 
 
  FSSVoices.Free; 
  FSREngines.Free; 
 
  for i := 0 to FPhraseFinishClients.Count - 1 do begin 
    Dispose (FPhraseFinishClients[i]); 
  end; 
  FPhraseFinishClients.Free; 
 
  if Assigned (FiDirectSS) then 
    FiDirectSS.Free; 
  if Assigned (FiDirectSR) then 
    FiDirectSR.Free; 
 
  if FHandle <> 0 then 
    DeallocateHWnd (FHandle); 
  inherited Destroy; 
end; 
 
procedure TApdCustomSapiEngine.CheckError (ErrorCode : DWORD); 
begin 
  case ErrorCode of 
    ApdSRERR_NONE                       : 
      begin 
      end; 
 
  { SS } 
 
    ApdTTSERR_INVALIDINTERFACE          : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_INVALIDINTERFACE); 
    ApdTTSERR_OUTOFDISK                 : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_OUTOFDISK); 
    ApdTTSERR_NOTSUPPORTED              : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_NOTSUPPORTED); 
    ApdTTSERR_VALUEOUTOFRANGE           : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_VALUEOUTOFRANGE); 
    ApdTTSERR_INVALIDWINDOW             : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_INVALIDWINDOW); 
    ApdTTSERR_INVALIDPARAM              : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_INVALIDPARAM); 
    ApdTTSERR_INVALIDMODE               : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_INVALIDMODE); 
    ApdTTSERR_INVALIDKEY                : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_INVALIDKEY); 
    ApdTTSERR_WAVEFORMATNOTSUPPORTED    : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                          ApdStrTTSERR_WAVEFORMATNOTSUPPORTED); 
    ApdTTSERR_INVALIDCHAR               : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_INVALIDCHAR); 
    ApdTTSERR_QUEUEFULL                 : 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrTTSERR_QUEUEFULL); 
    ApdTTSERR_WAVEDEVICEBUSY            : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_WAVEDEVICEBUSY); 
    ApdTTSERR_NOTPAUSED                 : 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrTTSERR_NOTPAUSED); 
    ApdTTSERR_ALREADYPAUSED             : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrTTSERR_ALREADYPAUSED); 
 
  { SR } 
 
    ApdSRERR_NOTENOUGHDATA              : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_NOTENOUGHDATA); 
    ApdSRERR_GRAMMARTOOCOMPLEX          : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMMARTOOCOMPLEX); 
    ApdSRERR_GRAMMARWRONGTYPE           : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMMARWRONGTYPE); 
    ApdSRERR_TOOMANYGRAMMARS            : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_INVALIDLIST); 
    ApdSRERR_INVALIDLIST                : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_INVALIDLIST); 
    ApdSRERR_GRAMTOOLARGE               : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMTOOLARGE); 
    ApdSRERR_INVALIDFLAG                : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_INVALIDFLAG); 
    ApdSRERR_GRAMMARERROR               : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMMARERROR); 
    ApdSRERR_INVALIDRULE                : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_INVALIDRULE); 
    ApdSRERR_RULEALREADYACTIVE          : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_RULEALREADYACTIVE); 
    ApdSRERR_RULENOTACTIVE              : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_RULENOTACTIVE); 
    ApdSRERR_NOUSERSELECTED             : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_NOUSERSELECTED); 
    ApdSRERR_BAD_PRONUNCIATION          : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_BAD_PRONUNCIATION); 
    ApdSRERR_DATAFILEERROR              : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_DATAFILEERROR); 
    ApdSRERR_GRAMMARALREADYACTIVE       : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMMARALREADYACTIVE); 
    ApdSRERR_GRAMMARNOTACTIVE           : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMMARNOTACTIVE); 
    ApdSRERR_GLOBALGRAMMARALREADYACTIVE : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                       ApdStrSRERR_GLOBALGRAMMARALREADYACTIVE); 
    ApdSRERR_LANGUAGEMISMATCH           : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_LANGUAGEMISMATCH); 
    ApdSRERR_MULTIPLELANG               : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_MULTIPLELANG); 
    ApdSRERR_LDGRAMMARNOWORDS           : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_LDGRAMMARNOWORDS); 
    ApdSRERR_NOLEXICON                  : 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrSRERR_NOLEXICON); 
    ApdSRERR_SPEAKEREXISTS              : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_SPEAKEREXISTS); 
    ApdSRERR_GRAMMARENGINEMISMATCH      : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_GRAMMARENGINEMISMATCH); 
    ApdSRERR_BOOKMARKEXISTS             : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_BOOKMARKEXISTS); 
    ApdSRERR_BOOKMARKDOESNOTEXIST       : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_BOOKMARKDOESNOTEXIST); 
    ApdSRERR_MICWIZARDCANCELED          : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_MICWIZARDCANCELED); 
    ApdSRERR_WORDTOOLONG                : 
      raise EApdSapiEngineException.Create (ErrorCode, 
                                            ApdStrSRERR_WORDTOOLONG); 
    ApdSRERR_BAD_WORD                   : 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrSRERR_BAD_WORD); 
    ApdE_WRONGTYPE                      : 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrE_WRONGTYPE); 
    ApdE_BUFFERTOOSMALL                 : 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrE_BUFFERTOOSMALL); 
    else 
      raise EApdSapiEngineException.Create (ErrorCode, ApdStrE_UNKNOWN); 
  end; 
end; 
 
procedure TApdCustomSapiEngine.DeRegisterPhraseFinishHook ( 
                                 PhraseFinishMethod : TApdPhraseFinishMethod); 
var 
  Idx : Integer; 
  Event : PApdRegisteredEvent; 
 
begin 
  for Idx := FPhraseFinishClients.Count - 1 downto 0 do begin 
    Event := FPhraseFinishClients[Idx]; 
    if (@Event.CallBack = @PhraseFinishMethod) then 
      FPhraseFinishClients.Delete (Idx); 
  end; 
end; 
 
function TApdCustomSapiEngine.GetSRAmplitude : Word; 
begin 
  result := FSRAmplitude; 
end; 
 
function TApdCustomSapiEngine.GetSRAutoGain : Integer; 
begin 
  if Assigned (FiDirectSR) then 
    FSRAutoGain := FiDirectSR.AutoGain; 
  Result := FSRAutoGain; 
end; 
 
procedure TApdCustomSapiEngine.InitializeSapi;                         {!!.01} 
{ InitializeSapi is called by Loaded to initialize the SAPI engines }  {!!.01} 
{ It should not be called directly UNLESS the TApdCustomSapiEngine  }  {!!.01} 
{ is being created dynamically.  In this case, InitializeSapi       }  {!!.01} 
{ be called after the creation to initialize the SAPI engine.       }  {!!.01} 
begin                                                                  {!!.01} 
  if InitSS then                                                       {!!.04} 
    InitializeSS;                                                      {!!.04} 
  if InitSR then                                                       {!!.04} 
    InitializeSR;                                                      {!!.04} 
end;                                                                   {!!.01} 
 
procedure TApdCustomSapiEngine.InitializeSpeaking (var CSet : Integer; 
                                                   var Options : Integer); 
begin 
  Speaking := True; 
  case CharSet of 
    csText           : CSet := ApdCHARSET_TEXT; 
    csIPAPhonetic    : CSet := ApdCHARSET_IPAPHONETIC; 
    csEnginePhonetic : CSet := ApdCHARSET_ENGINEPHONETIC; 
  else 
    CSet := ApdCHARSET_TEXT; 
  end; 
  Options := 0; 
  if toTagged in TTSOptions then 
    Options := Options or ApdTTSDATAFLAG_TAGGED; 
end; 
 
procedure TApdCustomSapiEngine.InitializeSR;                             {!!.04} 
begin                                                                    {!!.04} 
  if (not ((csDesigning in ComponentState) or                            {!!.04} 
           (csLoading in ComponentState))) and                           {!!.04} 
      (FiDirectSR = nil) then begin                                      {!!.04} 
 
    { Create the SAPI Interaces }                                        {!!.04} 
 
    try                                                                  {!!.04} 
      FiDirectSR := TDirectSR.Create (Self);                             {!!.04} 
      FiDirectSR.Visible := False;                                       {!!.04} 
      FSREngines.FiDirectSR := FiDirectSR;                               {!!.04} 
      FiDirectSR.Initialized := 1;                                       {!!.04} 
    except                                                               {!!.04} 
      on EOleError do                                                    {!!.04} 
        TriggerSRError (Self, 0, '', ApdStrE_CANNOTCREATESR);            {!!.04} 
    end;                                                                 {!!.04} 
 
    { Set the speaker.  Since there doesn't seem to be a way to determine 
      what the users are, use a default user.  Sapi will automatically 
      use this user name. } 
 
    try                                                                  {!!.04} 
      FiDirectSR.Speaker := scApdDefaultUser;                            {!!.04} 
    except                                                               {!!.04} 
      on EOleError do                                                    {!!.04} 
        TriggerSRError (Self, 0, '', ApdStrE_CANNOTSETSPEAKER);          {!!.04} 
    end;                                                                 {!!.04} 
 
    try                                                                  {!!.04} 
      FiDirectSR.Microphone := scApdDefaultMic;                          {!!.04} 
    except                                                               {!!.04} 
      on EOleError do                                                    {!!.04} 
        TriggerSRError (Self, 0, '', ApdStrE_CANNOTSETMIC);              {!!.04} 
    end;                                                                 {!!.04} 
 
    { Connect events }                                                   {!!.04} 
 
    FiDirectSR.OnPhraseFinish := TriggerPhraseFinish;                    {!!.04} 
    FiDirectSR.OnVUMeter := TriggerVUMeter;                              {!!.04} 
    FiDirectSR.OnUtteranceBegin := TriggerSpeakStart;                    {!!.04} 
    FiDirectSR.OnUtteranceEnd := TriggerSpeakStop;                       {!!.04} 
    FiDirectSR.OnInterference := TriggerInterference;                    {!!.04} 
    FiDirectSR.OnPhraseHypothesis := TriggerPhraseHypothesis;            {!!.04} 
    FiDirectSR.OnTraining := TriggerTrainingRequested;                   {!!.04} 
    FiDirectSR.OnWarning := TriggerSRWarning;                            {!!.04} 
    FiDirectSR.OnError := TriggerSRError;                                {!!.04} 
  end;                                                                   {!!.04} 
end;                                                                     {!!.04} 
 
procedure TApdCustomSapiEngine.InitializeSS;                             {!!.04} 
begin                                                                    {!!.04} 
  if (not ((csDesigning in ComponentState) or                            {!!.04} 
           (csLoading in ComponentState))) and                           {!!.04} 
      (FiDirectSS = nil) then begin                                      {!!.04} 
 
    { Create the SAPI Interaces }                                        {!!.04} 
 
    try                                                                  {!!.04} 
      FiDirectSS := TDirectSS.Create (Self);                             {!!.04} 
      FiDirectSS.Visible := False;                                       {!!.04} 
      FSSVoices.FiDirectSS := FiDirectSS;                                {!!.04} 
      FiDirectSS.Initialized := 1;                                       {!!.04} 
    except                                                               {!!.04} 
      on EOleError do                                                    {!!.04} 
        TriggerSSError (Self, 0, '', ApdStrE_CANNOTCREATESS);            {!!.04} 
    end;                                                                 {!!.04} 
 
    { Connect events }                                                   {!!.04} 
 
    FiDirectSS.OnAudioStart := TriggerAudioStart;                        {!!.04} 
    FiDirectSS.OnAudioStop := TriggerAudioStop;                          {!!.04} 
    FiDirectSS.OnError := TriggerSSError;                                {!!.04} 
    FiDirectSS.Onwarning := TriggerSSWarning;                            {!!.04} 
    FiDirectSS.OnAttribChanged := TriggerSSAttribChanged;                {!!.04} 
  end;                                                                   {!!.04} 
end;                                                                     {!!.04} 
 
function TApdCustomSapiEngine.IsSapi4Installed : Boolean; 
var 
  SysDir : PChar; 
begin 
  Result := True; 
  SysDir := StrAlloc (Max_Path); 
  try 
    if GetWindowsDirectory (SysDir, Max_Path) <> 0 then begin 
      if not FileExists (SysDir + '\Speech\Speech.DLL') then           {!!.01} 
        Result := False; 
    end; 
  finally 
    StrDispose (SysDir); 
  end;         
end; 
 
procedure TApdCustomSapiEngine.Listen; 
var 
  GrammarString : string; 
  i : Integer; 
begin 
  if SREngines.Count = 0 then 
    raise EApdSapiEngineException.CreateFmt (ecNoSREngines, [0]); 
  if Dictation then begin 
    GrammarString := '[Grammar]'^M^J'type=dictation'^M^J; 
    if WordList.Count > 0 then begin 
      GrammarString := GrammarString + '[WordGroups]'^M^J + 
                       '=ApdWords'^M^J + '[ApdWords]'^M^J; 
      for i := 0 to WordList.Count - 1 do 
        GrammarString := GrammarString + '=' + WordList[i] + ^M^J; 
    end; 
 
  end else begin 
    GrammarString := '[Grammar]'^M^J'type=cfg'^M^J; 
    if WordList.Count > 0 then begin 
      GrammarString := GrammarString + '[]'^M^J; 
      for i := 0 to WordList.Count - 1 do 
        GrammarString := GrammarString + '=' + WordList[i] + ^M^J; 
    end; 
  end; 
 
 
  FiDirectSR.GrammarFromString (GrammarString); 
 
  case Duplex of 
    sdFull : 
      Listening := True; 
    sdHalf : 
      if Speaking then begin 
        Speaking := False; 
        Listening := True; 
      end; 
    sdHalfDelayed : 
      if Speaking then 
        FWaitMode := wmWaitSpeaking; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.Loaded; 
begin 
  inherited Loaded; 
 
  if IsSapi4Installed then                                             {!!.04} 
    InitializeSapi                                                     {!!.01} 
  else begin                                                           {!!.04} 
    if Assigned (FOnSRError) then                                      {!!.04} 
      FOnSRError (Self, 0, '', ApdStrE_NOSAPI4);                       {!!.04} 
    if Assigned (FOnSSError) then                                      {!!.04} 
      FOnSSError (Self, 0, '', ApdStrE_NOSAPI4);                       {!!.04} 
  end;                                                                 {!!.04} 
end; 
 
procedure TApdCustomSapiEngine.PauseListening; 
begin 
  FiDirectSR.Pause; 
end; 
 
procedure TApdCustomSapiEngine.PauseSpeaking; 
begin 
  FiDirectSS.AudioPause; 
end; 
 
procedure TApdCustomSapiEngine.RegisterPhraseFinishHook ( 
                                 PhraseFinishMethod : TApdPhraseFinishMethod); 
 
var 
  Event : PApdRegisteredEvent; 
  Idx : Integer; 
  AlreadyRegistered : Boolean; 
 
begin 
  AlreadyRegistered := False; 
  for Idx := 0 to FPhraseFinishClients.Count - 1 do begin 
    Event := FPhraseFinishClients[Idx]; 
    if (@Event.CallBack = @PhraseFinishMethod) then 
      AlreadyRegistered := True; 
  end; 
  if not AlreadyRegistered then begin 
    New (Event); 
    Event.CallBack := PhraseFinishMethod; 
    Event.EventType := etPhraseFinish; 
    Event.Active := True; 
    FPhraseFinishClients.Add (Event);  
  end;     
end; 
 
procedure TApdCustomSapiEngine.ResumeListening; 
begin 
  FiDirectSR.Resume; 
end; 
 
procedure TApdCustomSapiEngine.ResumeSpeaking; 
begin 
  FiDirectSS.AudioResume; 
end; 
 
procedure TApdCustomSapiEngine.SetAutoTrain (v : Boolean); 
begin 
  if FAutoTrain <> v then 
    FAutoTrain := v; 
end; 
 
procedure TApdCustomSapiEngine.SetCharSet (v : TApdCharacterSet); 
begin 
  if FCharSet <> v then 
    FCharSet := v; 
end; 
 
procedure TApdCustomSapiEngine.SetDictation (v : Boolean); 
begin 
  if v <> FDictation then 
    FDictation := v; 
end; 
 
procedure TApdCustomSapiEngine.SetDuplex (v : TApdSapiDuplex); 
begin 
  if v <> FDuplex then 
    FDuplex := v; 
end; 
 
procedure TApdCustomSapiEngine.SetInitSR (const v : Boolean);            {!!.04} 
begin                                                                    {!!.04} 
  if v <> FInitSR then                                                   {!!.04} 
    FInitSR := v;                                                        {!!.04} 
end;                                                                     {!!.04} 
 
procedure TApdCustomSapiEngine.SetInitSS (const v : Boolean);            {!!.04} 
begin                                                                    {!!.04} 
  if v <> FInitSS then                                                   {!!.04} 
    FInitSS := v;                                                        {!!.04} 
end;                                                                     {!!.04} 
 
procedure TApdCustomSapiEngine.SetListening (v : Boolean); 
begin 
  if not Assigned (FiDirectSR) then begin                                {!!.04} 
    FListening := v;                                                     {!!.04} 
    Exit;                                                                {!!.04} 
  end;                                                                   {!!.04} 
                                                  
  if (not v) and FListening then begin 
    FiDirectSR.Deactivate; 
    { Put in a slight delay - sometimes the events get slightly out of sync } 
    DelayTicks (4, True); 
  end else if (v) and not (FListening) then 
    FiDirectSR.Activate; 
  if v <> FListening then 
    FListening := v; 
end; 
 
procedure TApdCustomSapiEngine.SetSpeaking (v : Boolean); 
begin 
  if not Assigned (FiDirectSS) then begin                                {!!.04} 
    FSpeaking := v;                                                      {!!.04} 
    Exit;                                                                {!!.04} 
  end;                                                                   {!!.04} 
 
  if (not v) and (FSpeaking) then 
    FiDirectSS.AudioReset; 
  if v <> FSpeaking then 
    FSpeaking := v; 
end; 
 
procedure TApdCustomSapiEngine.SetSRAutoGain (Value: Integer); 
begin 
  if FSRAutoGain <> Value then begin 
    FSRAutoGain := Value; 
    if Assigned (FiDirectSR) then 
      FiDirectSR.AutoGain := FSRAutoGain; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.SetTTSOptions (v : TApdTTSOptions); 
begin 
  if FTTSOptions <> v then 
    FTTSOptions := v; 
end; 
 
procedure TApdCustomSapiEngine.SetWordList (v : TStringList); 
begin 
  FWordList.Assign (v); 
end; 
 
procedure TApdCustomSapiEngine.ShowAboutDlg (const Caption : string); 
begin 
  ShowSSAboutDlg (Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowGeneralDlg (const Caption : string); 
begin 
  ShowSSGeneralDlg (Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowLexiconDlg (const Caption : string); 
begin 
  ShowSSLexiconDlg (Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowSRAboutDlg (const Caption : string); 
begin 
  FiDirectSR.AboutDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowSRGeneralDlg (const Caption : string); 
begin 
  FiDirectSR.GeneralDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowSRLexiconDlg (const Caption : string); 
begin 
  FiDirectSR.LexiconDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowSSAboutDlg (const Caption : string); 
begin 
  FiDirectSS.AboutDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowSSGeneralDlg (const Caption : string); 
begin 
  FiDirectSS.GeneralDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowTrainGeneralDlg (const Caption : string); 
begin 
  FiDirectSR.TrainGeneralDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowSSLexiconDlg (const Caption : string); 
begin 
  FiDirectSR.LexiconDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowTrainMicDlg (const Caption : string); 
begin 
  FiDirectSR.TrainMicDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.ShowTranslateDlg (const Caption : string); 
begin 
  FiDirectSS.TranslateDlg (Application.Handle, Caption); 
end; 
 
procedure TApdCustomSapiEngine.Speak (Text : string); 
var 
  CSet : Integer; 
  Options : Integer; 
begin 
  if Text = '' then 
    Exit; 
  if SSVoices.Count = 0 then 
    raise EApdSapiEngineException.CreateFmt (ecNoSSEngines, [0]); 
  InitializeSpeaking (CSet, Options); 
  FiDirectSS.FileName := #0; 
 
  case FDuplex of 
    sdHalf : 
      if Listening then begin 
        Listening := False; 
        FWaitMode := wmRestoreListen; 
      end; 
    sdFull : 
      begin 
      end; 
    sdHalfDelayed : 
      if Listening then begin 
        Listening := False; 
        FWaitMode := wmRestoreListen; 
      end; 
  end; 
   
  FiDirectSS.TextData (CSet, Options, Text); 
end; 
 
procedure TApdCustomSapiEngine.SpeakFile (FileName : string); 
var 
  fpIn : TFileStream; 
begin 
  fpIn := TFileStream.Create (FileName, fmOpenRead); 
  try 
    SpeakStream (fpIn, #0); 
  finally 
    fpIn.Free; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.SpeakFileToFile (const InFile, OutFile : string); 
var 
  fpIn : TFileStream; 
begin 
  fpIn := TFileStream.Create (InFile, fmOpenRead); 
  try 
    SpeakStream (fpIn, OutFile); 
  finally 
    fpIn.Free; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.SpeakStream (Stream : TStream; 
                                            FileName : string); 
 
  type 
    TApdCharSet = Set of Char; 
 
  function FindCharReverse (Buffer : PChar; StartAt : Integer; 
                            c : TApdCharSet) : Integer; 
  begin 
    while (StartAt >= 0) and (not (Buffer[StartAt] in c)) do 
      Dec (StartAt, 1); 
    Result := StartAt + 1; 
  end; 
 
var 
  CSet : Integer; 
  Options : Integer; 
  WorkString : array [0..8192] of Char; 
  i : Integer; 
  j : Integer; 
begin 
  if SSVoices.Count = 0 then 
    raise EApdSapiEngineException.CreateFmt (ecNoSSEngines, [0]); 
  InitializeSpeaking (CSet, Options); 
 
  case FDuplex of 
    sdHalf : 
      if Listening then 
        Listening := False; 
    sdFull : 
      begin 
      end; 
    sdHalfDelayed : 
      if Listening then begin 
        Listening := False; 
        FWaitMode := wmRestoreListen; 
      end; 
  end; 
   
  WorkString := ''; 
 
  while Stream.Position < Stream.Size do begin 
    i := Stream.Read (WorkString, 8192); 
    WorkString[i] := #$00; 
    if Stream.Position < Stream.Size then begin 
      j := FindCharReverse (WorkString, i, ['.', '!', '?']); 
      if j <= 0 then begin 
        j := FindCharReverse (WorkString, i, [' ', ',']); 
        if j > 0 then begin 
          Stream.Position := Stream.Position + (j - 8192); 
          WorkString[j] := #$00; 
        end 
      end else begin 
        Stream.Position := Stream.Position + (j - 8192); 
        WorkString[j] := #$00; 
      end; 
    end; 
 
    FiDirectSS.TextData (CSet, Options, WorkString); 
  end; 
end; 
 
procedure TApdCustomSapiEngine.SpeakToFile (const Text, FileName : string); 
var 
  CSet : Integer; 
  Options : Integer; 
begin 
  if Text = '' then 
    Exit; 
  if SSVoices.Count = 0 then 
    raise EApdSapiEngineException.CreateFmt (ecNoSSEngines, [0]); 
  InitializeSpeaking (CSet, Options); 
  FiDirectSS.FileName := FileName; 
 
  case FDuplex of 
    sdHalf : 
      if Listening then 
        Listening := False; 
    sdFull : 
      begin 
      end; 
    sdHalfDelayed : 
      if Listening then begin 
        Listening := False; 
        FWaitMode := wmRestoreListen; 
      end; 
  end; 
 
  FiDirectSS.TextData (CSet, Options, Text); 
end; 
 
procedure TApdCustomSapiEngine.StopListening; 
begin 
  Listening := False; 
end; 
 
procedure TApdCustomSapiEngine.StopSpeaking; 
begin 
  Speaking := False; 
end; 
 
procedure TApdCustomSapiEngine.TriggerAudioStart (Sender : TObject; 
                                                  hi : Integer; lo : Integer); 
begin 
  Speaking := True; 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSpeakStart) then 
    FOnSpeakStart (Sender); 
end; 
 
procedure TApdCustomSapiEngine.TriggerAudioStop (Sender : TObject; 
                                                 hi : Integer; lo : Integer); 
begin 
  Speaking := False; 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSpeakStop) then 
    FOnSpeakStop (Sender); 
 
  case FWaitMode of 
    wmWaitSpeaking : 
      begin 
        Listening := True; 
        FWaitMode := wmNone; 
      end; 
    wmRestoreListen : 
      begin 
        Listening := True; 
        FWaitMode := wmNone; 
      end; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.TriggerInterference (Sender : TObject; 
                                                    beginhi : Integer; 
                                                    beginlo : Integer; 
                                                    endhi : Integer; 
                                                    endlo : Integer; 
                                                    type_ : Integer); 
 
  function ConvertInterferenceType (InterferenceType : Integer) : 
                                                       TApdSRInterferenceType; 
  begin 
    case InterferenceType of 
      ApdSRMSGINT_AUDIODATA_STARTED : 
        Result := itAudioStarted; 
      ApdSRMSGINT_AUDIODATA_STOPPED : 
        Result := itAudioStopped; 
      ApdSRMSGINT_IAudio_STARTED : 
        Result := itDeviceOpened; 
      ApdSRMSGINT_IAudio_STOPPED : 
        Result := itDeviceClosed; 
      ApdSRMSGINT_NOISE : 
        Result := itNoise; 
      ApdSRMSGINT_TOOLOUD : 
        Result := itTooLoud; 
      ApdSRMSGINT_TOOQUIET : 
        Result := itTooQuiet; 
      else 
        Result := itUnknown; 
    end; 
  end; 
 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnInterference) then 
    FOnInterference (Sender, ConvertInterferenceType (type_)); 
end; 
 
procedure TApdCustomSapiEngine.TriggerPhraseFinish (Sender : TObject; 
                                                    flags : Integer; 
                                                    beginhi : Integer; 
                                                    beginlo : Integer; 
                                                    endhi : Integer; 
                                                    endlo : Integer; 
                                                    const Phrase : WideString; 
                                                    const parsed : WideString; 
                                                    results : Integer); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Phrase = '' then 
    Exit; 
  if Assigned (FOnPhraseFinish) then 
    FOnPhraseFinish (Sender, Phrase); 
  TriggerPhraseFinishClients (Phrase, Results); 
  case FWaitMode of 
    wmWaitListening : 
      begin 
        Listening := False; 
        FWaitMode := wmNone; 
      end; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.TriggerPhraseFinishClients (Phrase : string; 
                                                           Results : Integer); 
var 
  i : Integer; 
  Event : PApdRegisteredEvent; 
 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  for i := 0 to FPhraseFinishClients.Count - 1 do begin 
    Event := PApdRegisteredEvent (FPhraseFinishClients[i]); 
    Event.CallBack (Self, Phrase, Results); 
  end; 
end; 
 
procedure TApdCustomSapiEngine.TriggerPhraseHypothesis (Sender : TObject; 
                                                        flags : Integer; 
                                                        beginhi : Integer; 
                                                        beginlo : Integer; 
                                                        endhi : Integer; 
                                                        endlo : Integer; 
                                                        const Phrase : WideString; 
                                                        results : Integer); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnPhraseHypothesis) then 
    FOnPhraseHypothesis (Sender, Phrase); 
end; 
 
procedure TApdCustomSapiEngine.TriggerSpeakStart (Sender : TObject; 
                                                  beginhi : Integer; 
                                                  beginlo : Integer); 
begin 
  Speaking := True; 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSpeakStart) then 
    FOnSpeakStart (Sender); 
end; 
 
procedure TApdCustomSapiEngine.TriggerSpeakStop (Sender : TObject; 
                                                 beginhi : Integer; 
                                                 beginlo : Integer; 
                                                 endhi : Integer; 
                                                 endlo : Integer); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSpeakStop) then 
    FOnSpeakStop (Sender); 
 
  Speaking := False; 
  case FWaitMode of 
    wmWaitSpeaking : 
      begin 
        Listening := True; 
        FWaitMode := wmNone; 
      end; 
    wmRestoreListen : 
      begin 
        Listening := True; 
        FWaitMode := wmNone; 
      end; 
  end; 
end; 
 
procedure TApdCustomSapiEngine.TriggerSRError (Sender : TObject; 
                                               Error : LongWord; 
                                               const Details : WideString; 
                                               const Message : WideString); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSRError) then 
    FOnSRError (Sender, Error, Details, Message); 
end; 
 
procedure TApdCustomSapiEngine.TriggerSRWarning (Sender : TObject; 
                                                 Error : LongWord; 
                                                 const Details : WideString; 
                                                 const Message : WideString); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSRWarning) then 
    FOnSRWarning (Sender, Error, Details, Message); 
end; 
 
procedure TApdCustomSapiEngine.TriggerSSAttribChanged (Sender : TObject; 
                                                       Attribute: Integer); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSSAttributeChanged) then 
    FOnSSAttributeChanged (Sender, Attribute); 
end; 
 
procedure TApdCustomSapiEngine.TriggerSSError (Sender : TObject; 
                                               Error : LongWord; 
                                               const Details : WideString; 
                                               const Message : WideString); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSSError) then 
    FOnSSError (Sender, Error, Details, Message); 
end; 
 
procedure TApdCustomSapiEngine.TriggerSSWarning (Sender : TObject; 
                                                 Error : LongWord; 
                                                 const Details : WideString; 
                                                 const Message : WideString); 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnSSWarning) then 
    FOnSSWarning (Sender, Error, Details, Message); 
end; 
 
procedure TApdCustomSapiEngine.TriggerTrainingRequested (Sender : TObject; 
                                                         train : Integer); 
 
  function ConvertTrainingType (TrainingType : Integer) : TApdSRTrainingType; 
  begin 
    Result := []; 
    if (TrainingType and ApdSRGNSTRAIN_GENERAL) <> 0 then 
      Result := Result + [ttGeneral]; 
    if (TrainingType and ApdSRGNSTRAIN_GRAMMAR) <> 0 then 
      Result := Result + [ttCurrentGrammar]; 
    if (TrainingType and ApdSRGNSTRAIN_MICROPHONE) <> 0 then 
      Result := Result + [ttCurrentMic]; 
  end; 
 
begin 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if FAutoTrain then 
    PostMessage (FHandle, apw_SapiTrain, train, 0); 
  if Assigned (FOnTrainingRequested) then 
    FOnTrainingRequested (Sender, ConvertTrainingType (train)); 
end; 
 
procedure TApdCustomSapiEngine.TriggerVUMeter (Sender : TObject; 
                                               beginhi : Integer; 
                                               beginlo : Integer; 
                                               level : Integer); 
begin 
  FSRAmplitude := Level; 
  { Events may still be firing after components are destroyed - or while they 
    are being destroyed.  Check for this in all of the event triggers } 
  if csDestroying in ComponentState then 
    Exit; 
  if Assigned (FOnVUMeter) then 
    FOnVUMeter (Sender, level); 
end; 
 
procedure TApdCustomSapiEngine.WaitUntilDoneSpeaking; 
begin 
  while Speaking do 
    SafeYield; 
end; 
 
procedure TApdCustomSapiEngine.WndProc (var Message: TMessage); 
begin 
  case Message.Msg of 
    apw_SapiTrain : 
      begin 
        if (Message.wParam and ApdSRGNSTRAIN_GENERAL) <> 0 then 
          ShowTrainGeneralDlg (scApdTrainGeneral) 
        else if (Message.wParam and ApdSRGNSTRAIN_GRAMMAR) <> 0 then 
          ShowTrainGeneralDlg (scApdTrainGeneral) 
        else if (Message.wParam and ApdSRGNSTRAIN_MICROPHONE) <> 0 then 
          ShowTrainMicDlg (scApdTrainMic); 
      end; 
  end; 
  try 
    Dispatch (Message); 
    if Message.Msg = WM_QUERYENDSESSION then 
      Message.Result := 1; 
  except 
    Application.HandleException (Self); 
  end; 
end; 
 
end.