Please consider a donation to the Higher Intellect project. See https://preterhuman.net/donate.php or the Donate to Higher Intellect page for more info.

TinySRApp.c

From Higher Intellect Vintage Wiki
Jump to navigation Jump to search
/************************************************************

Created: Wednesday, May 4, 1994 at 1:50:15 PM
TinySRApp.c

Simple Speech Recognition Toolbox Sample Application

Copyright Apple Computer, Inc. 1994
All rights reserved

************************************************************/


#include "SpeechRecognition.h"
#include <GestaltEqu.h>
#include <Quickdraw.h>
#include <Dialogs.h>
#include <Fonts.h>
#include <AppleEvents.h>
#include <string.h>
#include <Menus.h>

/*****************************************************************************/

/* Prototypes and globals */

OSErr InitStuff (void);
OSErr InitAndStartSpeechRecognition (void);
void MainLoop (void);
void CleanupStuff (void);
void CleanupSpeechRecognitionStuff (void);
OSErr MakeALanguageModel (SRLanguageModel *lm);
pascal OSErr HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon);
void DisplayString (Str255 str);

DialogPtr gDialog;
SRRecognitionSystem gSystem;
SRRecognizer gRecognizer;
SRLanguageModel gModel;
Boolean gFinished;

#ifndef __MWERKS__
QDGlobals qd;
#endif

/*****************************************************************************/

void main ()
{
OSErr status = InitStuff ();
if (!status) {
MainLoop ();
CleanupStuff ();
}
}

/*****************************************************************************/

/* main is the entry point to his program. */

