Let the Music Play! (Matt Gertz)

Published 30 October 07 12:05 PM

Oh, boy.  Sorry I haven’t written any posts lately, but I’ve transitioned to a new job within Visual Studio and have been getting my sea legs there.  One of the job tasks is getting Visual Studio 2008 out to you folks, and while I’ve always been involved with that aspect of the product in the past, it was always to a lesser degree.  I could best describe each day now as “23 hours of nervous tension followed by one hour of utter panic” as we knock down the last few things that would otherwise keep us from shipping on time.

(Incidentally, in the spirit of making sure that the product works properly before we ship it, I’ve switched to writing code against Visual Studio 2008 using a build from last week.  Everything in this post, though, will still work using Visual Studio 2005, provided you have the current Windows Media Player.)

So, anyway, going forward I hope to do a post or two each month.  We’ll see how it goes, but it’s awfully hard to keep me from writing about Visual Basic, so I’m optimistic.  J  And on that note, on to today’s topic!

The problem with shuffling music

I’m a big music fan, with quite a large collection of songs that I’ve ripped onto my computer.  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) – I don’t hear the same old thing in the same old order every time.   The shuffle function gets a lot of use from me. 

There’s a difference between “shuffle” and “random” function, of course.  “Shuffle” 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 “random,” the next song is calculated on the fly.  Unfortunately, statistics being what they are, you’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.  

Most good playback engines on PCs and cars do “shuffle” instead of “random” these days because of this, but shuffle isn’t a panacea, either.  The problem is that there are songs which are meant to be played adjacent to another song or else they don’t make sense.  The disc authors will break up two songs on a track which (in the listener’s opinion) are really the part of same song.  Take, for example, Pink Floyd’s excellent “Dark Side of the Moon” album, which is replete with this sort of issue.  Really, is there anyone out there who would listen to track 8 (“Brain Damage”) without listening to track 9 (“Eclipse”)?  Not likely; it’s a jarring experience to just have the first track end abruptly.

So, what happens?  I throw my favorite songs from various artists into a playlist.  I sync that to my music player and head out to mow the lawn, hitting “shuffle” so I'm not always hearing the same thing.  Sure enough, after a few minutes, I'm enjoying the last few lines of Jackson Browne’s “The Load-Out”:

But we’ll be scheduled to appear

A thousand miles away from here…

<pop! disconnect!>

Is this the real life?  Is this just fantasy?

Caught in a landslide…

 

Mentally, I was expecting the track to continue into Jackson Browne’s “Stay” instead of randomly switching to Queen’s “Bohemian Rhapsody,” and, although I do like the latter song, the transition is pretty darn jarring.

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.   I’ll code that solution up in this blog, but first I’ll need to cover some of the basics of how you write code against the Windows Media Player.

Windows Media Player coding concepts

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’s quite a lot to it.  Fortunately, once you understand the basics, it’s pretty easy to work with.  There are four really important concepts:

1.       The player itself.  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.  Properties on the player include which of its controls show and its visibility, whether it auto-plays (via its “Settings” property), actions such as Play and Stop (via the Ctlcontrols property), and so on.

2.       The playlist.  This is the object that tells the player what media it should play.  You don’t “Dim” or “New” 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.

3.       The media.  Again, these are not objects that you create yourself.  There are methods on the player and the playlist which will return interface values (WMPLib.IWMPMedia) for them.  The playlist is made up of media objects.

Once you’ve got that in hand, the rest is pretty easy – honest!  Let’s run through some examples here.

Part 1:  Playing a song

The “Hello, world!” of a music player would be, of course, playing a song.  First, create a new Windows Application and make sure that the toolbox is displayed for the resulting form.  We’ll need to add the Windows Media control to the toolbox, so right-click on the toolbox and select “Choose Items…”  In the resulting dialog, navigate to the “COM Components” tab, scroll down towards the bottom, and check the box to the left of the Windows Media Player.  Press “OK,” and the Windows Media Player (which I will henceforth refer to as the WMP) will be added to your toolbox.  Drag an instance of it over to your form and size it however you like.  (By the way, I’m using the most recent version of WMP, which is version 11 and which you can download for free from Microsoft if you don’t already have it.  Earlier versions of the Windows Media Player might not support this all of this code, depending on how old they are.)

While the WMP is still selected, go to the property grid and change its name to “Player” (as the default name is quite a mouthful otherwise).   Now, double-click on the form background (not the WMP) to create the “Form1_Load” event.

