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

Freedb

The Freedb protocol is an old fashioned “send a command and get a reply” type.

Its documentation, presumably written by someone who knows how it all works, misses out lots of things that are obvious to them but not to us beginners.

Freedb can be accessed via HTTP, SMTP or via a TCP/IP connection to port 8880. As .NET is very good at making general TCP/IP connections the simplest thing to do is create a TCP/IP client. Even if you’re not interested in Freedb, the procedure for creating such a client is still worth knowing.

Add a new class called CCDDB to the project that has CCDAudio. We need to make use of the classes in System.Net.Sockets so add the following to the existing using statements:

using System.Net.Sockets;

To keep things simple the new class will have only one method, connect, and this will simply print the progress and results to the console. In a real application you would probably split up this single method into sub-methods and you would do something more useful with the final data.

We need some global variables:

class CCDDB
{
private NetworkStream freedbstream;
private TcpClient freedb;

Making the TCP/IP connection is simplicity itself. All that is required is a new TcpClient object:

public void connect()
{
freedb= new TcpClient(
"freedb.freedb.org", 8880);
Console.WriteLine( freedb.Connected);

The URL and port of the connection are included in the call to the constructor. When the constructor completes we have a TCP/IP connection established. As always, error handling is ignored for simplicity.

Notice that you can view the output of the console in the Ouput window within Visual Studio or Express. This allows you to follow the progress of the lookup and see the final result.

To actually receive and send data over the TCP/IP connection we need to retrieve the associated stream object. Stream objects are a general way of working with streams of data that can be read or written, such as disk files:

freedbstream = freedb.GetStream();

At this point we could continue and read the data sent back by the Freedb server but this is going to be a standard operation so it makes sense to create a private routine to do the job:

private string receive()
{
byte[] buff = new byte[2000];
freedbstream.Read(buff, 0,
buff.GetLength(0));
string temp=Encoding.ASCII.GetString(
buff);
char[] trail={'\n','\0','\r'};
return temp.TrimEnd(trail);
}

All that happens here is that we set up a byte array to act as a data buffer, read the stream and then use the Encoding object to convert the stream of bytes into an ASCII string. The final part of the processing uses the TrimEnd command to remove control codes and clean up the string. With this routine defined we can now add to the connect method:

Console.WriteLine(receive());

The server sends a welcome banner when you first connect so you should see something like:

201 kivi CDDBP server v1.5PL2 
ready at Fri Jul 31 19:16:37 2009

The next step is that you have to sign on to the server using the command:

cddb hello username hostname 
clientname version

where username is a name that identifies the user of the program, hostname is the client machine, clientname is the name of the program doing the search and version is its version number. All of this information is used to find out who is using Freedb and you should try to provide realistic values for each item.

To send this command it is easier to use a routine that can be reused:

private void send(string message)
{
byte[] buff = Encoding.ASCII.GetBytes(
message+"\n");
Console.WriteLine(message + "\n");
freedbstream.Write(buff, 0,
buff.GetLength(0));
}

The conversion from a string to an array of ASCII bytes is achieved using the Encoding object for a second time. Notice that without the carriage return “\n” added to the end of the string the server would ignore the command.

To keep track of what is happening the command is printed to the console and then written to the stream.

With the help of the send and receive routines the hello command can be sent and the reply examined:

send("cddb hello mike 
www.yoururl iProgrammerCD 1");
Console.WriteLine(receive());

You should change the username and hostname to something suitable. The program identifier iProgrammerCD and the version number “1” is entirely up to you to invent for your own program. If all goes well you should see a reply something like:

200 Hello and welcome 
mike@www.yoururl
running iProgrammerCD 1.

The 200 at the start of the line is a status/error code and this is explained in the documentation.

Now we are ready to lookup the details of the disc currently in the drive. To do this we first create a CCDAudio object and get the disc details:

CCDAudio CDAudio = new CCDAudio();
string diskdata=CDAudio.getDiscData();

This can be added to the click event handler of another button.

To actually look the disk up we have to compute a disc ID based on the disc data. This can be done locally and the documentation on the website explains how – but the Freedb server will also do the job for you via the “discid” command:

send("discid " + diskdata);
string response=receive();
Console.WriteLine(response);

The response from the server is in a human readable form and is something like:

200 Disc ID is 780ac90a

Ignoring the possibility of errors, this can be processed using the same Split method trick only this time splitting the string using a space character and using the fact that the disc ID will be the fourth item:

string[] temp=response.Split(' ');
String DiscId=temp[4];
Console.WriteLine(DiscId);

Now we have everything needed to perform the lookup. This is a two-step process. First we have to query the database to discover how many possible matches there are and what category of music the disc is in:

send("cddb query " + DiscId +
 " " + diskdata);
response = receive();
Console.WriteLine(response);

The query is simply – send the Disc ID and the disc data as before. The response can be quite complicated if there are multiple inexact matches. In this case you really have to show the user what has been found and ask them to pick the correct disc. For simplicity let's assume that there is only one exact match and in this case the response is something like:

200 newage 780ac90a 
Laurie Anderson / Strange Angels

The most important part of the response is the second item – the music category. This can be extracted using Split:

temp = response.Split(' ');
String categ = temp[1];

Now, at long last we can retrieve the data record which gives the track details for the disc using the “read” command:

send("cddb read " +categ  +
 " " +DiscId );
Console.WriteLine(receive());
Console.WriteLine(receive());

In this case all that is needed is the music category and the computed DiscId. The returned data gives the title of the disc, the computed DiscId and disk information, the track list and often lots of additional data – see the website for the full range of possibilities. The data is terminated by a “.” all alone on a separate line, hence the need for two uses of receive. Most users are only interested in the title and track data, however. Finally we have to log off Freedb and close the connection:

 send("quit");
Console.WriteLine(receive());
freedb.Close();
}

If you put a call to the connect method in a button click event handler you will discover that the details of the CD that is currently in the drive are displayed in the output window.

Now the real work begins in turning this into a useful application that stores the information retrieved in your own local database.

You should be able to discover how the other Freedb commands work now that you have the basics by reading the documentation on the website.

 

lookup

A typical CD data record returned from Freedb

If you would like the code for this project then register and click on CodeBin.

<ASIN:1592000290>

<ASIN:1556220782>

<ASIN:1428318062>



Last Updated ( Monday, 17 August 2009 )