Wednesday, December 31, 2008

How to tag MP3 files for Android, iTunes, iPhone, and Windows Explorer

Being a proud owner of a brand-new Android phone and having a couple of weeks of vacation over the holidays, I decided that this is the perfect time to reorganize my digital music collection and to rip the last few CDs for which I had not had the time before.

I had to go through some trial-and-error experiments to find a tagging scheme that works for me, so I figured that my results might be interesting for others as well. I'm going to try to make a mini-series of blog postings that explain how I tag my MP3 files. I do not claim that this is the one and only tagging scheme, but it works well for me. If you use a different tagging scheme that works better for you, please let me know.

Tagging across devices, players, and media types

Being me, I want my music to be tagged perfectly for the handful of devices and programs that I use. This includes my iPhone that I recently used mostly as a media player and now also my Android phone. On Windows my main audio player is iTunes, but sporadically I also use Windows Media Player, mainly because it starts up much faster. Finally, I want to use the capability of the Windows Explorer to show the track titles when viewing tracks in the file system.

Tagging MP3s perfectly across these players was more challenging than I anticipated. It is very important to use the right ID3 tags, and until recently, I wasn't even aware of some of them. Here is my list of features of a "perfect" tagging scheme:

  1. Files from the same disc (set) should be be recognized as such. If not tagged correctly, iTunes (and other players) show tracks from the same CD as belonging to multiple CDs. This happens mostly for compilations. See below for the solution.
  2. Files and folders should show cover art in high quality. I want to see my cover art when playing a song, when using iPhone/iTunes cover flow, and as thumbnails in Windows Explorer.
  3. The files should play in the correct order. This seems trivial, but unfortunately it isn't.

Getting the tagging right is not made easier by the quite diverse collection of media types in my collection. I have albums of one artist, compilations from multiple artists, audio books, ballroom dance music, comedy discs, movie sound tracks, musicals, and so on. I also have a number of single MP3 files of an old collection of chart samplers that I didn't want to keep in their entirety.

Getting compilations recognized as single discs

For today, I thought, I'd get started with how to get single discs recognized as single discs. Here is a ballroom dancing album that contains tracks from various artists:

Clearly, every track is labeled with the same album name, so one might expect that iTunes recognizes the tracks as belonging to the same album. Unfortunately, this is not the case. Here is the result:

iTunes only recognized files as belonging to the same album if they also are from the same artist. Fortunately, there is a simple way to make iTunes understand that this is indeed only one album. Just select all tracks, right click, and select "Get Info" in the context menu. Then edit the "Album Artist" tag to have the same value for all tracks. I usually choose "Various", sometimes "Soundtrack" or similar. The album artist field is also useful for albums of a single artist "Somebody" where individual tracks are from "Somebody feat. Somebody Else".

I usually do not edit ID3 tags in iTunes. There are quite some decent ID3 editors out there. My favorite one is ID3-TagIT. Unfortunately it is not developed any more, but it is still available for download from several download archives. Here is how I enter the same information in the "Detailed Information" editor:

Technically, the "Album Artist" information is stored in the 'TPE2' ID3 frame that is defined as follows: “The 'Band/Orchestra/Accompaniment' frame is used for additional information about the performers in the recording.” Arguably, this definition does not quite match what we use it for, but all players seem to use it as the "album artist" as intended.

Let me know if this explanation was helpful for you. Check back later for other topics I'd like to write about in future postings: Which ID3 version(s) to use, how to include cover art, how to handle sets of two or more discs, audio books, and what else comes to my mind until then. Let's hope that I find the time.

Saturday, December 20, 2008

View Android Source Code in Eclipse

Recently, I have been hacking around with Android a lot, and I think it's awesome.

Unfortunately, the Android SDK does not come with source code, and sometimes the docs are not so great, yet. Being an open source project, the Android sources are available online, but they are not very easy to access from Eclipse. For one, the source files are sometimes difficult to find as they are distributed over many individual Git repositories, and then I am not always online.

Integrating source files into Eclipse is usually quite easy, but the Android Eclipse plugin (ADT) does not allow to modify the Java Source Attachment of android.jar in the Android Library. Fortunately, you only have to find out what the default location for source code is. Eric Burke nicely describes how to find that out.

Long story short: Android source code needs to be placed in a "sources" subdirectory of the Android SDK. Here is what you need to do:

  1. Get the Android source code (install repo, repo init, repo sync)
  2. Move all Java sources into a "sources" subdirectory of the Android SDK

Step 2 sounds easier than it is. There are a lot of Java files in the Android sources, and they are sprinkled all over the place. Eclipse, however, needs the source files in a standard Java source directory structure: The path of a source file needs to match its package name. To simplify this task, I have written a short Python script that recursively searches for Java files and packs them into a ZIP file. Unpack that source file into a "sources" subdirectory of the Android SDK. Enjoy:

from __future__ import with_statement  # for Python < 2.6

import os
import re
import zipfile

# open a zip file
DST_FILE = 'sources.zip'
if os.path.exists(DST_FILE):
  print DST_FILE, "already exists"
  exit(1)
zip = zipfile.ZipFile(DST_FILE, 'w', zipfile.ZIP_DEFLATED)

# some files are duplicated, copy them only once
written = {}

# iterate over all Java files
for dir, subdirs, files in os.walk('.'):
  for file in files:
    if file.endswith('.java'):
      # search package name
      path = os.path.join(dir, file)
      with open(path) as f:
        for line in f:
          match = re.match(r'\s*package\s+([a-zA-Z0-9\._]+);', line)
          if match:
            # copy source into the zip file using the package as path
            zippath = match.group(1).replace('.', '/') + '/' + file
            if zippath not in written:
              written[zippath] = 1
              zip.write(path, zippath)
            break;
         
zip.close()