В этом посте я расскажу о том, как 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