In Form1_Load, we’ll create a new playlist for the WMP to play:

        Dim playlist As WMPLib.IWMPPlaylist

        playlist = Me.Player.newPlaylist("My groovy playlist", "")

 

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.  I’ve left it as the empty string because in this example I want to start with an empty playlist.  (Note that the new playlist is not automatically added to your library, so don’t worry about cluttering up your library here.  To actually make the playlist permanent, you’d need to call either importPlaylist or newPlaylist from the IWMPPlaylistCollection returned from Player.playlistCollection property.)

Now, I want to add a song to the new playlist:

        Dim item As WMPLib.IWMPMedia = Player.newMedia("file:///C:\Users\Matt\Music\Dead Can Dance\Spleen and Ideal\08 Avatar.wma")

        playlist.appendItem(item)

 

The argument to newMedia is a URL, so if I’m using a file from disk, I need to use a URL format (basically, prepend “file:/// to the absolute path in this case).  Of course, I normally wouldn’t hardcode this path; I’d read the file name from a file dialog, but I’ve already covered file dialog usage in a previous post so I’ll skip it here for clarity’s sake.

Next, I’ll add the playlist to the player:

        Player.currentPlaylist = playlist

 

Now, let’s press F5.  The application launches and, assuming that there’s no mistake in URL we specified, the music automatically starts playing.   You can use the WMP controls to control volume and so forth.

Now, it’s possible that you don’t want the music to play until the user actually pushes the “Play” button.  This is easy enough to do – simply add this line somewhere *before* you assign the playlist to the player:

Player.settings.autoStart = False

And now you’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.  Cool, huh?

Part 2: A smarter shuffle

Let’s start out with the following code in Form1_Load:

        Player.settings.autoStart = False ' Otherwise, playlists will automatically play when added to the player

 

        ' Create a new playlist

        Dim oldplaylist As WMPLib.IWMPPlaylist

        Dim newplaylist As WMPLib.IWMPPlaylist

        oldplaylist = Me.Player.newPlaylist("Original Sorted Playlist", "file:///c:\Users\Matt\Music\Playlists\One True Playlist.wpl")

        newplaylist = Me.Player.newPlaylist("Smart Shuffled Playlist", "")

 

Note that I’m creating two playlists here – one which identically matches a favorite playlist of mine, and one which is empty.  I’ll use the empty one to store my smartly-shuffled playlist.  Note that I could use Player.playlistCollection.getByName(“One True Playlist”).Item(0) to point to the existing playlist instead of a copy, but since I’m going to be removing media items from one list and moving them to another, that would be destructive to the original.  (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’m reusing most of the memory here anyway – that is, the media objects – I’m opting for a more readable implementation this time.  Either would work.)  Again, I would normally use a file dialog to browse to the playlist rather than hard-coding it – I’m just trying to keep it simple here.

I’ll need a random number generator to pick songs to pull over.  If you’ve read my earlier Euchre blog post, you’ll know I usually use a complex one to guarantee the best distribution I can get; however, this being just for a music player, I’ll go with plain-old Random() for brevity’s sake.  For the range of the random number, I’ll need to know how many songs we’ll be moving, which I can get from the playlist count.  For this first attempt, I’ll just shuffle without regard to disjointed songs:

        ' Randomize the values using system time as a seed

        Microsoft.VisualBasic.Randomize()

 

        ' Get the number of songs to use

        Dim numberOfSongs As Integer = oldplaylist.count

 

        ' The value i will keep track of the number of songs left to copy,

        ' which in turn helps us keep track of the range for valid random numbers.

        For songsRemaining As Integer = numberOfSongs - 1 To 0 Step -1

            ' Pick a random song from whatever remains in the old list:

            Dim SongToCopy As Integer = Microsoft.VisualBasic.Rnd() * songsRemaining

            Dim mediaItem = oldplaylist.Item(SongToCopy)

 

            ' Append it to the new list

            newplaylist.appendItem(mediaItem)

 

            ' Remove it from the old list, which will have its count decrease

            oldplaylist.removeItem(mediaItem)

        Next

 

        Player.currentPlaylist = newplaylist

 

The variable “songsRemaining” is pulling double-duty here – 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.

That code works fine for a simple shuffle (go ahead & try it, using one of your own playlists!), but it doesn’t do anything that Windows Media Player can’t already do.  So, now I want to massage this code into something which keeps certain songs together.  My general plan will be to have some sort of “tag” 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’ll bring the others along as well, in the proper order.  The trick will be figuring out what tag to use.  Fortunately, there are some custom fields associated with media items that I can leverage here.

Ideally, the information that gets downloaded with songs would pre-populate some field which would indicate that one song always belongs with another, but that unfortunately isn’t the case.   So, we’ll have to do it ourselves.  If you navigate to your music collection in File Explorer, you can right-click on a song and bring up a property sheet for it.  On the "Details" tab, towards the bottom, you’ll notice a property called “Part of set”.  We’re going to leverage that property to track that “togetherness” for an arc of songs.  (I could just as easily have leveraged the “Comments” property, for example, but using this one made more sense to me and as far as I could tell, none of my other songs were using it for something else.)  To set the property, first find an album which has songs that should play together.  For example, I’m going to use The Moody Blues’ release “Long Distance Voyager ,” which includes an arc of three songs at the end of the album which should always go together (“Painted Smile,” “Reflective Smile,” and “Veteran Cosmic Rocker”).  Right-clicking on the first song in the arc, I’ll set its “Part of set” field to 1 and apply the changes, then bring up the properties for the next song and set the field to 2, and then finally 3 for the last song of the arc.

I’ll then go into Windows Media (the desktop one, not the control you added) and create a playlist called “Test” which includes all of the songs from that album for my experiment.  You can do this by clicking “Create playlist” on the left side of the player, giving it the title "Test," dragging the appropriate songs to the resulting playlist editor on the right, and then clicking "Save playlist."  That’s the playlist I’ll be copying from – you can, of course, start with any playlist you like, but I wanted to keep the number of songs small while debugging the app.  (The playlist I used in the previous example does include the aforementioned Moody Blues tracks, but it also has about 600 other songs and thus is not the best choice to use when stepping through the debugger, as you might imagine.)

Now, in my code, I can check for the presence of one of the “Part of set” values and react by copying the adjacent songs in order as well as the randomly selected song.  Note that I’m assuming  that the original list is sorted in track order per each album (or partial album) included on the playlist – if not, you’ve got to do some additional work to look up the album information and see what should be kept adjacent to each other, whether it's all in the playlist somewhere, etc., all of which is an exercise that I’ll leave to the reader.  For my part, I’ll just check to make sure that the numbers are used contiguously and, if not, default to the “normal” copy behavior.  Here’s the final code; I’ll let the comments speak for themselves:

        Player.settings.autoStart = False ' Otherwise, playlists will automatically play when added to the player

 

        ' Create a new playlist

        Dim oldplaylist As WMPLib.IWMPPlaylist

        Dim newplaylist As WMPLib.IWMPPlaylist

 

        ' You should really use a file dialog to get this path to the existing playlist.

        oldplaylist = Me.Player.newPlaylist("Original Sorted Playlist", _

            "file:///c:\Users\MattGe\Music\Playlists\Test.wpl")

 

        ' This playlist is initially empty, and we’ll fill it with songs. 

        ' You could give the user the option of picking the name for it

        ' by reading it from a label control.

        newplaylist = Me.Player.newPlaylist("Smart Shuffled Playlist", "")

 

        ' Randomize the values using system time as a seed

        Microsoft.VisualBasic.Randomize()

 

        ' Get the number of songs to use

        Dim numberOfSongs As Integer = oldplaylist.count

 

        ' The value songsRemaining will keep track of

        ' the number of songs left to copy,

        ' which in turn helps us keep track of the range

        ' for valid random numbers.

        For songsRemaining As Integer = numberOfSongs - 1 To 0 Step -1

            ' Pick a random song from whatever remains in the old list:

            Dim songToCopy As Integer = _

                 Microsoft.VisualBasic.Rnd() * songsRemaining

            Dim mediaItem As WMPLib.IWMPMedia = oldplaylist.Item(songToCopy)

 

            ' Check the "Part of set" attribute -- see

            ' http://msdn2.microsoft.com/en-us/library/bb248408.aspx

            ' for a list of attributes for different media types.

            Dim sPartOfSet As String = mediaItem.getItemInfo("WM/PartOfSet")

 

            ' See if the value is a number.

            If sPartOfSet <> "" AndAlso IsNumeric(sPartOfSet) Then

                ' It's a number.  We may have an arc of songs here. 

                ' Get the number and rewind to the first one.

                ' If we run into anything unexpected then just

                ' do a normal copy.

 

                Dim iPartOfSet As Integer = sPartOfSet

 

                ' Make sure we don't go past the beginning of the list!

                If songToCopy - (iPartOfSet - 1) >= 0 Then

                    ' Rewind to what should be the beginning of

                    ' the arc and get the song.  (Hopefully, they’re all

                    ' there, but I’m not going to count on them being all

                    ' all there and initially in the right order.  My

                    ' default when confused will be to just copy the

                    ' originally picked song as if it wasn’t part of an arc.)

                    Dim currentSongToCopy As Integer = _

                        songToCopy - (iPartOfSet - 1)

 

                    Dim currentMediaItem As WMPLib.IWMPMedia = _

                        oldplaylist.Item(currentSongToCopy)

 

                    Dim sCurrentPartOfSet As String = _

                        currentMediaItem.getItemInfo("WM/PartOfSet")

 

                    ' Do some error checking here -- the attribute had

                    ' better be "1" – otherwise, do a normal copy instead

                    If Not sCurrentPartOfSet = "1" Then GoTo NormalCopy

 

                    ' OK, we're probably good to go, unless we coincidentally

                    ' got the beginning of another arc instead

                    ' due to discontinuous numbers.  Worse thing that happens

                    ' in that case is that we just copy a different

                    ' arc, and we’ll pick up these pieces later.

                    iPartOfSet = 0

                    While sCurrentPartOfSet <> "" _

                      AndAlso IsNumeric(sCurrentPartOfSet) _

                      AndAlso CInt(sCurrentPartOfSet) = iPartOfSet + 1

                        newplaylist.appendItem(currentMediaItem)

                        oldplaylist.removeItem(currentMediaItem)

                        iPartOfSet = iPartOfSet + 1 ' Copied one song

 

                        ' Check next song if there are any remaining

                        If currentSongToCopy = oldplaylist.count Then

                            Exit While

                        End If

 

                        currentMediaItem = _ oldplaylist.Item(currentSongToCopy)

                        sCurrentPartOfSet = currentMediaItem.getItemInfo("WM/PartOfSet")

                    End While

 

                    If iPartOfSet > 0 Then

                        ' We may have copied more than one song. 

                        ' Update the For loop variable

                        ' appropriately to compensate, since For loop

                        ' will only decrement by one.

                        songsRemaining = songsRemaining - (iPartOfSet - 1)

                    Else

                        ' Didn't copy anything -- must have been a

                        ' discontinuity.  Just copy the original song,

                        ' since user apparently doesn't care.

                        GoTo NormalCopy

                    End If

                Else

                    ' Error -- starting songs not available.  Just copy

                    ' the song, since user apparently doesn't care.

                    GoTo NormalCopy

                End If

            Else

                ' Just copy like normal

NormalCopy:     newplaylist.appendItem(mediaItem)

                oldplaylist.removeItem(mediaItem)

 

            End If

        Next

 

        ' Point player at the new playlist so it can be played

        Player.currentPlaylist = newplaylist

 

Immediately on hitting F5, you can play the songs in the new order on your PC, without fear of bizarre transitions from one song to the other.  However, to "take it on the road," you could also use the following code to add the playlist to your library and your file system:

        ' Save new playlist to library and Music\Playlists

        Player.playlistCollection.importPlaylist(newplaylist)

 

You could then use that playlist to sync to your music player or, if your music is already on a flash card, just copy that resulting WPL file to your flash card so that your Windows Media supporting device can play your songs in the new shuffled order.

So, play your party mixes or head out to jog knowing that you can get a pleasant randomness in your playlists without those jarring segues between unconnected songs!  ‘Til next time…

--Matt--*

by VBTeam
Filed under: , ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Music » Let the Music Play! (Matt Gertz) said on October 30, 2007 7:05 PM:

PingBack from http://musicarticles.info/?p=46628

# Coding4Fun said on November 1, 2007 11:43 AM:

Matt Gertz over at the Visual Basic Team talks about his big problem with shuffling music and starts

# Noticias externas said on November 1, 2007 12:44 PM:

Matt Gertz over at the Visual Basic Team talks about his big problem with shuffling music and starts

# David V. Corbin said on November 1, 2007 2:44 PM:

Now if you could just come up with an algorythm that plays only the "Good" songs....

# VBTeam said on November 2, 2007 11:35 AM:

Hi, David,

 I realize you're probably being tongue-in-cheek, but actually, implementing what you suggest wouldn't be too hard.  One of the attributes for a song is the rating (which you can modify per song).    The attribute in this case would be "UserRating" (discussed at http://msdn2.microsoft.com/en-us/library/bb249557.aspx), and you could query that value to select songs of only a certain rating, or move them forward in the list, or whatever.  (WMP already uses this attribute to populate some of its automatic lists.)  Or, if the thought of verifying all of those ratings doesn't appeal to you, you could use the "UserPlaycount" attribute as a sorting value instead, which would probably be more reflective of what you actually listen to.  You could further do something fun like convolving two attributes in a "Songs I like that I haven't heard in a while" query by leveraging the "UserLastPlayedTime" attribute.

You can find a list of all the attributes for audio items at http://msdn2.microsoft.com/en-us/library/bb248412.aspx.

Thanks for reading the blog!

--Matt--*

# saleem said on November 5, 2007 6:21 AM:

how to recieve all file names double clicked

to open in my program (like ctrl + a enter)

and how to recieve the file name double clicked when my media player is working

i used command$ to recieve file names but it receives just the name for one file

# VBTeam said on November 6, 2007 2:47 PM:

Hi, Saleem,

So, for your first question:  double-click only works on one object, whether you're in the file explorer or in your own application.  This is "by design" for double-click, since the double-click essentially changes the selection to be the item under the click.  To enact a verb on multiple selections, the only way is to to the multi-selection and then press "Enter" (which invokes the default verb, which is usually "Open" or "Edit"), or to right-click on one of the selected items and choose the appropriate action from the context menu.

For the second part of the question, I think you're asking how to make double-clicking a file launch your application to use that file.  First, you need to associate the application with the file type.  The happens one of two ways:

(1) In Windows XP, open file explorer and from one of the menus (I forget which one) select "File and folder options."  You'll get a property sheet which has a tab that allows you to set the default program for a given file type (like WMA or WAV, for example).  Just point it at your program.

(2) In Windows Vista, you can do the same thing from the "Default Programs" control panel.

(If you create an installer Setup program for your app, you can also set it up to make that association automatically, but bear in mind that customers don't usually like programs which quietly change file associations.  You use the File Types editor in the Setup program you create to do that.)

Now, when you double-click the file (or choose "open" by right-clicking on multiple selected files), it should launch your program.  The program can read the names of the files using the "My.Application.CommandLineArgs" functionality -- you can easily iterate through the file names using it.

Hope this helps,

 --Matt--*

# slcompany said on November 8, 2007 7:57 AM:

sorry

i think i did not make clear my question...

the question is

i made a mediaplayer with visual basic.net 2005

i made it single instance application

i also made setup for my program with file types mp3,wav,wmv,.... etc you know

the problem i found was

when i double click on myfile1.mp3

it is working (because i determined mp3 files in my setup and with special icon too)

but when i double click myfile2.mp3

while the first is being played

my program just activat and continue playing

the first file

what do i have to do to play the new file double clicked

2-

for recieving all file names double clicked

i used commandlineargs[] to get them

but it seems like an array of one item

i mean it just gives me a name of one file among

the double clicked files

..note1:

thank you for every thing Matt

...note2:

i want to tell you that i am vb.net biginner

i am working on it for about 3 months

...note3:

i am sorry if my english is not very good

finally ::

if you want to answer me can you send somthing like code or any thing to make clear your soloutions

and than you again

# VBTeam said on November 8, 2007 12:52 PM:

Hi, Saleem,

 No problem.  For question #1:  Yes, in the case where the single-instance application is already running, the default behavior is just to give focus to that app without altering anything, because Form_Load wouldn't be called (the form is already loaded).  Instead, you need to handle the "StartupNextInstance" event.  To do this, go to the project property page (the one where you set the "Make single instance application" checkbox) and click the "View Application Events" button.  This will take you to the code editor so that you can add event handlers to the MyApplication friend class.  Add an event handler similar to the one at the bottom of the topic at http://msdn2.microsoft.com/en-us/library/b9z4eyh8(VS.80).aspx -- this demonstrates how to examine the command-line arguments passed in.  Modify that example to stop the player (vis the Ctlcontrols collection on the Player object) and restart it with a different playlist based on the arguments you read.  (You can get to your player via the My.Forms collection -- i.e., My.Forms.Form1.Player.)

For question #2:  Yes, double-clicking when you have a bunch of files selected will only send one filename to the application.  That's by design in windows -- double-clicking changes the selection to one thing.  In order to have multiple file names passed to the application, you need to right-click the multi-selection and choose "open," or just press "Enter" while they are all selected -- that is the only way to get all of those file names passed to your application.

Hope this helps,

 --Matt--*

# VBTeam said on November 8, 2007 12:54 PM:

(Note that the hyperlink in my last response got underlined incorrectly by the blog software, so clicking it won't work -- the address should include everything up to the .aspx suffix, so you'll need to copy and paste the address into your browser to correctly navigate to the example.)

# saleem said on November 11, 2007 7:31 AM:

thank you matt for everything

for my 2nd question

what i did is..

i selected many files

and then pressed enter

then my application works

in my application form load

i did

messagebox.show(My.Application.Commandlineargs.items.count.tostring)

and this gave me the number (1) in my messagebox

i mean

when i check the lenght of

commandlinargs array

it's lenght is one item whether i select a file and press enter

or select many files and press enter

i tried to get the item name of the array

and in both cases was a name of one of the selected files

what do you thin the problem is

Note:can i get your email please ..?

-can you send information about you to my email

i liked you and want to recognise..if you have time

-can i send files to your email like my project files or somthing like

because i have many another problems and i need you help please

and thank you again

i asked help from other websites befor but i got no responding

you are the first who answer me

so thank you very much

# saleem said on November 11, 2007 7:41 AM:

thank you matt again

but for my 1st question i want to tell you

that i tried to handle startup next instance

i tried to messagebox(the file name which was double clicked when my application was playing a file)

i used messagebox.show(my.application.commandlineargs........tostring ...etc )

the problem is

this message gaved me the name of the file is being played

not the new double clicked file name..

why do you think this happens ?

# VBTeam said on November 12, 2007 1:29 PM:

Hi, Saleem,

 I think the best thing to do is have me write a blog post that demonstrates all of this in code.  I'll try to do that this week.

--Matt--*

# VBTeam said on November 12, 2007 2:21 PM:

Ah, never mind -- I see what the issue is.  It turns out that I was mistaken about how multiple files are handled in Windows.  I thought that they were handled one one command line, but that's not quite correct.  Also, it looks like the sample in the link I pointed to you is misleading.

(1) If you have a bunch of files selected and use Open (or whatever) to launch your application with them, they don't all appear as a command-line argument to FormLoad.  Only one of them will (generally the last one selected).  The other files will go through the StartupNextInstance handler, one at a time.  Essentially, Windows is trying to launch your application once for *each* selected object -- it doesn't combine them into one command-line argument.  Because your application is a single-instance application, that means that the other files will get routed, one at a time, to calls to StartupNextInstance.

(2) Ignore the "/input=" string in the sample I pointed you to.  It doesn't exist.  Instead, you get a fully-qualified path to the file, and you can use the argument by simply prepending "file:///" to it.

Now, knowing those two things, the rest is easy.  FOr my example, I would move all of the code in FormLoad (the code which loads and randomizes the files) to a separate function -- let's call it "MergePlaylist."  FormLoad should just create the new playlist but leave it empty, and then call MergeList with the file argument that it knows about.  StartupNewInstance will also just call MergeList with the argument that it knows about.  MergeList will then prepend the "file:///" marker and then merge in the playlist with the total new playlist in a random fashion.  You'll have to add code in MergePlaylist to make sure that you're not breaking up any existing arcs already in there, but that should be easy.

*That* should solve all of your problems.  Good luck!

--Matt--*

# VBTeam said on November 12, 2007 2:22 PM:

P.S.  I'll still write this up in a blog, so you'll be able to see my final coding solution.

# saleem said on November 13, 2007 6:31 AM:

thank you matt again

1)can you send how can i get all files names in coding

.....

2)i want to ask you about a good skin maker for vb.net programs

3)how can i handle a keyboard event when my form is minimized

