Tuesday, September 14, 2010

The Database

I needed a database that would allow the the Music Server to access information about Artists, Albums and Songs/Tracks in a simple and easy to access format. As already mentioned in the previous post the Web UI is written in javascript and working with JSON (http://json.org/) is probably the most forward data format available. If the database itself uses JSON for the data format life is made much simpler as there is really no marshaling to other formats required.

The core of the database is the songs/tracks file. This file contains around 8000 tracks in my music collection. To load this whole file into memory is really not feasible. The solution I came up was to use a basic form of indexing and access the file via the java.io.RandomAccessFile class. A track index is simply a length (length of the JSON track record) and an offset pointing to where it resides in the file. To access a track quickly all that is required is a simple data structure consisting of these two values.

The song/track JSON structure itself mimics the IDv3 MP3 tags that are read from the MP3 files. Here is an example of one :

{
  "album": "Legion of Boom",
  "author": "The Crystal Method",
  "date": "2004",
  "duration": 268,
  "mp3.bitrate.nominal.bps": 128000,
  "mp3.channels": 2,
  "mp3.copyright": false,
  "mp3.crc": false,
  "mp3.frequency.hz": 44100,
  "mp3.id3tag.genre": "Electronica",
  "mp3.id3tag.track": 4,
  "mp3.mode": "Joint Stereo",
  "mp3.original": false,
  "mp3.vbr": false,
  "mp3.version.layer": "Layer 3",
  "mp3.version.mpeg": "MPEG1",
  "path": "/Volumes/mp3/music/The Crystal Method/Legion of Boom/04 - The Crystal Method - The American Way - Legion of Boom.mp3",
  "title": "The American Way",
  "type": "mp3"
}

In addition to to the songs/tracks file there are a number of index files that associate track indexes to Artists and Albums.

There is an "Artists to Songs" index file. Each Artist is associated with an array of song indexes.

  "alice in chains": [
    {
      "length": 542,
      "offset": 1500107
    },
    {
      "length": 544,
      "offset": 1500649
    },
.....

There is an "Albums to Songs" index file. Each Album is associated with an array of song indexes.

  "...And Justice For All (mp3)": [
    {
      "length": 600,
      "offset": 3101248
    },
    {
      "length": 568,
      "offset": 3101848
    },

Also there is an "Artists to Albums" index file that handles finding the artist/album associations quickly.

  "arctic monkeys": [
    "Favourite Worst Nightmare (mp3)",
    "Whatever People Say I Am, That\'s What I\'m Not (mp3)",
    "Humbug (mp3)"
  ]

These 4 files made up the database for the initial version, however as development progressed I found that I needed to add 2 additional files :
  • An "ArtistId To Artists" file
  • A "Directory Information" file
The "ArtistId To Artists" file was required because of the discrepancies I found with the Artist names in my music collection. The would be a variety of combination that would ultimately match the same artist. For example "The Cure", "Cure" and "Cure, The". This id file ties the combinations together.

The "Directory Information" file came about when I wanted to add new music files to an existing database without starting from scratch. This file provides a snapshot of the directories providing the music files that can be used to compare what is being scanned off disk.

    Saturday, September 4, 2010

    Writing the Music Server software

    Having decided that I was going to write my own Music Server software from scratch I had to then figure out a number of core issues that were fundamental to succeeding.
    1. Create some form of database of track information to allow easy selection via a user interface.
    2. Decode and play the media files on the server and access track metadata (MP3 tags etc) to populate the track database.
    3. Create a User Interface that was accessible via the devices I had available (PC based browser running on lo resolution NetBook and an iTouch)
    4. Provide some form of service middleware to allow the UI to obtain data and control whats going on on the Server.
    1) The direction I took was decided by what I planned to use for 3). The User Interface was going to be HTML based supporting and number of different devices. I'm pretty familiar with writing DHTML and Ajax based applications. With that in mind one of the easiest data formats to deal with in javascript is JSON. I decided to create a database around JSON structures.

    2) As I was going to be writing java code the most straight forward answer was to use an implementation of the javax.sound API.  As luck would have it there is a very nice implementation available http://www.javazoom.net/index.shtml. Using JLayer, MP3SPI, VorbisSPI and Tritonus I was able to write java code that could obtain the metadata stored in the media files and also decode and play these files on the PC.

    3) I'm very familar with the dojotoolkit framework (http://www.dojotoolkit.org/) and I have also contributed a javascript serverside templating framework (http://www.zazl.org/) that allows easy dynamic creation of HTML via DTL (Django Template Language). Using both of these together I was able to put together a flexible HTML Web UI that supports regualar browsers and also Apple devices such as the iPhone and iTouch.

    4) As I was already writing java code in the form of a Web Application the solution for 4) was to write the service layer with servlets supporting a REST like API. The response format is JSON.