/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "PWSubChannel96.h" #include #include #include #include "log.h" PWSubChannel96::PWSubChannel96() { memset(data_, 0, 96); type_ = QMODE1DATA; } PWSubChannel96::PWSubChannel96(unsigned char *buf) { init(buf); } void PWSubChannel96::init(unsigned char *buf) { memcpy(data_, buf, 96); switch (getChannelByte(Q_CHAN, 0) & 0x0f) { case 1: type_ = QMODE1DATA; break; case 2: type_ = QMODE2; break; case 3: type_ = QMODE3; break; case 5: type_ = QMODE5TOC; break; default: type_ = QMODE_ILLEGAL; break; } } PWSubChannel96::~PWSubChannel96() { } SubChannel *PWSubChannel96::makeSubChannel(Type t) { PWSubChannel96 *chan = new PWSubChannel96; chan->type_ = t; switch (t) { case QMODE1TOC: case QMODE1DATA: chan->setChannelByte(Q_CHAN, 0, 0x01); break; case QMODE2: chan->setChannelByte(Q_CHAN, 0, 0x02); break; case QMODE3: chan->setChannelByte(Q_CHAN, 0, 0x03); break; case QMODE5TOC: chan->setChannelByte(Q_CHAN, 0, 0x05); break; case QMODE_ILLEGAL: chan->setChannelByte(Q_CHAN, 0, 0x00); break; } return chan; } SubChannel *PWSubChannel96::makeSubChannel(unsigned char *buf) { PWSubChannel96 *chan = new PWSubChannel96(buf); return chan; } void PWSubChannel96::setChannelByte(Channel chan, int byteNr, unsigned char value) { assert(byteNr >= 0 && byteNr < 12); register unsigned char setMask = 1 << chan; register unsigned char clearMask = ~setMask; register unsigned char *p = data_ + (byteNr * 8); register int i; for (i = 0; i < 8; i++) { if (value & 0x80) *p |= setMask; else *p &= clearMask; p++; value <<= 1; } } unsigned char PWSubChannel96::getChannelByte(Channel chan, int byteNr) const { assert(byteNr >= 0 && byteNr < 12); register unsigned char testMask = 1 << chan; register const unsigned char *p = data_ + (byteNr * 8); register unsigned char val = 0; register int i; for (i = 0; i < 8; i++) { val <<= 1; if ((*p) & testMask) val |= 0x01; p++; } return val; } const unsigned char *PWSubChannel96::data() const { return data_; } long PWSubChannel96::dataLength() const { return 96; } // calculate the crc over Q sub channel bytes 0-9 and stores it in byte 10,11 void PWSubChannel96::calcCrc() { register unsigned short crc = 0; register int i; for (i = 0; i < 10; i++) { register unsigned char data = getChannelByte(Q_CHAN, i); crc = crctab[(crc >> 8) ^ data] ^ (crc << 8); } crc = ~crc; setChannelByte(Q_CHAN, 10, crc >> 8); setChannelByte(Q_CHAN, 11, crc); } int PWSubChannel96::checkCrc() const { register unsigned short crc = 0; register int i; if (!crcValid_) { return 1; } for (i = 0; i < 10; i++) { register unsigned char data = getChannelByte(Q_CHAN, i); crc = crctab[(crc >> 8) ^ data] ^ (crc << 8); } crc = ~crc; if (getChannelByte(Q_CHAN, 10) == (crc >> 8) && getChannelByte(Q_CHAN, 11) == (crc & 0xff)) return 1; else return 0; } // sets P channel bit void PWSubChannel96::pChannel(int f) { register int i; if (f != 0) { for (i = 0; i < 96; i++) data_[i] |= 0x80; } else { for (i = 0; i < 96; i++) data_[i] &= 0x7f; } } // returns Q type SubChannel::Type PWSubChannel96::type() const { return type_; } // set Q type void PWSubChannel96::type(unsigned char type) { switch (type & 0x0f) { case 1: type_ = QMODE1DATA; break; case 2: type_ = QMODE2; break; case 3: type_ = QMODE3; break; case 5: type_ = QMODE5TOC; break; default: type_ = QMODE_ILLEGAL; break; } register unsigned char val = getChannelByte(Q_CHAN, 0); val &= 0xf0; val |= type & 0x0f; setChannelByte(Q_CHAN, 0, val); } // function for setting various Q sub channel fields void PWSubChannel96::ctl(int c) { assert((c & 0x0f) == 0); register unsigned char val = getChannelByte(Q_CHAN, 0); val &= 0x0f; val |= c & 0xf0; setChannelByte(Q_CHAN, 0, val); } unsigned char PWSubChannel96::ctl() const { register unsigned char val = getChannelByte(Q_CHAN, 0); return val >> 4; } void PWSubChannel96::trackNr(int t) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 1, bcd(t)); } int PWSubChannel96::trackNr() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 1)); } void PWSubChannel96::indexNr(int i) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 2, bcd(i)); } int PWSubChannel96::indexNr() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 2)); } void PWSubChannel96::point(int p) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 2, bcd(p)); } void PWSubChannel96::min(int m) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 3, bcd(m)); } int PWSubChannel96::min() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(getChannelByte(Q_CHAN, 3)); } void PWSubChannel96::sec(int s) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 4, bcd(s)); } int PWSubChannel96::sec() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(getChannelByte(Q_CHAN, 4)); } void PWSubChannel96::frame(int f) { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 5, bcd(f)); } int PWSubChannel96::frame() const { assert(type_ == QMODE1TOC || type_ == QMODE1DATA || type_ == QMODE5TOC); return bcd2int(getChannelByte(Q_CHAN, 5)); } void PWSubChannel96::zero(int z) { assert(type_ == QMODE5TOC); setChannelByte(Q_CHAN, 6, bcd(z)); } void PWSubChannel96::amin(int am) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 7, bcd(am)); } int PWSubChannel96::amin() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 7)); } void PWSubChannel96::asec(int as) { assert(type_ == QMODE1DATA); setChannelByte(Q_CHAN, 8, bcd(as)); } int PWSubChannel96::asec() const { assert(type_ == QMODE1DATA); return bcd2int(getChannelByte(Q_CHAN, 8)); } void PWSubChannel96::aframe(int af) { assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3); setChannelByte(Q_CHAN, 9, bcd(af)); } int PWSubChannel96::aframe() const { assert(type_ == QMODE1DATA || type_ == QMODE2 || type_ == QMODE3); return bcd2int(getChannelByte(Q_CHAN, 9)); } void PWSubChannel96::pmin(int pm) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 7, bcd(pm)); } void PWSubChannel96::psec(int ps) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 8, bcd(ps)); } void PWSubChannel96::pframe(int pf) { assert(type_ == QMODE1TOC || type_ == QMODE5TOC); setChannelByte(Q_CHAN, 9, bcd(pf)); } void PWSubChannel96::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) { assert(type_ == QMODE2); unsigned char buf[8]; int i; encodeCatalogNumber(buf, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13); buf[7] = 0; for (i = 0; i < 8; i++) setChannelByte(Q_CHAN, i + 1, buf[i]); } const char *PWSubChannel96::catalog() const { static char buf[14]; unsigned char in[7]; int i; for (i = 0; i < 7; i++) in[i] = getChannelByte(Q_CHAN, i + 1); decodeCatalogNumber(in, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11], &buf[12]); buf[13] = 0; return buf; } void PWSubChannel96::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) { assert(type_ == QMODE3); unsigned char buf[8]; int i; encodeIsrcCode(buf, c1, c2, o1, o2, o3, y1, y2, s1, s2, s3, s4, s5); for (i = 0; i < 8; i++) setChannelByte(Q_CHAN, i + 1, buf[i]); } const char *PWSubChannel96::isrc() const { static char buf[13]; unsigned char in[8]; int i; assert(type_ == QMODE3); for (i = 0; i < 8; i++) in[i] = getChannelByte(Q_CHAN, i + 1); decodeIsrcCode(in, &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], &buf[10], &buf[11]); buf[12] = 0; return buf; } void PWSubChannel96::print() const { if (type_ != QMODE_ILLEGAL) log_message(0, "P:%02x ", getChannelByte(P_CHAN, 0)); switch (type_) { case QMODE1TOC: case QMODE1DATA: case QMODE5TOC: log_message(0, "Q: (%02x) %02x,%02x %02x:%02x:%02x %02x %02x:%02x:%02x ", getChannelByte(Q_CHAN, 0), getChannelByte(Q_CHAN, 1), getChannelByte(Q_CHAN, 2), getChannelByte(Q_CHAN, 3), getChannelByte(Q_CHAN, 4), getChannelByte(Q_CHAN, 5), getChannelByte(Q_CHAN, 6), getChannelByte(Q_CHAN, 7), getChannelByte(Q_CHAN, 8), getChannelByte(Q_CHAN, 9)); break; case QMODE2: log_message(0, "Q: (%02x) MCN: %s %02x ", getChannelByte(Q_CHAN, 0), catalog(), getChannelByte(Q_CHAN, 9)); break; case QMODE3: log_message(0, "Q: (%02x) ISRC: %s %02x ", getChannelByte(Q_CHAN, 0), isrc(), getChannelByte(Q_CHAN, 9)); break; case QMODE_ILLEGAL: log_message(0, "INVALID QMODE: %02x", getChannelByte(Q_CHAN, 0)); break; } if (type_ != QMODE_ILLEGAL) log_message(0, "%04x %d", (getChannelByte(Q_CHAN, 10) << 8) | getChannelByte(Q_CHAN, 11), checkCrc()); } // sets R-W channel bits from 72 byte data buffer, used for CD-TEXT void PWSubChannel96::setRawRWdata(const unsigned char *data) { int i; for (i = 0; i < 96; i += 4) { data_[i] |= (data[0] >> 2) & 0x3f; data_[i + 1] |= ((data[0] << 4) & 0x30) | ((data[1] >> 4) & 0x0f); data_[i + 2] |= ((data[1] << 2) & 0x3c) | ((data[2] >> 6) & 0x03); data_[i + 3] |= data[2] & 0x3f; data += 3; } } // concatenates the R-W channel bits and writes them to provided 72 byte buffer void PWSubChannel96::getRawRWdata(unsigned char *data) const { int i; for (i = 0; i < 96; i += 4) { data[0] = ((data_[i] << 2) & 0xfc) | ((data_[i + 1] >> 4) & 0x03); data[1] = ((data_[i + 1] << 4) & 0xf0) | ((data_[i + 2] >> 2) & 0x0f); data[2] = ((data_[i + 2] << 6) & 0xc0) | (data_[i + 3] & 0x3f); data += 3; } }