Thanks for testing it!
Your one-liner works because it bypasses the busy check.
In the demo, Speak is ignored while mBusy is True. My mistake was starting the voice-list loading in the window's Opening event, before the window is shown. In that case the loading never finished, so mBusy stayed True and every click on Speak was silently ignored. The latest SpeechDemo.objo starts the loading in Opened instead, and then it works.
Why async: speaking can take several seconds, so the plugin runs it in the background rather than holding up the window.
Var finished As Boolean = Await mSpeaker.Speak(text)
This keeps the window responsive and also tells you when the speech has finished. It returns True if playback completes normally, or False if it was stopped with mSpeaker.Stop(). It also means any errors can be caught with Try/Catch.
Without Await, the speech will still play, but you won't know when it has finished, and any errors are lost.
Why mBusy: while speech is in progress, the plugin only allows Stop(). Changing Voice, Rate or Volume is refused, and a second Speak call has to wait until the first one is done. The flag disables those controls until the current call has finished.
Minimal version (event handlers can't be Async, so the button calls a helper):
Private Async Sub SayIt(text As String)
Try
Var finished As Boolean = Await mSpeaker.Speak(text)
Catch e As Exception
MessageBox("Speech failed: " + e.Message)
End Try
End Sub
# Button Pressed:
_ = SayIt(TextArea1.Text)