/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 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 #include #include #include "PlextorReaderScan.h" #include "PWSubChannel96.h" #include "PQSubChannel16.h" #include "Toc.h" #include "util.h" PlextorReaderScan::PlextorReaderScan(ScsiIf *scsiIf, unsigned long options) : PlextorReader(scsiIf, options) { int i; driverName_ = "Plextor CD-ROM Reader (scanning) - Version 1.0"; for (i = 0; i < maxScannedSubChannels_; i++) { if (options_ & OPT_PLEX_USE_PQ) scannedSubChannels_[i] = new PQSubChannel16; else scannedSubChannels_[i] = new PWSubChannel96; } } PlextorReaderScan::~PlextorReaderScan() { int i; for (i = 0; i < maxScannedSubChannels_; i++) { delete scannedSubChannels_[i]; scannedSubChannels_[i] = NULL; } } // static constructor CdrDriver *PlextorReaderScan::instance(ScsiIf *scsiIf, unsigned long options) { return new PlextorReaderScan(scsiIf, options); } Toc *PlextorReaderScan::readDisk(int session, const char *fname) { Toc *toc = CdrDriver::readDisk(session, fname); setBlockSize(MODE1_BLOCK_LEN); return toc; } int PlextorReaderScan::analyzeTrack(TrackData::Mode mode, int trackNr, long startLba, long endLba, Msf *indexIncrements, int *indexIncrementCnt, long *pregap, char *isrcCode, unsigned char *ctl) { int ret = analyzeTrackScan(mode, trackNr, startLba, endLba, indexIncrements, indexIncrementCnt, pregap, isrcCode, ctl); if ((options_ & OPT_PLEX_READ_ISRC) || ((options_ & OPT_PLEX_USE_PQ) && !(options_ & OPT_PLEX_PQ_BCD))) { // The ISRC code is usually not usable if the PQ channel data is // converted to hex numbers by the drive. Read them with the // appropriate command in this case *isrcCode = 0; if (mode == TrackData::AUDIO) readIsrc(trackNr, isrcCode); } return ret; } int PlextorReaderScan::readSubChannels(TrackData::SubChannelMode sm, long lba, long len, SubChannel ***chans, Sample *audioData) { unsigned char cmd[12]; int i; int retries = 5; long blockLen; if (options_ & OPT_PLEX_USE_PQ) blockLen = AUDIO_BLOCK_LEN + 16; else blockLen = AUDIO_BLOCK_LEN + 96; cmd[0] = 0xd8; // READ CDDA cmd[1] = 0; cmd[2] = lba >> 24; cmd[3] = lba >> 16; cmd[4] = lba >> 8; cmd[5] = lba; cmd[6] = 0; cmd[7] = len >> 16; cmd[8] = len >> 8; cmd[9] = len; if (options_ & OPT_PLEX_USE_PQ) cmd[10] = 0x01; else cmd[10] = 0x02; cmd[11] = 0; while (1) { if (sendCmd(cmd, 12, NULL, 0, transferBuffer_, len * blockLen, retries == 0 ? 1 : 0) != 0) { if (retries == 0) return 1; } else { break; } retries--; } #if 0 if (lba > 5000) { char fname[200]; sprintf(fname, "testout_%ld", lba); FILE *fp = fopen(fname, "w"); fwrite(transferBuffer_, blockLen, len, fp); fclose(fp); } #endif unsigned char *p = transferBuffer_ + AUDIO_BLOCK_LEN; for (i = 0; i < len; i++) { if (options_ & OPT_PLEX_USE_PQ) { if (!(options_ & OPT_PLEX_PQ_BCD)) { // Numbers in sub-channel data are hex instead of BCD. // We have to convert them back to BCD for the 'SubChannel' class. p[1] = SubChannel::bcd(p[1]); p[2] = SubChannel::bcd(p[2]); p[3] = SubChannel::bcd(p[3]); p[4] = SubChannel::bcd(p[4]); p[5] = SubChannel::bcd(p[5]); p[6] = SubChannel::bcd(p[6]); p[7] = SubChannel::bcd(p[7]); p[8] = SubChannel::bcd(p[8]); p[9] = SubChannel::bcd(p[9]); } ((PQSubChannel16*)scannedSubChannels_[i])->init(p); if (scannedSubChannels_[i]->type() != SubChannel::QMODE_ILLEGAL) { // the CRC of the sub-channel data is usually invalid -> mark the // sub-channel object that it should not try to verify the CRC scannedSubChannels_[i]->crcInvalid(); } } else { ((PWSubChannel96*)scannedSubChannels_[i])->init(p); } p += blockLen; } if (audioData != NULL) { p = transferBuffer_; for (i = 0; i < len; i++) { memcpy(audioData, p, AUDIO_BLOCK_LEN); p += blockLen; audioData += SAMPLES_PER_BLOCK; } } *chans = scannedSubChannels_; return 0; } int PlextorReaderScan::readAudioRange(ReadDiskInfo *info, int fd, long start, long end, int startTrack, int endTrack, TrackInfo *trackInfo) { if (!onTheFly_) { if ((options_ & OPT_PLEX_READ_ISRC) || ((options_ & OPT_PLEX_USE_PQ) && !(options_ & OPT_PLEX_PQ_BCD))) { int t; message(1, "Analyzing..."); for (t = startTrack; t <= endTrack; t++) { long totalProgress; message(1, "Track %d...", t + 1); totalProgress = t * 1000; totalProgress /= info->tracks; sendReadCdProgressMsg(RCD_ANALYZING, info->tracks, t + 1, 0, totalProgress); trackInfo[t].isrcCode[0] = 0; readIsrc(t + 1, trackInfo[t].isrcCode); if (trackInfo[t].isrcCode[0] != 0) message(2, "Found ISRC code."); totalProgress = (t + 1) * 1000; totalProgress /= info->tracks; sendReadCdProgressMsg(RCD_ANALYZING, info->tracks, t + 1, 1000, totalProgress); } message(1, "Reading..."); } } return CdrDriver::readAudioRangeParanoia(info, fd, start, end, startTrack, endTrack, trackInfo); }