void CDialogueManager::LoadDialogue(const char *szFilename)
{
	int scriptNum;
	int sentenceNum;
	int strLen;
	char* buffer;
	// Load in all the dialogue from file at beginning of game
	ifstream in;

	in.open(szFilename,ios_base::in | ios_base::binary);

	if( in.is_open() )
	{
		in.read((char*)&scriptNum,sizeof(int));

		for( int script = 0; script < scriptNum; script++ )
		{
			in.read((char*)&strLen,sizeof(int));
			buffer = new char[strLen+1];
			in.read(buffer,strLen);
			buffer[strLen] = '\0';
			string szName = buffer;
			CScript* newScript = new CScript(szName);

			delete[] buffer;

			in.read((char*)&sentenceNum,sizeof(int));
			for( int sentence = 0; sentence < sentenceNum; sentence++ )
			{
				in.read((char*)&strLen,sizeof(int));
				buffer = new char[strLen+1];
				in.read(buffer,strLen);
				buffer[strLen] = '\0';
				string szSentence = buffer;
				
				delete[] buffer;

				in.read((char*)&strLen,sizeof(int));
				buffer = new char[strLen+1];
				in.read(buffer,strLen);
				buffer[strLen] = '\0';
				string szTrigger = buffer;

				delete[] buffer;

				CSentence* newSentence = new CSentence(szSentence,szTrigger);
				if( strLen < 1 )
					newSentence->SetEventBool(false);
				else
					newSentence->SetEventBool(true);

				newScript->AddSentence(newSentence);
			}

			m_vScripts.push_back(newScript);
		}
	}

	in.close();
}
bool CSoundCombiner::IsCombinedFileChecksumValid( IFileSystem *filesystem, char const *outfile, CUtlVector< CombinerEntry >& info )
{
	unsigned int computedChecksum = CheckSumWork( filesystem, info );

	char fullpath[ MAX_PATH ];
	Q_strncpy( fullpath, outfile, sizeof( fullpath ) );
	filesystem->GetLocalPath( outfile, fullpath, sizeof( fullpath ) );

	CSentence sentence;

	bool valid = false;

	if ( LoadSentenceFromWavFile( fullpath, sentence ) )
	{
		unsigned int diskFileEmbeddedChecksum = sentence.GetDataCheckSum();

		valid = computedChecksum == diskFileEmbeddedChecksum;

		if ( !valid )
		{
			Warning( "  checksum computed %u, disk %u\n",
				computedChecksum, diskFileEmbeddedChecksum );
		}
	}
	else
	{
		Warning( "CSoundCombiner::IsCombinedFileChecksumValid:  Unabled to load %s\n", fullpath );
	}

	CleanupWork();
	return valid;
}
static int GetConjProperties(const CSentence& S, int WordNo, ConjFromWhatList& FromWhere,int& iConjIndex, int UpperBorder)
{
	if( (WordNo == -1) || (WordNo >= UpperBorder) )
		return -1;

	int OborotNo = S.m_Words[WordNo].GetOborotNo();

	if	(		OborotNo != -1 
			&& 	S.GetOpt()->m_pOborDic->m_Entries[OborotNo].HasPartOfSpeech(S.GetOpt()->m_Conjunction) 
		)
	{
		for(size_t i = WordNo ; i < UpperBorder; i++ )	
			if( S.m_Words[i].HasOborot2())
			{
				FromWhere = FROM_OBOR_DIC;
				iConjIndex = OborotNo;
				return WordNo + 1;
			}
	}

	iConjIndex = S.m_Words[WordNo].m_SubordinateConjNo;
	int HomonymNo;
	if	(		(iConjIndex != -1 )
			&&	!S.IsRelativSentencePronoun(0, WordNo, HomonymNo)
		)
	{
		FromWhere = FROM_SUB_CONJ;
		return WordNo+1;
	}

	return -1;
}
void CSentence::Append( float starttime, const CSentence& src )
{
#if PHONEME_EDITOR
	int i;
	// Combine
	for ( i = 0 ; i < src.m_Words.Size(); i++ )
	{
		CWordTag *word = src.m_Words[ i ];

		CWordTag *newWord = new CWordTag( *word );

		newWord->m_flStartTime += starttime;
		newWord->m_flEndTime += starttime;

		// Offset times
		int c = newWord->m_Phonemes.Count();
		for ( int i = 0; i < c; ++i )
		{
			CPhonemeTag *tag = newWord->m_Phonemes[ i ];
			tag->AddStartTime( starttime );
			tag->AddEndTime( starttime );
		}

		AddWordTag( newWord );
	}

	if ( src.GetText()[ 0 ] )
	{
		char fulltext[ 4096 ];
		if ( GetText()[ 0 ] )
		{
			Q_snprintf( fulltext, sizeof( fulltext ), "%s %s", GetText(), src.GetText() );
		}
		else
		{
			Q_strncpy( fulltext, src.GetText(), sizeof( fulltext ) );
		}
		SetText( fulltext );
	}

	int c = src.m_EmphasisSamples.Size();
	for ( i = 0; i < c; i++ )
	{
		CEmphasisSample s = src.m_EmphasisSamples[ i ];

		s.time += starttime;

		m_EmphasisSamples.AddToTail( s );
	}

	// Or in voice duck settings
	m_bShouldVoiceDuck |= src.m_bShouldVoiceDuck;
#else
	Assert( 0 );
#endif
}
Beispiel #5
0
string GetNodeGrmStr(const CSentence& Sentence, const CRelationsIterator& RelIt, int GroupNo, int WordNo, string& Lemma)
{
	Lemma = "";
	if (GroupNo != -1)
		return "";
	else {
		size_t ClauseNo = Sentence.GetMinClauseByWordNo(WordNo);
		const CClause& Clause = Sentence.GetClause(ClauseNo);
		const CMorphVariant* pSynVar = &*Clause.GetSynVariantByNo(0);
		int UnitNo = pSynVar->UnitNoByWordNo(WordNo);
		const CSynUnit& U = pSynVar->m_SynUnits[UnitNo];
		Lemma = Sentence.GetWords()[WordNo].GetHomonym(U.m_iHomonymNum)->m_strLemma;
		return Sentence.GetOpt()->GetGramTab()->GrammemsToStr(U.m_iGrammems | U.m_TypeGrammems);
	}
}
bool CSoundCombiner::LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io )
{
	sentence.Reset();

	InFileRIFF riff( wavfile, io );

	// UNDONE: Don't use printf to handle errors
	if ( riff.RIFFName() != RIFF_WAVE )
	{
		return false;
	}

	// set up the iterator for the whole file (root RIFF is a chunk)
	IterateRIFF walk( riff, riff.RIFFSize() );

	// This chunk must be first as it contains the wave's format
	// break out when we've parsed it
	bool found = false;
	while ( walk.ChunkAvailable() && !found )
	{
		switch( walk.ChunkName() )
		{
		case WAVE_VALVEDATA:
			{
				found = true;
				CSoundCombiner::ParseSentence( sentence, walk );
			}
			break;
		}
		walk.ChunkNext();
	}

	return true;
}
Beispiel #7
0
void GetGroups(const CSentence& Sentence, const CAgramtab& A, string& Res)
{
	int nClausesCount = Sentence.GetClausesCount();

	for (int ClauseNo = 0; ClauseNo<nClausesCount; ClauseNo++)
	{
		const CClause& Clause = Sentence.GetClause(ClauseNo);
		int nCvar = Clause.m_SynVariants.size();

		if (Clause.m_SynVariants.empty()) continue;

		int nVmax = Clause.m_SynVariants.begin()->m_iWeight;
		for (CSVI pSynVar = Clause.m_SynVariants.begin(); pSynVar != Clause.m_SynVariants.end(); pSynVar++)
		{
			if (pSynVar->m_iWeight < nVmax) break;

			const CMorphVariant& V = *pSynVar;
			Res += Format("\t<synvar>\n");

			// print the clause
			{
				int ClauseType = (V.m_ClauseTypeNo == -1) ? UnknownSyntaxElement : Clause.m_vectorTypes[V.m_ClauseTypeNo].m_Type;;
				string Type;
				if (ClauseType != UnknownSyntaxElement)
					Type = (const char*)A.GetClauseNameByType(ClauseType);
				else
					Type = "EMPTY";
				Res += Format("\t\t<clause type=\"%s\">%s</clause>\n", Type.c_str(), GetWords(Sentence, Clause).c_str());
			}


			for (int GroupNo = 0; GroupNo < V.m_vectorGroups.GetGroups().size(); GroupNo++)
			{
				const CGroup& G = V.m_vectorGroups.GetGroups()[GroupNo];
				Res += Format("\t\t<group type=\"%s\">%s</group>\n",
					Sentence.GetOpt()->GetGroupNameByIndex(G.m_GroupType),
					GetWords(Sentence, G).c_str());
			};
			Res += Format("\t</synvar>\n");
		}
	}


}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : store - 
//-----------------------------------------------------------------------------
void CSoundCombiner::StoreValveDataChunk( CSentence& sentence )
{
	// Buffer and dump data
	CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );

	sentence.SaveToBuffer( buf );

	// Copy into store
	m_pOutIterator->ChunkWriteData( buf.Base(), buf.TellPut() );
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &walk - 
//-----------------------------------------------------------------------------
void CSoundCombiner::ParseSentence( CSentence& sentence, IterateRIFF &walk )
{
	CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );

	buf.EnsureCapacity( walk.ChunkSize() );
	walk.ChunkRead( buf.Base() );
	buf.SeekPut( CUtlBuffer::SEEK_HEAD, walk.ChunkSize() );

	sentence.InitFromDataChunk( buf.Base(), buf.TellPut() );
}
Beispiel #10
0
void GetRelations(const CSentence& Sentence, string& Result)
{
	CRelationsIterator RelIt;
	RelIt.SetSentence(&Sentence);
	for (int i = 0; i<Sentence.m_vectorPrClauseNo.size(); i++)
		RelIt.AddClauseNoAndVariantNo(Sentence.m_vectorPrClauseNo[i], 0);
	RelIt.BuildRelations();
	for (long RelNo = 0; RelNo < RelIt.GetRelations().size(); RelNo++)
	{
		const CSynOutputRelation& piRel = RelIt.GetRelations()[RelNo];
		string RelName = Sentence.GetOpt()->GetGroupNameByIndex(piRel.m_Relation.type);
		string Src = GetNodeStr(Sentence, RelIt, piRel.m_iSourceGroup, piRel.m_Relation.m_iFirstWord);
		string Trg = GetNodeStr(Sentence, RelIt, piRel.m_iTargetGroup, piRel.m_Relation.m_iLastWord);
		string SrcLemma, TrgLemma;
		string SrcGrm = GetNodeGrmStr(Sentence, RelIt, piRel.m_iSourceGroup, piRel.m_Relation.m_iFirstWord, SrcLemma);
		string TrgGrm = GetNodeGrmStr(Sentence, RelIt, piRel.m_iTargetGroup, piRel.m_Relation.m_iLastWord, TrgLemma);
		string GramRel = Sentence.GetOpt()->GetGramTab()->GrammemsToStr(piRel.m_Relation.m_iGrammems);

		Result += Format("\t<rel name=\"%s\" gramrel=\"%s\" lemmprnt=\"%s\" grmprnt=\"%s\" lemmchld=\"%s\" grmchld=\"%s\" > %s -> %s </rel>\n",
			RelName.c_str(), GramRel.c_str(), SrcLemma.c_str(), SrcGrm.c_str(), TrgLemma.c_str(), TrgGrm.c_str(), Src.c_str(), Trg.c_str());
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *phonemes - 
//-----------------------------------------------------------------------------
void LogPhonemes( CSentence& sentence )
{
	return;

	Log( "Phonemecount == %i\n", sentence.CountPhonemes() );

	for ( int i = 0; i < sentence.m_Words.Size(); i++ )
	{
		const CWordTag *w = sentence.m_Words[ i ];

		for ( int j = 0; j < w->m_Phonemes.Size(); j++ )
		{
			const CPhonemeTag *p = w->m_Phonemes[ j ];
			Log( "Phoneme %s %u to %u\n", p->GetTag(), p->m_uiStartByte, p->m_uiEndByte );
		}
	}
}
bool CSentencesCollection::ReadAndProcessSentences(const CPlmLineCollection* piPlmLine)
{
	const size_t LinesCount =  piPlmLine->m_Items.size();
	
	if( !m_pSyntaxOptions->IsValid())
			return false;
	

	if (m_bEnableProgressBar)
			printf ("Starting Syntax\n");

	time_t t1;
	time  (&t1);
	
	for (size_t LineNo = 0; LineNo < LinesCount; ) 
	{
		if (m_bEnableProgressBar)
				printf ("%i of %i       \r", LineNo, LinesCount);

		CSentence* S = m_pSyntaxOptions->NewSentence();
		if (!S)
		{
			m_pSyntaxOptions->OutputErrorString("Cannot allocate space for the new sentence!");
			return false;
		};
		try
		{

			S->m_pSyntaxOptions = m_pSyntaxOptions;

			bool bResult = S->ReadNextFromPlmLines(piPlmLine,LineNo);

			if (m_bLogProcessedSentence)
			{
				FILE * fp = fopen ("last_read_sentence.log", "w");
				fprintf (fp, "%s\n",S->GetSentenceBeginStr().c_str());
				fclose(fp);
			};

			if( !bResult )
			{
				//  a parse error occurs 
				delete S;
				return false;		
			};

		}
		catch (...)
		{

			m_pSyntaxOptions->OutputErrorString("Cannot read a sentence from Mapost");
			delete S;
			return false;
		};

		
		if( S->m_Words.empty() )
		{
			// no not-empty sentence can be found, we are at the end of the text
			delete S;
			break;
		}


		try
		{
			bool bRes = S->BuildClauses();

			if( !bRes )
			{
				delete S;
				return false;
			};

			S->CalculatePrimitiveClausesCount();

			
			if (m_bEnableProgressBar)
			{
				if (S->m_bPanicMode)
					printf ("    found a \"panic\" sentence\n");
			};

			m_vectorSents.push_back(S);

		}
		catch (...)
		{
			if (m_bEnableProgressBar)
			{
				printf ("\n");
				if (!S->m_Words.empty())
					printf ("exception at offset %i\n", S->m_Words[0].m_GraphematicalUnitOffset);
			};
			 
			delete S;
			m_pSyntaxOptions->OutputErrorString("An exception in Synan occurred!");
			return false;
		};
		
		
	}

	if (m_bEnableProgressBar)
	{
		time_t t2;
		time  (&t2);
		printf ("Finish             \n");
		int seconds = t2-t1;
		printf ("Time : %i\n", seconds);
		printf ("Count of tokens : %i\n", LinesCount);
		if (seconds > 0)
			printf ("The speed is %i tokens pro second\n", LinesCount/seconds);
	};
	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Given a wave file and a string of words "text", creates a CFG from the
//  sentence and stores the resulting words/phonemes in CSentence
// Input  : *wavname - 
//			text - 
//			sentence - 
//			(*pfnPrint - 
// Output : SR_RESULT
//-----------------------------------------------------------------------------
SR_RESULT ExtractPhonemes( const char *wavname, CSpDynamicString& text, CSentence& sentence, void (*pfnPrint)( const char *fmt, ...) )
{
	// Assume failure
	SR_RESULT result = SR_RESULT_ERROR;

	if ( text.Length() <= 0 )
	{
		pfnPrint( "Error:  no rule / text specified\n" );
		return result;
	}

	USES_CONVERSION;
	HRESULT hr;
	
	CUtlVector < WORDRULETYPE > wordRules;

	CComPtr<ISpStream> cpInputStream;
	CComPtr<ISpRecognizer> cpRecognizer;
	CComPtr<ISpRecoContext> cpRecoContext;
	CComPtr<ISpRecoGrammar> cpRecoGrammar;
	CComPtr<ISpPhoneConverter>  cpPhoneConv;
    
	// Create basic SAPI stream object
	// NOTE: The helper SpBindToFile can be used to perform the following operations
	hr = cpInputStream.CoCreateInstance(CLSID_SpStream);
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Stream object not installed?\n" );
		return result;
	}

	CSpStreamFormat sInputFormat;
	
	// setup stream object with wav file MY_WAVE_AUDIO_FILENAME
	//   for read-only access, since it will only be access by the SR engine
	hr = cpInputStream->BindToFile(
		T2W(wavname),
		SPFM_OPEN_READONLY,
		NULL,
		sInputFormat.WaveFormatExPtr(),
		SPFEI_ALL_EVENTS );

	if ( FAILED( hr ) )
	{
		pfnPrint( "Error: couldn't open wav file %s\n", wavname );
		return result;
	}
	
	// Create in-process speech recognition engine
	hr = cpRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer);
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 In process recognizer object not installed?\n" );
		return result;
	}

	// Create recognition context to receive events
	hr = cpRecognizer->CreateRecoContext(&cpRecoContext);
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to create recognizer context\n" );
		return result;
	}
	
	// Create a grammar
	hr = cpRecoContext->CreateGrammar( EP_GRAM_ID, &cpRecoGrammar );
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to create recognizer grammar\n" );
		return result;
	}

	LANGID englishID = 0x409; // 1033 decimal

	bool userSpecified = false;
	LANGID langID = SpGetUserDefaultUILanguage();

	// Allow commandline override
	if ( CommandLine()->FindParm( "-languageid" ) != 0 )
	{
		userSpecified = true;
		langID = CommandLine()->ParmValue( "-languageid", langID );
	}

	// Create a phoneme converter ( so we can convert to IPA codes )
	hr = SpCreatePhoneConverter( langID, NULL, NULL, &cpPhoneConv );
	if ( FAILED( hr ) )
	{
		if ( langID != englishID )
		{
			if ( userSpecified )
			{
				pfnPrint( "Warning:  SAPI 5.1 Unable to create phoneme converter for command line override -languageid %i\n", langID );
			}
			else
			{
				pfnPrint( "Warning:  SAPI 5.1 Unable to create phoneme converter for default UI language %i\n",langID );
			}

			// Try english!!!
			langID = englishID;
			hr = SpCreatePhoneConverter( langID, NULL, NULL, &cpPhoneConv );
		}

		if ( FAILED( hr ) )
		{
			pfnPrint( "Error:  SAPI 5.1 Unable to create phoneme converter for English language id %i\n", langID );
			return result;
		}
		else
		{
			pfnPrint( "Note:  SAPI 5.1 Falling back to use english -languageid %i\n", langID );
		}
	}
	else if ( userSpecified )
	{
		pfnPrint( "Note:  SAPI 5.1 Using user specified -languageid %i\n",langID );
	}

	SPSTATEHANDLE hStateRoot;
	// create/re-create Root level rule of grammar
	hr = cpRecoGrammar->GetRule(L"Root", 0, SPRAF_TopLevel | SPRAF_Active, TRUE, &hStateRoot);
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to create root rule\n" );
		return result;
	}

	// Inactivate it so we can alter it
	hr = cpRecoGrammar->SetRuleState( NULL, NULL, SPRS_INACTIVE );
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to deactivate grammar rules\n" );
		return result;
	}

	// Create the rule set from the words in text
	{
		CSpDynamicString currentWord;
		WCHAR *pos = ( WCHAR * )text;
		WCHAR str[ 2 ];
		str[1]= 0;

		while ( *pos )
		{
			if ( *pos == L' ' /*|| *pos == L'.' || *pos == L'-'*/ )
			{
				// Add word to rule set
				if ( currentWord.Length() > 0 )
				{
					AddWordRule( cpRecoGrammar, &hStateRoot, &wordRules, currentWord );
					currentWord.Clear();
				}
				pos++;
				continue;
			}

			// Skip anything that's inside a [ xxx ] pair.
			if ( *pos == L'[' )
			{
				while ( *pos && *pos != L']' )
				{
					pos++;
				}

				if ( *pos )
				{
					pos++;
				}
				continue;
			}

			str[ 0 ] = *pos;

			currentWord.Append( str );
			pos++;
		}

		if ( currentWord.Length() > 0 )
		{
			AddWordRule( cpRecoGrammar, &hStateRoot, &wordRules, currentWord );
		}

		if ( wordRules.Size() <= 0 )
		{
			pfnPrint( "Error:  Text %s contained no usable words\n", text );
			return result;
		}

		// Build all word to word transitions in the grammar
		if ( !BuildRules( cpRecoGrammar, &hStateRoot, &wordRules ) )
		{
			pfnPrint( "Error:  Rule set for %s could not be generated\n", text );
			return result;
		}
	}

	// check for recognitions and end of stream event
	const ULONGLONG ullInterest = 
		SPFEI(SPEI_RECOGNITION) | SPFEI(SPEI_END_SR_STREAM) | SPFEI(SPEI_FALSE_RECOGNITION) | 
		SPFEI(SPEI_PHRASE_START ) | SPFEI(SPEI_HYPOTHESIS ) | SPFEI(SPEI_INTERFERENCE) ;
	hr = cpRecoContext->SetInterest( ullInterest, ullInterest );
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to set interest level\n" );
		return result;
	}	
	// use Win32 events for command-line style application
	hr = cpRecoContext->SetNotifyWin32Event();
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to set win32 notify event\n" );
		return result;
	}
	// connect wav input to recognizer
	// SAPI will negotiate mismatched engine/input audio formats using system audio codecs, so second parameter is not important - use default of TRUE
	hr = cpRecognizer->SetInput(cpInputStream, TRUE);
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to associate input stream\n" );
		return result;
	}	

	// Activate the CFG ( rather than using dictation )
	hr = cpRecoGrammar->SetRuleState( NULL, NULL, SPRS_ACTIVE );
	if ( FAILED( hr ) )
	{
		switch ( hr )
		{
		case E_INVALIDARG:
			pfnPrint( "pszName is invalid or bad. Alternatively, pReserved is non-NULL\n" );
			break;
		case SP_STREAM_UNINITIALIZED:
			pfnPrint( "ISpRecognizer::SetInput has not been called with the InProc recognizer\n" );
			break;
		case SPERR_UNINITIALIZED:
			pfnPrint( "The object has not been properly initialized.\n");
			break;
		case SPERR_UNSUPPORTED_FORMAT:
			pfnPrint( "Audio format is bad or is not recognized. Alternatively, the device driver may be busy by another application and cannot be accessed.\n" );
			break;
		case SPERR_NOT_TOPLEVEL_RULE:
			pfnPrint( "The rule pszName exists, but is not a top-level rule.\n" );
			break;
		default:
			pfnPrint( "Unknown error\n" );
			break;
		}
		pfnPrint( "Error:  SAPI 5.1 Unable to activate rule set\n" );
		return result;
	}

	// while events occur, continue processing
	// timeout should be greater than the audio stream length, or a reasonable amount of time expected to pass before no more recognitions are expected in an audio stream
	BOOL fEndStreamReached = FALSE;
	while (!fEndStreamReached && S_OK == cpRecoContext->WaitForNotifyEvent( SR_WAVTIMEOUT ))
	{
		CSpEvent spEvent;
		// pull all queued events from the reco context's event queue
		
		while (!fEndStreamReached && S_OK == spEvent.GetFrom(cpRecoContext))
		{
			// Check event type
			switch (spEvent.eEventId)
			{
			case SPEI_INTERFERENCE:
				{
					SPINTERFERENCE interference = spEvent.Interference();

					switch ( interference )
					{
					case SPINTERFERENCE_NONE:
						pfnPrint( "[ I None ]\r\n" );
						break;
					case SPINTERFERENCE_NOISE:
						pfnPrint( "[ I Noise ]\r\n" );
						break;
					case SPINTERFERENCE_NOSIGNAL:
						pfnPrint( "[ I No Signal ]\r\n" );
						break;
					case SPINTERFERENCE_TOOLOUD:
						pfnPrint( "[ I Too Loud ]\r\n" );
						break;
					case SPINTERFERENCE_TOOQUIET:
						pfnPrint( "[ I Too Quiet ]\r\n" );
						break;
					case SPINTERFERENCE_TOOFAST:
						pfnPrint( "[ I Too Fast ]\r\n" );
						break;
					case SPINTERFERENCE_TOOSLOW:
						pfnPrint( "[ I Too Slow ]\r\n" );
						break;
					default:
						break;
					}
				}
				break;
			case SPEI_PHRASE_START:
				pfnPrint( "Phrase Start\r\n" );
				sentence.MarkNewPhraseBase();
				break;

			case SPEI_HYPOTHESIS:
			case SPEI_RECOGNITION:
			case SPEI_FALSE_RECOGNITION:
				{
                    CComPtr<ISpRecoResult> cpResult;
                    cpResult = spEvent.RecoResult();

                    CSpDynamicString dstrText;
                    if (spEvent.eEventId == SPEI_FALSE_RECOGNITION)
                    {
                        dstrText = L"(Unrecognized)";

						result = SR_RESULT_FAILED;

						// It's possible that the failed recog might have more words, so see if that's the case
						EnumeratePhonemes( cpPhoneConv, cpResult, sentence );
					}
                    else
                    {
						// Hypothesis or recognition success
                        cpResult->GetText( (ULONG)SP_GETWHOLEPHRASE, (ULONG)SP_GETWHOLEPHRASE, TRUE, &dstrText, NULL);

						EnumeratePhonemes( cpPhoneConv, cpResult, sentence );

						if ( spEvent.eEventId == SPEI_RECOGNITION )
						{
							result = SR_RESULT_SUCCESS;
						}

						pfnPrint( va( "%s%s\r\n", spEvent.eEventId == SPEI_HYPOTHESIS ? "[ Hypothesis ] " : "", dstrText.CopyToChar() ) );
					}
                    
                    cpResult.Release();
				}
				break;
				// end of the wav file was reached by the speech recognition engine
            case SPEI_END_SR_STREAM:
				fEndStreamReached = TRUE;
				break;
			}
			
			// clear any event data/object references
			spEvent.Clear();
		}// END event pulling loop - break on empty event queue OR end stream
	}// END event polling loop - break on event timeout OR end stream
	
	// Deactivate rule
	hr = cpRecoGrammar->SetRuleState( NULL, NULL, SPRS_INACTIVE );
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to deactivate rule set\n" );
		return result;
	}

	// close the input stream, since we're done with it
	// NOTE: smart pointer will call SpStream's destructor, and consequently ::Close, but code may want to check for errors on ::Close operation
	hr = cpInputStream->Close();
	if ( FAILED( hr ) )
	{
		pfnPrint( "Error:  SAPI 5.1 Unable to close input stream\n" );
		return result;
	}

	return result;
}
//-----------------------------------------------------------------------------
// Purpose: Walk list of words and phonemes and create phoneme tags in CSentence object
//  FIXME:  Right now, phonemes are assumed to evenly space out across a word.
// Input  : *converter - 
//			result - 
//			sentence - 
//-----------------------------------------------------------------------------
void EnumeratePhonemes( ISpPhoneConverter *converter, const ISpRecoResult* result, CSentence& sentence )
{
	USES_CONVERSION;

	// Grab access to element container
	ISpPhrase *phrase = ( ISpPhrase * )result;
	if ( !phrase )
		return;

    SPPHRASE *pElements;
	if ( !SUCCEEDED( phrase->GetPhrase( &pElements ) ) )
		return;

	// Only use it if it's better/same size as what we already had on-hand
	if ( pElements->Rule.ulCountOfElements > 0 )
		//(unsigned int)( sentence.m_Words.Size() - sentence.GetWordBase() ) )
	{
		sentence.ResetToBase();

		// Walk list of words
		for ( ULONG i = 0; i < pElements->Rule.ulCountOfElements; i++ )
		{
			unsigned int wordstart, wordend;

			// Get start/end sample index
			wordstart	= pElements->pElements[i].ulAudioStreamOffset + (unsigned int)pElements->ullAudioStreamPosition;
			wordend		= wordstart + pElements->pElements[i].ulAudioSizeBytes;

			// Create word tag
			CWordTag *w = new CWordTag( W2T( pElements->pElements[i].pszDisplayText ) );
			Assert( w );
			w->m_uiStartByte = wordstart;
			w->m_uiEndByte   = wordend;

			sentence.AddWordTag( w );

			// Count # of phonemes in this word
			SPPHONEID pstr[ 2 ];
			pstr[ 1 ] = 0;
			WCHAR wszPhoneme[ SP_MAX_PRON_LENGTH ];

			const SPPHONEID *current;
			SPPHONEID phoneme;
			current = pElements->pElements[i].pszPronunciation;
			float total_weight = 0.0f;
			while ( 1 )
			{
				phoneme = *current++;
				if ( !phoneme )
					break;

				pstr[ 0 ] = phoneme;
				wszPhoneme[ 0 ] = L'\0';

				converter->IdToPhone( pstr, wszPhoneme );

				total_weight += WeightForPhoneme( W2A( wszPhoneme ) );
			}

			current = pElements->pElements[i].pszPronunciation;

			// Decide # of bytes/phoneme weight
			float psize = 0;
			if ( total_weight )
			{
				psize = ( wordend - wordstart ) / total_weight;
			}

			int number = 0;

			// Re-walk the phoneme list and create true phoneme tags
			float startWeight = 0.0f;
			while ( 1 )
			{
				phoneme = *current++;
				if ( !phoneme )
					break;

				pstr[ 0 ] = phoneme;
				wszPhoneme[ 0 ] = L'\0';

				converter->IdToPhone( pstr, wszPhoneme );
 
				CPhonemeTag *p = new CPhonemeTag( W2A( wszPhoneme ) );
				Assert( p );
				
				float weight = WeightForPhoneme( W2A( wszPhoneme ) );

				p->m_uiStartByte = wordstart + (int)( startWeight * psize );
				p->m_uiEndByte	 = p->m_uiStartByte + (int)( psize * weight );

				startWeight += weight;

				// Convert to IPA phoneme code
				p->SetPhonemeCode( TextToPhoneme( p->GetTag() ) );

				sentence.AddPhonemeTag( w, p );

				number++;
			}
		}	
	}

	// Free memory
    ::CoTaskMemFree(pElements);
}
int CSentence::CanLinkSimpleSimilar(int CommaWordNo) 
{
	try
	{

		/*
			if comma is at the very  beginning of ath the end, then exit
		*/
		if	(		(CommaWordNo == 0) 
				||	(CommaWordNo + 1 >= m_Words.size() )
			)
			return -1;


		if (GetOpt()->m_Language == morphGerman)
		{
			// we can use CSentence::m_GroupsUnion if Tomita is enabled
			for (size_t i=0; i< m_GroupsUnion.GetGroups().size(); i++)
			{
				const CGroup& group = m_GroupsUnion.GetGroups()[i];
				//  ignore groups which contain only three words and the second word is 
				// a comma (a clause delimiter)
				if (group.size() == 3)
					if (m_Words[group.m_iFirstWord+1].m_bComma)
						continue;

				if	(		(group.m_iFirstWord < CommaWordNo) 
						&&	(group.m_iLastWord > CommaWordNo)
					)
					return group.m_iLastWord;
			};
			return -1;
		};


		const int Radius = (GetOpt()->m_Language == morphGerman)? 10 : 6;
		int StartClauseWordNo = max(0, CommaWordNo - Radius);
		CSentence* pSent = GetOpt()->NewSentence();
		if (!pSent)
			throw CExpc ("Cannot create sentence");
		
		for (int i = StartClauseWordNo; i < min((int)m_Words.size(), CommaWordNo + Radius); i++)
            pSent->m_Words.push_back(m_Words[i]);
		

		CClause C(pSent, 0,  pSent->m_Words.size() - 1);
		pSent->AddClause(C);	
		pSent->m_bShouldUseTwoPotentialRule = false;
		pSent->RunSyntaxInClauses(SimpleSimilarRules);
		
		int Result = -1;
		const CClause& prClause = pSent->m_Clauses[0];
		for (CSVI it = prClause.m_SynVariants.begin(); (Result == -1)&& (it!=prClause.m_SynVariants.end()); it++)
			for (size_t i=0; i< it->m_vectorGroups.GetGroups().size(); i++)
			{
				const CGroup& group = it->m_vectorGroups.GetGroups()[i];
				//  ignore groups which contain only three words and the second word is 
				// a comma (a clause delimiter)
				if (group.size() == 3)
				{
					const CSynUnit& U = it->m_SynUnits[group.m_iFirstWord+1];
					if (pSent->m_Words[U.m_SentPeriod.m_iFirstWord].m_bComma)
						continue;
				};

				if	(		(group.m_iFirstWord+StartClauseWordNo < CommaWordNo) 
						&&	(group.m_iLastWord+StartClauseWordNo > CommaWordNo)
					)
				{
					Result = group.m_iLastWord + StartClauseWordNo;
					break;
				};
			}
		
		delete pSent;

		return Result;
	}
	catch(...)
	{
		OutputErrorString("Failed RunSyntaxInClause(CanLinkSimpleSimilar)");
		return -1;
	}

}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : drawHelper - 
//			rcWorkSpace - 
//-----------------------------------------------------------------------------
void PhonemeEditor::CloseCaption_Redraw( CChoreoWidgetDrawHelper& drawHelper, RECT& rcWorkSpace, CSentence& sentence )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	float starttime = m_nLeftOffset / GetPixelsPerSecond();
	float endtime = w2() / GetPixelsPerSecond() + starttime;

	RECT rcCC;
	CloseCaption_GetTrayTopBottom( rcCC );

	int ypos = rcCC.top;

	const char *fontName = "Arial Unicode MS";

	RECT rcTitle = rcCC;
	OffsetRect( &rcTitle, 0, -20 );
	rcTitle.left = 15;
	rcTitle.right = w2();

	drawHelper.DrawColoredText( "Arial", 15, FW_BOLD, PEColor( COLOR_PHONEME_CC_TEXT ), rcTitle,
		"Close caption..." );

	drawHelper.DrawColoredLine( PEColor( COLOR_PHONEME_CC_TAG_FILLER_NORMAL ), PS_SOLID, 1,
		0, rcCC.top-1, w2(), rcCC.top-1 );
	drawHelper.DrawColoredLine( PEColor( COLOR_PHONEME_CC_TAG_FILLER_NORMAL ), PS_SOLID, 1,
		0, rcCC.bottom, w2(), rcCC.bottom );
	

	bool drawselected;
	for ( int pass = 0; pass < 2 ; pass++ )
	{
		drawselected = pass == 0 ? false : true;

		int count = sentence.GetCloseCaptionPhraseCount( CC_ENGLISH );
		for (int k = 0; k < count; k++)
		{
			CCloseCaptionPhrase *phrase = sentence.GetCloseCaptionPhrase( CC_ENGLISH, k );
			if ( !phrase )
				continue;

			if ( phrase->GetSelected() != drawselected )
				continue;

			float t1 = phrase->GetStartTime();
			float t2 = phrase->GetEndTime();

			// Tag it
			float frac = ( t1 - starttime ) / ( endtime - starttime );

			int xpos = ( int )( frac * rcWorkSpace.right );

			//if ( frac <= 0.0 )
			//	xpos = 0;

			// Draw duration
			float frac2  = ( t2 - starttime ) / ( endtime - starttime );
			if ( frac2 < 0.0 )
				continue;

			int xpos2 = ( int )( frac2 * rcWorkSpace.right );

			// Draw line and vertical ticks
			RECT rcPhrase;
			CloseCaption_GetPhraseRect( phrase, rcPhrase );

			/*
			rcPhrase.left = xpos;
			rcPhrase.right = xpos2;
			rcPhrase.top = ypos;
			rcPhrase.bottom = ypos + m_nTickHeight - 1;
			*/

			drawHelper.DrawFilledRect( 
				PEColor( phrase->GetSelected() ? COLOR_PHONEME_CC_TAG_SELECTED : COLOR_PHONEME_CC_TAG_FILLER_NORMAL ), 
				rcPhrase );

			COLORREF border = PEColor( phrase->GetSelected() ? COLOR_PHONEME_CC_TAG_BORDER_SELECTED : COLOR_PHONEME_CC_TAG_BORDER );

			drawHelper.DrawOutlinedRect( border, PS_SOLID, 1, rcPhrase );

			//if ( frac >= 0.0 && frac <= 1.0 )
			{
				int fontsize = 9;

				RECT rcText;
				rcText.left = xpos;
				rcText.right = xpos2;
				rcText.top = rcCC.top;
				rcText.bottom = rcCC.bottom;

				int availw = xpos2 - xpos;

				int tokenCount = phrase->CountTokens();
				if ( tokenCount >= 1 )
				{
					int pixelsPerToken = availw / tokenCount;

					rcText.right = rcText.left + pixelsPerToken;
					
					for ( int i = 0; i < tokenCount; i++ )
					{
						wchar_t const *token = phrase->GetToken( i );
						if ( token && token[ 0 ] )
						{
							int texw = drawHelper.CalcTextWidthW( fontName,
								fontsize,
								FW_NORMAL,
								L"%s", token );

							RECT rcOutput = rcText;

							if ( texw < pixelsPerToken )
							{
								rcOutput.left += ( pixelsPerToken - texw ) / 2;
							}

							if ( i != tokenCount - 1 )
							{
								// Draw  divider
								drawHelper.DrawColoredLine( border, PS_SOLID, 1,
									rcText.right, rcText.top + 5, rcText.right, rcText.bottom - 5 );
							}

							drawHelper.DrawColoredTextW( 
								fontName, 
								fontsize, 
								FW_NORMAL, 
								PEColor( phrase->GetSelected() ? COLOR_PHONEME_CC_TAG_TEXT_SELECTED : COLOR_PHONEME_CC_TAG_TEXT ), 
								rcOutput,
								L"%s", token );
						}

						OffsetRect( &rcText, pixelsPerToken, 0 );
					}
				}
			}
		}
	}

	RECT rcOutput;
	CloseCaption_GetCCAreaRect( rcOutput );
	CloseCaption_DrawCCArea( drawHelper, rcOutput );
}
//-----------------------------------------------------------------------------
// Purpose: Given a wavfile and a list of inwords, determines the word/phonene 
//  sample counts for the sentce
// Input  : *wavfile - 
//			*inwords - 
//			*outphonemes{	text.Clear( - 
// Output : SR_RESULT
//-----------------------------------------------------------------------------
static SR_RESULT SAPI_ExtractPhonemes( 
	const char *wavfile,
	int numsamples,
	void (*pfnPrint)( const char *fmt, ... ),
	CSentence& inwords,
	CSentence& outwords )
{
	LogReset();

	USES_CONVERSION;

	CSpDynamicString text;
	text.Clear();

	HKEY hkwipe;
	LONG lResult = RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\Speech\\RecoProfiles", 0, KEY_ALL_ACCESS, &hkwipe );
	if ( lResult == ERROR_SUCCESS )
	{
		RecursiveRegDelKey( hkwipe );
		RegCloseKey( hkwipe );
	}

	if ( strlen( inwords.GetText() ) <= 0 )
	{
		inwords.SetTextFromWords();
	}

	// Construct a string from the inwords array
	text.Append( T2W( inwords.GetText() ) );

	// Assume failure
	SR_RESULT result = SR_RESULT_ERROR;

	if ( text.Length() > 0 )
	{
		CSentence sentence;

		pfnPrint( "Processing...\r\n" );

		// Give it a try
		result = ExtractPhonemes( wavfile, text, sentence, pfnPrint );

		pfnPrint( "Finished.\r\n" );
		// PrintWordsAndPhonemes( sentence, pfnPrint );

		// Copy results to outputs
		outwords.Reset();

		outwords.SetText( inwords.GetText() );
		
		Log( "Starting\n" );
		LogWords( inwords );

		if ( SR_RESULT_ERROR != result )
		{
			int i;

			Log( "Hypothesized\n" );
			LogWords( sentence );

			for( i = 0 ; i < sentence.m_Words.Size(); i++ )
			{
				CWordTag *tag = sentence.m_Words[ i ];
				if ( tag )
				{
					// Skip '...' tag
					if ( stricmp( tag->GetWord(), "..." ) )
					{
						CWordTag *newTag = new CWordTag( *tag );

						outwords.m_Words.AddToTail( newTag );
					}
				}
			}

			// Now insert unrecognized/skipped words from original list
			//
			int frompos = 0, topos = 0;

			while( 1 )
			{
				// End of source list
				if ( frompos >= inwords.m_Words.Size() )
					break;

				const CWordTag *fromTag = inwords.m_Words[ frompos ];

				// Reached end of destination list, just copy words over from from source list until
				//  we run out of source words
				if ( topos >= outwords.m_Words.Size() )
				{
					// Just copy words over
					CWordTag *newWord = new CWordTag( *fromTag );

					// Remove phonemes
					while ( newWord->m_Phonemes.Size() > 0 )
					{
						CPhonemeTag *kill = newWord->m_Phonemes[ 0 ];
						newWord->m_Phonemes.Remove( 0 );
						delete kill;
					}

					outwords.m_Words.AddToTail( newWord );
					frompos++;
					topos++;
					continue;
				}

				// Destination word
				const CWordTag *toTag = outwords.m_Words[ topos ];

				// Words match, just skip ahead
				if ( !stricmp( fromTag->GetWord(), toTag->GetWord() ) )
				{
					frompos++;
					topos++;
					continue;
				}

				// The only case we handle is that something in the source wasn't in the destination

				// Find the next source word that appears in the destination
				int skipAhead = frompos + 1;
				bool found = false;
				while ( skipAhead < inwords.m_Words.Size() )
				{
					const CWordTag *sourceWord = inwords.m_Words[ skipAhead ];
					if ( !stricmp( sourceWord->GetWord(), toTag->GetWord() ) )
					{
						found = true;
						break;
					}

					skipAhead++;
				}

				// Uh oh destination has words that are not in source, just skip to next destination word?
				if ( !found )
				{
					topos++;
				}
				else
				{
					// Copy words from from source list into destination
					// 
					int skipCount = skipAhead - frompos;

					while ( --skipCount>= 0 )
					{
						const CWordTag *sourceWord = inwords.m_Words[ frompos++ ];
						CWordTag *newWord = new CWordTag( *sourceWord );

						// Remove phonemes
						while ( newWord->m_Phonemes.Size() > 0 )
						{
							CPhonemeTag *kill = newWord->m_Phonemes[ 0 ];
							newWord->m_Phonemes.Remove( 0 );
							delete kill;
						}

						outwords.m_Words.InsertBefore( topos, newWord );
						topos++;
					}

					frompos++;
					topos++;
				}
			}

			Log( "\nDone simple check\n" );

			LogWords( outwords );
			LogPhonemes( outwords );

			ComputeMissingByteSpans( numsamples, outwords );

			Log( "\nFinal check\n" );

			LogWords( outwords );
			LogPhonemes( outwords );
		}
	}
	else
	{
		pfnPrint( "Input sentence is empty!\n" );
	}

	// Return results
	return result;
}