1*9a747e4fSDavid du Colombier 2*9a747e4fSDavid du ColombierCDDB DISCID 3*9a747e4fSDavid du Colombier----------- 4*9a747e4fSDavid du Colombier 5*9a747e4fSDavid du ColombierBoth forms of CDDB access require that the software compute a "disc 6*9a747e4fSDavid du ColombierID" which is an identifier that is used to access the CDDB. The disc 7*9a747e4fSDavid du ColombierID is a 8-digit hexadecimal (base-16) number, computed using data from 8*9a747e4fSDavid du Colombiera CD's Table-of-Contents (TOC) in MSF (Minute Second Frame) form. The 9*9a747e4fSDavid du Colombieralgorithm is listed below in Appendix A. 10*9a747e4fSDavid du Colombier 11*9a747e4fSDavid du ColombierIt is crucial that your software compute the disc ID correctly. If it 12*9a747e4fSDavid du Colombierdoes not generate the correct disc ID, it will not be compatible with CDDB. 13*9a747e4fSDavid du ColombierMoreover, if your software submits CDDB entries with bad disc IDs to the 14*9a747e4fSDavid du ColombierCDDB archives, it could compromise the integrity of the CDDB. 15*9a747e4fSDavid du Colombier 16*9a747e4fSDavid du Colombier[...] 17*9a747e4fSDavid du Colombier 18*9a747e4fSDavid du ColombierAPPENDIX A - CDDB DISCID ALGORITHM 19*9a747e4fSDavid du Colombier---------------------------------- 20*9a747e4fSDavid du Colombier 21*9a747e4fSDavid du ColombierThe following is a C code example that illustrates how to generate the 22*9a747e4fSDavid du ColombierCDDB disc ID. [...] A text description 23*9a747e4fSDavid du Colombierof the algorithm follows, which should contain the necessary information 24*9a747e4fSDavid du Colombierto code the algorithm in any programming language. 25*9a747e4fSDavid du Colombier 26*9a747e4fSDavid du Colombier 27*9a747e4fSDavid du Colombierstruct toc { 28*9a747e4fSDavid du Colombier int min; 29*9a747e4fSDavid du Colombier int sec; 30*9a747e4fSDavid du Colombier int frame; 31*9a747e4fSDavid du Colombier}; 32*9a747e4fSDavid du Colombier 33*9a747e4fSDavid du Colombierstruct toc cdtoc[100]; 34*9a747e4fSDavid du Colombier 35*9a747e4fSDavid du Colombierint 36*9a747e4fSDavid du Colombierread_cdtoc_from_drive(void) 37*9a747e4fSDavid du Colombier{ 38*9a747e4fSDavid du Colombier /* Do whatever is appropriate to read the TOC of the CD 39*9a747e4fSDavid du Colombier * into the cdtoc[] structure array. 40*9a747e4fSDavid du Colombier */ 41*9a747e4fSDavid du Colombier return (tot_trks); 42*9a747e4fSDavid du Colombier} 43*9a747e4fSDavid du Colombier 44*9a747e4fSDavid du Colombierint 45*9a747e4fSDavid du Colombiercddb_sum(int n) 46*9a747e4fSDavid du Colombier{ 47*9a747e4fSDavid du Colombier int ret; 48*9a747e4fSDavid du Colombier 49*9a747e4fSDavid du Colombier /* For backward compatibility this algorithm must not change */ 50*9a747e4fSDavid du Colombier 51*9a747e4fSDavid du Colombier ret = 0; 52*9a747e4fSDavid du Colombier 53*9a747e4fSDavid du Colombier while (n > 0) { 54*9a747e4fSDavid du Colombier ret = ret + (n % 10); 55*9a747e4fSDavid du Colombier n = n / 10; 56*9a747e4fSDavid du Colombier } 57*9a747e4fSDavid du Colombier 58*9a747e4fSDavid du Colombier return (ret); 59*9a747e4fSDavid du Colombier} 60*9a747e4fSDavid du Colombier 61*9a747e4fSDavid du Colombierunsigned long 62*9a747e4fSDavid du Colombiercddb_discid(int tot_trks) 63*9a747e4fSDavid du Colombier{ 64*9a747e4fSDavid du Colombier int i, 65*9a747e4fSDavid du Colombier t = 0, 66*9a747e4fSDavid du Colombier n = 0; 67*9a747e4fSDavid du Colombier 68*9a747e4fSDavid du Colombier /* For backward compatibility this algorithm must not change */ 69*9a747e4fSDavid du Colombier 70*9a747e4fSDavid du Colombier i = 0; 71*9a747e4fSDavid du Colombier 72*9a747e4fSDavid du Colombier while (i < tot_trks) { 73*9a747e4fSDavid du Colombier n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec); 74*9a747e4fSDavid du Colombier i++; 75*9a747e4fSDavid du Colombier } 76*9a747e4fSDavid du Colombier 77*9a747e4fSDavid du Colombier t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) - 78*9a747e4fSDavid du Colombier ((cdtoc[0].min * 60) + cdtoc[0].sec); 79*9a747e4fSDavid du Colombier 80*9a747e4fSDavid du Colombier return ((n % 0xff) << 24 | t << 8 | tot_trks); 81*9a747e4fSDavid du Colombier} 82*9a747e4fSDavid du Colombier 83*9a747e4fSDavid du Colombiermain() 84*9a747e4fSDavid du Colombier{ 85*9a747e4fSDavid du Colombier int tot_trks; 86*9a747e4fSDavid du Colombier 87*9a747e4fSDavid du Colombier tot_trks = read_cdtoc_from_drive(); 88*9a747e4fSDavid du Colombier printf("The discid is %08x", cddb_discid(tot_trks)); 89*9a747e4fSDavid du Colombier} 90*9a747e4fSDavid du Colombier 91*9a747e4fSDavid du Colombier 92*9a747e4fSDavid du ColombierThis code assumes that your compiler and architecture support 32-bit 93*9a747e4fSDavid du Colombierintegers. 94*9a747e4fSDavid du Colombier 95*9a747e4fSDavid du ColombierThe cddb_discid function computes the discid based on the CD's TOC data 96*9a747e4fSDavid du Colombierin MSF form. The frames are ignored for this purpose. The function is 97*9a747e4fSDavid du Colombierpassed a parameter of tot_trks (which is the total number of tracks on 98*9a747e4fSDavid du Colombierthe CD), and returns the discid integer number. 99*9a747e4fSDavid du Colombier 100*9a747e4fSDavid du ColombierIt is assumed that cdtoc[] is an array of data structures (records) 101*9a747e4fSDavid du Colombiercontaining the fields min, sec and frame, which are the minute, second 102*9a747e4fSDavid du Colombierand frame offsets (the starting location) of each track. This 103*9a747e4fSDavid du Colombierinformation is read from the TOC of the CD. There are actually 104*9a747e4fSDavid du Colombiertot_trks + 1 "active" elements in the array, the last one being the 105*9a747e4fSDavid du Colombieroffset of the lead-out (also known as track 0xAA). 106*9a747e4fSDavid du Colombier 107*9a747e4fSDavid du ColombierThe function loops through each track in the TOC, and for each track 108*9a747e4fSDavid du Colombierit takes the (M * 60) + S (total offset in seconds) of the track and 109*9a747e4fSDavid du Colombierfeeds it to cddb_sum() function, which simply adds the value of each digit 110*9a747e4fSDavid du Colombierin the decimal string representation of the number. A running sum of this 111*9a747e4fSDavid du Colombierresult for each track is kept in the variable n. 112*9a747e4fSDavid du Colombier 113*9a747e4fSDavid du ColombierAt the end of the loop: 114*9a747e4fSDavid du Colombier1. t is calculated by subtracting the (M * 60) + S offset of the lead-out 115*9a747e4fSDavid du Colombierminus the (M * 60) + S offset of first track (yielding the length of 116*9a747e4fSDavid du Colombierthe disc in seconds). 117*9a747e4fSDavid du Colombier 118*9a747e4fSDavid du Colombier2. The result of (n modulo FFh) is left-shifted by 24 bits. 119*9a747e4fSDavid du Colombier 120*9a747e4fSDavid du Colombier3. t is left shifted by 8. 121*9a747e4fSDavid du Colombier 122*9a747e4fSDavid du ColombierThe bitwise-OR operation of result 2., 3. and the tot_trks number is 123*9a747e4fSDavid du Colombierused as the discid. 124*9a747e4fSDavid du Colombier 125*9a747e4fSDavid du ColombierThe discid is represented in hexadecimal form for the purpose of 126*9a747e4fSDavid du Colombierxmcd cddb file names and the DISCID= field in the xmcd cddb file itself. 127*9a747e4fSDavid du ColombierIf the hexadecimal string is less than 8 characters long, it is 128*9a747e4fSDavid du Colombierzero-padded to 8 characters (i.e., 3a8f07 becomes 003a8f07). All 129*9a747e4fSDavid du Colombieralpha characters in the string should be in lower case, where 130*9a747e4fSDavid du Colombierapplicable. 131*9a747e4fSDavid du Colombier 132*9a747e4fSDavid du ColombierImportant note for clients using the MS-Windows MCI interface: 133*9a747e4fSDavid du Colombier 134*9a747e4fSDavid du ColombierThe Windows MCI interface does not provide the MSF location of the 135*9a747e4fSDavid du Colombierlead-out. Thus, you must compute the lead-out location by taking the 136*9a747e4fSDavid du Colombierstarting position of the last track and add the length of the last track 137*9a747e4fSDavid du Colombierto it. However, the MCI interface returns the length of the last track 138*9a747e4fSDavid du Colombieras ONE FRAME SHORT of the actual length found in the CD's TOC. In most 139*9a747e4fSDavid du Colombiercases this does not affect the disc ID generated, because we truncate 140*9a747e4fSDavid du Colombierthe frame count when computing the disc ID anyway. However, if the 141*9a747e4fSDavid du Colombierlead-out track has an actual a frame count of 0, the computed quantity 142*9a747e4fSDavid du Colombier(based on the MSF data returned from the MCI interface) would result in 143*9a747e4fSDavid du Colombierthe seconds being one short and the frame count be 74. For example, 144*9a747e4fSDavid du Colombiera CD with the last track at an offset of 48m 32s 12f and having a 145*9a747e4fSDavid du Colombiertrack length of 2m 50s 63f has a lead-out offset of 51m 23s 0f. Windows 146*9a747e4fSDavid du ColombierMCI incorrectly reports the length as 2m 50s 62f, which would yield a 147*9a747e4fSDavid du Colombierlead-out offset of 51m 22s 74f, which causes the resulting truncated 148*9a747e4fSDavid du Colombierdisc length to be off by one second. This will cause an incorrect disc 149*9a747e4fSDavid du ColombierID to be generated. You should thus add one frame to the length of the 150*9a747e4fSDavid du Colombierlast track when computing the location of the lead-out. 151*9a747e4fSDavid du Colombier 152*9a747e4fSDavid du ColombierThe easiest way for Windows clients to compute the lead-out given information 153*9a747e4fSDavid du Colombierin MSF format is like this: 154*9a747e4fSDavid du Colombier 155*9a747e4fSDavid du Colombier(offset_minutes * 60 * 75) + (offset_seconds * 75) + offset_frames + 156*9a747e4fSDavid du Colombier(length_minutes * 60 * 75) + (length_seconds * 75) + length_frames + 1 = X 157*9a747e4fSDavid du Colombier 158*9a747e4fSDavid du ColombierWhere X is the offset of the lead-out in frames. To find the lead-out in 159*9a747e4fSDavid du Colombierseconds, simply divide by 75 and discard the remainder. 160