RIP freedb.org -- Add notes/todos re migrating to MusicBrainz
[zcdrip] / zdiscid.c
1 /* zdiscid.c -- Print the CDDB disc ID for an audio CD  */
2
3 /* 
4  * Copyright (C) 2006 - 2011 Steve Youngs
5  */
6
7 /* 
8  * Author:        Steve Youngs <steve@steveyoungs.com>
9  * Maintainer:    Steve Youngs <steve@steveyoungs.com>
10  * Created:       <2006-08-13>
11  */
12  
13 /*
14  * This file is part of zcdrip.  
15
16  * Redistribution and use in source and binary forms, with or without  
17  * modification, are permitted provided that the following conditions  
18  * are met:  
19
20  * 1. Redistributions of source code must retain the above copyright  
21  *    notice, this list of conditions and the following disclaimer.  
22
23  * 2. Redistributions in binary form must reproduce the above copyright  
24  *    notice, this list of conditions and the following disclaimer in the  
25  *    documentation and/or other materials provided with the distribution.  
26
27  * 3. Neither the name of the author nor the names of any contributors  
28  *    may be used to endorse or promote products derived from this  
29  *    software without specific prior written permission.  
30
31  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR  
32  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
33  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
34  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  
35  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR  
36  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF  
37  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
38  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
39  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
40  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN  
41  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
42  */
43
44 /*
45  * Commentary:
46  *  
47  *   Print the CDDB disc ID for an audio CD.
48  */
49
50 /* Code: */
51 #include <stdio.h>
52 #include <fcntl.h>
53 #include <unistd.h>
54 #include <sys/ioctl.h>
55 #include <linux/cdrom.h>
56
57 #define FAILURE_NOCD -1
58
59 struct toc {
60         int min, sec, frame;
61 } cdtoc[100];
62
63 int read_toc();
64 int cddb_sum(int);
65 unsigned get_cddb_id(int);
66
67 int
68 read_toc()
69 {
70         int drive = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
71         struct cdrom_tochdr tochdr;
72         struct cdrom_tocentry tocentry;
73         int i;
74
75         if (ioctl(drive, CDROMREADTOCHDR, &tochdr) != 0) {
76                 fprintf(stderr, "No disc in drive\n");
77                 close(drive);
78                 return FAILURE_NOCD;
79         }
80
81         for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
82                 tocentry.cdte_track = i;
83                 tocentry.cdte_format = CDROM_MSF;
84                 ioctl(drive, CDROMREADTOCENTRY, &tocentry);
85                 cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
86                 cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
87                 cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
88                 cdtoc[i-1].frame += cdtoc[i-1].min * 60 * 75;
89                 cdtoc[i-1].frame += cdtoc[i-1].sec * 75;
90         }
91         tocentry.cdte_track = 0xAA;
92         tocentry.cdte_format = CDROM_MSF;
93         ioctl(drive, CDROMREADTOCENTRY, &tocentry);
94         cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
95         cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
96         cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
97         cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min * 60 * 75;
98         cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec * 75;
99         close(drive);
100         return tochdr.cdth_trk1;
101 }
102
103 int
104 cddb_sum(int n)
105 {
106         int ret = 0;
107
108         while (n > 0) {
109                 ret = ret + (n % 10);
110                 n = n / 10;
111         }
112
113         return ret;
114 }
115
116 unsigned
117 get_cddb_id(int ntrks)
118 {
119         int i, t, n;
120         
121         i = t = n = 0;
122
123         while (i < ntrks) {
124                 n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
125                 i++;
126         }
127
128         t = ((cdtoc[ntrks].min * 60) + cdtoc[ntrks].sec) -
129                 ((cdtoc[0].min * 60) + cdtoc[0].sec);
130
131         return ((n % 0xff) << 24 | t << 8 | ntrks);
132 }
133
134 int
135 main(int argc, char **argv)
136 {
137         int ntrks, i;
138
139         ntrks = read_toc();
140
141         switch (ntrks) {
142         case 0:
143         case 1:
144                 fprintf(stderr, "Disc is not an audio CD\n");
145                 return 1;
146         case -1:
147                 return ntrks;
148         default:
149                 break;
150         }
151
152         printf("%08x %d", get_cddb_id(ntrks), ntrks);
153         for (i = 0; i < ntrks; i++) {
154                 printf(" %d", cdtoc[i].frame);
155         }
156         printf(" %d\n", (cdtoc[ntrks].frame) / 75);
157         return 0;
158 }
159
160 /* zdiscid.c ends here */
161