Обучение профилю распознавания речи с использованием SAPI 5.4C++

Программы на C++. Форум разработчиков
Anonymous
 Обучение профилю распознавания речи с использованием SAPI 5.4

Сообщение Anonymous »

Я разрабатываю C++ DLL, которая используется приложением C# через взаимодействие. Целью DLL является обучение профилю распознавания речи «По умолчанию». Приложение C# только отправляет обучающий текст и получает уведомления о завершении каждого обучающего файла, чтобы оно могло отправить следующий обучающий текст. Пользователь читает обучающий текст в приложении C#, а библиотека C++ DLL выполняет распознавание.
Я прочитал несколько статей и разработал поток этого кода на основе описания Эрика Брауна здесь. . Существуют примеры использования существующих WAV-файлов для достижения этой цели, однако цель состоит в том, чтобы повторить то, что Windows делает с обучением профиля речи.
Я вставил ниже полный код с обработкой ошибок. , заголовочный файл с оболочкой C и код C# опущен в надежде, что кто-нибудь сможет помочь.
Возникли следующие проблемы:
  • Файл .wav создается, но не воспроизводится. Файл можно открыть
    в программе для редактирования аудио, и он воспроизводится с очень высокой
    скоростью.
  • Чтение второго обучающего текста (например, StarListening), wav файл
    перезаписан.
  • AppendTranscript приводит к ошибке FAILED (ошибка p!=0).
Глобальные переменные:
CComPtr cpRecognizer2;
CComPtr cpRecognizer;
CComPtr cpProfileToken;
CComPtr cpRecoContext;
CComPtr cpRecoGrammar;
CComPtr cpAudio;
CComPtr cpObjectToken;
CComPtr cpTranscript;
CComPtr cpRecoProfile;
CComPtr cpRecoResult;
CComPtr cpStream;
CComPtr cpStreamFormat;

WCHAR *pwszRecoProfileName;
WCHAR* pwszRecoResultText;
CSpDynamicString TrText;

ULONG CSIDL_LOCAL_APPDATA = 28;
ULONG CSIDL_FLAG_CREATE = 32768;

LoopFunciton для распознавания и создания WAV-файлов на основе профиля речи по умолчанию.

void LoopFunction()
{
HRESULT hr = S_OK;

while (running.load()) {
// Wait for recognition events
CSpEvent spEvent;
while (spEvent.GetFrom(cpRecoContext) == S_OK)
{
if (spEvent.eEventId == SPEI_RECOGNITION)
{
// Get the reco result
cpRecoResult = spEvent.RecoResult();
// release recognition result pointer in event object
spEvent.Clear();
StopListening();

// if recognition received, and result stored then store the audio
if (cpRecoResult)
{
//GetStorageFileName retrieves the object token file name from the registry.
LPWSTR lpFileName;
hr = cpObjectToken->GetStorageFileName(CLSID_NULL, L"TrainingAudio.wav", L"TrainingAudio\\ESTE_%d.wav", CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, &lpFileName);

// Get da recognized text
hr = cpRecoResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, FALSE, &pwszRecoResultText, NULL);

// get stream pointer to recognized audio
hr = cpRecoResult->GetAudio(0, 0, &cpStreamFormat);

// Create a stream object
hr = cpStream.CoCreateInstance(CLSID_SpStream);

// create file on hard-disk for storing recognized audio, and Bind the stream to the file
hr = cpStream->BindToFile(lpFileName, SPFM_CREATE_ALWAYS, NULL, NULL, SPFEI_ALL_EVENTS);

ULONG cbWritten = 0;

//Continuously transfer data between the two streams until no more data is found (i.e. end of stream)
while (TRUE)
{
STATSTG stats;
hr = cpStreamFormat->Stat(&stats, NULL);

BYTE bBuffer[1000];
ULONG cbRead;

hr = cpStreamFormat->Read(bBuffer, 1000, &cbRead);

if (SUCCEEDED(hr) && cbRead > 0)
{
hr = cpStream->Write(bBuffer, cbRead, &cbWritten);
}

if (cbRead < 1000)
{
break;
}
}

// Use QueryInterface on the stream object to obtain the Transrcript
hr = cpStream->QueryInterface(&cpTranscript);

// Clear Transcript and Append trainingText to stream
hr = cpTranscript->AppendTranscript(NULL);
hr = cpTranscript->AppendTranscript(TrText);

// explicitly close the file-based stream to flush file data and allow app to immediately use the file
hr = cpStream->Close();
::CoTaskMemFree(lpFileName);
}
}
}
}
}


CreateRecoEngine настраивает все из профиля речи по умолчанию. Обратный вызов для приложения C# выполнен.
void CreateRecoEngine(void(*callback)(bool))
{
HRESULT hr = CoInitialize(NULL);

// Create InprocRecognizer
hr = cpRecognizer2.CoCreateInstance(CLSID_SpInprocRecognizer);

// Query ISpRecognizer for use with ISpRecognizer2 to access SetTrainingState
hr = cpRecognizer2.QueryInterface(&cpRecognizer);

// Get the default audio input token.
hr = SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOIN, &cpObjectToken);

// Set the audio input to our token.
hr = cpRecognizer->SetInput(cpObjectToken, TRUE);

// Create the default audio input object.
hr = SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN, &cpAudio);

// Set the audio input to our object.
hr = cpRecognizer->SetInput(cpAudio, TRUE);

// Get the default recognition profile
hr = SpGetDefaultTokenFromCategoryId(SPCAT_RECOPROFILES, &cpRecoProfile);

// Assign the default recognition profile to recognizer
hr = cpRecognizer->SetRecoProfile(cpRecoProfile);

// Set Reco state to Active always
hr = cpRecognizer->SetRecoState(SPRST_ACTIVE_ALWAYS);

// Create recognition context
hr = cpRecognizer->CreateRecoContext(&cpRecoContext);

// Set up the grammar
hr = cpRecoContext->CreateGrammar(1, &cpRecoGrammar);

// Load a simple dictation grammar
hr = cpRecoGrammar->LoadDictation(NULL, SPLO_STATIC);

// Turn on training
hr = cpRecognizer2->SetTrainingState(TRUE, TRUE);

// Activate retained audio settings with default format (that is, SR engine recognition format).
hr = cpRecoContext->SetAudioOptions(SPAO_RETAIN_AUDIO, &GUID_NULL, NULL);

// Run recognition loop on seperate thread
running = true;
loopThread = std::thread(LoopFunction);

callback(true);
}


StartListening получает обучающий текст из приложения C# и передает его в глобальную переменную для использования в LoopFunciton.
void StartListening(const char* trainingText)
{
HRESULT hr = S_OK;

// Set global variable to traingText
TrText = trainingText;

// Activate the grammar
hr = cpRecoGrammar->SetDictationState(SPRS_ACTIVE);
}


void StopListening()
{
HRESULT hr = S_OK;

// Stop recognition loop
running = false;

// Turn off dictation
hr = cpRecoGrammar->SetDictationState(SPRS_INACTIVE);

// Turn off Training
hr = cpRecognizer2->SetTrainingState(FALSE, TRUE);
}



Подробнее здесь: https://stackoverflow.com/questions/790 ... g-sapi-5-4

Вернуться в «C++»