Reputation: 165
I am making speech to text app in C# window form it was working fine and running in visual studio but
when I click on button the button start recognizing but when I again click on the button to stop recognizing it is not stop and start recognizing until I closed the application
How can I solve this?
My code:
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp5
{
public partial class Form1 : Form
{
public async Task RecognitionWithMicrophoneAsync()
{
var config = SpeechConfig.FromSubscription("key", "region");
var stopRecognition = new TaskCompletionSource<int>();
using (var recognizer = new SpeechRecognizer(config))
{
//var result = await recognizer.RecognizeOnceAsync().ConfigureAwait(false);
recognizer.Recognizing += (s, e) =>
{
//Console.WriteLine("Say something...");
};
recognizer.Recognized += (s, e) =>
{
// Checks result.
if (e.Result.Reason == ResultReason.RecognizedSpeech)
{
//Console.WriteLine($"RECOGNIZED: Text={e.Result.Text}");
SendKeys.SendWait(e.Result.Text);
//tb_1.Text += result.Text;
}
else if (e.Result.Reason == ResultReason.NoMatch)
{
Console.WriteLine($"NOMATCH: Speech could not be recognized.");
}
};
recognizer.Canceled += (s, e) =>
{
Console.WriteLine($"CANCELED: Reason={e.Reason}");
if (e.Reason == CancellationReason.Error)
{
Console.WriteLine($"CANCELED: ErrorCode={e.ErrorCode}");
Console.WriteLine($"CANCELED: ErrorDetails={e.ErrorDetails}");
Console.WriteLine($"CANCELED: Did you update the subscription info?");
}
button1.Enabled = true;
picture_btn.Image = Properties.Resources.green;
stopRecognition.TrySetResult(0);
};
recognizer.SessionStarted += (s, e) =>
{
//Console.WriteLine("\n Session started event.");
};
recognizer.SessionStopped += (s, e) =>
{
//Console.WriteLine("\n Session stopped event.");
//Console.WriteLine("\nStop recognition.");
stopRecognition.TrySetResult(0);
};
// Starts continuous recognition. Uses StopContinuousRecognitionAsync() to stop recognition.
await recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
// Waits for completion.
// Use Task.WaitAny to keep the task rooted.
Task.WaitAny(new[] { stopRecognition.Task });
// Stops recognition.
await recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
picture_btn.Image = Properties.Resources.red;
picture_btn.Enabled = false;
RecognitionWithMicrophoneAsync().Wait();
//if (button1.Enabled)
//{
// button1.Enabled = true;
// RecognitionWithMicrophoneAsync().Wait();
// }
// else
//{
// button1.Enabled = false;
//RecognitionWithMicrophoneAsync().Start();
//}
//Console.WriteLine("Please press enter to exit.");
//Console.ReadLine();
}
}
}
Upvotes: 1
Views: 640
Reputation: 16679
If your form only has a single button, then you will not be able to click it again if you disable the button. That is the thing about disabling it, it will stop responding to click events.
If you want to use the
Button.Enabled
state and chain a sequence of events, then you will find it simpler to use multiple buttons, you will see this in many interface designs. You can even overlay the buttons so as to look like it is the same button, however when using overlays you would toggle the button'sVisible
state, notEnabled
For your commented out code to work, simply do not disable the button.
Ideally, you would have a property or field in the view model that controls the state, in WinForms we can also use the Tag
property on a control to assign any arbitrary values we may need to keep track of state, instead of disabling the button.
I still prefer the VM/Property for discretely storing state, but this makes for a simple low-code solution and now that you are aware of it you may find novel uses for this
Tag
property in the future.
The next issue is that we don't want to constrain the instance of recognizer
to a single function scope, we want recognizer
to be stored on the member so that we can interact with it from repeated entries to the button click event handler.
private async void button1_Click(object sender, EventArgs e)
{
var button = sender as Button;
var listening = (button.Tag as bool?).GetValueOrDefault();
if(!listening)
{
button.Tag = true;
button.Image = Properties.Resources.red;
await recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
}
else
{
button.Tag = false;
button.Image = Properties.Resources.green;
await recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
}
}
The code for the rest of your form now looks like this:
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
namespace SpechToTextForms
{
public partial class Form1 : Form
{
SpeechRecognizer recognizer;
SpeechConfig config;
public Form1()
{
InitializeComponent();
config = SpeechConfig.FromSubscription("key", "region");
// TODO: set other configuration parameters
recognizer = new SpeechRecognizer(config);
recognizer.Recognizing += (s, e) =>
{
Console.WriteLine("Recognizing: {0}", e.Result);
};
recognizer.Recognized += (s, e) =>
{
// Checks result.
if (e.Result.Reason == ResultReason.RecognizedSpeech)
{
Console.WriteLine($"RECOGNIZED: Text={e.Result.Text}");
//SendKeys.SendWait(e.Result.Text);
tb_1.Text += " " + result.Text;
}
else if (e.Result.Reason == ResultReason.NoMatch)
{
Console.WriteLine($"NOMATCH: Speech could not be recognized.");
}
};
recognizer.Canceled += (s, e) =>
{
Console.WriteLine($"CANCELED: Reason={e.Reason}");
if (e.Reason == CancellationReason.Error)
{
Console.WriteLine($"CANCELED: ErrorCode={e.ErrorCode}");
Console.WriteLine($"CANCELED: ErrorDetails={e.ErrorDetails}");
Console.WriteLine($"CANCELED: Did you update the subscription info?");
}
picture_btn.Tag = false;
picture_btn.Image = Properties.Resources.green;
};
recognizer.SessionStarted += (s, e) =>
{
Console.WriteLine("\n Session started event.");
};
recognizer.SessionStopped += (s, e) =>
{
//Console.WriteLine("\n Session stopped event.");
//Console.WriteLine("\nStop recognition.");
picture_btn.Tag = false;
picture_btn.Image = Properties.Resources.green;
};
}
private void Form1_Load(object sender, EventArgs e)
{
}
private async void button1_Click(object sender, EventArgs e)
{
var button = sender as Button;
var listening = (button.Tag as bool?).GetValueOrDefault();
if (!listening)
{
button.Tag = true;
button.Image = Properties.Resources.red;
await recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
}
else
{
button.Tag = false;
button.Image = Properties.Resources.green;
await recognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
}
}
}
}
For the purposes of a demo like this, I hve commented out the use of SendKeys
as this can make a mess if you try debugging and talking at the same time, but still a bit of fun ;)
Upvotes: 1