Find the CD
Written by Mike James   
Monday, 17 August 2009
Article Index
Find the CD
Getting a CD fingerprint
Freedb

 

Getting a CD fingerprint

The MCI makes it very easy to create an audio player but the real reason we are looking at it is to get the data needed to lookup a disc in a database.

The information needed is the number of tracks, the exact starting time of each track measured in frames and the total playing time of the disc in seconds.

A frame is the basic unit that an audio CD works in and it represents 1/75th of a second of sound.

Getting the number of tracks is easy and getting the start time of each track is easy because MCI supports these operations. Getting the total playing time of the disc is more of a problem as this has to be worked out from other data.

The simplest way to work is to add a new method getDiscData to the existing CCDAudio class. This will be designed to return a string formatted as:

tracks start of track 1 start of track 2 … start of final track total playing time

This isn’t a particularly general format but it is the one that makes looking up the disc easy.

The first part of the method simply gets the number of tracks on the disc after setting the MCI into minute, second, frame format:

public string getDiscData()
{
StringBuilder command =
new StringBuilder(256);
err = mciSendString(
"set cdaudio time format msf",
response, 128, 0);
if (err != 0) { return err.ToString(); };
err = mciSendString(
"status cdaudio number of tracks",
response, 128, 0);
if (err != 0) { return err.ToString(); };
int tracks = Convert.ToInt32(
response.ToString());
command.Append(tracks+" ");

The return value is built up using a StringBuilder. Notice that again the error handling is left for the calling problem to deal with. The new method simply returns the error code as a string.

Now that we know the number of tracks we simply use the MCI API to query the starting position of each one in turn. The starting position of each track is also saved in an array called offsets:

int[] offsets = new int[tracks];
string[] temp;
int minutes, seconds, frames;

Getting the starting position of each track is easy:

for (int i = 1; i <= tracks; i++)
{
err = mciSendString(
"status cdaudio position track " +
i.ToString(), response, 128, 0);

The response string now contains the starting position formatted as minutes:seconds:frames. The easiest way to separate these values is to use the Split method with the colon as the delimiter:

temp = (response.ToString()).Split(':');

This returns a string array in temp, corresponding to the original response string, split into parts as determined by the occurrences of the colon. From this we extract the individual values:

minutes = Convert.ToInt32(temp[0]);
seconds = Convert.ToInt32(temp[1]);
frames = Convert.ToInt32(temp[2]);

Now we have the starting position in minutes, seconds and frames this can be converted into total number of frames and stored in the array and the string that we are building up:

 offsets[i - 1] = minutes * 60 * 75 +
 seconds * 75 + frames;
command.Append(offsets[i-1]+" ");
}

The last part is the hardest, but still not that difficult - we need the total playing time of the disc in seconds.

This is something that the MCI doesn’t provide but it can be worked out by adding the length of the last track to its starting position. First we need the length of the last track:

err = mciSendString(
"status cdaudio length track " +
tracks.ToString(), response, 128, 0);

Next we process this to separate out the minutes, seconds and frames:

temp = (response.ToString()).Split(':');
minutes = Convert.ToInt32(temp[0]);
seconds = Convert.ToInt32(temp[1]);
frames = Convert.ToInt32(temp[2]) + 1;

The plus one is there because the Freedb website claims that the MCI interface returns the length of the last track minus one frame. Converting the length to frames and adding it to the starting position of the last track gives us the total playing time in frames:

int playtime;
playtime=offsets[tracks-1]
+ minutes * 60*75
+ seconds*75+frames;

Dividing by 75 gives the length in seconds and allows us to complete the string that we have been building up:

 playtime = playtime / 75;
command.Append(playtime);
return command.ToString();
}

You can try the method out using something like:

string c = CDAudio.getDiscData();
Console.WriteLine(c);

This information isn’t of much use to you in its raw form but submitted to Freedb it is the key to finding the disc record stored in the database.

<ASIN:0764536508>

<ASIN:0321122461>

<ASIN:1592003494>



Last Updated ( Monday, 17 August 2009 )