OSErr InitStuff ()
{
OSErr status = noErr;
Rect rBounds;
GrafPtr oldPort;
SRLanguageObjectFlags autoFin = kSRNoFinishing;
MenuHandle menuH;

/* Adjust heap */
MaxApplZone();
MoreMasters();
MoreMasters();

/* Init toolboxes */
InitGraf(&qd.thePort);
InitFonts();
FlushEvents(everyEvent,0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(0);
InitCursor();

menuH = NewMenu (1,"\pSR Test");
if (menuH) InsertMenu (menuH, 0);
AddResMenu(menuH,'DRVR');
DrawMenuBar();


/* Make a dialog in which we'll display results */
SetRect (&rBounds, 50,50,450,150);
gDialog = NewDialog(NULL,&rBounds,"\p",true,dBoxProc,(WindowPtr)-1,false,0,NULL);
if (!gDialog)
status = -1;
else {
GetPort (&oldPort);
SetPort (gDialog);
MoveTo (10,80);
TextSize (9);
DrawString ("\p(Say 'Hi', 'Goodbye', 'What time is it', or 'What day is it'. Click here to exit.)");
SetPort (oldPort);
}


if (!status)
status = InitAndStartSpeechRecognition ();

if (!status)
gFinished = false;
else
gFinished = true;

return status;
}

/*****************************************************************************/

/* This routine initializes speech recognition, installs an AppleEvent handler
to handle result notifications from the Speech Recognition Toolbox, calls
another routine to build a simple language model (which specifies a few
phrases a user can say), makes that language model active by calling
SRSetLanguageModel, and starts the recognizer listening. A more realistic
application would have more complicated language models (perhaps having
different language models for different contexts -- using SRSetLanguageModel
to make the appropriate one active), or would use the language model
manipulation routines in the Speech Recognition Toolbox to change the
active language model as the program was used to reflect what the user
might say in any given situation.
*/

OSErr InitAndStartSpeechRecognition ()
{
OSErr status;
long attributes;

/* The SROpenRecognitionSystem loads lots of data and can take a few
seconds, so display a message indicating this may take a moment.
This would be a good place to show the watch cursor as well. */
DisplayString ("\pStarting up...");

/* Make sure SpeechRecognition Toolbox is available */
status = Gestalt (gestaltSpeechRecognitionVersion, &attributes);
/* Version number must be at least 1.5 to support Speech Recognition Toolbox API
documented here. */
if (!status)
if (attributes < 0x00000150)
status = -1;

/* Open a SRRecognitionSystem */
if (!status)
status = SROpenRecognitionSystem (&gSystem, kSRDefaultRecognitionSystemID);

/* We don't want the default feedback or listening modes */
if (false && !status)
{
short feedbackModes = kSRNoFeedbackNoListenModes;
status = SRSetProperty (gSystem, kSRFeedbackAndListeningModes,
&feedbackModes, sizeof (feedbackModes));
}

/* Create a recognizer with default speech source -- e.g. the desktop microphone */
if (!status)
status = SRNewRecognizer (gSystem, &gRecognizer, kSRDefaultSpeechSource);

/* Install an AppleEvent handler so recognizer can send us recognition results.
We could alternatively use a callback routine. That's described elsewhere. */
if (!status)
status = AEInstallEventHandler(kAESpeechSuite, kAESpeechDone,
NewAEEventHandlerProc (HandleSpeechDoneAppleEvent), 0, false);

/* For this example, we will just make one language model,
make it active, and start listening. */

/* Make a simple language model (LM) */
if (!status)
status = MakeALanguageModel (&gModel);

/* Use this LM in recognition */
if (!status)
status = SRSetLanguageModel (gRecognizer, gModel);

/* Release our reference to the LM now, since we don't need it any more.
The recognizer keeps it's own reference to the LM until we release the
recognizer. */
if (!status)
status = SRReleaseObject (gModel);


/* Have the recognizer start processing sound */
if (!status)
status = SRStartListening (gRecognizer);

if (!status)
DisplayString ("\pReady");
else
DisplayString ("\pBummer");

return status;
}


/*****************************************************************************/

void MainLoop ()
{
Boolean gotEvent;
EventRecord event;
DialogPtr theDialog;
short itemHit;
Point pt;
GrafPtr oldPort;

/* Here's our overly-simple main event loop */
/* We quit if mouse is clicked in window, */
/* or if any key is clicked. */
/* We also dispatch AppleEvents. */
while (!gFinished) {
gotEvent = WaitNextEvent(everyEvent, &event, 0xFFFFFFFF, NULL);
if (IsDialogEvent(&event))
DialogSelect(&event, &theDialog, &itemHit);
if (gotEvent)
switch (event.what) {
case mouseDown :
pt = event.where;
GetPort (&oldPort);
SetPort (gDialog);
GlobalToLocal (&pt);
if (PtInRect (pt, &((GrafPtr)gDialog)->portRect))
gFinished = true;
SetPort (oldPort);
break;
case keyDown :
gFinished = true;
break;
case kHighLevelEvent :
AEProcessAppleEvent(&event);
break;
default :
break;
}
}
}

/*****************************************************************************/

void CleanupStuff ()
{
CleanupSpeechRecognitionStuff ();

if (gDialog)
DisposeDialog (gDialog);
}

/*****************************************************************************/

void CleanupSpeechRecognitionStuff ()
{
OSErr status;
status = SRStopListening (gRecognizer); /* stop processing incoming sound */
status = SRReleaseObject (gRecognizer); /* balance SRNewRecognizer call */
status = SRCloseRecognitionSystem (gSystem); /* balance SROpenRecognitionSystem call */
}

/*****************************************************************************/

/* Here we build a language model to tell the recognizer what it should listen
for. Of course, these strings should never be hard-coded into any app, but
we're doing it here so that under Think you don't need to provide any
resources.
*/

OSErr MakeALanguageModel (SRLanguageModel *model)
{
OSErr status;
SRLanguageModel newModel;
const char *lmName = "<Sample LM>";
const char *phraseStrings[] = {
"Hi",
"Goodbye",
"What time is it",
"What day is it",
0
};
const char **phraseStr = phraseStrings;


/* make a simple language model (LM) */
status = SRNewLanguageModel (gSystem, &newModel, lmName, strlen (lmName));

/* add each phrase to LM */
if (!status) {
while (!status && *phraseStr) {
status = SRAddText (newModel, *phraseStr, strlen (*phraseStr), 0);
phraseStr++;
}

/* release newly created LM if an error occured while adding phrases */
if (status)
SRReleaseObject (newModel);
}

/* return new LM */
if (!status)
*model = newModel;

return status;
}

/*****************************************************************************/

/* Here's an AppleEvent handler for handling the kAESpeechDone event of the
kAESpeechSuite -- i.e. the event indicating a recognition attempt was made.
The keySRSpeechStatus parameter gives the status of the recognition. If it
is noErr, then the keySRSpeechResult parameter gives a SRRecognitionResult with the
various representations of the words the user spoke.
*/

pascal OSErr HandleSpeechDoneAppleEvent (AppleEvent *theAEevt, AppleEvent* reply, long refcon)
{
long actualSize;
DescType actualType;
OSErr status = 0, recStatus = 0;
SRRecognitionResult recResult;
Str255 str;
Size len;

/* Get status */
status = AEGetParamPtr(theAEevt,keySRSpeechStatus, typeShortInteger,
&actualType, (Ptr)&recStatus, sizeof(status), &actualSize);

/* Get result */
if (!status && !recStatus)
status = AEGetParamPtr(theAEevt,keySRSpeechResult,
typeSRSpeechResult, &actualType, (Ptr)&recResult,
sizeof(SRRecognitionResult), &actualSize);

/* Get text of words in result.
Could also get actual phrase, path, or LM objects using other
format property selectors. If we did that, we'd also want to
release those objects when we were done using them here.*/
if (!status) {
len = 255;
status = SRGetProperty (recResult, kSRTEXTFormat, str+1, &len);
if (!status) {
str[0] = len;

// Release SRRecognitionResult since we are done with it!!!
// The toolbox has given us a reference to this object, and
// assumes we are still using it until we call SRReleaseObject
// with it.
SRReleaseObject (recResult);
}
}

if (!status)
DisplayString (str);
else
DisplayString ("\pRecognition error");

return status;
}

/*****************************************************************************/

void DisplayString (Str255 str)
{
GrafPtr oldPort;
Rect theRect;

GetPort (&oldPort);
SetPort (gDialog);
theRect = ((GrafPtr)gDialog)->portRect;
theRect.bottom = theRect.bottom-30;
EraseRect(&theRect);
TextSize (12);
MoveTo (40,30);
DrawString (str);
SetPort (oldPort);
}

/*****************************************************************************/

See Also