Showing posts with label music. Show all posts
Showing posts with label music. Show all posts

Wednesday, November 26, 2014

Creating a Shuffled Classical Music Playlist

I have a reasonably large classical music collection, and sometimes I'm in the mood to put classical music on, but I don't want to choose exactly what. Yes, I could find some classical music radio station, either over the air or on the internet, but having grown up in an age before universal streaming, sometimes I just want to listen to my music. I'm generally a big fan of randomly shuffled music, and I like Smart Playlists in iTunes. Using smart playlists, I can set up metadata-based playlists like "play a random selection of all rock or blues tracks rated 4 stars or higher than have not been played in the last 3 months."

Classical music is different than rock, pop, blues, jazz, country or most other forms of music. Besides the obvious things, you're often more interested in the composer rather than the performer. For example, I know I like Beethoven better than Vivaldi, but I wouldn't say that I like the Boston Symphony better than the New York Philharmonic. (This isn't 100% true, particularly for solo artists - I might have particular pianists, violinists, etc. that I really like.)

You'll notice another difference with classical music if you try to listen to it by shuffling tracks. You might get the second movement of a Mendelssohn symphony, followed by the third movement of a string quartet, followed by the first movement of a piano concerto, followed by the William Tell Overture. This is not quite what I'm looking for - I'd rather have it play the entire symphony, followed by the entire string quartet, followed by the whole piano concerto, followed by the William Tell Overture.

I could shuffle by album, but that's not quite "shuffle-y" enough. Plus, occasionally I have a piece that spans two discs. I have a nice recording of Tchaikovsky's Symphonies 4, 5, and 6 on two discs, but the poor Fifth Symphony gets split across the discs.

In other words, I don't want to shuffle by track but by work. A classical work is the typical unit of composition and performance - Beethoven wrote the 5th symphony as a cohesive whole, and usually all four movements are performed together and in succession.

Fortunately, iTunes supports classical composers and works, sort of. If you right-click on a track and choose "Get Info", you'll see something like this:



There is a specific field for Composer, but what about Work? Well, it turns out that iTunes treats the Grouping field as the work, at least for tracks in the Classical genre. You used to be able to see this in the Classical Music smart playlist in older version of iTunes, but apparently they've changed things around in more recent versions so it doesn't say anything about the work there anymore.

To aid in the effort of adding composer and grouping information, I made smart playlists called "Classical with No Composer" and "Classical with No Work Grouping", which help to identify where I need to add metadata:


It's relatively easy to add composer information to everything, but quite a bit more work to add Work groupings if you have a large classical music collection. It turns out that having the Work entered for everything is nice, but not critically important, as I'll get to in a minute.

What I want, then, is to get all the tracks in the Classical genre that have a composer, group them by work, then shuffle the works, while preserving the track order within the work. Building on some earlier work coding against the iTunes API, this ultimately evolved into a high-level LINQ expression that's fairly expressive:

                 List<IITFileOrCDTrack > tracks =
                    iTunes.Library.FileTracks
                        .InGenre( "Classical")
                        .WithComposer()
                        .WithFile()
                        .ShuffleByWork()
                        .ToList();
  
This expression uses several extension methods on IEnumerable<IITFileOrCDTrack>:

         public static IEnumerable< IITFileOrCDTrack> InGenre(this IEnumerable<IITFileOrCDTrack > trackCollection, string genreName)
        {
            return from IITFileOrCDTrack track in trackCollection
                where track.Genre == genreName
                select track;
        }

        public static IEnumerable< IITFileOrCDTrack> WithComposer(this IEnumerable<IITFileOrCDTrack > trackCollection)
        {
            return from IITFileOrCDTrack track in trackCollection
                   where !string .IsNullOrWhiteSpace(track.Composer)
                   select track;
        }

        public static IEnumerable< IITFileOrCDTrack> WithFile(this IEnumerable<IITFileOrCDTrack > trackCollection)
        {
            return from IITFileOrCDTrack track in trackCollection
                   where File .Exists(track.Location)
                   select track;
        }
  
These are pretty straightforward, but obviously the ShuffleByWork method is the hard part. But first, we need a simple ClassicalWork class:

    public class ClassicalWork
    {
        public string Composer { get; private set ; }
        public string Album { get; private set ; }
        public string Name { get; private set ; }
    }
  
This class also has a constructor, plus the System.Object overrides Equals(), GetHashCode(), and ToString() methods, but nothing spectacular here.

The ShuffleByWork() method starts out by grouping all the tracks into ClassicalWork objects:

             var workGroups = from filetrack in filetracks
                             group filetrack by new ClassicalWork(filetrack.Composer, filetrack.Album, Classical.WorkName(filetrack.Grouping, filetrack.Name));
  
The Classical.WorkName() static method constructs the best possible name for the work. If we have a Grouping for the particular track, well, we know that's the work name, so we go with that. If not, we look at the track name. Overtures are normally only one track, and are good to intersperse between longer works, so if the track name contains "overture" return it as the work name. Otherwise, we just an empty string, which means that this track isn't really part of a work (but we'll still include it in the shuffled playlist).

Grouping tracks in this manner is really what defines what we consider to be a work. All tracks on a particular album that have the same composer and work name (as defined above) are considered to be the same work as far as our shuffling goes. This means that all tracks on an album that have the same composer but don't have the same Grouping will still get grouped together into one pseudo-work. In practice, this is fine - if I have several tracks on an album by Sibelius, say, but don't know anything else about whether they fit together, it's perfectly OK to group them together.

So now workGroups is a list of all the works we're dealing with, each with a list of the tracks in the work. Next, we just shuffle all the work groups:

             var shuffledWorkGroups = workGroups.Shuffle();
  
The Shuffle() extension method is perfectly generic (in both senses of the word) and could be used to shuffle any collection - a deck of cards, etc:
        public static IEnumerable<T> Shuffle<T>( this IEnumerable <T> enumerable)
        {
            var random = new Random();
            var shuffled = from item in enumerable
                           orderby random.Next()
                           select item;

            return shuffled;
        }
  
The last thing to do in the ShuffleByWork() method is to iterate through each item in our shuffled work groupings, and return the tracks in each grouping ordered by the original track number:

             foreach (var workGroup in shuffledWorkGroups)
            {
                // Work name is workGroup.Key;
                var tracks = workGroup.OrderBy(t => t.TrackNumber);
                 foreach (IITFileOrCDTrack track in tracks)
                {
                    yield return track;
                }
            }
  
Next, we'll create a playlist, deleting an existing playlist if necessary:

                IITUserPlaylist playlist = iTunes.FindPlaylistByName(playlistName);
                if (playlist != null )
                {
                    playlist.Delete();
                }
                playlist = iTunes.CreatePlaylist(playlistName);
                foreach (var track in tracks)
                {
                    playlist.AddTrack(track);
                }
Once the program runs, the playlist obligingly shows up in iTunes:


Finally, we'll create an M3U playlist, which is a very simple text file and will allow non-iTunes apps to access the data. 

We'd like to shuffle this on a regular basis, so I need to create a little batch file that can be run as a scheduled task every night. The essence of that is this line:

ClassicalPlaylist.exe "Classical Shuffle" "%USERPROFILE%\Music\My Playlists\Classical Shuffle.m3u"

With that done, I can point all the various music devices and services in my home (Sonos, Plex, etc.) to that .m3u file,

The project and source code is up on Github if you want to take a look.

Thursday, October 4, 2012

90/180 BPM Running Playlists and Beat Detection Software

In my last post, I discussed my motivation for coming up with an iPod playlist of songs with tempos and 90 or 180 beats per minute (BPM), to listen to while running. This helps in running with a cadence of 180 strides per minute. Fortunately, the interwebs oblige with lots of suitable running playlists, as well as quite an extensive list at jog.fm.

With sample playlists in hand, I was able to put together one based on my own collection of music that looks something like this:

Ramblin' Man - The Allman Brothers Band
Never Is Enough - Barenaked Ladies
Wild Honey Pie - The Beatles
I'm a Loser - The Beatles
One After 909 - Beatles
Run for Your Life - The Beatles
Norwegian Wood (This Bird Has Flown) - The Beatles
Can't Find My Way Home - Blind Faith / Eric Clapton
Subterranean Homesick Blues - Bob Dylan
From A Buick 6 - Bob Dylan
Modern Love (1999 Digital Remaster) - David Bowie
16 Military Wives - The Decemberists
The Boys of Summer - Don Henley
Man With a Mission - Don Henley
Maxine - Donald Fagen
Son of a Preacher Man - Dusty Springfield
At Last - Etta James
It's Your Thing - Isley Brothers
Feelin' Alright - Joe Cocker
One More Time - Joe Jackson
All My Love - Led Zeppelin
Custard Pie - Led Zeppelin
Boom, Like That - Mark Knopfler
Don't Crash the Ambulance - Mark Knopfler
Sunday Morning - Maroon 5
The Impression That I Get - The Mighty Mighty Bosstones
The Flyer - Nanci Griffith
Live Forever - Oasis
All Around the World or the Myth of Fingerprints - Paul Simon
The Obvious Child - Paul Simon
In Your Eyes - Peter Gabriel
Watching the Clothes - The Pretenders
Precious - Pretenders
Fat Bottomed Girls - Queen
Finest Worksong - R.E.M.
Breaking the Girl - Red Hot Chili Peppers
Give It Away - Red Hot Chili Peppers
Yertle the Turtle - The Red Hot Chili Peppers
Black Cow - Steely Dan
Hello It's Me - Todd Rundgren
Bright Side Of The Road - Van Morrison

If you noticed that this list is full of a lot of moldy oldies, you're right. But I'm of a certain age, and that's what's in my iTunes. In any event, it's not a bad list, and I have been running happily with it for several weeks. However, I quickly tire of almost anything, and longer term I would like more variety. Now, I should say that I own a lot of music. The CD rack holds about 800 discs, and it's full, and other CDs are squirreled away in various other locations. There are about 15,000 tracks in my iTunes music library, so I probably own a lot more tracks that are 90 or 180 BPM. How to find them?  Ideally I'd like something that could crawl through all of my iTunes tracks, analyze the music, and automatically fill in the BPM information. I know it’s not going to be fast, but that's OK. It can run overnight if necessary, or over many nights, for that matter. I found three programs for Windows, free and commercial, that claim to do what I'm looking for.

Cadence Desktop Pro


The Big Kahuna in the very sparse field of automatic beat detection software seems to be Cadence Desktop Pro. It claims to do pretty much exactly what I want: it communicates with iTunes so it knows about your playlists, and makes it fairly easy to select a playlist or part of one, find and display the tempo for each track, and then gives you the option of saving the BPM info back to the tracks. It also gives you a way to verify the tempo by playing a track and tapping with the beat on the space bar.



I downloaded and installed the trial version, and my initial results were good enough that I went ahead and paid $6.99 for the full version. The problem is, it crashes... a lot. It worked well at the beginning, but after a while it became completely unusable. Apparently this happens for other people who have a lot of tracks in their iTunes library. If you have a modest collection of tracks, probably less than a thousand, Cadence Desktop Pro is a very good tool for the purpose. Otherwise, you might want to evaluate carefully before buying.

MixMeister BPM Analyzer


MixMeister BPM Analyzer is a free tool intended for DJ's to find the perfect beat, but looks promising for those of us who don't make it into nightclubs much these days. Its user interface is a bit simpler than Cadence Desktop, and it doesn't integrate with iTunes - it just works off music files on the filesystem. You can browse to a directory, and the program will analyze all music files in that directory as well as all subdirectories (incidentally, it only works with WAV, MP3, and WMA formats). This allowed me to quickly find several more songs in the 88-92 BPM range in an old playlist directory of running songs:


All in all, I like this tool. It's very fast, maybe about 5 seconds per song on my reasonably high-end developers' PC. It automatically saves the Beats Per Minute data to each track, so you could certainly use it in conjunction with smart playlists on iTunes.

BPM Detector Pro


The final entry in the world of automatic beat detectors is BPM Detector Pro. This is also a file-based program, and works quickly, but the look and feel is certainly nothing to write home about:



The trial version is very limited, as you can only analyze three songs at a time. I never did figure out its scheme for exporting BPM data. According to the help file, "Source files may either be renamed, or copied to a new file with a new name. In either case the BPM value can be placed either at the beginning or at the end of the new file name." I didn't want it to do either, and fortunately it didn't create any new files, unless it put them an undisclosed location.

Conclusion


At $24.95 for the full version of BPM Detector Pro, I'll be sticking with MixMeister BPM Analyzer. Besides working well and being free, they also get bonus points for not including the word "Pro" in their name.


Thursday, September 27, 2012

Barefoot Running and the Perfect Beat

Blame it on Born To Run.

No, not the Bruce Springsteen album or song, but the book by Christopher McDougall chronicling his journeys among ultramarathoners, a native Mexican tribe of (seemingly) superathletes, and his own running pain. The main point of the book is: everything you know about running is wrong. Specifically, shoes. All that padding and stability and motion control just gets in the way of the natural sensory feedback your feet give you when you run barefoot, leading to bad running form and eventually, for most people, injuries. To put it bluntly, the shoes are indirectly causing the very injuries they're supposed to be preventing.



I have been running more or less regularly since the fall of 2000, when my wife and I found out we were expecting our first child. At the time I didn't lead an unhealthy lifestyle exactly, but I wasn't getting a great deal of exercise either, and if I wanted to be around to see this kid grow up, I needed to take better care of myself. I joined a gym, started on cardio machines, transitioned to treadmill running and outside running. I ran my first Peachtree Road Race in 2002 and did quite a few races over the next few years, mostly 10Ks but also a few 5Ks and one half-marathon. Some nagging injuries led me to give up running for a couple of years, but I found I really missed it so I made the effort to start up again in 2010 - about the time I learned about Born To Run. The book was a revelation, and made a lot of sense to me - after all, humans have been running barefoot for thousands of years - do we really need expensive, high-tech shoes to keep from injuring ourselves? I tried some barefoot running but the bigger impact (no pun intended) on my running came in the form of some more minimalist shoes and more careful attention to my form.

McDougall's book talks a good bit about correcting your running form, as merely taking off your shoes isn't enough. Most of us need to unlearn years of bad habits, such as landing on your heels, developed from running in highly-cushioned shoes. Correcting one's running form isn't easy, even for McDougall, who had the benefit of some of the best running coaches around. I found some YouTube videos and other sites which helped, but I wasn't sure I was on the right track. I felt like I needed some coaching, but I'm basically too cheap to hire a personal trainer; plus, all this barefoot/minimalist running stuff, as trendy as it was, was still new, and I doubted that there was an abundance of coaches out there who knew what they were talking about.

Big Peach Running Co. Logo


Fortunately, the good folks at Big Peach started to offer Good Form Running classes for a modest fee. This technique, very much in line with the barefoot running craze, divides running form into four areas: posture, mid-foot landing, cadence, and lean. Breaking it down like this lets you work on one thing at a time. The cadence part is particularly simple: aim for 180 strides per minute, or 90 per minute on each foot, which will give you a shorter, more efficient stride, while at the same time discouraging you from landing on your heels. I had known about the 180 strides per minute guideline for some time, and briefly tried running with a metronome, but I wasn't crazy about it. However, the class suggested running with an iPod playlist consisting of songs with tempos at 90 or 180 beats per minute. I hadn't thought about doing this before, but it made a lot of sense for me - I run with an iPod Nano (although usually listening to podcasts), and I have a lot of music in iTunes. Surely some fraction of the thousands of songs were at the correct tempo, right?

In the next post I'll discuss my efforts at putting together a playlist of suitable songs.