Обучение сапи: создание транскрипционных файлов wav и добавление путей к файлам в реестр

Мы пытаемся провести акустическое обучение, но не можем создать записанные аудиофайлы, как это сделать? Также мы используем GetTranscript и Appendtranscript, но мы не можем получить интерфейс ISpTranscript для ISpStream, если мы откроем поток в режиме READWRITE, так как же создать файлы WAV с транскрипцией?

hr = SPBindToFile(L"e:\\file1.wav", SPFM_OPEN_READONLY,
    &cpStream);
hr = cpStream.QueryInterface(&cpTranscript);
// We get a error here for as E_NONINTERFACE if SPFM_OPEN_READWRITE  
hr = cpTranscript->AppendTranscript(sCorrectText);
hr = cpTranscript->GetTranscript(&pwszTranscript);
// GIVES CORRECT TRANSCRIPT 

//READING THIS AGAIN ON NEXT EXECUTION TIME DOES NOT GIVE THE TRANSCRIPT

hr = SPBindToFile(L"e:\\file1.wav", SPFM_OPEN_READONLY,
    &cpStream);
hr = cpStream.QueryInterface(&cpTranscript);
//THIS GIVE THE ERROR E_NONINTERFACE

После этого нам нужно добавить путь к файлу в реестр. Мы делаем это с помощью следующего кода.

CComPtr<ISpObjectToken> cpObjToken;



ULONG                     CSIDL_LOCAL_APPDATA = 28;
ULONG                     CSIDL_FLAG_CREATE = 32768;
GUID guid0;
LPWSTR FileName2;

hr = cpRecognizerBase->GetRecoProfile(&cpObjToken);
hr = CoCreateGuid(&guid0);
hr = cpObjToken->GetStorageFileName(guid0, L"Test",   L"F:\\sample6.wav",CSIDL_FLAG_CREATE, &FileName2);
//this code runs fine but the file is never added to the registry

Будем признательны за любые указатели. Этот вопрос связан с заданным здесь вопросом Файлы обучения речи и расположение реестра

Спасибо


person Noobcoder    schedule 18.03.2012    source источник


Ответы (1)


В этом посте я расскажу о том, как appendTranscript успешно выполнять упражнения, и о тренировке речи с использованием файлов WAV (благодарность Биллу Хатчинсону). Все есть в C++.

E_NONINTERFACE происходит, если ISPStream не имеет содержимого. Например, файл был пустым; вызов не удался, но все равно вернул s_OK (по какой-то причине это происходит). Поэтому обычно я сначала проверяю, есть ли в потоке какое-либо содержимое. Вы можете сделать это, проверив его размер:

Вот пример. Если он имеет размер 0 или какой-то абсурдно большой размер, то очевидно, что он вернул неверное значение. Имейте в виду, что возвращаемое значение - ULARGE_INTEGER.

STATSTG streamInfo;
cpStream->Stat(&streamInfo, STATFLAG_DEFAULT);
ULARGE_INTEGER streamSizeULI;
streamSizeULI = streamInfo.cbSize;

SPBindToFile работает только с SPFM_OPEN_READONLY и SPFM_CREATE_ALWAYS, поэтому вам придется использовать один из них.

Что касается того, как сохранить добавленную стенограмму, кажется, что вы не можете сохранить ее напрямую, если файл wav уже существует (или, по крайней мере, я не знаю, как). Если файл еще не существует, вы можете создать новый ispstream, и когда вы передадите ему аудиоинформацию, например, голосом или микрофоном (в Интернете есть множество примеров), вы можете добавить стенограмму, и она будет прикреплена . Я привожу пример ниже.

Добавление стенограммы в новый файл:

