{"id":5293,"date":"2007-10-30T15:05:00","date_gmt":"2007-10-30T15:05:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2007\/10\/30\/let-the-music-play-matt-gertz\/"},"modified":"2024-07-05T14:39:27","modified_gmt":"2024-07-05T21:39:27","slug":"let-the-music-play-matt-gertz","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/let-the-music-play-matt-gertz\/","title":{"rendered":"Let the Music Play! (Matt Gertz)"},"content":{"rendered":"<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Oh, boy.<span>&nbsp; <\/span>Sorry I haven&rsquo;t written any posts lately, but I&rsquo;ve transitioned to a new job within Visual Studio and have been getting my sea legs there.<span>&nbsp; <\/span>One of the job tasks is getting Visual Studio 2008 out to you folks, and while I&rsquo;ve always been involved with that aspect of the product in the past, it was always to a lesser degree.<span>&nbsp; <\/span>I could best describe each day now as &ldquo;23 hours of nervous tension followed by one hour of utter panic&rdquo; as we knock down the last few things that would otherwise keep us from shipping on time.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">(Incidentally, in the spirit of making sure that the product works properly before we ship it, I&rsquo;ve switched to writing code against Visual Studio 2008 using a build from last week.<span>&nbsp; <\/span>Everything in this post, though, will still work using Visual Studio 2005, provided you have the current Windows Media Player.)<\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">So, anyway, going forward I hope to do a post or two each month.<span>&nbsp; <\/span>We&rsquo;ll see how it goes, but it&rsquo;s awfully hard to keep me from writing about Visual Basic, so I&rsquo;m optimistic.<span>&nbsp; <\/span><\/font><span><span>J<\/span><\/span><font face=\"Calibri\"><span>&nbsp; <\/span>And on that note, on to today&rsquo;s topic!<\/font><\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">The problem with shuffling music<\/font><\/h2>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">I&rsquo;m a big music fan, with quite a large collection of songs that I&rsquo;ve ripped onto my computer.<span>&nbsp; <\/span>One of the things that I really appreciate about playing music on my PC is that I can listen to random tracks as if I were listening to a radio station (a radio station that always plays what I like and has no chatter) &ndash; I don&rsquo;t hear the same old thing in the same old order every time.<span>&nbsp;&nbsp; <\/span>The shuffle function gets a lot of use from me.<span>&nbsp; <\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font size=\"3\"><font face=\"Calibri\">There&rsquo;s a difference between &ldquo;shuffle&rdquo; and &ldquo;random&rdquo; function, of course.<span>&nbsp; <\/span>&ldquo;Shuffle&rdquo; generates a random list from an existing list and then plays that temporary list from beginning to end (so as to avoid replays), whereas with &ldquo;random,&rdquo; the next song is calculated on the fly.<span>&nbsp; <\/span>Unfortunately, statistics being what they are, you&rsquo;ve got a good chance in the latter case of hearing the same song twice (or more) in a session before all of the songs have been heard.<span>&nbsp;&nbsp; <\/span><\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Most good playback engines on PCs and cars do &ldquo;shuffle&rdquo; instead of &ldquo;random&rdquo; these days because of this, but shuffle isn&rsquo;t a panacea, either.<span>&nbsp; <\/span>The problem is that there are songs which are meant to be played adjacent to another song or else they don&rsquo;t make sense.<span>&nbsp; <\/span>The disc authors will break up two songs on a track which (in the listener&rsquo;s opinion) are really the part of same song.<span>&nbsp; <\/span>Take, for example, Pink Floyd&rsquo;s excellent &ldquo;Dark Side of the Moon&rdquo; album, which is replete with this sort of issue.<span>&nbsp; <\/span>Really, is there anyone out there who would listen to track 8 (&ldquo;Brain Damage&rdquo;) without listening to track 9 (&ldquo;Eclipse&rdquo;)?<span>&nbsp; <\/span>Not likely; it&rsquo;s a jarring experience to just have the first track end abruptly. <\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">So, what happens?<span>&nbsp; <\/span>I throw my favorite songs from various artists into a playlist.<span>&nbsp; <\/span>I sync that to my music player and head out to mow the lawn, hitting &ldquo;shuffle&rdquo; so I&#8217;m not always hearing the same thing.<span>&nbsp; <\/span>Sure enough, after a few minutes, I&#8217;m enjoying the last few lines of Jackson Browne&rsquo;s &ldquo;The Load-Out&rdquo;:<\/font><\/p>\n<p class=\"MsoNoSpacing\"><i><font size=\"3\"><font face=\"Calibri\">But we&rsquo;ll be scheduled to appear <\/p>\n<p><\/font><\/font><\/i><\/p>\n<p class=\"MsoNoSpacing\"><i><font size=\"3\"><font face=\"Calibri\">A thousand miles away from here&hellip;<\/p>\n<p><\/font><\/font><\/i><\/p>\n<p class=\"MsoNoSpacing\"><font face=\"Calibri\" size=\"3\">&lt;pop! disconnect!&gt;<\/font><\/p>\n<p class=\"MsoNoSpacing\"><i><font size=\"3\"><font face=\"Calibri\">Is this the real life?<span>&nbsp; <\/span>Is this just fantasy?<\/p>\n<p><\/font><\/font><\/i><\/p>\n<p class=\"MsoNoSpacing\"><i><font size=\"3\"><font face=\"Calibri\">Caught in a landslide&hellip;<\/p>\n<p><\/font><\/font><\/i><\/p>\n<p class=\"MsoNoSpacing\"><i><\/p>\n<p><font face=\"Calibri\" size=\"3\">&nbsp;<\/font><\/p>\n<p><\/i><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Mentally, I was expecting the track to continue into Jackson Browne&rsquo;s &ldquo;Stay&rdquo; instead of randomly switching to Queen&rsquo;s &ldquo;Bohemian Rhapsody,&rdquo; and, although I do like the latter song, the transition is pretty darn jarring.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">What I really want is a way to shuffle my tracks to get that nice sense of randomness, but also keep certain songs together to prevent any jarring playback from inappropriate segues.<span>&nbsp;&nbsp; <\/span>I&rsquo;ll code that solution up in this blog, but first I&rsquo;ll need to cover some of the basics of how you write code against the Windows Media Player.<\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Windows Media Player coding concepts<\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The Windows Media Player control is a very powerful control with a lot of functionality, but understanding its object model involves a bit of a learning curve because there&rsquo;s quite a lot to it.<span>&nbsp; <\/span>Fortunately, once you understand the basics, it&rsquo;s pretty easy to work with.<span>&nbsp; <\/span>There are four really important concepts:<\/font><\/p>\n<p class=\"MsoListParagraphCxSpFirst\"><span><span><font face=\"Calibri\" size=\"3\">1.<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\"><font face=\"Calibri\"><b>The player itself<\/b>.<span>&nbsp; <\/span>Being a COM control, it gets wrapped for .NET so that you can write code against it without resorting to Declares, etc., and ends up being an object of type AxWMPLib.AxWindowsMediaPlayer.<span>&nbsp; <\/span>Properties on the player include which of its controls show and its visibility, whether it auto-plays (via its &ldquo;Settings&rdquo; property), actions such as Play and Stop (via the Ctlcontrols property), and so on.<\/font><\/font><\/p>\n<p class=\"MsoListParagraphCxSpMiddle\"><span><span><font face=\"Calibri\" size=\"3\">2.<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\"><font face=\"Calibri\"><b>The playlist<\/b>.<span>&nbsp; <\/span>This is the object that tells the player what media it should play.<span>&nbsp; <\/span>You don&rsquo;t &ldquo;Dim&rdquo; or &ldquo;New&rdquo; a playlist; instead, you ask the player for a new or existing playlist, and it returns an interface of type WMPLib.IWMPPlaylist to the result, on which you can then call methods.<\/font><\/font><\/p>\n<p class=\"MsoListParagraphCxSpLast\"><span><span><font face=\"Calibri\" size=\"3\">3.<\/font><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/span><\/span><font size=\"3\"><font face=\"Calibri\"><b>The media<\/b>.<span>&nbsp; <\/span>Again, these are not objects that you create yourself.<span>&nbsp; <\/span>There are methods on the player and the playlist which will return interface values (WMPLib.IWMPMedia) for them.<span>&nbsp; <\/span>The playlist is made up of media objects.<\/font><\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Once you&rsquo;ve got that in hand, the rest is pretty easy &ndash; honest!<span>&nbsp; <\/span>Let&rsquo;s run through some examples here. <\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Part 1:<span>&nbsp; <\/span>Playing a song <\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The &ldquo;Hello, world!&rdquo; of a music player would be, of course, playing a song.<span>&nbsp; <\/span>First, create a new Windows Application and make sure that the toolbox is displayed for the resulting form.<span>&nbsp; <\/span>We&rsquo;ll need to add the Windows Media control to the toolbox, so right-click on the toolbox and select &ldquo;Choose Items&hellip;&rdquo;<span>&nbsp; <\/span>In the resulting dialog, navigate to the &ldquo;COM Components&rdquo; tab, scroll down towards the bottom, and check the box to the left of the Windows Media Player.<span>&nbsp; <\/span>Press &ldquo;OK,&rdquo; and the Windows Media Player (which I will henceforth refer to as the WMP) will be added to your toolbox.<span>&nbsp; <\/span>Drag an instance of it over to your form and size it however you like.<span>&nbsp; <\/span>(By the way, I&rsquo;m using the most recent version of WMP, which is version 11 and which you can download for free from Microsoft if you don&rsquo;t already have it.<span>&nbsp; <\/span>Earlier versions of the Windows Media Player might not support this all of this code, depending on how old they are.)<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">While the WMP is still selected, go to the property grid and change its name to &ldquo;Player&rdquo; (as the default name is quite a mouthful otherwise).<span>&nbsp;&nbsp; <\/span>Now, double-click on the form background (not the WMP) to create the &ldquo;Form1_Load&rdquo; event.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">In Form1_Load, we&rsquo;ll create a new playlist for the WMP to play:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> playlist <span>As<\/span> WMPLib.IWMPPlaylist<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>playlist = <span>Me<\/span>.Player.newPlaylist(<span>&#8220;My groovy playlist&#8221;<\/span>, <span>&#8220;&#8221;<\/span>)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The first argument to newPlaylist is the name of the new playlist, and the second is a URL to an existing Playlist with whose contents we want to initialize it.<span>&nbsp; <\/span>I&rsquo;ve left it as the empty string because in this example I want to start with an empty playlist.<span>&nbsp; <\/span>(Note that the new playlist is not automatically added to your library, so don&rsquo;t worry about cluttering up your library here.<span>&nbsp; <\/span>To actually make the playlist permanent, you&rsquo;d need to call either importPlaylist or newPlaylist from the IWMPPlaylistCollection returned from Player.playlistCollection property.)<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, I want to add a song to the new playlist:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> item <span>As<\/span> WMPLib.IWMPMedia = Player.newMedia(<span>&#8220;file:\/\/\/C:UsersMattMusicDead Can DanceSpleen and Ideal8 Avatar.wma&#8221;<\/span>)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>playlist.appendItem(item)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The argument to newMedia is a URL, so if I&rsquo;m using a file from disk, I need to use a URL format (basically, prepend &ldquo;<\/font><a href=\"\/\/\/\"><font face=\"Calibri\" color=\"#0000ff\" size=\"3\">file:\/\/\/<\/font><\/a><font face=\"Calibri\" size=\"3\">&rdquo; <span>&nbsp;<\/span>to the absolute path in this case).<span>&nbsp; <\/span>Of course, I normally wouldn&rsquo;t hardcode this path; I&rsquo;d read the file name from a file dialog, but I&rsquo;ve already covered file dialog usage in a previous post so I&rsquo;ll skip it here for clarity&rsquo;s sake.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Next, I&rsquo;ll add the playlist to the player:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Player.currentPlaylist = playlist<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, let&rsquo;s press F5.<span>&nbsp; <\/span>The application launches and, assuming that there&rsquo;s no mistake in URL we specified, the music automatically starts playing.<span>&nbsp;&nbsp; <\/span>You can use the WMP controls to control volume and so forth.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, it&rsquo;s possible that you don&rsquo;t want the music to play until the user actually pushes the &ldquo;Play&rdquo; button.<span>&nbsp; <\/span>This is easy enough to do &ndash; simply add this line somewhere *<b>before<\/b>* you assign the playlist to the player:<\/font><\/p>\n<p class=\"MsoNormal\"><span>Player.settings.autoStart = <span>False<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">And now you&rsquo;ve got a way to play any media file (or set of media files) from inside your Windows application, with the user in full control of the playback.<span>&nbsp; <\/span>Cool, huh?<\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Part 2: A smarter shuffle<\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Let&rsquo;s start out with the following code in Form1_Load:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Player.settings.autoStart = <span>False<\/span> <span>&#8216; Otherwise, playlists will automatically play when added to the player<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; Create a new playlist<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> oldplaylist <span>As<\/span> WMPLib.IWMPPlaylist<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> newplaylist <span>As<\/span> WMPLib.IWMPPlaylist<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>oldplaylist = <span>Me<\/span>.Player.newPlaylist(<span>&#8220;Original Sorted Playlist&#8221;<\/span>, <span>&#8220;file:\/\/\/c:UsersMattMusicPlaylistsOne True Playlist.wpl&#8221;<\/span>)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>newplaylist = <span>Me<\/span>.Player.newPlaylist(<span>&#8220;Smart Shuffled Playlist&#8221;<\/span>, <span>&#8220;&#8221;<\/span>)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Note that I&rsquo;m creating two playlists here &ndash; one which identically matches a favorite playlist of mine, and one which is empty.<span>&nbsp; <\/span>I&rsquo;ll use the empty one to store my smartly-shuffled playlist.<span>&nbsp; <\/span>Note that I could use <\/font><b><span>Player.playlistCollection.getByName(&ldquo;One True Playlist&rdquo;).Item(0)<\/span><\/b><font face=\"Calibri\" size=\"3\"> to point to the existing playlist instead of a copy, but since I&rsquo;m going to be removing media items from one list and moving them to another, that would be destructive to the original.<span>&nbsp; <\/span>(I could also have sorted within one copied list like I did with card shuffling in an earlier blog post, and avoid even using a second list, but since I&rsquo;m reusing most of the memory here anyway &ndash; that is, the media objects &ndash; I&rsquo;m opting for a more readable implementation this time.<span>&nbsp; <\/span>Either would work.)<span>&nbsp; <\/span>Again, I would normally use a file dialog to browse to the playlist rather than hard-coding it &ndash; I&rsquo;m just trying to keep it simple here.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">I&rsquo;ll need a random number generator to pick songs to pull over.<span>&nbsp; <\/span>If you&rsquo;ve read my earlier Euchre blog post, you&rsquo;ll know I usually use a complex\none to guarantee the best distribution I can get; however, this being just for a music player, I&rsquo;ll go with plain-old Random() for brevity&rsquo;s sake.<span>&nbsp; <\/span>For the range of the random number, I&rsquo;ll need to know how many songs we&rsquo;ll be moving, which I can get from the playlist count.<span>&nbsp; <\/span>For this first attempt, I&rsquo;ll just shuffle without regard to disjointed songs:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/span><span>&#8216; Randomize the values using system time as a seed<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Microsoft.VisualBasic.Randomize()<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; Get the number of songs to use<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> numberOfSongs <span>As<\/span> <span>Integer<\/span> = oldplaylist.count<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; The value i will keep track of the number of songs left to copy,<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; which in turn helps us keep track of the range for valid random numbers.<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>For<\/span> songsRemaining <span>As<\/span> <span>Integer<\/span> = numberOfSongs &#8211; 1 <span>To<\/span> 0 <span>Step<\/span> -1<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; Pick a random song from whatever remains in the old list:<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> SongToCopy <span>As<\/span> <span>Integer<\/span> = Microsoft.VisualBasic.Rnd() * songsRemaining<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> mediaItem = oldplaylist.Item(SongToCopy)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; Append it to the new list<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>newplaylist.appendItem(mediaItem)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>&#8216; Remove it from the old list, which will have its count decrease<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>oldplaylist.removeItem(mediaItem)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Next<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Player.currentPlaylist = newplaylist<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The variable &ldquo;<\/font><span>songsRemaining<\/span><font face=\"Calibri\" size=\"3\">&rdquo; is pulling double-duty here &ndash; it makes sure (via the For loop) that I copy over exactly as many songs as possible, and it also constrains the random variable to however songs are remaining in the initial list.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">That code works fine for a simple shuffle (go ahead &amp; try it, using one of your own playlists!), but it doesn&rsquo;t do anything that Windows Media Player can&rsquo;t already do.<span>&nbsp; <\/span>So, now I want to massage this code into something which keeps certain songs together.<span>&nbsp; <\/span>My general plan will be to have some sort of &ldquo;tag&rdquo; on songs to indicate that they below with another song, and then if I encounter a random media item which is part of that duo (or trio, or whatever), I&rsquo;ll bring the others along as well, in the proper order.<span>&nbsp; <\/span>The trick will be figuring out what tag to use.<span>&nbsp; <\/span>Fortunately, there are some custom fields associated with media items that I can leverage here.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Ideally, the information that gets downloaded with songs would pre-populate some field which would indicate that one song always belongs with another, but tha<\/font><\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Oh, boy.&nbsp; Sorry I haven&rsquo;t written any posts lately, but I&rsquo;ve transitioned to a new job within Visual Studio and have been getting my sea legs there.&nbsp; One of the job tasks is getting Visual Studio 2008 out to you folks, and while I&rsquo;ve always been involved with that aspect of the product in the [&hellip;]<\/p>\n","protected":false},"author":258,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[22,195],"tags":[101,165,166],"class_list":["post-5293","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-matt-gertz","category-visual-basic","tag-matt-gertz","tag-vb2005","tag-vb2008"],"acf":[],"blog_post_summary":"<p>Oh, boy.&nbsp; Sorry I haven&rsquo;t written any posts lately, but I&rsquo;ve transitioned to a new job within Visual Studio and have been getting my sea legs there.&nbsp; One of the job tasks is getting Visual Studio 2008 out to you folks, and while I&rsquo;ve always been involved with that aspect of the product in the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/5293","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/258"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=5293"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/5293\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=5293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=5293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=5293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}