Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Speech Recognition Manager /
Chapter 1 - Speech Recognition Manager / Using the Speech Recognition Manager


Building a Language Model

You specify the words and phrases you want recognized by assigning a language model to a recognizer. Listing 1-5 illustrates one way to construct a language model. It calls the SRNewLanguageModel function to create a new empty language model and then calls other routines to add words and phrases to that model. The function MyBuildLanguageModel defined in Listing 1-5 constructs a language model for the BNF diagram shown on page 1-11.

IMPORTANT
There are many other ways to create language models. For example, you might read the basic words and phrases from resources of type 'STR#', or you might read language objects from a resource or data file using the functions SRNewLanguageObjectFromHandle or SRNewLanguageObjectFromDataFile (as shown later, in "Saving and Loading Language Objects" on page 1-35). The techniques used in Listing 1-5 are intended only to illustrate one way of building embedded language models and a top-level language model.
The function MyBuildLanguageModel takes an existing recognition system as a parameter. See "Opening Recognition Systems and Recognizers" on page 1-16 for information on opening recognition systems.

Listing 1-5 Creating a language model

SRLanguageModel MyBuildLanguageModel (SRRecognitionSystem mySystem);

/* creates a language model for the following BNF:
<TopLM>= <call> <person> | schedule meeting with <person> |view today's schedule;
<call>= call | phone | dial;
<person>= Arlo | Brent | Matt | my wife;
*/

const long  kTopLMRefCon = 'top ';
const long  kCallPersonRefCon = 'call';

const char  kCallLMName[] = "<call>";
const char *kCallSynonyms[] = {"call", "phone", "dial", NULL};

const char  kPersonLMName[] = "<person>";
const char *kPersonNames[] = {"Arlo", "Brent", "Matt", "my wife", NULL};

const char  kTopLMName[] = "<TopLM>";
const char  kScheduleMeetingWith[] = "schedulemeeting with";
const char  kViewTodaysSchedule[] = "view today's schedule";

