#region CPL License /* Nuclex Framework Copyright (C) 2002-2009 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using Nuclex.Support.Tracking; namespace Nuclex.Audio.Metadata { /// /// Opens connections to a CDDB database and allows querying of CD titles /// public static class Cddb { #region struct Credentials /// Credentials with which to log into a CDDB server public struct Credentials { /// Initializes a new CDDB login credentials structure /// Login name of the user /// Host name of the client /// NAme of the connecting client software /// Version number of the client software public Credentials( string user, string hostName, string clientName, string version ) { this.User = user; this.HostName = hostName; this.ClientName = clientName; this.Version = version; } /// Login name of user. Example: johndoe public string User; /// Host name of client. Example: abc.fubar.com public string HostName; /// /// The name of the connecting client. Example: xmcd, cda, EasyCD, et cetera. /// /// /// Do not use the name of another client which already exists. /// public string ClientName; /// Version number of client software. Example: v1.0PL0 public string Version; } #endregion // struct Credentials #region struct DTitle /// Stores the contents of a CDDB DTITLE field public struct DTitle { /// Initializes a new CDDB DTITLE structure /// Artist that released the song or the album /// Name of the song or of the album public DTitle(string artist, string title) { this.Artist = artist; this.Title = title; } /// Artist that released the song or the album public string Artist; /// Name of the song or of the album public string Title; } #endregion // struct DTitle #region struct Disc /// Informations about a disc that has been queried for public struct Disc { /// Initializes a new disc informations structure /// Category the disc is catalogued under /// CDDB disc id of the disc /// The artist of the disc /// The title of the disc public Disc(string category, int discId, string artist, string title) { this.Category = category; this.DiscId = discId; this.Artist = artist; this.Title = title; } /// Musical category of the CD, possibly wrong /// /// When CDDB came to existence, only 11 musical categories were defined with /// a strong bias towards the creator's musical knowledge and/or taste. /// Furthermore, CDDB servers a wary of changing these categories due to /// crappy clients that are likely to break. Thus, today the categories are /// mainly used to provide additional storage slots if duplicate disc ids occur. /// public string Category; /// CDDB disc id of the disc public int DiscId; /// Artist of the CD public string Artist; /// Title of the CD public string Title; } #endregion // struct Disc #region struct DatabaseEntry /// Stores the contents of an XMCD database file public struct DatabaseEntry { /// Frame offsets of the individual tracks on the CD public int[] TrackFrameOffsets; /// Total length of the CD in seconds public int DiscLengthSeconds; /// Revision number of the database entry public int Revision; /// Application that has submitted the CDDB database entry public string Submitter; /// CDDB disc ids for this disc /// /// Storing multiple CDDB disc ids in a database entry has been deprecated, /// normally you should only encounter entries with a single CDDB disc id. /// public int[] DiscIds; /// Name of the artist who released this album /// /// If the CD is a sampler consisting of tracks from several artists, this /// field will be set to 'Various' /// public string Artist; /// Name of this album public string Album; /// Year that album was released in public int Year; /// Name of the genre the CD is categorized under public string Genre; /// Track titles of the individual tracks on the CD public DTitle[] Tracks; } #endregion // struct DatabaseEntry /// /// Calculates the 'disc id' of a CD for submission or retrieval from a CDDB database /// /// /// Total length of the CD (from the beginning of the first track to the end of the /// last track) in seconds /// /// /// Offsets of the individual tracks on the CD in seconds /// /// The CDDB disc id of a CD with the provided characteristics /// /// Disc ids are not guaranteed to be unique. In fact, it is quite likely to find /// duplicate ids all over the place. This is due to the CDDB disc id algorithm /// which is severely flawed and has to be accepted. See the remarks on the /// enumeration for how to get up to 11 CDs with the same /// disc id enlisted in a CDDB database. /// public static int CalculateDiscId( int discLengthSeconds, int[] trackOffsetsSeconds ) { int trackCount = trackOffsetsSeconds.Length; // First, the checksum needs to be calculated. This is done by calculating the // sum of digits for the starting offset (in seconds) of each track on the CD, // which are then added together and taken modulo 255 to arrive at the checksum. int offsetChecksum = 0; for(int trackIndex = 0; trackIndex < trackCount; ++trackIndex) { int trackOffsetSeconds = trackOffsetsSeconds[trackIndex]; // Calculate the sum of digits for this track's starting offset int sumOfDigits = 0; while(trackOffsetSeconds > 0) { sumOfDigits += trackOffsetSeconds % 10; trackOffsetSeconds /= 10; } offsetChecksum += sumOfDigits; } offsetChecksum %= 255; // The rest of the CDDB disc id calculation is trivial: after the checksum (stored in // the highest byte), the next two bytes carry the total length of the CD in seconds // and the lowest byte is the number of tracks on the cD. int discId = (offsetChecksum << 24) | (discLengthSeconds << 8) | (trackCount & 0xFF); return discId; } /// Splits a CDDB DTITLE field into its artist and album name parts /// /// String containing a CDDB DTITLE field that will be split /// /// Two strings containing the artist and the album name public static DTitle SplitDiscTitle(string discTitle) { int separatorIndex = discTitle.IndexOf(" / "); if(separatorIndex == -1) { return new DTitle(discTitle, discTitle); } else { return new DTitle( discTitle.Substring(0, separatorIndex), discTitle.Substring(separatorIndex + 3) ); } } /// Establishes a connection to a public freedb database mirror /// Credentials by which to log in to the CDDB server /// A request that provides the CDDB connection upon completion public static Request Connect(Credentials credentials) { return Connect("freedb.freedb.org", credentials); } /// /// Establishes a connection to the specified CDDB compatible database server /// /// URL or IP address of the server to connect to /// Credentials by which to log in to the CDDB server /// A request that provides the CDDB connection upon completion public static Request Connect(string server, Credentials credentials) { Requests.CddbConnectionRequest connectionRequest = new Requests.CddbConnectionRequest(server, 8880, credentials); connectionRequest.Start(); return connectionRequest; } } } // namespace Nuclex.Audio.Metadata