Phoneme Notifications

Phoneme notifications are sent using the standard notification method (callback or message). The message identifier is the DECtalk_Visual_Message registered window message. The data portions of the message contain a structure that indicates the current phoneme, the next phoneme (not yet implemented), and the duration of the current phoneme.

The callback (and message) parameters are as follows:

uiMsg DECtalk_Visual_Message

lParam1 A DWORD that maps the dwData part of the PHONEME_TAG structure

lParam2 The time, in system milliseconds (timeGetTime()), when the phoneme started

The union PHONEME_TAG (from ttsapi.h) defines the data format for the phoneme part of the message. The following is included for reference, but the definitions always should be taken from ttsapi.h.

typedef struct {

UCHAR cThisPhoneme; // current phoneme

UCHAR cNextPhoneme; // next phoneme, if known

WORD wDuration; // duration in milliseconds

} PHONEME_MARK;

typedef union {\

PHONEME_MARK pmData;

DWORD dwData

} PHONEME_TAG

The cThisPhoneme and cNextPhoneme fields are ASCII printable single-character phoneme identifiers. The phoneme identifiers are specific to each language. The phoneme identifiers for cThisPhoneme and cNextPhoneme are as follows:

English Phoneme Identifiers

An example callback routine to show phoneme notification is as follows:

VOID TTSCallbackRoutine (LONG lParam1,

LONG lParam2,

DWORD dwInstanceParam,

UINT uiMsg)

{

PHONEME_TAG ptPhoneme; // place to put phoneme data..

ptPhoneme.dwData = lParam2;

fprintf(fpLogfil,”{%ld} “,timeGetTime());

if (uiMsg == uiID_Index_Msg)

{

fprintf(fpLogfil,

“ [Index] p1=%081x p2=%081x i=%081x”,

lParam1, lParam2, dwInstanceParam);

// watch for index marks..

if (lParam2 == 1)

uiSystemState = TEXT_STARTED;

if (lParam2 == 2)

uiSystemState = TEXT_DONE

}

else if (uiMsg == uiID_Error_Msg)

{

fprintf(fpLogfil,

“ [Error] p1=%081x p2=%081x, i=%081x”,

lParam1, lParam2, dwInstanceParam);

}

else if (uiMsg == uiID_Buffer_Msg)

{

fprintf(fpLogfil,

“ [Buffer] p1=%081x p2=%081x, i=%081x”,

lParam1, lParam2, dwInstanceParam);

}

else if (uiMsg == uiID_Visual_Msg)

char szThisPhoneme[10]=””;

char szNextPhoneme[10]=””;

fprintf(fpLogfil,

“ [Visual] p1=%081x p2=%081x, i=%081x”,

lParam1, lParam2, dwInstanceParam);

// decode it..

if (ptPhoneme.pmData.cThisPhoneme ==’\0’)

{

// null

strcpy (szThisPhoneme,”<null>”);

}

else

{

szThisPhoneme[0]=

ptPhoneme.pmData.cThisPhoneme;

szThisPhoneme[1]=’\0’;

}

if (ptPhoneme.pmData.cNextPhoneme ==’\0’)

{

// null

strcpy (szNextPhoneme,”<null>”);

}

else

{

szNextPhoneme[0]=

ptPhoneme.pmData.cThisPhoneme;

szNextPhoneme[1]=’\0’;

}

fprintf(fpLogfil,

“ time: %ld this:%s next:%s expected at %ld”,

lParam1,

szThisPhoneme,

szNextPhoneme,

timeGetTime()+ptPhoneme.pmData.wDuration);

}

else

{

fprintf(fpLogfil,

“ [??] msg=%081x, p1=%081x p2=%081x, i=%081x”

(DWORD)uiMsg, lParam1, lParam2,

dwInstanceParam);

}

fprintf(fpLogfil, “\n”);

}