いくつかの異なる外部入力 (キーボードの押下、モーション ジェスチャ、音声) を受け取り、同様の出力を生成できるアプリケーションを作成しています (たとえば、キーボードで「T」を押すと、「Travel」という単語を発声するのと同じことが行われます)。うるさい)。そのため、どの入力マネージャーにもお互いのことを知られたくありません。具体的には、Kinect の内蔵マイクを使用しているにもかかわらず、Kinect マネージャーに (可能な限り) Speech マネージャーのことを知られたくありません (Speech マネージャーはどのマイクでも動作するはずです)。Microsoft.Speech ではなく、Speech Manager で System.Speech を使用しています。
Kinect モーション認識モジュールが有効になるとすぐに、音声モジュールが入力の受信を停止するという問題があります。スケルトンストリームとオーディオストリームを反転する、オーディオストリームをさまざまな方法でキャプチャするなど、たくさんのことを試しました。最終的に問題を絞り込みました。モジュールを初期化する方法について何かがうまく機能しません私のアプリケーションはイベントを扱います。
モーション キャプチャが開始されるまで、アプリケーションはうまく機能します。Kinect モジュールを完全に除外すると、メイン メソッドは次のようになります。
// Main.cs
public static void Main()
{
// Create input managers
KeyboardMouseManager keymanager = new KeyboardMouseManager();
SpeechManager speechmanager = new SpeechManager();
// Start listening for keyboard input
keymanager.start();
// Start listening for speech input
speechmanager.start()
try
{
Application.Run();
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace);
}
}
私Application.Run()
のGUIは外部プログラムによって処理されているため、使用しています。この C# アプリケーションの唯一の仕事は、入力イベントを受け取り、その入力に基づいて外部スクリプトを実行することです。
キーボード モジュールと音声モジュールの両方が散発的にイベントを受け取ります。一方、Kinect は常にイベントを生成します。私のジェスチャが同様に頻繁に発生しない場合は、各ポーリング間に待機時間があるポーリング ループが答えになる可能性があります。ただし、Kinect を使用してマウスの動きを制御しています... スケルトン イベントのキャプチャ間で待機する余裕はありません。私のスケルトン キャプチャ ループは、可能な限り一定である必要があります。Kinect マネージャーを同じスレッド (またはメッセージ ポンプ?) に置くことができないため、これは大きな問題を引き起こしました。同じスレッドにいると、キーボードまたは音声イベントが一貫して通過できなくなります。その代わり、System.Windows.Forms
で動作するようにしApplication.Run()
ます。さて、私の主な方法は次のようになります。
// Main.cs
public static void Main()
{
// Create input managers
KeyboardMouseManager keymanager = new KeyboardMouseManager();
KinectManager kinectManager = new KinectManager();
SpeechManager speechmanager = new SpeechManager();
// Start listening for keyboard input
keymanager.start();
// Attempt to launch the kinect sensor
bool kinectLoaded = kinectManager.start();
// Use the default microphone (if applicable) if kinect isn't hooked up
// Use the kinect microphone array if the kinect is working
if (kinectLoaded)
{
speechmanager.start(kinectManager);
}
else
{
speechmanager.start();
}
try
{
// THIS IS THE PLACE I THINK I'M DOING SOMETHING WRONG
Application.Run(kinectManager);
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace);
}
何らかの理由で、Kinect センサーが開始されるとすぐに、Kinect マイクはその「デフォルト性」を失います (この観察が正しくない場合、または回避策がある場合は、お知らせください)。start()
そのため、Speech マネージャーで次のような特別なメソッドを作成する必要がありました。
// SpeechManager.cs
/** For use with the Kinect Microphone **/
public void start(KinectManager kinect)
{
// Get the speech recognizer information
RecognizerInfo recogInfo = SpeechRecognitionEngine.InstalledRecognizers().FirstOrDefault();
if (null == recogInfo)
{
Console.WriteLine("Error: No recognizer information found on Kinect");
return;
}
SpeechRecognitionEngine recognizer = new SpeechRecognitionEngine(recogInfo.Id);
// Loads all of the grammars into the recognizer engine
loadSpeechBindings(recognizer);
// Set speech event handler
recognizer.SpeechRecognized += speechRecognized;
using (var s = kinect.getAudioSource().Start() )
{
// Set the input to the Kinect audio stream
recognizer.SetInputToAudioStream(s, new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));
// Recognize asycronous speech events
recognizer.RecognizeAsync(RecognizeMode.Multiple);
}
}
参考までstart()
に、Kinect マネージャーのメソッドは次のようになります。
// KinectManager.cs
public bool start()
{
// Code from Microsoft Sample
kinect = (from sensorToCheck in KinectSensor.KinectSensors where sensorToCheck.Status == KinectStatus.Connected select sensorToCheck).FirstOrDefault();
// Fail elegantly if no kinect is detected
if (kinect == null)
{
connected = false;
Console.WriteLine("Couldn't find a Kinect");
return false;
}
// Start listening
kinect.Start();
// Enable listening for all skeletons
kinect.SkeletonStream.Enable();
// Obtain the KinectAudioSource to do audio capture
source = kinect.AudioSource;
source.EchoCancellationMode = EchoCancellationMode.None; // No AEC for this sample
source.AutomaticGainControlEnabled = false; // Important to turn this off for speech recognition
kinect.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(allFramesReady);
connected = true;
return true;
}
そのため、モーション キャプチャを無効にすると (main() を最初のコード セグメントに似せて)、音声認識は正常に機能します。モーション キャプチャを有効にすると、モーションはうまく機能しますが、音声が認識されません。どちらの場合も、キーボード イベントは常に機能します。エラーはなく、トレースによって、音声マネージャーのすべてのデータが正しく初期化されていることがわかりました...音声認識イベントが消えたようです。入力モジュールが独立して機能するように、このコードを再編成するにはどうすればよいですか? スレッドを使用しますか、それとも別の方法で Application.Run() だけを使用しますか?