SRLanguageModel MyBuildLanguageModel (SRRecognitionSystem mySystem)
{
   OSErr          myErr = noErr;
   SRLanguageModelmyCallLM = 0, myPersonLM = 0, myTopLM = 0;
   SRPath         myPath;
   char **        myStringArray;
   char *         myCurrString;
   
   /* create an embedded language model named "<call>" */
   myErr = SRNewLanguageModel(mySystem, &myCallLM, kCallLMName, strlen(kCallLMName));
   if (!myErr) {
      SRPhrase    myPhrase;
      
      myStringArray = (char **) kCallSynonyms;
      while ((myCurrString = *myStringArray) != NULL) {
         /* note that we call SRNewPhrase instead of SRNewWord */
         /* so that we don't have to know if any of the synonyms */
         /* is more than one word */
         myErr = SRNewPhrase(mySystem, &myPhrase, myCurrString, 
                                             strlen(myCurrString));
         if (!myErr) {
            myErr = SRAddLanguageObject(myCallLM, myPhrase);
            SRReleaseObject(myPhrase);       /* balances SRNewPhrase */
         }
         myStringArray++;
      }
   }

   /* create an embedded language model named "<person>" */
   /* Note that this code uses SRAddText, */
   /* a useful shortcut that calls SRNewPhrase internally. */
   if (!myErr)
      myErr = SRNewLanguageModel(mySystem, &myPersonLM, kPersonLMName, 
                                             strlen(kPersonLMName));
   if (!myErr) {
      long     myRefCon = 0;
      
      myStringArray = (char **) kPersonNames;
      while ((myCurrString = *myStringArray) != NULL) {
         myErr = SRAddText(myPersonLM, myCurrString, strlen(myCurrString), 
                                                   myRefCon++);
         /* Note that by setting the refcon in the SRAddText call, */
         /* we can use it later when processing the search result. */
         
         myStringArray++;
      }
   }

   /* create a top-level language model named "<TopLM>" */
   if (!myErr)
      myErr = SRNewLanguageModel(mySystem, &myTopLM, kTopLMName,strlen(kTopLMName));
   
   /* we set the refcon of the top-level language model, */
   /* so that we can identify it in the recognition result */
   if (!myErr)
      myErr = SRSetProperty(myTopLM, kRefCon, &kTopLMRefCon, sizeof(kTopLMRefCon));

   /* create a path for "<call> <person>" and add to "<TopLM>" */
   if (!myErr) myErr = SRNewPath(mySystem, &myPath);
   if (!myErr){
      if (!myErr) myErr = SRAddLanguageObject(myPath, myCallLM);
      if (!myErr) myErr = SRAddLanguageObject(myPath, myPersonLM);
      if (!myErr) myErr = SRAddLanguageObject(myTopLM, myPath);
   
      /* we set the refcon of the path, */
      /* so that we can identify it in the search result */
      if (!myErr) myErr = SRSetProperty(myPath, kSRRefCon, &kCallPersonRefCon, 
                                          sizeof(kCallPersonRefCon));
      SRReleaseObject(myPath);            /* balances SRNewPath */
   }

   /* create path for "schedule meeting with <person>" and add to "<TopLM>" */
   if (!myErr) myErr = SRNewPath(mySystem, &myPath);
   if (!myErr) 
      myErr = SRAddText(myPath, kScheduleMeetingWith,
                                    strlen(kScheduleMeetingWith), 0);
      if (!myErr) myErr = SRAddLanguageObject(myPath, myPersonLM);
      if (!myErr) myErr = SRAddLanguageObject(myTopLM, myPath);
      SRReleaseObject(myPath);            /* balances SRNewPath */
   }

   /* add "view today's schedule" to "<TopLM>" */
   if (!myErr)
      myErr = SRAddText(myTopLM, kViewTodaysSchedule, 
                                    strlen(kViewTodaysSchedule), 0);
   
   if (myCallLM)
      myErr = SRReleaseObject(myCallLM);/* balances SRNewLanguageModel */
   if (myPersonLM)
      myErr = SRReleaseObject(myPersonLM);/* balances SRNewLanguageModel */

   return myTopLM;
}
The MyBuildLanguageModel function creates the embedded language models used in the example language model and then adds them to the top-level language model myTopLM. As you can see, you can add a word or a phrase to a language model in several ways. You can use the sequence of functions SRNewPhrase, SRAddLanguageObject, and SRReleaseObject. Alternatively, you can use the function SRAddText, which adds some text directly to a language model without having you explicitly create objects for that text. Also, notice that calls to SRNewObject are balanced with calls to SRReleaseObject for any object reference that won't be needed outside the routine (namely, all objects except myTopLM, which is returned at the end of the routine).

Note particularly that the MyBuildLanguageModel function defined in Listing 1-5 sets the kSRRefCon property of the various language objects it creates to known values. For example, MyBuildLanguageModel sets the kSRRefCon property of a name to an index into the array of names, like this:

myErr = SRAddText(myPersonLM, myCurrString, 
                           strlen(myCurrString), myRefCon++);
Later, when interpreting recognition results, you can read a language object's kSRRefCon property to determine what the user said. See "Interpreting Recognition Results," beginning on page 1-31 for details.

Often, you'll want to designate certain words or phrases as optional. For example, you might wish to let the user say "meeting with Arlo" in addition to "schedule meeting with Arlo" (that is, making the word "schedule" optional). You can designate any language object as optional by setting its optional property, as illustrated in Listing 1-6.

Listing 1-6 Making a word optional

/* suppose that the word myWord has already been created */
Boolean  myVal = TRUE;

myErr = SRSetProperty(myWord, kSROptional, &myVal, sizeof(myVal));

Previous Book Contents Book Index Next

© Apple Computer, Inc.
22 JAN 1997