PQChannelEncoder.cc
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:12k
源码类别:

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1998  Andreas Mueller <mueller@daneb.ping.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.  * $Log: PQChannelEncoder.cc,v $
  21.  * Revision 1.3  1998/09/06 13:34:22  mueller
  22.  * Use 'message()' for printing messages.
  23.  *
  24.  * Revision 1.2  1998/08/30 19:10:32  mueller
  25.  * Added handling of Catalog Number and ISRC codes.
  26.  *
  27.  * Revision 1.1  1998/08/25 19:29:27  mueller
  28.  * Initial revision
  29.  *
  30.  */
  31. static char rcsid[] = "$Id: PQChannelEncoder.cc,v 1.3 1998/09/06 13:34:22 mueller Exp $";
  32. #include <config.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <assert.h>
  36. #include "PQChannelEncoder.h"
  37. #include "Msf.h"
  38. #include "Track.h"
  39. #include "util.h"
  40. PQChannelEncoder::PQChannelEncoder() 
  41. {
  42.   cueSheet_ = NULL;
  43.   cueSheetLen_ = 0;
  44.   toc_ = NULL;
  45.   tocLen_ = 0;
  46.   discType_ = 0;
  47.   current_ = NULL;
  48.   catalog_ = NULL;
  49.   isrc_ = NULL;
  50. }
  51. PQChannelEncoder::~PQChannelEncoder()
  52. {
  53.   int i;
  54.   for (i = 0; i < tocLen_; i++) {
  55.     delete toc_[i];
  56.   }
  57.   delete[] toc_;
  58.   delete[] cueSheet_;
  59.   delete current_;
  60.   delete catalog_;
  61.   delete isrc_;
  62. }
  63. int PQChannelEncoder::setCueSheet(SubChannel *chan, unsigned char discType, 
  64.   const unsigned char *sheet, int len,
  65.   const Msf &leadInStart)
  66. {
  67.   int tocEnt, i;
  68.   subChannel_ = chan;
  69.   if (!(discType == 0 || discType == 0x10 || discType == 0x20)) {
  70.     message(-3, "Illegal disc type.");
  71.     return 1;
  72.   }
  73.   if ((len % sizeof(CueSheetEntry)) != 0) {
  74.     message(-3, "Illegal cue sheet length.");
  75.     return 1;
  76.   }
  77.   discType_ = discType;
  78.   cueSheetLen_ = len / sizeof(CueSheetEntry);
  79.   cueSheet_ = new CueSheetEntry[cueSheetLen_ + 1];
  80.   memcpy(cueSheet_, sheet, len);
  81.   // mark end of queue sheet with a zeroed entry
  82.   memset(cueSheet_ + cueSheetLen_, 0, sizeof(CueSheetEntry));
  83.   // create some sub channel objects
  84.   catalog_ = subChannel_->makeSubChannel(SubChannel::QMODE2);
  85.   isrc_ = subChannel_->makeSubChannel(SubChannel::QMODE3);
  86.   current_ = subChannel_->makeSubChannel(SubChannel::QMODE1DATA);
  87.   
  88.   if (analyzeCueSheet() != 0) {
  89.     return 1;
  90.   }
  91.   // create PQ sub channels for toc in lead-in
  92.   tocLen_ = lastTrackNr_ - firstTrackNr_ + 1 + 3/*A0, A1, A2*/;
  93.   toc_ = new (SubChannel*)[tocLen_];
  94.   for (i = 0; i < tocLen_; i++) {
  95.     toc_[i] = subChannel_->makeSubChannel(SubChannel::QMODE1TOC);
  96.   }
  97.   CueSheetEntry *run;
  98.   for (run = actCueSheetEntry_, tocEnt = 0; 
  99.        (run->ctlAdr & 0x0f) != 1 || run->trackNr != 0xaa; run++) {
  100.     if ((run->ctlAdr & 0x0f) == 1 && run->trackNr > 0 && run->trackNr <= 99 &&
  101. run->indexNr == 1) {
  102.       toc_[tocEnt]->ctl(run->ctlAdr & 0xf0);
  103.       toc_[tocEnt]->point(run->trackNr);
  104.       toc_[tocEnt]->pmin(run->min);
  105.       toc_[tocEnt]->psec(run->sec);
  106.       toc_[tocEnt]->pframe(run->frame);
  107.       tocEnt++;
  108.     }
  109.   }
  110.   toc_[tocEnt]->point(0xa0);
  111.   toc_[tocEnt]->pmin(firstTrackNr_);
  112.   toc_[tocEnt]->psec(discType_);
  113.   tocEnt++;
  114.   toc_[tocEnt]->point(0xa1);
  115.   toc_[tocEnt]->pmin(lastTrackNr_);
  116.   tocEnt++;
  117.   toc_[tocEnt]->point(0xa2);
  118.   toc_[tocEnt]->pmin(leadOutStart_.min());
  119.   toc_[tocEnt]->psec(leadOutStart_.sec());
  120.   toc_[tocEnt]->pframe(leadOutStart_.frac());
  121.   tocEnt++;
  122.   assert(tocEnt == tocLen_);
  123.   // setup encoder dynamic data
  124.   abslba_ = leadInStart.lba() - 450150;
  125.   trlba_ = 0;
  126.   writeIsrc_ = 0;
  127.   deferredCatalog_ = 0;
  128.   deferredIsrc_ = 0;
  129.   actTocEnt_ = actTocCount_ = 0;
  130.   run = nextCueSheetEntry(actCueSheetEntry_, 1);
  131.   assert(run != NULL);
  132.   nextTransitionLba_ = Msf(run->min, run->sec, run->frame).lba() - 150;
  133.   run = nextCueSheetEntry(actCueSheetEntry_, firstTrackNr_, 1);
  134.   assert(run != NULL);
  135.   nextTrackStartLba_ = Msf(run->min, run->sec, run->frame).lba() - 150;
  136.   return 0;
  137. }
  138. int PQChannelEncoder::analyzeCueSheet()
  139. {
  140.   int i;
  141.   CueSheetEntry *ent;
  142.   int prevTrackNr = -1;
  143.   long prevLba = -1;
  144.   long lba;
  145.   firstTrackNr_ = 0;
  146.   lastTrackNr_ = 0;
  147.   leadOutStart_ = 0;
  148.   actCueSheetEntry_ = NULL;
  149.   writeCatalog_ = 0;
  150.   for (ent = cueSheet_, i = 0; i < cueSheetLen_; ent++, i++) {
  151.     switch (ent->ctlAdr & 0x0f) {
  152.     case 1:
  153.       if (ent->min > 89 || ent->sec > 59 || ent->frame > 74) {
  154. message(-3, "Illegal time field value at cue sheet entry: %d",
  155. i);
  156. return 1;
  157.       }
  158.       if (ent->trackNr == 0) { // indicates lead-in
  159. if (i == 0 || (writeCatalog_ && i == 2)) { // must be first entry
  160.   actCueSheetEntry_ = ent;
  161. }
  162. else {
  163.   message(-3, "Illegal track number at cue sheet entry: %d", i);
  164.   return 1;
  165. }
  166.       }
  167.       else if (ent->trackNr == 0xaa) { // indicates lead-out
  168. if (i == cueSheetLen_ - 1) { // must be last entry
  169.   leadOutStart_ = Msf(ent->min, ent->sec, ent->frame);
  170. }
  171. else {
  172.   message(-3, "Illegal track number at cue sheet entry: %d", i);
  173.   return 1;
  174. }
  175.       }
  176.       else if (ent->trackNr <= 99) { // data track
  177. if (firstTrackNr_ == 0) {
  178.   firstTrackNr_ = ent->trackNr;
  179.   prevTrackNr = ent->trackNr;
  180. }
  181. else {
  182.   if (ent->trackNr != prevTrackNr && ent->trackNr != prevTrackNr + 1) {
  183.     message(-3, 
  184.     "Wrong track number sequence at cue sheet entry: %d", i);
  185.     return 1;
  186.   }
  187.   prevTrackNr = ent->trackNr;
  188. }
  189. lastTrackNr_ = ent->trackNr;
  190.       }
  191.       else {
  192. message(-3, "Illegal track number at cue sheet entry: %d", i);
  193. return 1;
  194.       }
  195.       if (ent->trackNr != 0) {
  196. lba = Msf(ent->min, ent->sec, ent->frame).lba();
  197. if (lba <= prevLba) {
  198.   message(-3, 
  199.   "Time field does not increase at cue sheet entry: %d", i);
  200.   return 1;
  201. }
  202. prevLba = lba;
  203.       }
  204.       break;
  205.     case 2:
  206.       if (i != 0) {
  207. message(-3, "Catalog number must be first cue sheet entry.");
  208. return 1;
  209.       }
  210.       if ((cueSheet_[1].ctlAdr & 0x0f) != 2) {
  211. message(-3, "Missing second catalog number entry.");
  212. return 1;
  213.       }
  214.       writeCatalog_ = 1;
  215.       catalog_->catalog(ent->trackNr, ent->indexNr, ent->dataForm, ent->scms,
  216. ent->min, ent->sec, ent->frame, cueSheet_[1].trackNr,
  217. cueSheet_[1].indexNr, cueSheet_[1].dataForm,
  218. cueSheet_[1].scms, cueSheet_[1].min, cueSheet_[1].sec);
  219.       // skip next entry
  220.       ent++;
  221.       i++;
  222.       break;
  223.     case 3:
  224.       if (((ent + 1)->ctlAdr & 0x0f) != 3) {
  225. message(-3, "Missing second ISRC code entry.");
  226. return 1;
  227.       }
  228.       // skip next entry
  229.       ent++;
  230.       i++;
  231.       break;
  232.     default:
  233.       message(-3, "Illegal adr field at cue sheet entry: %d.", i);
  234.       return 1;
  235.       break;
  236.     }
  237.   }
  238.   if (actCueSheetEntry_ == NULL) {
  239.     message(-3, "Cue sheet contains no lead-in entry.");
  240.     return 1;
  241.   }
  242.   if (leadOutStart_.lba() == 0) {
  243.     message(-3, "Cue sheet contains no lead-out entry.");
  244.     return 1;
  245.   }
  246.   if (firstTrackNr_ == 0) {
  247.     message(-3, "Cue sheet contains no data track.");
  248.     return 1;
  249.   }
  250.   return 0;
  251. }
  252. void PQChannelEncoder::encode(long lba, unsigned char *in, long blocks,
  253.       unsigned char *out)
  254. {
  255.   long clen = subChannel_->dataLength();
  256.   long outBlockSize = AUDIO_BLOCK_LEN + clen;
  257.   long inBlockSize = AUDIO_BLOCK_LEN;
  258.   const SubChannel *chan;
  259.   long i;
  260.   
  261.   for (i = 0; i < blocks; i++, lba++) {
  262.     chan = encodeSubChannel(lba);
  263.     clen = chan->dataLength();
  264.     memcpy(out + i * outBlockSize, in + i * inBlockSize, inBlockSize);
  265.     memcpy(out + i * outBlockSize + inBlockSize, chan->data(), clen);
  266.   }
  267. }
  268. const SubChannel *PQChannelEncoder::encodeSubChannel(long lba)
  269. {
  270.   int newTransition = 0;
  271.   SubChannel *chan = NULL;
  272.   
  273.   // check consistency of internal lba with external lba
  274.   assert(lba == abslba_);
  275.   if (lba == nextTransitionLba_) {
  276.     // switch to next transition
  277.     //message(2, "Switching to next transition at lba: %ld", lba);
  278.     nextTransition();
  279.     newTransition = 1;
  280.   }
  281.   if (actCueSheetEntry_->trackNr == 0) {
  282.     // lead-in sector
  283.     chan = toc_[actTocEnt_];
  284.     Msf m(trlba_);
  285.     chan->min(m.min());
  286.     chan->sec(m.sec());
  287.     chan->frame(m.frac());
  288.     // advance to next to entry
  289.     if (++actTocCount_ == 3) {
  290.       actTocCount_ = 0;
  291.       if (++actTocEnt_ == tocLen_) {
  292. actTocEnt_ = 0;
  293.       }
  294.     }
  295.   }
  296.   else {
  297.     // data or lead-out sector
  298.     // Q channel setup
  299.     // catalog number
  300.     if (writeCatalog_ && 
  301. (deferredCatalog_ || (abslba_ % 90) == 0)) {
  302.       if (newTransition) {
  303. deferredCatalog_ = 1;
  304.       }
  305.       else {
  306. deferredCatalog_ = 0;
  307. chan = catalog_;
  308. chan->aframe(Msf(abslba_ + 150).frac());
  309.       }
  310.     }
  311.     // ISRC code
  312.     if (writeIsrc_ && 
  313. (deferredIsrc_ || (abslba_ % 90) == 50 || (abslba_ % 90) == -40)) {
  314.       if (newTransition) {
  315. deferredIsrc_ = 1;
  316.       }
  317.       else {
  318. deferredIsrc_ = 0;
  319. chan = isrc_;
  320. chan->aframe(Msf(abslba_ + 150).frac());
  321.       }
  322.     }
  323.     if (chan == NULL) {
  324.       // Current position
  325.       chan = current_;
  326.       Msf m(trlba_ < 0 ? -trlba_ : trlba_);
  327.       chan->min(m.min());
  328.       chan->sec(m.sec());
  329.       chan->frame(m.frac());
  330.       
  331.       m = Msf(abslba_ + 150);
  332.       chan->amin(m.min());
  333.       chan->asec(m.sec());
  334.       chan->aframe(m.frac());
  335.     }
  336.     // P channel setup
  337.     if (trlba_ <= 0 || 
  338. (abslba_ >= nextTrackStartLba_ - 150 && 
  339.  abslba_ <= nextTrackStartLba_)) {
  340.       // set P channel flag in pre-gap and 2 seconds before next track starts
  341.       chan->pChannel(1);
  342.     }
  343.     else if (abslba_ >= leadOutStart_.lba() ) {
  344.       // P channel flag is 0 2 secs from start of lead-out, after that
  345.       // flag alternates at 2 Hz.
  346.       chan->pChannel(((trlba_ - 150) % 38) < 19 ? 1 : 0);
  347.     }
  348.     else {
  349.       chan->pChannel(0);
  350.     }
  351.   }
  352.   abslba_++;
  353.   trlba_++;
  354.   assert(chan != NULL);
  355.   chan->calcCrc();
  356.   return chan;
  357. }
  358. void PQChannelEncoder::nextTransition()
  359. {
  360.   CueSheetEntry *nextEnt, *ent , *ent1;
  361.   nextEnt = nextCueSheetEntry(actCueSheetEntry_, 1);
  362.   assert(nextEnt != NULL);
  363.   if (nextEnt->trackNr != actCueSheetEntry_->trackNr) {
  364.     // new track started
  365.     // check for ISRC code cue sheet entry
  366.     if ((ent = nextCueSheetEntry(actCueSheetEntry_, 3)) != NULL &&
  367. ent->trackNr == nextEnt->trackNr) {
  368.       ent1 = ent + 1;
  369.       isrc_->isrc(ent->indexNr, ent->dataForm, ent->scms, ent->min, ent->sec,
  370.   ent->frame, ent1->indexNr, ent1->dataForm, ent1->scms,
  371.   ent1->min, ent1->sec, ent1->frame);
  372.       writeIsrc_ = 1;
  373.     }
  374.     else {
  375.       writeIsrc_ = 0;
  376.     }
  377.     deferredIsrc_ = 0;
  378.     // setup 'trlba'
  379.     if (nextEnt->indexNr == 0) {
  380.       // track has a pre-gap -> determine length
  381.       ent = nextCueSheetEntry(nextEnt, nextEnt->trackNr, 1);
  382.       assert(ent != NULL);
  383.       
  384.       trlba_ = Msf(nextEnt->min, nextEnt->sec, nextEnt->frame).lba() -
  385. Msf(ent->min, ent->sec, ent->frame).lba();
  386.     }
  387.     else {
  388.       trlba_ = 0;
  389.     }
  390.   }
  391.     
  392.   actCueSheetEntry_ = nextEnt;
  393.   
  394.   current_->ctl(actCueSheetEntry_->ctlAdr & 0xf0);
  395.   current_->trackNr(actCueSheetEntry_->trackNr);
  396.   current_->indexNr(actCueSheetEntry_->indexNr);
  397.   if (writeCatalog_)
  398.     catalog_->ctl(actCueSheetEntry_->ctlAdr & 0xf0);
  399.   if (writeIsrc_)
  400.     isrc_->ctl(actCueSheetEntry_->ctlAdr & 0xf0);
  401.   if (actCueSheetEntry_->trackNr != 0xaa) {
  402.     // find next transition point
  403.     ent = nextCueSheetEntry(actCueSheetEntry_, 1);
  404.     assert(ent != NULL);
  405.     nextTransitionLba_ = Msf(ent->min, ent->sec, ent->frame).lba() - 150;
  406.     if (actCueSheetEntry_->indexNr == 1) {
  407.       // find next track start lba
  408.       if (actCueSheetEntry_->trackNr == lastTrackNr_)
  409. ent = nextCueSheetEntry(actCueSheetEntry_, 0xaa, 1);
  410.       else
  411. ent = nextCueSheetEntry(actCueSheetEntry_,
  412. actCueSheetEntry_->trackNr + 1, 1);
  413.       assert(ent != NULL);
  414.       nextTrackStartLba_ = Msf(ent->min, ent->sec, ent->frame).lba() - 150;
  415.     }
  416.   }
  417. }
  418. CueSheetEntry *PQChannelEncoder::nextCueSheetEntry(CueSheetEntry *act,
  419.    int adr)
  420. {
  421.   if (act->trackNr == 0xaa) {
  422.     return NULL;
  423.   }
  424.   act++;
  425.   while (act->ctlAdr != 0) {
  426.     if ((act->ctlAdr & 0x0f) == adr) {
  427.       return act;
  428.     }
  429.     act++;
  430.   }
  431.   return NULL;
  432. }
  433. CueSheetEntry *PQChannelEncoder::nextCueSheetEntry(CueSheetEntry *act,
  434.    int trackNr, int indexNr)
  435. {
  436.   if (act->trackNr == 0xaa) {
  437.     return NULL;
  438.   }
  439.   act++;
  440.   while (act->ctlAdr != 0) {
  441.     if ((act->ctlAdr & 0x0f) == 1 && act->trackNr == trackNr &&
  442. act->indexNr == indexNr) {
  443.       return act;
  444.     }
  445.     act++;
  446.   }
  447.   return NULL;
  448. }