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