В этом посте я расскажу, как успешно выполнить 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;
}