i mean

in jetaudio you can next the song by pressing nextmedia button

and this works even you are working on another program(i.e playing a game like fifa... )

4)

i made the owner of vedio a panel on form2

the problem is panel does not responding to mouse doubleclick event

but respond to mousedown event

why do you think this happens

(i want to maximize vedio form by double clicking not by mousedown)

another thing

why when i make my video in  fullscreen

my form stop responding to any keyboard event

i mean

i made form2 closes when press escape

every thing works very good untill i make the vedio

in fullscreen mode

then my form2 never responds again to keypress or keydown events

even i make it in normal mode

........

finally

why the vedio owner always be at front

i mean

no control you add to your form above the panel(owner) appears above it is always behind(never appear when vedio is playing)

i tried to add a trackbar above the panel to control video seeking

it did not work

# VBTeam said on November 13, 2007 11:17 AM:

(1) I'm going to post the blog today which will show how you get the filenames.

(2) Alas, I don't know anything about skin makers.

(3) Usually, apps that handle keystrokes when minimized aren't actually minimized -- there's still a form up somewhere (possibly invisible) which catches the keystrokes.  It's generally not considered a good thing to do since it confuses the user.

(4) I haven't noticed the problem, as I really haven't done much with video playback; however, I do know that video involves a painting sequence -- that painting has to be fast, so it might be a bit-blast.  I'm not sure, though -- you might ask the Windows Media team since they own that control.

