2012-02-24 95 views
1

我想寫一個C#應用程序使用Windows窗體和System.Speech將WAV文件轉換爲文本。我在網上看到很多關於如何做到這一點的示例,但沒有一個是非常強大的。我希望編寫一個應用程序,它可以使用BackgroundWorker線程解析較小的大型WAV文件,但在我的線程的DoWork函數中,當它調用engine.Recognize()時會收到以下異常:SpeechRecognitionEngine BackgroundWorker

「No audio輸入被提供給該識別器。使用方法SetInputToDefaultAudioDevice如果將麥克風連接到系統,否則使用SetInputToWaveFile,SetInputToWaveStream或SetInputToAudioStream從執行語音識別預錄音頻」

這裏是在我的DoWork()的代碼功能:

SpeechRecognitionEngine engine = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("en-US")); 
engine.SetInputToWaveFile(fname); 
engine.LoadGrammar(new DictationGrammar()); 
engine.BabbleTimeout = TimeSpan.FromSeconds(10.0); 
engine.EndSilenceTimeout = TimeSpan.FromSeconds(10.0); 
engine.EndSilenceTimeoutAmbiguous = TimeSpan.FromSeconds(10.0); 
engine.InitialSilenceTimeout = TimeSpan.FromSeconds(10.0); 

BackgroundWorker w = (BackgroundWorker)sender; 
while (true) 
{  
RecognitionResult data = engine.Recognize(); 
if (data == null) 
    break; 
if (w == null) //our thread died from beneath us 
    break; 
if (!w.IsBusy) //our thread died from beneath us 
    break; 
if (w.CancellationPending) //notice to cancel 
    break; 
w.ReportProgress(0, data.Text); 
} 

我是l運行多個運行此代碼的BackgroundWorker線程。如果我使用單個線程,我不會看到這個問題。

+0

我還沒有SAPI工作多年,但是從我的頭頂,我記得他們可以跑單了處理COM服務器的,所以如果你試圖讓倍數simultanously工作,這不是默認情況下,你將不得不共享音頻源和進程識別器。 – 2012-02-24 01:00:22

+0

我注意到試圖在BackgroundWorker線程中使用SpeechRecognitionEngine類會導致此異常。 – user1229658 2012-02-24 02:35:47

回答

1

您可以嘗試這種方法。我測試了它的控制檯和Windows窗體應用程序類型。

class Program { 
    public static void Main() { 
     var r1 = new Recognizer(@"c:\proj\test.wav"); 
     r1.Completed += (sender, e) => Console.WriteLine(r1.Result.Text); 

     var r2 = new Recognizer(@"c:\proj\test.wav"); 
     r2.Completed += (sender, e) => Console.WriteLine(r2.Result.Text); 

     Console.ReadLine(); 
    } 
} 

class Recognizer { 
    private readonly string _fileName; 
    private readonly AsyncOperation _operation; 
    private volatile RecognitionResult _result; 

    public Recognizer(string fileName) { 
     _fileName = fileName; 
     _operation = AsyncOperationManager.CreateOperation(null);    
     _result = null; 

     var worker = new Action(Run); 
     worker.BeginInvoke(delegate(IAsyncResult result) { 
      worker.EndInvoke(result); 
     }, null);    
    } 

    private void Run() { 
     try { 
      SpeechRecognitionEngine engine = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("en-US")); 
      engine.SetInputToWaveFile(_fileName); 
      engine.LoadGrammar(new DictationGrammar()); 
      engine.BabbleTimeout = TimeSpan.FromSeconds(10.0); 
      engine.EndSilenceTimeout = TimeSpan.FromSeconds(10.0); 
      engine.EndSilenceTimeoutAmbiguous = TimeSpan.FromSeconds(10.0); 
      engine.InitialSilenceTimeout = TimeSpan.FromSeconds(10.0); 
      _result = engine.Recognize(); 
     } 
     finally { 
      _operation.PostOperationCompleted(delegate { 
       RaiseCompleted(); 
      }, null); 
     } 
    } 

    public RecognitionResult Result { 
     get { return _result; } 
    } 

    public event EventHandler Completed; 

    protected virtual void OnCompleted(EventArgs e) { 
     if (Completed != null) 
      Completed(this, e); 
    } 

    private void RaiseCompleted() { 
     OnCompleted(EventArgs.Empty); 
    } 
} 
+0

很酷,謝謝!今天早上我玩了這段代碼,我認爲這會起作用 - 儘管我不明白爲什麼SpeechRecognitionEngine不能是多線程的。我有一個問題 - 看起來Completed事件處理程序在另一個線程的上下文中運行,所以我無法更新UI。你能修改你的例子來調用調用(UI)線程上的回調嗎? – user1229658 2012-02-25 15:37:51

+0

我使用了這裏描述的代碼並使其工作。 http://www.codeproject.com/Articles/11848/Another-way-to-Invoke-UI-from-a-Worker-Thread – user1229658 2012-02-25 15:54:06

+0

最後一個問題 - 取消這些異步操作的最佳方式是什麼,如果Windows窗體在操作中間關閉? – user1229658 2012-02-25 16:37:53