Macro of the Day: Windows Media Player

Have you ever wanted to control your media player with your voice? Well now you can! With today’s Macro of the Day, you can say things like “Play Hotel California”, or “Play The Eagles”, or, “Play Genre Rock”, and even “Play something by The Eagles”.

Today’s macro is one of the first Macros I created when we were developing WSR Macros, and I’ve tweaked it off and on for the last couple years. It’s currently in really good shape, and demonstrates some neat concepts like clarification, using named states, Jscript, and for the first time, it demonstrates the wmpMediaControl, wmpMediaPlay, and wmpMediaItems XML elements from the WSR Macro schema.

Let’s take a look at the first command in the macro, and the one I use the most:

<command>

    <listenFor>play ?the artist [Artists]</listenFor>
    <listenFor>play ?the band [Artists]</listenFor>
    <listenFor>play ?the group [Artists]</listenFor>

    <setTextFeedback>Playing Artist {[*Artist]}</setTextFeedback>
    <wmpMediaControl command="pause"/>
    <disambiguate title="Which artist do you want to play?" prompt="Choose an Artist" timeout="25" propname="Artist"/>

    <setState name="playMediaTypeName" value="Artist"/>
    <setState name="playMediaTypeValue" value="{[*Artist]}"/>
    <setState name="playMediaAttrName" value="WM/AlbumArtist"/>
    <setState name="playMediaAttrValue" value="{[Artist]}"/>
    <emulateRecognition>Play what I asked for</emulateRecognition>

</command>

This command listens for a few different ways to say “Play the artist [artist]”. When that, or one if it’s alternatives is recognized, the macro set’s the text feedback, tells the Media Player to pause, and then prompts the user if necessary to clarify (or disambiguate as we say inside the Speech group). After which, it sets a few named states to keep track of the last verbal request, and then emulates “Play what I asked for”.

“Rob, why are you doing that?” … good question. The first reason is to demonstrate how you can sequence macros together. You’ll see with the other commands for albums and tracks, that they all do some very similar things. By using named states, we can in effect make a voice based sub-routine. The added bonus is that I can also say “Play what I asked for”, and the last media play command will be performed.

Let’s look at the Play what I asked for command:

<command>

    <listenFor>Play what I asked for ?again</listenFor>

    <wmpMediaControl command="pause"/>
    <setTextFeedback speak="true">Playing {[playMediaTypeName]} {[playMediaTypeValue]}</setTextFeedback>
    <wmpMediaPlay attrname="{[playMediaAttrName]}" attrvalue="{[playMediaAttrValue]}"/>

</command>

This command simply pauses the media player, set’s the text feedback to say what it’s about to play, and then it starts playing what was asked for. There are two parts to wmpMediaPlay element is that enable you to tell the media player what to play. You can think of these two as a name and value pair. You can tell it to play an artist (“WM/AlbumArtist”) named The Eagles (“The Eagles”). The first is called the attribute name, and the second is the attribute value. You can learn more about what’s available by looking at the documentation on MSDN for the Windows Media Player SDK.

Let’s see how the Play Album command is similar to the Play Artist.

<command>

    <listenFor>play ?the album ?named [Albums]</listenFor>
    <listenFor>play ?the C D ?named [Albums]</listenFor>
    <listenFor>play ?the [Albums] C D</listenFor>
    <listenFor>play ?the [Albums] album</listenFor>

    <setTextFeedback>Playing Album {[*Album]}</setTextFeedback>
    <wmpMediaControl command="pause"/>
    <disambiguate title="Which album do you want to play?" prompt="Choose an Album" timeout="25" propname="Album"/>

    <setState name="playMediaTypeName" value="Album"/>
    <setState name="playMediaTypeValue" value="{[*Album]}"/>
    <setState name="playMediaAttrName" value="WM/AlbumTitle"/>
    <setState name="playMediaAttrValue" value="{[Album]}"/>
    <emulateRecognition>Play what I asked for</emulateRecognition>

