Macro of the Day: Microphone Control

I've got two microphones that I use most of the time.

  1. An Andrea SoundMAX SuperBeam 2 element array-microphone from Andrea Electronics
  2. An xTag wireless microphone from RevoLabs

I really love both of them, and I use them interchangeably throughout the day.

If I'm doing quick command and control stuff while I'm typing, I prefer to use the Andrea microphone. That way, I can just mash the <ctrl-windows> key, say what I want (like "Insert my public signature") and wishes come true.

However, if I'm a more relaxed position, doing dictation, or not sitting near my PC (I have a couch in my office :-)), I'll use my wireless xTag microphone.

But ... Having two different microphones causes me a bit of a problem sometimes. I have to actually switch back and forth between the two microphones. That's certainly possible in Vista with Windows Speech Recognition, but it's not as easy as I wanted it to be.

Thus ... A new "Macro of the day!" was born.

Today's macro allows you to say one of the following things:

Microphone
Switch microphone

[microphone] microphone
Switch to [microphone]
Switch to [microphone] microphone

The first two commands will simply bring up a dialog and let you pick which microphone you want to use. The 2nd group of commands will automatically switch to the microphone you want by simply by saying "Andrea microphone", or "xTag microphone".

Now... I till have to use one of the microphones to switch to the other one, but now it's a seamless transfer.

Here's the macro both in copy/paste form, as well as a direct link to my macro library on MSDN here:

<speechMacros>

  <!--

  Author:  Rob Chambers [MSFT]
  Contact: listen@microsoft.com

  ================
  What can I say?
  ================

    Microphone
    Switch microphone

    [microphone] microphone
    Switch to [microphone]
    Switch to [microphone] microphone

  ================
  How does it work
  ================
  This macro demonstrates how to build a dynamic rule based on
  the audio inputs that the Speech API (SAPI) knows to exist
  on the PC.

  Upon recognition, it will disambiguate the microphone name
  if it's ambiguous (or not included in the phrase), and then
  ultimately set the current microphone to use.

  -->

<command priority="100">
  <listenFor>Microphone</listenFor>
  <listenFor>*+ microphone</listenFor>
  <listenFor>[microphone] microphone</listenFor>
  <listenFor>Switch microphone</listenFor>
  <listenFor>Switch to *+ microphone</listenFor>
  <listenFor>Switch to [microphone] ?microphone</listenFor>
  <disambiguate title="Which microphone do you want to use?" prompt="Choose a Microphone" timeout="15" propname="TokenId"/>
  <script language="VBScript">
    <![CDATA[

      ' Get the token id that was stored as a semantic property in the populated by script below,
      ' as well as the text that was spoken in this utterance that generated the token id semantic property
      strMicrophoneTokenId = "{[TokenId]}"
      strMicrophoneName = "{[*TokenId]}"

      ' If there was no matching microphone spoken (e.g. if the user just said, "Microphone")   
      If (strMicrophoneTokenId = "") Then

        ' Find the rule generator script below, and tell it to update the list of microhpones on teh system
        Set audioInputs = CommandSet.RuleGenerators("microphone").Script.UpdateMicrophones()

        ' Loop thru each of those inputs, and prepare to ask the user which to use with a ChooseForList object
        For i = 0 to audioInputs.Count - 1
          Call ChooseFromList.Items.AddItem(audioInputs(i).Phrase, audioInputs(i).Property)
        Next
        ' Go ahead and ask the user which microhpone to use
        audioInputIndex = ChooseFromList.Choose("Change the default audio input from " + Result.RecoContext.Recognizer.AudioInput.GetDescription() + " to:", "Change audio input")

        ' If the user made a selection, update the token id and what the text for that token is
        If (audioInputIndex >= 0) Then
          strMicrophoneName = audioInputs(audioInputIndex).Phrase
          strMicrophoneTokenId = audioInputs(audioInputIndex).Property
        End If

      End If

      ' If we know what microhone to switch to now...
      If (strMicrophoneTokenId <> "") Then

        ' Tell the speech ux to go to off mode (273 is WM_COMMAND, and 102 is "Off" for the speech ux in Vista)
        Call Application.SendMessage("MS:SpeechTopLevel", "", 273, 102, 0)

        ' Update the default for the input category to the new microphone token id
        Result.RecoContext.Recognizer.GetAudioInputs()(0).Category.Default = strMicrophoneTokenId
        ' Let the user know what we did, but automatically time out after 1 second
        Call Application.Alert("Switched to " & strMicrophoneName , "Microphone", 1)

      End If

    ]]>
  </script>
</command>
<ruleScript name="microphone" propname="TokenId" language="VBScript">
  <![CDATA[

    ' Update the list of Microphones right now
    Call UpdateMicrophones()

    Function UpdateMicrophones()

      ' Clear all the items in case we're updating the list
      Call Rule.Items.RemoveAll

      ' Create a shared recognizer, get the audio inputs that recognizer can use
      ' and add each of the inputs as a phrase to the rule (using the token id as the property)
      Set recognizer = CreateObject("SAPI.SpSharedRecognizer")
      Set audioInputs = recognizer.GetAudioInputs()
      For i = 0 to audioInputs.Count - 1
        Call Rule.Items.AddItem(audioInputs(i).GetDescription(), audioInputs.Item(i).Id, True)
      Next

      ' Commit the changes to the rule now, and return the items to the caller. This enables
      ' us the command's script to use this function to update the list and return the list
      ' in a single call/function.
      Call Rule.Commit
      Set UpdateMicrophones = Rule.Items
    End Function

  ]]>
</ruleScript>

</speechMacros>