How to Write an Ultimate Shuffle Algorithm for MP3 Collections in C#

algorithmsccollectionsrandomsorting

I'm looking for pseudocode suggestions for sorting my mp3 files in a way that avoids title and artist repetition. I listen to crooners – Frank Sinatra, Tony Bennett, Ella Fitzgerald etc. singing old standards. Each artist records many of the same songs – Fly Me To The Moon, The Way You Look Tonight, Stardust etc. My goal is to arrange the songs (or order the playlist) with the maximum space between artists and song titles. So if I have 2000 songs and 20 are by Ella I'd like to hear her only once in every 100 songs. If 10 artists sing Fly Me To The Moon I'd like to hear it once in every 200 songs. Of course I want to combine these two requirements to create my "ultimate shuffle".

I know this is a fairly wide open question. I haven't started programming it yet so I'm just looking for suggestions of a good approach to take. I actually have some other requirements regarding evenly spacing other song attributes but I won't get into that here.


As a starting point I'm modifying code I found here to manipulate mp3 files and read ID3 tags.

I wrote a small app that satisfies my need using parsifal's answer below. I also wrote a follow up question here. Thanks for all the great responses!

Best Answer

Do you want to run your program once and generate a playlist, or pick the next song live?

If the latter, then the answer is simple:

  • Create an array that contains all of your songs, with artist and title
  • Create a list (linked list preferable) to hold recently-played song titles. This list starts out empty, and each time you play a song you add it to the list. When the list hits your desired "no song repeat" size, drop the oldest (first) entry.
  • Ditto for a list of artists.

Picking a song then becomes the following sequence of steps:

  1. Randomly pick a song from the "all songs" array. This is just a random number between 0 and the size of the array.
  2. See if that song is already in the played songs list. If it is, go back to step #1.
  3. See if the artist is already in the played artist list. If it is, go back to step #1.
  4. Add the song artist/title to the appropriate lists, dropping old entries if needed.
  5. Play the song.

There are a couple of possible issues, but they should only matter if you're doing this as homework and not a real project.

  • As @Dukeling said in a comment, if your collection is dramatically unbalanced in favor of a single artist or song title, you may get into a loop where you constantly reject songs. In practice, this is not going to be an issue. The solution is that you need to reduce the size of the "already seen" lists. And adding counters at steps #2 and #3 can tell you if it's a problem (if you see 10 failures in a row, raise a warning and/or reduce the size of the list).
  • If you're trying to produce a playlist that contains all of your songs played only once, you'll need to remove songs from the source array. This will also change how you deal with too many "recently played" failures (because eventually you might end up with only one artist in your source array).
  • If your ID3 tags are anything like mine, they contain plenty of misspellings. Does "Duke Ellington" need to be different from "Duke Elingten"? If yes, then look into using a Levenstein matcher when scanning the "recently played" lists.
Related Topic