void recordAndAppendTranscriptInOneOperation() {
HRESULT             hr = S_OK;
CComPtr <ISpVoice>      cpVoice;
CComPtr <ISpStream>     cpStream;
CComPtr<ISpTranscript>  cpTranscript;
CSpStreamFormat         cAudioFmt;

//Create    a   SAPI    Voice   
hr  =   cpVoice.CoCreateInstance(CLSID_SpVoice);

char filePathOut[] = R"(C:\SAPI\SampleOutput\SP_Sample.wav)";

//Set   the audio   format                              
if(SUCCEEDED(hr))   
{       
    hr  =   cAudioFmt.AssignFormat(SPSF_22kHz16BitMono);    
}

//Call  SPBindToFile,   a   SAPI    helper  method,     to  bind    the audio       
if(SUCCEEDED(hr))   
{
    hr = SPBindToFile(filePathOut, SPFM_CREATE_ALWAYS, &cpStream, &cAudioFmt.FormatId(), cAudioFmt.WaveFormatExPtr());
}

//set   the output  to  cpStream    so  that    the output  audio   data    wil                             
if(SUCCEEDED(hr))   
{       
    hr = cpVoice->SetOutput(cpStream, TRUE);    
}

//Speak the text    “hello  world”  synchronously                               
if(SUCCEEDED(hr))   
{       
    hr = cpVoice->Speak(L"Hello World", SPF_DEFAULT, NULL);
}

//close the stream  
if(SUCCEEDED(hr))   
{
    PWCHAR                      pwszTranscript;
    char NewTranscriptAsString[] = R"(This is a test)";
    LPCWSTR NewTranscript = charToLPSTRW(NewTranscriptAsString);

    hr = cpStream.QueryInterface(&cpTranscript);
    hr = cpTranscript->AppendTranscript(NULL);
    hr = cpTranscript->AppendTranscript(NewTranscript);
    hr = cpTranscript->GetTranscript(&pwszTranscript);

    hr  =   cpStream->Close();  
}

//Release   the stream  and voice   object  
cpStream.Release(); 
cpVoice.Release();
 }

У Билла Хатчинсона (один из источников по ссылкам ниже) есть код, который можно использовать для обучения распознавателя без внесения всех изменений в реестр и т. Д. Я включил это в конце этого поста. У него есть функция (TrainOne), которая обучает распознаватель файл за файлом через поток памяти. Вы можете передать ему уже существующие файлы WAV. В частности, либо WAV с транскриптами, либо WAV без транскриптов и (затем предоставить транскрипцию функции во время вызова). Пожалуйста, взгляните на него, так как он очень информативный.

Вот коллекция всех знаний, связанных с SAPI, которые я нашел, которые будут полезны другим, пытающимся разобраться в этом беспорядке. Я также скоро опубликую свое собственное полное решение для обучения SAPI:

Пример обучающего кода:

Поскольку код SAPI Билла Хатчинсона является одним из немногих надежных примеров использования SAPI для обучения в Интернете, я включил его сообщение из Google ниже на случай, если он однажды будет удален / утерян:

#include "stdafx.h"
#include "sphelper.h"
#include <sapi.h>
#include <string.h>
//MAIN() is last function below
inline HRESULT ReturnResult(ISpRecoContext * pRecoCtxt, ISpRecoResult
** ppResult)
{
        HRESULT hr = S_OK;
        CSpEvent spEvent;
        while (S_OK == pRecoCtxt->WaitForNotifyEvent(INFINITE))
        {
                while (S_OK == spEvent.GetFrom(pRecoCtxt))
                {
                        switch (spEvent.eEventId)
                        {
                                case SPEI_RECOGNITION:
                                        *ppResult = spEvent.RecoResult();
                                        if (*ppResult)
                                        {
                                                (*ppResult)->AddRef();
                                        }
                                        return hr;
                                case [OTHER EVENTS]
                    spEvent.Clear();
        }
        return hr;
}
inline HRESULT TrainOneFile(ISpRecoContext * cpRecoCtxt, ISpRecognizer
* cpRecognizerBase, ISpRecoGrammar * cpGrammar)
{
        CComPtr<ISpStream>      cpStream;
        CComPtr<ISpRecoResult>        cpResult;
        CComPtr<ISpTranscript>  cpTranscript;
        PWCHAR                  pwszTranscript;
        HRESULT hr = S_OK;
        hr = cpStream.CoCreateInstance(CLSID_SpStream);
        // Bind a stream to an existing wavefile
        if (SUCCEEDED(hr))        {
                hr = cpStream->BindToFile(L"C:\\XX.wav",                                                        SPFM_OPEN_READONLY,
                        NULL,
                        NULL,
                        SPFEI_ALL_EVENTS);
        }
        if (SUCCEEDED(hr)){
                hr = cpStream.QueryInterface(&cpTranscript);
        }
        if (SUCCEEDED(hr)) {
                hr = cpTranscript->GetTranscript(&pwszTranscript);
        }
        //THIS IS ALTERNATE CODE FOR PREVIOUS LINE, FOR SOUND FILES THAT
DON’T HAVE A TRANSCRIPT ATTACHED
        LPCWSTR sCorrectText = L"Anyone who has spent time on a farm knows
there is a rhythm to the year.";
        if (SUCCEEDED(hr)){
                hr = cpTranscript->AppendTranscript(s);
        }
        if (SUCCEEDED(hr))        {
                hr = cpTranscript->GetTranscript(&pwszTranscript);
        }
        if(SUCCEEDED(hr)){
                hr = cpRecognizerBase->SetInput(cpStream, TRUE);
        }
        USES_CONVERSION;
        CSpDynamicString dstrText;
        if (SUCCEEDED (hr)){
                hr = cpGrammar->SetDictationState(SPRS_ACTIVE);
        }
        if (SUCCEEDED(hr)){
                hr = ReturnResult(cpRecoCtxt, &cpResult);
        }
        if (SUCCEEDED(hr)){
                hr = cpGrammar->SetDictationState( SPRS_INACTIVE );
        }
        if ((cpResult) &&(SUCCEEDED(hr))){
                hr = cpResult-
>GetText(SP_GETWHOLEPHRASE,SP_GETWHOLEPHRASE,TRUE,&dstrText,NULL);
        }
        CComPtr<ISpRecoResult2> cpResult2;
        if (SUCCEEDED(hr)){
                hr = cpResult.QueryInterface<ISpRecoResult2>(&cpResult2);
        }
        if (SUCCEEDED(hr)){
//COMMITTEXT SHOULD FORCE ADAPTATION OF MODELS TO CORRECT TEXT
//(THO IT SHOULD BE REDUNDANT WITH SETTRAININGSTATE() ?)
                hr = cpResult2-
>CommitText(SP_GETWHOLEPHRASE,SP_GETWHOLEPHRASE,sCorrectText,SPCF_DEFINITE_CORRECTION);
                cpResult.Release();
                cpResult2.Release();
        }
        return hr;
}

int _tmain(int argc, _TCHAR* argv[])
{
        HRESULT hr = S_OK;
        CComPtr<ISpRecognizer2> cpRecognizer;
        CComPtr<ISpRecoContext> cpRecoCtxt;
        CComPtr<ISpRecoGrammar> cpGrammar;
        CComPtr<ISpRecognizer> cpRecognizerBase;
        hr = ::CoInitialize(NULL);
            if (SUCCEEDED(hr)) {
                hr = cpRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer);
        }
        if (SUCCEEDED(hr)){
                hr = cpRecognizer.QueryInterface<ISpRecognizer>(&cpRecognizerBase);
        }
        if (SUCCEEDED(hr)){
                hr = cpRecognizerBase->CreateRecoContext(&cpRecoCtxt);
        }
        if (cpRecoCtxt){
                hr = cpRecoCtxt->CreateGrammar(0, &cpGrammar);
        }
        if (SUCCEEDED(hr)){
                hr = cpGrammar->LoadDictation(NULL, SPLO_STATIC);
        }
        if (SUCCEEDED(hr)){
                hr = cpRecognizer->SetTrainingState(TRUE, TRUE);
        }
        if (SUCCEEDED(hr)){
                hr = cpRecoCtxt->SetNotifyWin32Event();
        }
        if (SUCCEEDED(hr)){
                hr = cpRecoCtxt->SetInterest(
                        SPFEI(SPEI_RECOGNITION)|
                        SPFEI(SPEI_HYPOTHESIS)|
                        SPFEI(SPEI_FALSE_RECOGNITION),
                        SPFEI(SPEI_RECOGNITION)|
                        SPFEI(SPEI_HYPOTHESIS)|
                        SPFEI(SPEI_FALSE_RECOGNITION));
        }
        if (SUCCEEDED(hr)){
                hr = TrainOneFile(cpRecoCtxt, cpRecognizerBase, cpGrammar);
        }
        if (SUCCEEDED(hr)){//RERUN TO CHECK FOR IMPROVEMENT
                hr = TrainOneFile(cpRecoCtxt, cpRecognizerBase, cpGrammar);
        }
        cpRecognizer->SetTrainingState(FALSE, TRUE);//should turn off and
save changes
        ::CoUninitialize();
        return 0;
}
person Tyler S. Loeper    schedule 21.02.2019