</command>

As you can see, it’s very similar to the Play Artist command. In fact, the only real differences are that what we listen for is slightly different, the prompts are slightly different, and the attribute that we tell the mediaPlayerPlay element to play (via the named states) is different.

Now both of these top level commands that use the Play what I asked for command to actually do the work also are referring to other “rules”. How do those get defined? Good question. The Answer: With the wmpMediaItems element. Let’s look at both of those for Artist and Albums:

<wmpMediaItems
    name="Artists"
    propname="Artist"
    attrname="WM/AlbumArtist"
      />

<wmpMediaItems
    name="Albums"
    propname="Album"
    attrname="WM/AlbumTitle"
      />

That’s it. It’s that simple. In fact, these elements will actually pay attention to changes in the media library and they’ll automatically update themselves with the new artists and albums. This could have been done with Jscript and the Media Player OCX, but since I really wanted this to work super well, I just went ahead and included it directly in the schema.

There are a lot of other commands in this macro, but instead of telling you all the details, I’m going to leave it for discussion in the comments…

One of my favorite commands here is the “Play something by [artist]” command. Try it out. See if you can see how it works.

If you don’t understand how something works, let me know…

Here’s the whole macro:

<?xml version="1.0" encoding="utf-8"?>

<!-- Windows Media Player -->
<speechMacros>

    <!-- Start Media Player -->
    <command>

        <listenFor>Media Player</listenFor>
        <emulateRecognition>start Media Player</emulateRecognition>

    </command>

    <!-- Play Artist Command -->
    <command>

        <listenFor>play ?the artist [Artists]</listenFor>
        <listenFor>play ?the band [Artists]</listenFor>
        <listenFor>play ?the group [Artists]</listenFor>

        <setTextFeedback>Playing Artist {[*Artist]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <disambiguate title="Which artist do you want to play?" prompt="Choose an Artist" timeout="25" propname="Artist"/>

        <setState name="playMediaTypeName" value="Artist"/>
        <setState name="playMediaTypeValue" value="{[*Artist]}"/>
        <setState name="playMediaAttrName" value="WM/AlbumArtist"/>
        <setState name="playMediaAttrValue" value="{[Artist]}"/>
        <emulateRecognition>Play what I asked for</emulateRecognition>

    </command>

    <!-- Play Album Command -->
    <command>

        <listenFor>play ?the album ?named [Albums]</listenFor>
        <listenFor>play ?the C D ?named [Albums]</listenFor>
        <listenFor>play ?the [Albums] C D</listenFor>
        <listenFor>play ?the [Albums] album</listenFor>

        <setTextFeedback>Playing Album {[*Album]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <disambiguate title="Which album do you want to play?" prompt="Choose an Album" timeout="25" propname="Album"/>

        <setState name="playMediaTypeName" value="Album"/>
        <setState name="playMediaTypeValue" value="{[*Album]}"/>
        <setState name="playMediaAttrName" value="WM/AlbumTitle"/>
        <setState name="playMediaAttrValue" value="{[Album]}"/>
        <emulateRecognition>Play what I asked for</emulateRecognition>

    </command>

    <!-- Play Genre Command -->
    <command>

        <listenFor>play ?the genre [Genres]</listenFor>

        <setTextFeedback>Playing Genre {[*Genre]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <disambiguate title="Which genre do you want to play?" prompt="Choose a Genre" timeout="25" propname="Genre"/>

        <setState name="playMediaTypeName" value="Genre"/>
        <setState name="playMediaTypeValue" value="{[*Genre]}"/>
        <setState name="playMediaAttrName" value="WM/Genre"/>
        <setState name="playMediaAttrValue" value="{[Genre]}"/>
        <emulateRecognition>Play what I asked for</emulateRecognition>

    </command>

    <!-- Play Track Command -->
    <command>

        <listenFor>play ?the track ?named [TrackNames]</listenFor>

        <setTextFeedback>Playing Track {[*SourceURL]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <disambiguate title="Which track do you want to play?" prompt="Choose a Track" timeout="25" propname="SourceURL"/>

        <setState name="playMediaTypeName" value="Track"/>
        <setState name="playMediaTypeValue" value="{[*SourceURL]}"/>
        <setState name="playMediaAttrName" value="SourceURL"/>
        <setState name="playMediaAttrValue" value="{[SourceURL]}"/>
        <emulateRecognition>Play what I asked for</emulateRecognition>

    </command>

    <!-- Play Anything Command -->
    <command>

        <listenFor>play [GenreArtistAlbumTrack]</listenFor>

        <setTextFeedback>Playing {[*GenreArtistAlbumTrack]}</setTextFeedback>
        <wmpMediaControl command="pause"/>

        <script language="JScript" >
        <![CDATA[
        genreArtistAlbumTrack = "{[*GenreArtistAlbumTrack]}";
        matchingGenres = CommandSet.RuleGenerators("Genres").Rule.Items.FindTextMatches(genreArtistAlbumTrack);
        matchingArtists = CommandSet.RuleGenerators("Artists").Rule.Items.FindTextMatches(genreArtistAlbumTrack);
        matchingAlbums = CommandSet.RuleGenerators("Albums").Rule.Items.FindTextMatches(genreArtistAlbumTrack);
        matchingTracks = CommandSet.RuleGenerators("TrackNames").Rule.Items.FindTextMatches(genreArtistAlbumTrack)
        addMediaItems("Genre:", matchingGenres, ChooseFromList.Items);
        addMediaItems("Artist:", matchingArtists, ChooseFromList.Items);
        addMediaItems("Album:", matchingAlbums, ChooseFromList.Items);
        addMediaItems("Track:", matchingTracks, ChooseFromList.Items);

        if (ChooseFromList.Items.Count == 0)
        {
            Command.Exit(1);
        }
        chosen = ChooseFromList.Items.Count == 1
            ? 0
            : ChooseFromList.Choose("What did you want to play?", "Play media");

        NamedStates.ClearNamedState("playMediaAttrName");
        NamedStates.ClearNamedState("playMediaAttrValue");
        NamedStates.ClearNamedState("playMediaTypeName");
        NamedStates.ClearNamedState("playMediaTypeValue");

        chosen = findMatchingItem(matchingGenres, chosen, "WM/Genre", "Genre");
        chosen = findMatchingItem(matchingArtists, chosen, "WM/AlbumArtist", "Artist");
        chosen = findMatchingItem(matchingAlbums, chosen, "WM/AlbumTitle", "Album");
        chosen = findMatchingItem(matchingTracks, chosen, "SourceURL", "Track");
        if (NamedStates.IsNamedStateSet("playMediaAttrName") && NamedStates.IsNamedStateSet("playMediaAttrValue"))
        {
            Application.EmulateRecognition("Play what I asked for");
        }

        function addMediaItems(prefix, itemsToAdd, collectionToAddTo)
        {
            for (i = 0; i < itemsToAdd.Count; i++)
            {
                item = itemsToAdd.item(i);
                collectionToAddTo.AddItem(prefix + " " + item.Phrase, item.Property);
            }
        }
        function findMatchingItem(matchingItems, chosen, playMediaAttrName, playMediaTypeName)
        {
            if (chosen >= 0 && chosen < matchingItems.Count)
            {
                NamedStates.SetNamedStateValue("playMediaAttrName", playMediaAttrName);
                NamedStates.SetNamedStateValue("playMediaAttrValue", matchingItems.Item(chosen).Property);
                NamedStates.SetNamedStateValue("playMediaTypeName", playMediaTypeName);
                NamedStates.SetNamedStateValue("playMediaTypeValue", matchingItems.Item(chosen).Phrase);
                chosen = -1;
            }
            else
            {
                chosen = chosen - matchingItems.Count;
            }
            return chosen;
        }

        ]]>
        </script>
    </command>

    <!-- Play Artist/Album/Track/Genre Command -->
    <command>

        <listenForList propname="PlayWhat">
            <item propval="Genres">Play Genre</item>
            <item propval="Genres">+Genres</item>
            <item propval="Artists">Play Artist</item>
            <item propval="Artists">+Artists</item>
            <item propval="Albums">Play Album</item>
            <item propval="Albums">Play C D</item>
            <item propval="Albums">+Albums</item>
            <item propval="Albums">+C +Ds</item>
            <item propval="TrackNames">Play Song</item>
            <item propval="TrackNames">Play Track</item>
            <item propval="TrackNames">+Song</item>
            <item propval="TrackNames">+Tracks</item>
        </listenForList>

        <setTextFeedback>Playing {[*PlayWhat]}</setTextFeedback>
        <wmpMediaControl command="pause"/>

        <script language="JScript" >
        <![CDATA[
        playWhat = "{[PlayWhat]}";
        matchingItems = CommandSet.RuleGenerators(playWhat).Rule.Items;
        addMediaItems("", matchingItems, ChooseFromList.Items);

        if (ChooseFromList.Items.Count == 0)
        {
            Command.Exit(1);
        }
        chosen = ChooseFromList.Items.Count == 1
            ? 0
            : ChooseFromList.Choose("What did you want to play?", "Play " + playWhat);

        NamedStates.ClearNamedState("playMediaAttrName");
        NamedStates.ClearNamedState("playMediaAttrValue");
        NamedStates.ClearNamedState("playMediaTypeName");
        NamedStates.ClearNamedState("playMediaTypeValue");
        if (playWhat == "Genres") {
            playMediaTypeName = "Genre";
            playMediaAttrName = "WM/Genre";
        }
        else if (playWhat == "Artists") {
            playMediaTypeName = "Artist";
            playMediaAttrName = "WM/AlbumArtist";
        }
        else if (playWhat == "Albums") {
            playMediaTypeName = "Album";
            playMediaAttrName = "WM/AlbumTitle";
        }
        else if (playWhat == "TrackNames") {
            playMediaTypeName = "Track";
            playMediaAttrName = "SourceURL";
        }

        chosen = findMatchingItem(matchingItems, chosen, playMediaAttrName, playMediaTypeName);
        if (NamedStates.IsNamedStateSet("playMediaAttrName") && NamedStates.IsNamedStateSet("playMediaAttrValue"))
        {
            Application.EmulateRecognition("Play what I asked for");
        }

        function addMediaItems(prefix, itemsToAdd, collectionToAddTo)
        {
            for (i = 0; i < itemsToAdd.Count; i++)
            {
                item = itemsToAdd.item(i);
                collectionToAddTo.AddItem(prefix + " " + item.Phrase, item.Property);
            }
        }
        function findMatchingItem(matchingItems, chosen, playMediaAttrName, playMediaTypeName)
        {
            if (chosen >= 0 && chosen < matchingItems.Count)
            {
                NamedStates.SetNamedStateValue("playMediaAttrName", playMediaAttrName);
                NamedStates.SetNamedStateValue("playMediaAttrValue", matchingItems.Item(chosen).Property);
                NamedStates.SetNamedStateValue("playMediaTypeName", playMediaTypeName);
                NamedStates.SetNamedStateValue("playMediaTypeValue", matchingItems.Item(chosen).Phrase);
                chosen = -1;
            }
            else
            {
                chosen = chosen - matchingItems.Count;
            }
            return chosen;
        }

        ]]>
        </script>
    </command>

    <!-- Play the album that has [track name] on it -->
    <command>

        <listenFor>Play the album that has [AlbumByTrackName] on it</listenFor>
        <listenFor>Play the C D that has [AlbumByTrackName] on it</listenFor>

        <setTextFeedback>Playing the Album that has {[*AlbumByTrackName]} on it</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <disambiguate title="Which track's album do you want to play?" prompt="Choose a Track" timeout="25" propname="AlbumByTrackName"/>

        <setState name="playMediaTypeName" value="Album"/>
        <setState name="playMediaTypeValue" value="{[*AlbumByTrackName]}"/>
        <setState name="playMediaAttrName" value="WM/AlbumTitle"/>
        <setState name="playMediaAttrValue" value="{[AlbumByTrackName]}"/>

        <emulateRecognition>Play what I asked for</emulateRecognition>

    </command>

    <!-- Play the artist that sang [track name] -->
    <command>

        <listenFor>Play the artist that sang [ArtistByTrackName]</listenFor>
        <listenFor>Play the artist who sang [ArtistByTrackName]</listenFor>
        <listenFor>Play the band that sang [ArtistByTrackName]</listenFor>
        <listenFor>Play the band who sang [ArtistByTrackName]</listenFor>
        <listenFor>Play the group that sang [ArtistByTrackName]</listenFor>
        <listenFor>Play the group who sang [ArtistByTrackName]</listenFor>

        <setTextFeedback>Playing the artist that sang {[*ArtistByTrackName]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <disambiguate title="Which track's artist do you want to play?" prompt="Choose a Track" timeout="25" propname="ArtistByTrackName"/>

        <setState name="playMediaTypeName" value="Artist"/>
        <setState name="playMediaTypeValue" value="{[*ArtistByTrackname]}"/>
        <setState name="playMediaAttrName" value="WM/AlbumArtist"/>
        <setState name="playMediaAttrValue" value="{[ArtistByTrackName]}"/>
        <emulateRecognition>Play what I asked for</emulateRecognition>

    </command>

    <!-- Play something sang by [TrackOrAlbumByArtist] -->
    <command>

        <listenFor>Play something ?sang by [TrackOrAlbumByArtist]</listenFor>
        <listenFor>Play something [TrackOrAlbumByArtist]</listenFor>
        <listenFor>Play something [TrackOrAlbumByArtist] sang</listenFor>

        <setTextFeedback>Playing something by {[*TrackOrAlbumByArtist]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <script language="JScript" >
            <![CDATA[
        trackOrAlbumByArtist = "{[*TrackOrAlbumByArtist]}";
        matchingAlbums = CommandSet.RuleGenerators("AlbumByArtist").Rule.Items.FindTextMatches(trackOrAlbumByArtist);
        matchingTracks = CommandSet.RuleGenerators("TrackNameByArtist").Rule.Items.FindTextMatches(trackOrAlbumByArtist)
        addMediaItems("Album:", matchingAlbums, ChooseFromList.Items);
        addMediaItems("Track:", matchingTracks, ChooseFromList.Items);

        if (ChooseFromList.Items.Count == 0)
        {
            Command.Exit(1);
        }
        chosen = ChooseFromList.Items.Count == 1
            ? 0
            : ChooseFromList.Choose("What do you want to play?", "Play media");

        NamedStates.ClearNamedState("playMediaAttrName");
        NamedStates.ClearNamedState("playMediaAttrValue");
        NamedStates.ClearNamedState("playMediaTypeName");
        NamedStates.ClearNamedState("playMediaTypeValue");

        chosen = findMatchingItem(matchingAlbums, chosen, "WM/AlbumTitle", "Album");
        chosen = findMatchingItem(matchingTracks, chosen, "Name", "Track");
        if (NamedStates.IsNamedStateSet("playMediaAttrName") && NamedStates.IsNamedStateSet("playMediaAttrValue"))
        {
            Application.EmulateRecognition("Play what I asked for");
        }
        function addMediaItems(prefix, itemsToAdd, collectionToAddTo)
        {
            for (i = 0; i < itemsToAdd.Count; i++)
            {
                item = itemsToAdd.item(i);
                collectionToAddTo.AddItem(prefix + " " + item.Property + " (" + item.Phrase + ")", item.Property);
            }
        }
        function findMatchingItem(matchingItems, chosen, playMediaAttrName, playMediaTypeName)
        {
            if (chosen >= 0 && chosen < matchingItems.Count)
            {
                NamedStates.SetNamedStateValue("playMediaAttrName", playMediaAttrName);
                NamedStates.SetNamedStateValue("playMediaAttrValue", matchingItems.Item(chosen).Property);
                NamedStates.SetNamedStateValue("playMediaTypeName", playMediaTypeName);
                NamedStates.SetNamedStateValue("playMediaTypeValue", matchingItems.Item(chosen).Property);
                chosen = -1;
            }
            else
            {
                chosen = chosen - matchingItems.Count;
            }
            return chosen;
        }

        ]]>
        </script>

    </command>

    <!--
    Play something written in [TrackNameByYear]
    <command>

        <listenFor>Play something written in [TrackOrAlbumByYear]</listenFor>

        <setTextFeedback>Playing something written in {[*TrackOrAlbumByYear]}</setTextFeedback>
        <wmpMediaControl command="pause"/>
        <script language="JScript" >
            <![CDATA[
        trackOrAlbumByYear = "{[*TrackOrAlbumByYear]}";
        matchingAlbums = CommandSet.RuleGenerators("AlbumByYear").Rule.Items.FindTextMatches(trackOrAlbumByYear);
        matchingTracks = CommandSet.RuleGenerators("TrackNameByYear").Rule.Items.FindTextMatches(trackOrAlbumByYear)
        addMediaItems("Album:", matchingAlbums, ChooseFromList.Items);
        addMediaItems("Track:", matchingTracks, ChooseFromList.Items);

        if (ChooseFromList.Items.Count == 0)
        {
            Command.Exit(1);
        }
        chosen = ChooseFromList.Items.Count == 1
            ? 0
            : ChooseFromList.Choose("What do you want to play?", "Play media");

        NamedStates.ClearNamedState("playMediaAttrName");
        NamedStates.ClearNamedState("playMediaAttrValue");
        NamedStates.ClearNamedState("playMediaTypeName");
        NamedStates.ClearNamedState("playMediaTypeValue");

        chosen = findMatchingItem(matchingAlbums, chosen, "WM/AlbumTitle", "Album");
        chosen = findMatchingItem(matchingTracks, chosen, "Name", "Track");
        if (NamedStates.IsNamedStateSet("playMediaAttrName") && NamedStates.IsNamedStateSet("playMediaAttrValue"))
        {
            Application.EmulateRecognition("Play what I asked for");
        }
        function addMediaItems(prefix, itemsToAdd, collectionToAddTo)
        {
            for (i = 0; i < itemsToAdd.Count; i++)
            {
                item = itemsToAdd.item(i);
                collectionToAddTo.AddItem(prefix + " " + item.Property + " (" + item.Phrase + ")", item.Property);
            }
        }
        function findMatchingItem(matchingItems, chosen, playMediaAttrName, playMediaTypeName)
        {
            if (chosen >= 0 && chosen < matchingItems.Count)
            {
                NamedStates.SetNamedStateValue("playMediaAttrName", playMediaAttrName);
                NamedStates.SetNamedStateValue("playMediaAttrValue", matchingItems.Item(chosen).Property);
                NamedStates.SetNamedStateValue("playMediaTypeName", playMediaTypeName);
                NamedStates.SetNamedStateValue("playMediaTypeValue", matchingItems.Item(chosen).Property);
                chosen = -1;
            }
            else
            {
                chosen = chosen - matchingItems.Count;
            }
            return chosen;
        }

        ]]>
        </script>
    </command>
    -->

    <!-- Play what I asked for -->
    <command>

        <listenFor>Play what I asked for ?again</listenFor>

        <wmpMediaControl command="pause"/>
        <setTextFeedback speak="true">Playing {[playMediaTypeName]} {[playMediaTypeValue]}</setTextFeedback>
        <wmpMediaPlay attrname="{[playMediaAttrName]}" attrvalue="{[playMediaAttrValue]}"/>

    </command>
  <!-- Navigation -->
  <command>

    <listenFor>+next track</listenFor>
    <listenFor>+next song</listenFor>
    <listenFor>+go to ?the +next ?track</listenFor>
    <listenFor>+go to ?the +next song</listenFor>

    <wmpMediaControl command="pause"/>
    <speak>Playing the next track</speak>
    <wmpMediaControl command="next"/>
    <waitFor seconds=".5"/>
    <wmpMediaControl command="play"/>

  </command>

  <command>

    <listenFor>+previous track</listenFor>
    <listenFor>+previous song</listenFor>
    <listenFor>+go to ?the +previous ?track</listenFor>
    <listenFor>+go to ?the +previous song</listenFor>

    <wmpMediaControl command="pause"/>
    <speak>Playing the previous track</speak>
    <wmpMediaControl command="previous"/>
    <waitFor seconds=".5"/>
    <wmpMediaControl command="play"/>

  </command>

  <command>

    <listenFor>[GoBack] one track</listenFor>
    <listenFor>[GoBack] one song</listenFor>

    <listenFor>[GoBack] [1to20times] tracks</listenFor>
    <listenFor>[GoBack] [1to20times] songs</listenFor>

    <wmpMediaControl command="pause"/>
    <speak>Skipping back {[times]} tracks</speak>
    <wmpMediaControl command="previous" times="{[times]}"/>
    <waitFor seconds=".5"/>
    <wmpMediaControl command="play"/>

  </command>

  <command>

    <listenFor>[GoForward] one track</listenFor>
    <listenFor>[GoForward] one song</listenFor>

    <listenFor>[GoForward] [1to20times] tracks</listenFor>
    <listenFor>[GoForward] [1to20times] songs</listenFor>

    <wmpMediaControl command="pause"/>
    <speak>Skipping ahead {[times]} tracks</speak>
    <wmpMediaControl command="next" times="{[times]}"/>
    <waitFor seconds=".5"/>
    <wmpMediaControl command="play"/>

  </command>

  <command>
    <listenFor>+play music</listenFor>
    <wmpMediaControl command="play"/>
  </command>

  <command>
    <listenFor>+stop music</listenFor>
    <listenFor>+stop playing ?music</listenFor>
    <wmpMediaControl command="stop"/>
  </command>

  <command>
    <listenFor>+pause music</listenFor>
    <wmpMediaControl command="pause"/>
  </command>

  <command>
    <listenFor>+Repeat ?on</listenFor>
    <listenFor>Turn on +repeat</listenFor>
    <listenFor>Turn +repeat on</listenFor>
    <wmpMediaControl command="loop_on"/>
    <wmpMediaControl command="pause"/>
    <speak>Repeat is now turned on</speak>
    <wmpMediaControl command="play"/>
  </command>

  <command>
    <listenFor>+Repeat +off</listenFor>
    <listenFor>Turn +off +repeat</listenFor>
    <listenFor>Turn +repeat +off</listenFor>
    <wmpMediaControl command="loop_off"/>
    <wmpMediaControl command="pause"/>
    <speak>Repeat is now turned off</speak>
    <wmpMediaControl command="play"/>
  </command>

  <command>
    <listenFor>+Toggle +repeat ?setting</listenFor>
    <wmpMediaControl command="loop_toggle"/>
    <wmpMediaControl command="pause"/>
    <speak>Toggled the repeat setting</speak>
    <wmpMediaControl command="play"/>
  </command>

  <command>
    <listenFor>+Shuffle ?on</listenFor>
    <listenFor>Turn +on +shuffle</listenFor>
    <listenFor>Turn +shuffle +on</listenFor>
    <wmpMediaControl command="shuffle_on"/>
    <wmpMediaControl command="pause"/>
    <speak>Shuffle is now turned on</speak>
    <wmpMediaControl command="play"/>
  </command>

  <command>
    <listenFor>+Shuffle</listenFor>
    <listenFor>Turn +off +shuffle</listenFor>
    <listenFor>Turn +shuffle +off</listenFor>
    <wmpMediaControl command="shuffle_off"/>
    <wmpMediaControl command="pause"/>
    <speak>Shuffle is now turned off</speak>
    <wmpMediaControl command="play"/>
  </command>

  <command>
    <listenFor>+Toggle +shuffle ?setting</listenFor>
    <wmpMediaControl command="shuffle_toggle"/>
    <wmpMediaControl command="pause"/>
    <speak>Toggled the shuffle setting</speak>
    <wmpMediaControl command="play"/>
  </command>

  <!-- Command Set Rules -->

  <!-- Various ways to say, "Go Back" -->
  <listenForList name="GoBack">
    <item>+go +back</item>
    <item>+go +up</item>
    <item>+go +down</item>
    <item>+skip +back</item>
    <item>+skip +up</item>
    <item>+skip +down</item>
  </listenForList>

  <!-- Various ways to say, "Go Forward"-->
  <listenForList name="GoForward">
    <item>+go +forward</item>
    <item>+go +ahead</item>
    <item>+go +down</item>
    <item>+skip +forward</item>
    <item>+skip +ahead</item>
    <item>+skip +down</item>
  </listenForList>

  <numbers name="1to20times" propname="times" start="1" stop="20"/>

  <wmpMediaItems
      name="Artists"
      propname="Artist"
      attrname="WM/AlbumArtist"
        />

  <wmpMediaItems
      name="Albums"
      propname="Album"
      attrname="WM/AlbumTitle"
        />

  <wmpMediaItems
      name="Genres"
      propname="Genre"
      attrname="WM/Genre"
        />

  <wmpMediaItems
      name="TrackNames"
      propname="SourceURL"
      propvalue="[SourceURL]"
      attrname="MediaType"
      attrvalue="AUDIO"
      listenFor="[Name]"
      />

   <wmpMediaItems
      name="AlbumByTrackName"
      propname="Album"
      propvalue="[WM/AlbumTitle]"
      attrname="MediaType"
      attrvalue="AUDIO"
      listenFor="[Name]"
      />

   <wmpMediaItems
      name="ArtistByTrackName"
      propname="Artist"
      propvalue="[WM/AlbumArtist]"
      attrname="MediaType"
      attrvalue="AUDIO"
      listenFor="[Name]"
      />

    <rule name="GenreArtistAlbumTrack">
        <list>
            <ruleref name="TrackNames"/>
            <ruleref name="Artists"/>
            <ruleref name="Albums"/>
            <ruleref name="Genres"/>
        </list>
    </rule>

    <wmpMediaItems
        name="TrackNameByArtist"
        propname="TrackName"
        propvalue="[Name]"
        attrname="MediaType"
        attrvalue="AUDIO"
        listenFor="[WM/AlbumArtist]"
      />

    <wmpMediaItems
        name="AlbumByArtist"
        propname="Album"
        propvalue="[WM/AlbumTitle]"
        attrname="MediaType"
        attrvalue="AUDIO"
        listenFor="[WM/AlbumArtist]"
      />

    <rule name="TrackOrAlbumByArtist">
        <list>
            <ruleref name="TrackNameByArtist"/>
            <ruleref name="AlbumByArtist"/>
        </list>
    </rule>

    <!--
    <wmpMediaItems
        name="TrackNameByYear"
        propname="TrackName"
        propvalue="[Name]"
        attrname="MediaType"
        attrvalue="AUDIO"
        listenFor="[WM/Year]"
      />

    <wmpMediaItems
        name="AlbumByYear"
        propname="Album"
        propvalue="[WM/AlbumArtist]"
        attrname="MediaType"
        attrvalue="AUDIO"
        listenFor="[WM/Year]"
      />

    <rule name="TrackOrAlbumByYear">
        <list>
            <ruleref name="TrackNameByYear"/>
            <ruleref name="AlbumByYear"/>
        </list>
    </rule>
    -->
</speechMacros>