xref: /plan9-contrib/acme/bin/source/acd/discid (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
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