--Matt--*

# VBTeam said on November 13, 2007 11:19 AM:

(3.5) I've never tried using a panel with media player -- not sure what would be going on here, sorry.

# The Visual Basic Team said on November 13, 2007 1:27 PM:

(This post assumes that you’ve read my previous post on Windows Media at http://blogs.msdn.com/vbteam/archive/2007/10/30/let-the-music-play-matt-gertz.aspx

# Noticias externas said on November 13, 2007 1:35 PM:

(This post assumes that you’ve read my previous post on Windows Media at http://blogs.msdn.com/vbteam

# VBTeam said on November 13, 2007 3:56 PM:

Saleem, my latest post is up now -- it should answer your questions around the command-line arguments.  Enjoy!

--Matt--*

# saleem said on November 15, 2007 7:02 AM:

thank you matt for every thing

# saleem said on November 19, 2007 6:02 AM:

hi matt

i asked you befor about handle keyboard events while

your application is minimized

you told me that there shoulde be somthing

not minimized to handle events even i don't see it

i am thinking to add a new form to my application

and make its capacity=0

(because if it is hidden it can't handle events)

i think it is not a good idea

because your form should be active to handle keyboard events

.......

is not there a way to watch keyboard with every timer tick?

or somthing like

onkeypress do.....

or

if keypressed do...

and put it in timer do you think this works?

and thank you again?

.......

can you tell me if you know

how this is achieved in jetaudio and windows mediaplayer

is visual c++ better than visual basic?

i mean does c++ have special tools to do this

.....

somthing like assembly code for watching keyboard input or somthing so...

and thank you again.........

# The Visual Basic Team said on September 20, 2008 2:13 AM:

Well, that was… intense. You may have noticed the lack of articles coming from my direction. I have been

# JFS said on May 9, 2009 9:35 AM:

I want to hide WMP on my form and create my own controls for it.  But whether I use WMP on the form or hide it and create my own controls, when I play something from the form, WMP is no longer minimized, but becomes a regular window on the desktop.  Is there any way to keep WMP minimized on the desktop?

# VBTeam said on May 11, 2009 12:49 PM:

Hi, JFS,

 Try setting uiMode to invisible on the WMP control (see http://msdn.microsoft.com/en-us/library/dd563546(VS.85).aspx for more details on uiMode) and see if that works.  It might not; if WMP is already launched as a separate app on your OS, I think it's going to preferentially activate it, and I don't know how to stop that.  (I notice a very similar behavior with Office, for example -- if I have a Word document minimized, and then double-click on another Word document's icon, the first document will restore when the second is opened -- kind of annoying, actually.)

# Mahir said on July 2, 2009 1:11 PM:

matt see i made my media player and it plays songs and instead of making a new playlist i made a list box so if i select the song and press a button "PLAY" it plays the selected song once its over it doesnt go ovr to d next song how do i do tat

2. it doesnt play mpeg4 files

3 how do i put a burner in it

4. how do i make sure that if i select a song and press enter it starts playin

PS: I'm 14 so make it simpler to write d code

# VBTeam said on July 20, 2009 1:54 PM:

Hi, Mahir,

 Sorry for the late response -- I've been on vacation for the past couple of weeks.  So, in order:

(1) Songs will only proceed to the next song automatically if they are part of a playlist.  You could write code to check for the termination of one song and then automatically call the next one, but then you'd essentially be duplicating what playlists already give you, so that's not efficient.  You're already duplicating WMP somewhat by having the listbox, since the full UI mode of WMP will already show you the list of songs.  It seems to me that what you're really asking is "how do I create my own UI on top of WMP, instead of using the default UI" -- if so, you'll need to handle the events that are sent when a trick changes.  Start with the documentation for IWMPEvents at http://msdn.microsoft.com/en-us/library/bb905806.aspx.

(2) See http://support.microsoft.com/kb/835861 -- maybe this is the issue that you are running into?

(3) Use the methods on the IWMPCdromBurn interface -- see http://msdn.microsoft.com/en-us/library/dd563081(VS.85).aspx.  You can get a reference to the IWMPCdromBurn interface (which essentially represents your CD burner) from the get_cdromCollection method from the AxWindowsMediaPlayer. (I've never used any of this before and so I am not familiar with it myself.)  

(4) Remember that you can assign objects to listboxes -- you don't have to just assign strings.  The listbox will use the "ToString" method to determine what it shows.  If the object's ToString method shows something other than what you'd expect, it's best to wrap the object and create your own ToString method.  So, for example:

Class MyMediaWrapper

 Private m As WMPLib.IWMPMedia

 Sub New(ByVal mediaItem As WMPLib.IWMPMedia)

   m = mediaItem

 End Sub

 Public ReadOnly Property Media() As WMPLib.IWMPMedia

   Get

     return m

   End Get

 Overrides Function ToString() As String

   Dim s As String

   m.get_Name(s)

   Return s

 End Function

End Class

So, create a MyMediaWrapper to represent a track, add it to the listbox, and when it's chosen, retrieve the media item using the property Media that you created, and use CtlControls.playItem() on the AxWindowsMediaPlayer to play it.

Hope this helps!

 --Matt--*

# Colin Reid said on August 19, 2009 11:30 AM:

I have follwoed your code at the start of the article to write a new playlist to my library. I have used VB2008 (for WMP11) to select track titles, numbers and locations from an MS Access database.

When I open WMP and try and play the new playlist I get an error message

"Windows Media Player cannot find the file. If you are trying to play, burn, or sync an item that is in your library, the item might point to a file that has been moved, renamed, or deleted."

I note that the track number (from the individual WMA files) are not separate but are included  with the title.

I wonder if using the prepend “file:///” to the track location is the problem?

Like you I want to be able to write playlists and synch them to my Walkman but not have the fag of dragging and dropping tracks in WMP.

Any ideas what I am doing wrong?

Colin Reid

ickleton@aol.com

# VBTeam said on August 19, 2009 3:15 PM:

Hi, Colin,

 A couple of points:

(1) You mentioned the track number (presumably as a potential cause):  WMP's default (when ripping music from media) is to include the track number as part of the filename when it creates the file.  But once it's in there, it's just part of the string, and no longer has any real relevance otherwise.  (I regularly change the track metadata without bothering to change the corresponding filename -- in fact, even though the filename is initially constructed from the track number and the track name, you can change it to anything you want thereafter -- WMP is usually good about seeing those changes afterwards, though sometimes you have to prod it.)  So, as long as you are pointing to the actual full filename, you should be OK.

(2) You only need to use the file:/// prefix when loading a playlist to the media player in code.  The tracks within the playlist should not be using it; they are pathed relative to the playlist.  For example, the tracks of a playlist look something like this:

           <media src="..\Pink Floyd\Dark Side of the Moon\08 Brain Damage.wma" cid="{2B680CA5-1A7D-40EC-9188-B25E85D66A9D}" tid="{A2EDDF17-31B5-4379-A364-44F567A71895}"/>

           <media src="..\Pink Floyd\Dark Side of the Moon\09 Eclipse.wma" cid="{479AC96E-A50B-4A89-A187-BF8877C301AD}" tid="{5DE121DE-0E3B-44F9-9573-0450372EE1B5}"/>

           <media src="..\Cake\Comfort Eagle\04_-_Short_SkirtLong_Jacket_(Album_Version).mp3" cid="{76055DB1-0791-4B52-A8B1-9AF0A045459A}" tid="{1F6F67A8-9E1D-4C33-95A3-7B22853A087F}"/>

           <media src="..\Alan Parsons\Valid Path\09 Chomolungma.wma" cid="{D53D322F-67BE-4E78-B9CC-417DC83C6EAA}" tid="{FDF9630F-69C5-4300-B360-9152F0281EF0}"/>

           <media src="..\Dead Can Dance\Spleen and Ideal\08 Avatar.wma" cid="{D82F6E54-973E-4D5C-BE7F-598E37A4C597}" tid="{36DEC1A5-F977-4771-89E5-C9510750692B}"/>

If you can't get it to work, here's what I'd like you to try:  Launch your homemade program and add a few tracks, saving the resulting playlist.  Now add the same tracks to a new playlist, using WMP to create the playlist.  Now use Notepad to compare the two playlists and see where the difference is.

--Matt--*

# VBTeam said on August 19, 2009 3:17 PM:

(Slight typo:  I said "...pointing to the actual full filename..."  As I mentioned later, the path contained int he playlist is actually a relative path -- the point I was trying to make was that the filename was just a filename and as long as it matches what's on disk, you're OK.)

--Matt--*

# Colin Reid said on August 21, 2009 11:15 AM:

Thanks for your rapid and useful reply as the problem is now solved.

The problem, I discovered by close inspection of the two playlists in Notepad, was that my(!) code was giving the wrong track number in reassembling the WMA file name.

Also, that track number now appears in the left most column as in other WMP generated playlists.  The playlist now plays without the errror message.

Once again, many thanks

regards

Colin Reid

# VBTeam said on August 24, 2009 1:25 PM:

Excellent!  Glad to be of assistance and that your code works now.

--Matt--*

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

This Blog

Syndication

Page view tracker