1 /* cdrdao - write audio CD-Rs in disc-at-once mode
2 *
3 * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "PQSubChannel16.h"
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <assert.h>
25
26 #include "log.h"
27
PQSubChannel16()28 PQSubChannel16::PQSubChannel16()
29 {
30 memset(data_, 0, 16);
31 type_ = QMODE1DATA;
32 }
33
34
~PQSubChannel16()35 PQSubChannel16::~PQSubChannel16()
36 {
37 }
38
makeSubChannel(Type t)39 SubChannel *PQSubChannel16::makeSubChannel(Type t)
40 {
41 PQSubChannel16 *chan = new PQSubChannel16;
42
43 chan->type_ = t;
44
45 switch (t) {
46 case QMODE1TOC:
47 case QMODE1DATA:
48 chan->data_[0] = 0x01;
49 break;
50
51 case QMODE2:
52 chan->data_[0] = 0x02;
53 break;
54
55 case QMODE3:
56 chan->data_[0] = 0x03;
57 break;
58
59 case QMODE5TOC:
60 chan->data_[0] = 0x05;
61 break;
62
63 case QMODE_ILLEGAL:
64 chan->data_[0] = 0x00;
65 break;
66 }
67
68 return chan;
69 }
70
init(unsigned char * buf)71 void PQSubChannel16::init(unsigned char *buf)
72 {
73 memcpy(data_, buf, 16);
74
75 switch (data_[0] & 0x0f) {
76 case 1:
77 type_ = QMODE1DATA;
78 break;
79
80 case 2:
81 type_ = QMODE2;
82 break;
83
84 case 3:
85 type_ = QMODE3;
86 break;
87
88 case 5:
89 type_ = QMODE5TOC;
90 break;
91
92 default:
93 type_ = QMODE_ILLEGAL;
94 break;
95 }
96 }
97
makeSubChannel(unsigned char * buf)98 SubChannel *PQSubChannel16::makeSubChannel(unsigned char *buf)
99 {
100 PQSubChannel16 *chan = new PQSubChannel16;
101
102 chan->init(buf);
103
104 return chan;
105 }
106
107
data() const108 const unsigned char *PQSubChannel16::data() const
109 {
110 return data_;
111 }
112
dataLength() const113 long PQSubChannel16::dataLength() const
114 {
115 return 16;
116 }
117
118 // calculate the crc over Q sub channel bytes 0-9 and stores it in byte 10,11
calcCrc()119 void PQSubChannel16::calcCrc()
120 {
121 register unsigned short crc = 0;
122 register int i;
123
124 for (i = 0; i < 10; i++) {
125 crc = crctab[(crc >> 8) ^ data_[i]] ^ (crc << 8);
126 }
127
128 data_[10] = crc >> 8;
129 data_[11] = crc;
130 }
131
checkCrc() const132 int PQSubChannel16::checkCrc() const
133 {
134 register unsigned short crc = 0;
135 register int i;
136
137 if (!crcValid_) {
138 return 1;
139 }
140
141 for (i = 0; i < 10; i++) {
142 crc = crctab[(crc >> 8) ^ data_[i]] ^ (crc << 8);
143 }
144
145 if (data_[10] == (crc >> 8) && data_[11] == (crc & 0xff))
146 return 1;
147 else
148 return 0;
149 }
150
151 // returns Q type
type() const152 SubChannel::Type PQSubChannel16::type() const
153 {
154 return type_;
155 }
156
157 // set Q type
type(unsigned char type)158 void PQSubChannel16::type(unsigned char type)
159 {
160 switch (type & 0x0f) {
161 case 1:
162 type_ = QMODE1DATA;
163 break;
164
165 case 2:
166 type_ = QMODE2;
167 break;
168
169 case 3:
170 type_ = QMODE3;
171 break;
172
173 case 5:
174 type_ = QMODE5TOC;
175 break;
176
177 default:
178 type_ = QMODE_ILLEGAL;
179 break;
180 }
181
182 data_[0] &= 0xf0;
183 data_[0] |= type & 0x0f;
184 }
185
186 // sets P channel bit
pChannel(int f)187 void PQSubChannel16::pChannel(int f)
188 {
189 data_[15] = f != 0 ? 0x80 : 0;
190 }
191
192
193 // function for setting various Q sub channel fields
194
ctl(int c)195 void PQSubChannel16::ctl(int c)
196 {
197 assert((c & 0x0f) == 0);
198
199 data_[0] &= 0x0f;
200 data_[0] |= c & 0xf0;
201 }
202
ctl() const203 unsigned char PQSubChannel16::ctl() const
204 {
205 return data_[0] >> 4;
206 }
207
trackNr(int t)208 void PQSubChannel16::trackNr(int t)
209 {
210 assert(type_ == QMODE1DATA);
211 data_[1] = bcd(t);
212 }
213
trackNr() const214 int PQSubChannel16::trackNr() const
215 {
216 assert(type_ == QMODE1DATA);
217 return bcd2int(data_[1]);
218 }
219
indexNr(int i)220 void PQSubChannel16::indexNr(int i)
221 {
222 assert(type_ == QMODE1DATA);
223 data_[2] = bcd(i);
224 }
225
indexNr() const226 int PQSubChannel16::indexNr() const
227 {
228 assert(type_ == QMODE1DATA);
229 return bcd2int(data_[2]);
230 }
231
point(int p)232 void PQSubChannel16::point(int p)
233 {
234 assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
235 data_[2] = bcd(p);
236 }
237
min(int m)238 void PQSubChannel16::min(int m)
239 {
240 assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
241 data_[3] = bcd(m);
242 }
243
min() const244 int PQSubChannel16::min() const
245 {
246 assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
247 return bcd2int(data_[3]);
248 }
249
sec(int s)250 void PQSubChannel16::sec(int s)
251 {
252 assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
253 data_[4] = bcd(s);
254 }
255
sec() const256 int PQSubChannel16::sec() const
257 {
258 assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
259 return bcd2int(data_[4]);
260 }
261
frame(int f)262 void PQSubChannel16::frame(int f)
263 {
264 assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
265 data_[5] = bcd(f);
266 }
267
frame() const268 int PQSubChannel16::frame() const
269 {
270 assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC);
271 return bcd2int(data_[5]);
272 }
273
zero(int z)274 void PQSubChannel16::zero(int z)
275 {
276 assert(type_ == QMODE5TOC);
277 data_[6] = bcd(z);
278 }
279
amin(int am)280 void PQSubChannel16::amin(int am)
281 {
282 assert(type_ == QMODE1DATA);
283 data_[7] = bcd(am);
284 }
285
amin() const286 int PQSubChannel16::amin() const
287 {
288 assert(type_ == QMODE1DATA);
289 return bcd2int(data_[7]);
290 }
291
asec(int as)292 void PQSubChannel16::asec(int as)
293 {
294 assert(type_ == QMODE1DATA);
295 data_[8] = bcd(as);
296 }
297
asec() const298 int PQSubChannel16::asec() const
299 {
300 assert(type_ == QMODE1DATA);
301 return bcd2int(data_[8]);
302 }
303
aframe(int af)304 void PQSubChannel16::aframe(int af)
305 {
306 assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3);
307 data_[9] = bcd(af);
308 }
309
aframe() const310 int PQSubChannel16::aframe() const
311 {
312 assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3);
313 return bcd2int(data_[9]);
314 }
315
pmin(int pm)316 void PQSubChannel16::pmin(int pm)
317 {
318 assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
319 data_[7] = bcd(pm);
320 }
321
psec(int ps)322 void PQSubChannel16::psec(int ps)
323 {
324 assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
325 data_[8] = bcd(ps);
326 }
327
pframe(int pf)328 void PQSubChannel16::pframe(int pf)
329 {
330 assert(type_ == QMODE1TOC || type_ == QMODE5TOC);
331 data_[9] = bcd(pf);
332 }
333
catalog(char n1,char n2,char n3,char n4,char n5,char n6,char n7,char n8,char n9,char n10,char n11,char n12,char n13)334 void PQSubChannel16::catalog(char n1, char n2, char n3, char n4, char n5,
335 char n6, char n7, char n8, char n9, char n10,
336 char n11, char n12, char n13)
337 {
338 assert(type_ == QMODE2);
339
340 encodeCatalogNumber(data_ + 1, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10,
341 n11, n12, n13);
342 data_[8] = 0;
343 }
344
catalog() const345 const char *PQSubChannel16::catalog() const
346 {
347 static char buf[14];
348
349 assert(type_ == QMODE2);
350
351 decodeCatalogNumber(data_ + 1, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4],
352 &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10],
353 &buf[11], &buf[12]);
354
355 buf[13] = 0;
356
357 return buf;
358 }
359
isrc(char c1,char c2,char o1,char o2,char o3,char y1,char y2,char s1,char s2,char s3,char s4,char s5)360 void PQSubChannel16::isrc(char c1, char c2, char o1, char o2, char o3,
361 char y1, char y2, char s1, char s2, char s3,
362 char s4, char s5)
363 {
364 assert(type_ == QMODE3);
365
366 encodeIsrcCode(data_ + 1, c1, c2, o1, o2, o3, y1, y2, s1, s2, s3, s4, s5);
367 }
368
369
isrc() const370 const char *PQSubChannel16::isrc() const
371 {
372 static char buf[13];
373
374 assert(type_ == QMODE3);
375
376 decodeIsrcCode(data_ + 1, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4],
377 &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10],
378 &buf[11]);
379 buf[12] = 0;
380
381 return buf;
382 }
383
384
print() const385 void PQSubChannel16::print() const
386 {
387 if (type_ != QMODE_ILLEGAL)
388 log_message(0, "P:%02x ", data_[15]);
389
390 switch (type_) {
391 case QMODE1TOC:
392 case QMODE1DATA:
393 case QMODE5TOC:
394 log_message(0, "Q: (%02x) %02x,%02x %02x:%02x:%02x %02x %02x:%02x:%02x ",
395 data_[0], data_[1], data_[2], data_[3], data_[4], data_[5],
396 data_[6], data_[7], data_[8], data_[9]);
397 break;
398 case QMODE2:
399 log_message(0, "Q: (%02x) MCN: %s %02x ", data_[0], catalog(), data_[9]);
400 break;
401 case QMODE3:
402 log_message(0, "Q: (%02x) ISRC: %s %02x ", data_[0], isrc(), data_[9]);
403 break;
404 case QMODE_ILLEGAL:
405 log_message(0, "INVALID QMODE: %02x", data_[0]);
406 break;
407 }
408
409 if (type_ != QMODE_ILLEGAL)
410 log_message(0, "%04x %d", (data_[10] << 8) | data_[11], checkCrc());
411 }
412
checkConsistency()413 int PQSubChannel16::checkConsistency()
414 {
415 switch (type_) {
416 case QMODE1DATA:
417 if (!isBcd(data_[3]) || !isBcd(data_[4]) || !isBcd(data_[5]) ||
418 !isBcd(data_[7]) || !isBcd(data_[8]) || !isBcd(data_[9]))
419 return 0;
420 break;
421
422 case QMODE1TOC:
423 case QMODE2:
424 case QMODE3:
425 case QMODE5TOC:
426 case QMODE_ILLEGAL:
427 // no checks, yet
428 break;
429 }
430
431 return SubChannel::checkConsistency();
432 }
433