Track.cc
上传用户:weiliju62
上传日期:2007-01-06
资源大小:619k
文件大小:38k
- /* cdrdao - write audio CD-Rs in disc-at-once mode
- *
- * Copyright (C) 1998, 1999 Andreas Mueller <mueller@daneb.ping.de>
- *
- * 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.
- */
- /*
- * $Log: Track.cc,v $
- * Revision 1.9 1999/04/05 11:03:01 mueller
- * Added CD-TEXT support.
- *
- * Revision 1.8 1999/04/02 20:36:21 mueller
- * Created implementation class that contains all mutual member data.
- *
- * Revision 1.7 1999/03/27 19:52:26 mueller
- * Added data track support.
- *
- * Revision 1.6 1999/01/10 15:09:47 mueller
- * Fixed bug in sub-track list.
- *
- * Revision 1.5 1998/11/15 12:19:13 mueller
- * Added several functions for manipulating track/index marks.
- *
- * Revision 1.4 1998/09/22 19:17:19 mueller
- * Added seeking to and reading of samples for GUI.
- *
- * Revision 1.3 1998/08/15 17:58:13 mueller
- * Added missing printing of index increment data in 'print()'.
- *
- */
- static char rcsid[] = "$Id: Track.cc,v 1.9 1999/04/05 11:03:01 mueller Exp mueller $";
- #include <config.h>
- #include <stddef.h>
- #include <assert.h>
- #include <ctype.h>
- #include <string.h>
- #include "Track.h"
- #include "util.h"
- #include "TrackDataList.h"
- #include "CdTextItem.h"
- #include "edc_ecc/ecc.h"
- Track::Track(TrackData::Mode t) : length_(0), start_(0), end_(0)
- {
- type_ = t;
- nofSubTracks_ = 0;
- subTracks_ = lastSubTrack_ = NULL;
- nofIndices_ = 0;
- index_ = new Msf[98](0);
- isrcValid_ = 0;
- flags_.copy = 0; // digital copy not permitted
- flags_.preEmphasis = 0; // no pre-emphasis
- flags_.audioType = 0; // two channel audio
- }
- Track::Track(const Track &obj)
- : length_(obj.length_), start_(obj.start_), end_(obj.end_),
- cdtext_(obj.cdtext_)
- {
- int i;
- SubTrack *run;
- type_ = obj.type_;
- nofSubTracks_ = obj.nofSubTracks_;
- subTracks_ = lastSubTrack_ = NULL;
- for (run = obj.subTracks_; run != NULL; run = run->next_) {
- if (subTracks_ == NULL) {
- subTracks_ = lastSubTrack_ = new SubTrack(*run);
- }
- else {
- lastSubTrack_->next_ = new SubTrack(*run);
- lastSubTrack_->next_->pred_ = lastSubTrack_;
- lastSubTrack_ = lastSubTrack_->next_;
- }
- }
- nofIndices_ = obj.nofIndices_;
- index_ = new Msf[98](0);
- for (i = 0; i < nofIndices_; i++) {
- index_[i] = obj.index_[i];
- }
-
- isrcValid_ = obj.isrcValid_;
- memcpy(isrcCountry_, obj.isrcCountry_, 2);
- memcpy(isrcOwner_, obj.isrcOwner_, 3);
- memcpy(isrcYear_, obj.isrcYear_, 2);
- memcpy(isrcSerial_, obj.isrcSerial_, 5);
- flags_ = obj.flags_;
- }
- Track::~Track()
- {
- SubTrack *run = subTracks_;
- SubTrack *next = NULL;
- while (run != NULL) {
- next = run->next_;
- delete run;
- run = next;
- }
- delete[] index_;
- }
- // Returns first sub-track or 'NULL' if no sub-tracks are defined
- const SubTrack *Track::firstSubTrack() const
- {
- return subTracks_ != NULL ? subTracks_ : NULL;
- }
- // Returns last sub-track or 'NULL' if no sub-tracks are defined
- const SubTrack *Track::lastSubTrack() const
- {
- return lastSubTrack_ != NULL ? lastSubTrack_ : NULL;
- }
- // Appends given sub-track to list of sub-tracks.
- // return: 0: OK
- // 1: tried to append PAD sub-track
- int Track::append(const SubTrack &strack)
- {
- if (strack.type() == SubTrack::PAD) {
- return 1;
- }
- if (lastSubTrack_ != NULL && lastSubTrack_->type() == SubTrack::PAD &&
- lastSubTrack_->mode() == strack.mode()) {
- // remove padding sub track
- delete removeSubTrack(lastSubTrack_);
- }
- // append sub track
- insertSubTrackAfter(lastSubTrack_, new SubTrack(strack));
- update();
- return 0;
- }
- // Traverses all sub-tracks to update summary data of track.
- void Track::update()
- {
- long lenLba = 0; // accumulates total length of track in blocks
- unsigned long slength; // length of track in samples
- unsigned long padLen; // padding length
- unsigned long blen; // block length for current data mode
- SubTrack *run, *next;
- SubTrack *pad;
- TrackData::Mode dataMode;
- // remove all padding sub-tracks
- run = subTracks_;
- while (run != NULL) {
- next = run->next_;
- if (run->type() == SubTrack::PAD) {
- delete removeSubTrack(run);
- }
- run = next;
- }
- if ((run = subTracks_) != NULL) {
- do {
- dataMode = run->mode();
- if (run->mode() == TrackData::AUDIO) {
- blen = SAMPLES_PER_BLOCK;
- }
- else {
- blen = TrackData::dataBlockSize(run->mode());
- }
- slength = 0;
- // find continues range of sub tracks with same data mode
- do {
- slength += run->length();
- run = run->next_;
- } while (run != NULL && run->mode() == dataMode);
-
- if ((padLen = slength % blen) != 0) {
- padLen = blen - padLen;
- pad = new SubTrack(SubTrack::PAD, 0, TrackData(dataMode, padLen));
-
- if (run != NULL) {
- insertSubTrackAfter(run->pred_, pad);
- }
- else {
- insertSubTrackAfter(lastSubTrack_, pad);
- }
- slength += padLen;
- }
- // at this point 'slength' should be a multiple of 'blen'
- assert(slength % blen == 0);
- lenLba += slength / blen;
-
- } while (run != NULL);
- }
- length_ = Msf(lenLba);
- slength = 0;
- for (run = subTracks_; run != NULL; run = run->next_) {
- run->start(slength); // set start position of sub-track
- slength += run->length();
- }
- // reset 'start_' if necessary
- if (start_.lba() >= length_.lba()) {
- start_ = Msf(0);
- }
- }
- // Sets logical start of track, everthing before start (if != 0) is taken
- // as pre-gap. FIXME: Already set index marks are not updated.
- // return: 0: OK
- // 1: given start behind track end
- int Track::start(Msf s)
- {
- if (s.lba() >= length_.lba()) {
- return 1;
- }
- start_ = s;
- return 0;
- }
- // Sets end of user area of track which is the start of the post-gap.
- // An index entry is created at this point. The pre-gap length must be
- // set with 'start()' before this function can be called.
- // return: 0: OK
- // 1: start of post-gap is behind or at track end
- // 2: post-gap within pre-gap
- // 3: cannot create index mark, 98 index marks are already defined
- int Track::end(Msf e)
- {
- if (e.lba() >= length_.lba()) {
- return 1;
- }
- if (e.lba() != 0 && e.lba() <= start_.lba()) {
- return 2;
- }
- if (e.lba() != 0) {
- // add index mark for post-gap
- if (addIndex(Msf(e.lba() - start_.lba())) == 1) {
- // already 98 index increments defined
- return 3;
- }
- }
- end_ = e;
- return 0;
- }
- // Appends given index to index increment list.
- // return: 0: OK
- // 1: > 98 index increments
- // 2: index at or beyond track end
- // 3: index at start
- int Track::appendIndex(const Msf &index)
- {
- if (nofIndices_ == 98) {
- return 1;
- }
- if (index.lba() >= (length_ - start_).lba()) {
- return 2;
- }
- if (index.lba() == 0) {
- return 3;
- }
- index_[nofIndices_] = index;
- nofIndices_ += 1;
- return 0;
- }
- // Adds index at given position
- // return: 0: OK
- // 1: > 98 index increments
- // 2: cannot add index at specified position
- int Track::addIndex(const Msf &index)
- {
- int i;
- if (nofIndices_ == 98) {
- return 1;
- }
- if (index.lba() >= (length_ - start_).lba()) {
- return 2;
- }
- if (index.lba() == 0) {
- return 2;
- }
- for (i = 0; i < nofIndices_; i++) {
- if (index.lba() == index_[i].lba())
- return 2;
- if (index.lba() < index_[i].lba())
- break;
- }
- if (i == nofIndices_) {
- // append index
- index_[nofIndices_] = index;
- nofIndices_ += 1;
- }
- else {
- int pos = i;
- for (i = nofIndices_; i > pos; i--)
- index_[i] = index_[i - 1];
- index_[pos] = index;
- nofIndices_ += 1;
- }
-
- return 0;
- }
- // Removes specified index.
- // return 0: OK
- // 1: index not found
- int Track::removeIndex(int index)
- {
- int i;
- if (index < 0 || index >= nofIndices_)
- return 1;
-
- for (i = index; i < nofIndices_ - 1; i++)
- index_[i] = index_[i + 1];
- nofIndices_ -= 1;
- return 0;
- }
- // returns index increment
- Msf Track::getIndex(int i) const
- {
- if (i >= nofIndices_ || i < 0) {
- return Msf(0);
- }
- else {
- return index_[i];
- }
- }
- int Track::check() const
- {
- SubTrack *st;
- int ret;
- for (st = subTracks_; st != NULL; st = st->next_) {
- if ((ret = st->check()) != 0) {
- return ret;
- }
- }
- return 0;
- }
- // Sets ISRC code. Expected string: "CCOOOYYSSSSS"
- // C: country code (ASCII)
- // O: owner code (ASCII)
- // Y: year ('0'-'9')
- // S: serial number ('0'-'9')
- // return: 0: OK
- // 1: ilegal ISRC string
- int Track::isrc(const char *isrc)
- {
- int i;
- if (isrc == NULL) {
- isrcValid_ = 0;
- return 0;
- }
- if (strlen(isrc) != 12) {
- return 1;
- }
- for (i=0; i < 5; i++) {
- if (!(isdigit(isrc[i]) || isupper(isrc[i]))) {
- return 1;
- }
- }
- for (i = 5; i < 12; i++) {
- if (!isdigit(isrc[i])) {
- return 1;
- }
- }
- isrcCountry_[0] = isrc[0];
- isrcCountry_[1] = isrc[1];
- isrcOwner_[0] = isrc[2];
- isrcOwner_[1] = isrc[3];
- isrcOwner_[2] = isrc[4];
- // store BCD
- isrcYear_[0] = isrc[5] - '0';
- isrcYear_[1] = isrc[6] - '0';
-
- isrcSerial_[0] = isrc[7] - '0';
- isrcSerial_[1] = isrc[8] - '0';
- isrcSerial_[2] = isrc[9] - '0';
- isrcSerial_[3] = isrc[10] - '0';
- isrcSerial_[4] = isrc[11] - '0';
-
- isrcValid_ = 1;
- return 0;
- }
- const char *Track::isrc() const
- {
- static char buf[13];
-
- if (!isrcValid_)
- return NULL;
- buf[0] = isrcCountry_[0];
- buf[1] = isrcCountry_[1];
- buf[2] = isrcOwner_[0];
- buf[3] = isrcOwner_[1];
- buf[4] = isrcOwner_[2];
- buf[5] = isrcYear_[0] + '0';
- buf[6] = isrcYear_[1] + '0';
- buf[7] = isrcSerial_[0] + '0';
- buf[8] = isrcSerial_[1] + '0';
- buf[9] = isrcSerial_[2] + '0';
- buf[10] = isrcSerial_[3] + '0';
- buf[11] = isrcSerial_[4] + '0';
- buf[12] = 0;
- return buf;
- }
- int Track::isPadded() const
- {
- SubTrack *run;
- for (run = subTracks_; run != NULL; run = run->next_) {
- if (run->type() == SubTrack::PAD)
- return 1;
- }
- return 0;
- }
- // writes out track data in TOC file syntax
- void Track::print(ostream &out) const
- {
- SubTrack *st;
- int i;
- out << "TRACK " << TrackData::mode2String(type());
- out << endl;
- if (!copyPermitted())
- out << "NO ";
- out << "COPY" << endl;
- if (type() == TrackData::AUDIO) {
- if (!preEmphasis())
- out << "NO ";
- out << "PRE_EMPHASIS" << endl;
- if (audioType() == 0)
- out << "TWO_CHANNEL_AUDIO" << endl;
- else
- out << "FOUR_CHANNEL_AUDIO" << endl;
-
- if (isrcValid()) {
- out << "ISRC "" << isrcCountry(0) << isrcCountry(1)
- << isrcOwner(0) << isrcOwner(1) << isrcOwner(2)
- << (char)(isrcYear(0) + '0') << (char)(isrcYear(1) + '0')
- << (char)(isrcSerial(0) + '0') << (char)(isrcSerial(1) + '0')
- << (char)(isrcSerial(2) + '0') << (char)(isrcSerial(3) + '0')
- << (char)(isrcSerial(4) + '0') << """ << endl;
- }
- cdtext_.print(1, out);
- }
- for (st = subTracks_; st != NULL; st = st->next_) {
- st->print(out);
- }
- if (start_.lba() != 0) {
- out << "START " << start_.str() << endl;
- }
- for (i = 0; i < nofIndices_; i++) {
- out << "INDEX " << index_[i].str() << endl;
- }
- }
- // Locates 'SubTrack' that contains specified sample.
- // return: found 'SubTrack' or 'NULL' if given sample is out of range
- SubTrack *Track::findSubTrack(unsigned long sample) const
- {
- SubTrack *run;
- if (sample >= length_.samples())
- return NULL;
- for (run = subTracks_;
- run != NULL && run->next_ != NULL;
- run = run->next_) {
- if (sample < run->next_->start())
- return run;
- }
- return run;
- }
- void Track::countSubTracks()
- {
- SubTrack *run;
- nofSubTracks_ = 0;
- for (run = subTracks_; run != NULL; run = run->next_)
- nofSubTracks_++;
- }
- // move track start or index increment within track range
- // return: 0: OK
- // 1: track length would be shorter than 4 seconds
- // 2: cannot cross index boundary
- int Track::moveIndex(int index, long lba)
- {
- int i;
- long rangeMin;
- long rangeMax;
- assert(index > 0 && index - 2 < nofIndices_);
- assert(lba >= 0 && index < length_.lba());
- if (index == 1) {
- if (nofIndices_ > 0 && lba >= start_.lba() + getIndex(0).lba())
- return 2;
- if (lba > length_.lba() - 4 * 75)
- return 1;
- // adjust index increments to new track start
- for (i = 0; i < nofIndices_; i++) {
- index_[i] = Msf(index_[i].lba() + start_.lba() - lba);
- }
- start_ = Msf(lba);
- return 0;
- }
- // adjust 'index' for index array access
- index -= 2;
- if (lba <= start_.lba())
- return 2;
- lba -= start_.lba();
- rangeMin = (index == 0 ? 0 : index_[index - 1].lba());
- rangeMax =
- (index == nofIndices_ - 1 ? length_.lba() - start_.lba() :
- index_[index + 1].lba());
- if (lba > rangeMin && lba < rangeMax) {
- index_[index] = Msf(lba);
- return 0;
- }
- return 2;
- }
- TrackDataList *Track::removeToEnd(unsigned long sample)
- {
- SubTrack *strun;
- SubTrack *store;
- int i;
- assert(sample > 0 && sample < length_.samples());
- strun = findSubTrack(sample);
- assert(strun != NULL);
- TrackDataList *list = new TrackDataList;
- if (sample == strun->start()) {
- // we don't have to split the TrackData object
- list->append(new TrackData(*strun));
- // cannot be the first SubTrack because 'sample' > 0
- strun->pred_->next_ = NULL;
- lastSubTrack_ = strun->pred_;
-
- store = strun;
- strun = strun->next_;
- delete store;
- }
- else {
- // split audio data object
- TrackData *part1, *part2;
- strun->split(sample - strun->start(), &part1, &part2);
- list->append(part2);
- store = new SubTrack(strun->type(), *part1);
- delete part1;
- if (strun->pred_ == NULL) {
- subTracks_ = store;
- }
- else {
- strun->pred_->next_ = store;
- store->pred_ = strun->pred_;
- }
- lastSubTrack_ = store;
-
- store = strun;
- strun = strun->next_;
- delete store;
- }
-
- while (strun != NULL) {
- list->append(new TrackData(*strun));
- store = strun;
- strun = strun->next_;
- delete store;
- }
- countSubTracks();
- update();
- checkConsistency();
- // adjust index increments
- for (i = 0; i < nofIndices_; i++) {
- if (index_[i].lba() + start_.lba() >= length_.lba()) {
- nofIndices_ = i;
- break;
- }
- }
- return list;
- }
- TrackDataList *Track::removeFromStart(unsigned long sample)
- {
- SubTrack *strun;
- SubTrack *store, *start;
- int i;
- assert(sample > 0 && sample < length_.samples());
- TrackDataList *list = new TrackDataList;
- for (strun = subTracks_;
- strun != NULL && strun->next_ != NULL;
- strun = strun->next_) {
- if (sample < strun->next_->start())
- break;
- else
- list->append(new TrackData(*strun));
- }
- assert(strun != NULL);
- start = subTracks_;
- if (sample == strun->start()) {
- // we don't have to split the TrackData object
- // cannot be the first SubTrack because 'sample' > 0
- strun->pred_->next_ = NULL;
- subTracks_ = strun;
- subTracks_->pred_ = NULL;
- }
- else {
- // split actual sub track
- TrackData *part1, *part2;
- strun->split(sample - strun->start(), &part1, &part2);
-
- list->append(part1);
- store = new SubTrack(strun->type(), *part2);
- delete part2;
- store->next_ = strun->next_;
- if (store->next_ != NULL)
- store->next_->pred_ = store;
- strun->next_ = NULL;
- subTracks_ = store;
- if (strun == lastSubTrack_)
- lastSubTrack_ = store;
- }
- // remove unlinked sub tracks
- while (start != NULL) {
- store = start;
- start = start->next_;
- delete store;
- }
-
- countSubTracks();
- update();
- checkConsistency();
- // adjust index increments
- for (i = 0; i < nofIndices_; i++) {
- if (index_[i].lba() + start_.lba() >= length_.lba()) {
- nofIndices_ = i;
- break;
- }
- }
- return list;
- }
-
- void Track::prependTrackData(const TrackDataList *list)
- {
- SubTrack *start = NULL;
- SubTrack *last = NULL;
- SubTrack *ent;
- const TrackData *run;
- if (list->count() == 0)
- return;
- for (run = list->first(); run != NULL; run = list->next()) {
- ent = new SubTrack(SubTrack::DATA, *run);
- if (last == NULL) {
- start = ent;
- }
- else {
- last->next_ = ent;
- ent->pred_ = last;
- }
- last = ent;
- }
- if (subTracks_ == NULL) {
- subTracks_ = start;
- lastSubTrack_ = last;
- }
- else {
- last->next_ = subTracks_;
- subTracks_->pred_ = last;
- subTracks_ = start;
- }
- mergeSubTracks(); // this will also update the sub track counter
- update();
- checkConsistency();
- }
- void Track::appendTrackData(const TrackDataList *list)
- {
- SubTrack *start = NULL;
- SubTrack *last = NULL;
- SubTrack *ent;
- const TrackData *run;
- if (list->count() == 0)
- return;
- for (run = list->first(); run != NULL; run = list->next()) {
- ent = new SubTrack(SubTrack::DATA, *run);
- if (last == NULL) {
- start = ent;
- }
- else {
- last->next_ = ent;
- ent->pred_ = last;
- }
- last = ent;
- }
- if (lastSubTrack_ != NULL) {
- if (lastSubTrack_->type() == SubTrack::PAD)
- lastSubTrack_->type_ = SubTrack::DATA;
- lastSubTrack_->next_ = start;
- start->pred_ = lastSubTrack_;
- lastSubTrack_ = last;
- }
- else {
- subTracks_ = start;
- lastSubTrack_ = last;
- }
- mergeSubTracks(); // this will also update the sub track counter
- update();
- checkConsistency();
- }
- void Track::appendTrackData(const Track *track)
- {
- SubTrack *run, *ent;
- for (run = track->subTracks_; run != NULL; run = run->next_) {
- ent = new SubTrack(*run);
- if (lastSubTrack_ == NULL) {
- subTracks_ = ent;
- }
- else {
- lastSubTrack_->next_ = ent;
- ent->pred_ = lastSubTrack_;
- }
- lastSubTrack_ = ent;
- }
- mergeSubTracks(); // this will also update the sub track counter
- update();
- checkConsistency();
- }
- TrackDataList *Track::removeTrackData(unsigned long start, unsigned long end)
- {
- SubTrack *run;
- TrackData *part1, *part2, *part3;
- unsigned long plen;
- if (start > end || end >= length_.samples())
- return NULL;
- SubTrack *startSt = findSubTrack(start);
- SubTrack *endSt = findSubTrack(end);
- assert(startSt != NULL);
- assert(endSt != NULL);
- TrackDataList *list = new TrackDataList;
- if (startSt == endSt) {
- if (start == startSt->start() &&
- end == startSt->start() + startSt->length() - 1) {
- // remove complete sub track
- list->append(new TrackData(*startSt));
- }
- else if (start == startSt->start()) {
- // remove first part of sub track
- startSt->split(end + 1 - startSt->start(), &part1, &part2);
- list->append(part1);
- insertSubTrackAfter(startSt, new SubTrack(startSt->type(), *part2));
- delete part2;
- }
- else if (end == startSt->start() + startSt->length() - 1) {
- // remove last part of sub track
- startSt->split(start - startSt->start(), &part1, &part2);
- list->append(part2);
- insertSubTrackAfter(startSt, new SubTrack(startSt->type(), *part1));
- delete part1;
- }
- else {
- // remove middle part of sub track
- startSt->split(start - startSt->start(), &part1, &part2);
- insertSubTrackAfter(startSt->pred_,
- new SubTrack(startSt->type(), *part1));
- plen = part1->length();
- delete part1;
- part2->split(end + 1 - startSt->start() - plen, &part1, &part3);
- list->append(part1);
- insertSubTrackAfter(startSt, new SubTrack(startSt->type(), *part3));
- delete part3;
- delete part2;
- }
- delete removeSubTrack(startSt);
- }
- else {
- if (start == startSt->start()) {
- // remove complete sub track
- list->append(new TrackData(*startSt));
- }
- else {
- startSt->split(start - startSt->start(), &part1, &part2);
- list->append(part2);
- insertSubTrackAfter(startSt->pred_,
- new SubTrack(startSt->type(), *part1));
- delete part1;
- }
- for (run = startSt->next_; run != endSt; run = run->next_)
- list->append(new TrackData(*(startSt->next_)));
- if (end == endSt->start() + endSt->length() - 1) {
- // remove complete sub track
- list->append(new TrackData(*endSt));
- }
- else {
- endSt->split(end + 1 - endSt->start(), &part1, &part2);
- list->append(part1);
- insertSubTrackAfter(endSt, new SubTrack(endSt->type(), *part2));
- delete part2;
- }
- while (startSt->next_ != endSt)
- delete removeSubTrack(startSt->next_);
- delete removeSubTrack(startSt);
- delete removeSubTrack(endSt);
- }
- // adjust index marks
- unsigned long len;
- long preGapAdj = 0;
- long slba = 0;
- long elba = 0;
- long indexMove = 0;
- long indexAdj = 0;
- int i;
- if (start < start_.samples()) {
- if (end < start_.samples()) {
- len = end - start + 1;
- slba = -1;
- elba = -1;
- }
- else {
- len = start_.samples() - start;
- elba = (end - start_.samples()) / SAMPLES_PER_BLOCK;
- slba = 0;
- indexMove = (end - start_.samples() + 1) / SAMPLES_PER_BLOCK;
- if (((end - start_.samples() + 1) % SAMPLES_PER_BLOCK) != 0)
- indexMove += 1;
- }
- preGapAdj = len / SAMPLES_PER_BLOCK;
- if ((len % SAMPLES_PER_BLOCK) != 0)
- indexAdj = 1;
- }
- else {
- slba = (start - start_.samples()) / SAMPLES_PER_BLOCK;
- if (((start - start_.samples()) % SAMPLES_PER_BLOCK) != 0)
- slba += 1;
- elba = (end - start_.samples()) / SAMPLES_PER_BLOCK;
- indexMove = (end - start + 1) / SAMPLES_PER_BLOCK;
- if (((end - start + 1) % SAMPLES_PER_BLOCK) != 0)
- indexMove += 1;
- }
-
- i = 0;
- while (i < nofIndices_) {
- if (index_[i].lba() >= slba && index_[i].lba() <= elba) {
- removeIndex(i);
- continue;
- }
- else if (index_[i].lba() > elba) {
- if (index_[i].lba() - indexMove <= 0) {
- removeIndex(i);
- continue;
- }
- else {
- index_[i] = Msf(index_[i].lba() - indexMove);
- }
- if (i > 0 && index_[i - 1].lba() == index_[i].lba()) {
- removeIndex(i);
- continue;
- }
- }
- if (index_[i].lba() - indexAdj <= 0) {
- removeIndex(i);
- continue;
- }
- else {
- index_[i] = Msf(index_[i].lba() - indexAdj);
- }
- i++;
- }
- // adjust pre-gap length
- start_ = Msf(start_.lba() - preGapAdj);
-
- mergeSubTracks(); // this will also update the sub track counter
- update();
- checkConsistency();
- return list;
- }
- void Track::insertTrackData(unsigned long pos, const TrackDataList *list)
- {
- const TrackData *run;
- TrackData *part1, *part2;
- SubTrack *st;
- unsigned long len;
- long blen;
- int i;
- if (list == NULL || list->first() == NULL || list->length() == 0)
- return;
- if (pos >= length_.samples()) {
- // append data
- for (run = list->first(); run != NULL; run = list->next()) {
- insertSubTrackAfter(lastSubTrack_, new SubTrack(SubTrack::DATA, *run));
- }
- }
- else {
- st = findSubTrack(pos);
- assert(st != NULL);
- len = list->length();
- if (pos == st->start()) {
- for (run = list->first(); run != NULL; run = list->next()) {
- insertSubTrackAfter(st->pred_, new SubTrack(SubTrack::DATA, *run));
- }
- }
- else {
- st->split(pos - st->start(), &part1, &part2);
-
- insertSubTrackAfter(st->pred_, new SubTrack(SubTrack::DATA, *part1));
- insertSubTrackAfter(st, new SubTrack(st->type(), *part2));
- delete part1;
- delete part2;
-
- for (run = list->first(); run != NULL; run = list->next()) {
- insertSubTrackAfter(st->pred_, new SubTrack(SubTrack::DATA, *run));
- }
-
- delete removeSubTrack(st);
- }
- blen = len / SAMPLES_PER_BLOCK;
- if (pos <= start_.samples()) {
- start_ = Msf(start_.lba() + blen);
- }
- else {
- for (i = 0; i < nofIndices_; i++) {
- if (index_[i].samples() >= pos)
- index_[i] = Msf(index_[i].lba() + blen);
- }
- }
- }
- mergeSubTracks(); // this will also update the sub track counter
- update();
- checkConsistency();
- return;
- }
-
- void Track::mergeSubTracks()
- {
- SubTrack *run = subTracks_;
- SubTrack *newSubTrack;
- TrackData *mergedData;
- while (run != NULL && run->next_ != NULL) {
- if (run->type() == run->next_->type() &&
- (mergedData = run->merge(run->next_)) != NULL) {
- newSubTrack = new SubTrack(run->type(), *mergedData);
- delete mergedData;
- newSubTrack->next_ = run->next_->next_;
- if (newSubTrack->next_ != NULL)
- newSubTrack->next_->pred_ = newSubTrack;
- if (run->pred_ == NULL) {
- subTracks_ = newSubTrack;
- }
- else {
- run->pred_->next_ = newSubTrack;
- newSubTrack->pred_ = run->pred_;
- }
- if (run->next_ == lastSubTrack_)
- lastSubTrack_ = newSubTrack;
- delete run->next_;
- delete run;
- run = newSubTrack;
- }
- else {
- run = run->next_;
- }
- }
- countSubTracks();
- }
- void Track::checkConsistency()
- {
- SubTrack *run, *last = NULL;
- long cnt = 0;
- for (run = subTracks_; run != NULL; last = run, run = run->next_) {
- cnt++;
- if (run->pred_ != last)
- message(-3, "Track::checkConsistency: wrong pred pointer.");
- }
- if (last != lastSubTrack_)
- message(-3, "Track::checkConsistency: wrong last pointer.");
- if (cnt != nofSubTracks_)
- message(-3, "Track::checkConsistency: wrong sub track counter.");
- }
- // Inserts 'newSubTrack' after existing sub track 'subTrack'. If 'subTrack'
- // is NULL it will be prepended.
- void Track::insertSubTrackAfter(SubTrack *subTrack, SubTrack *newSubTrack)
- {
- if (subTrack == NULL) {
- if (subTracks_ == NULL) {
- subTracks_ = lastSubTrack_ = newSubTrack;
- newSubTrack->next_ = newSubTrack->pred_ = NULL;
- }
- else {
- newSubTrack->next_ = subTracks_;
- subTracks_->pred_ = newSubTrack;
- newSubTrack->pred_ = NULL;
- subTracks_ = newSubTrack;
- }
- }
- else {
- newSubTrack->next_ = subTrack->next_;
- if (newSubTrack->next_ != NULL) {
- newSubTrack->next_->pred_ = newSubTrack;
- }
- else {
- lastSubTrack_ = newSubTrack;
- }
- subTrack->next_ = newSubTrack;
- newSubTrack->pred_ = subTrack;
- }
- nofSubTracks_ += 1;
- checkConsistency();
- }
- // Removes given sub track from list. Returns the removed sub track.
- SubTrack *Track::removeSubTrack(SubTrack *subTrack)
- {
- if (subTrack->pred_ == NULL) {
- assert(subTrack == subTracks_);
- subTracks_ = subTrack->next_;
- if (subTracks_ != NULL) {
- subTracks_->pred_ = NULL;
- }
- else {
- lastSubTrack_ = NULL;
- }
- }
- else {
- subTrack->pred_->next_ = subTrack->next_;
- if (subTrack->next_ != NULL) {
- subTrack->next_->pred_ = subTrack->pred_;
- }
- else {
- lastSubTrack_ = subTrack->pred_;
- }
- }
- nofSubTracks_ -= 1;
- subTrack->next_ = subTrack->pred_ = NULL;
- checkConsistency();
- return subTrack;
- }
- // Fills provided buffer with an audio block that contains zero data
- // encoded with given mode.
- // encMode: encoding mode, see 'Track::readBlock()'
- // mode: sector mode
- // lba : absolute address of sector
- // buf : caller provided buffer that is filled with 2352 bytes
- void Track::encodeZeroData(int encMode, TrackData::Mode mode, long lba,
- char *buf)
- {
- if (encMode == 0) {
- memset(buf, 0, AUDIO_BLOCK_LEN);
- switch (mode) {
- case TrackData::AUDIO:
- break;
- case TrackData::MODE0:
- do_encode_L2((unsigned char *)buf, MODE_0, lba);
- scramble_L2((unsigned char *)buf);
- break;
- case TrackData::MODE1:
- case TrackData::MODE1_RAW:
- do_encode_L2((unsigned char *)buf, MODE_1, lba);
- scramble_L2((unsigned char *)buf);
- break;
- case TrackData::MODE2:
- case TrackData::MODE2_RAW:
- do_encode_L2((unsigned char *)buf, MODE_2, lba);
- scramble_L2((unsigned char *)buf);
- break;
- case TrackData::MODE2_FORM1:
- case TrackData::MODE2_FORM_MIX: // encode as form 1
- do_encode_L2((unsigned char *)buf, MODE_2_FORM_1, lba);
- scramble_L2((unsigned char *)buf);
- break;
- case TrackData::MODE2_FORM2:
- // setup sub header
- buf[16+2] = 0x20;
- buf[16+6] = 0x20;
- do_encode_L2((unsigned char *)buf, MODE_2_FORM_2, lba);
- scramble_L2((unsigned char *)buf);
- break;
- }
- }
- else if (encMode == 1) {
- switch (mode) {
- case TrackData::AUDIO:
- memset(buf, 0, AUDIO_BLOCK_LEN);
- break;
- case TrackData::MODE0:
- memset(buf, 0, MODE0_BLOCK_LEN);
- break;
- case TrackData::MODE1:
- case TrackData::MODE1_RAW:
- memset(buf, 0, MODE1_BLOCK_LEN);
- break;
- case TrackData::MODE2:
- case TrackData::MODE2_RAW:
- case TrackData::MODE2_FORM_MIX:
- memset(buf, 0, MODE2_BLOCK_LEN);
- break;
- case TrackData::MODE2_FORM1:
- memset(buf, 0, MODE2_BLOCK_LEN);
- break;
- case TrackData::MODE2_FORM2:
- memset(buf, 0, MODE2_BLOCK_LEN);
- // setup sub header
- buf[2] = 0x20;
- buf[6] = 0x20;
- break;
- }
- }
- else {
- message(-3, "Illegal encoding mode in 'Track::encodeZeroData()'.");
- }
- }
- void Track::addCdTextItem(CdTextItem *item)
- {
- assert(CdTextItem::isTrackPack(item->packType()));
- cdtext_.add(item);
- }
- void Track::removeCdTextItem(CdTextItem::PackType type, int blockNr)
- {
- cdtext_.remove(type, blockNr);
- }
- TrackReader::TrackReader(const Track *t) : reader(NULL)
- {
- track_ = t;
- readPos_ = 0;
- readPosSample_ = 0;
- readSubTrack_ = NULL;
- open_ = 0;
- }
- TrackReader::~TrackReader()
- {
- if (open_) {
- closeData();
- }
- track_ = NULL;
- readSubTrack_ = NULL;
- }
- void TrackReader::init(const Track *t)
- {
- if (open_) {
- closeData();
- }
- track_ = t;
- readSubTrack_ = NULL;
- }
- // initiates reading track
- // return: 0: OK
- // 1: data file could not be opened
- // 2: could not seek to start position
- int TrackReader::openData()
- {
- assert(open_ == 0);
- assert(track_ != NULL);
- int ret = 0;
- open_ = 1;
- readPos_ = 0;
- readPosSample_ = 0;
- readSubTrack_ = track_->subTracks_;
- reader.init(readSubTrack_);
- if (readSubTrack_ != NULL) {
- ret = reader.openData();
- }
- return ret;
- }
- void TrackReader::closeData()
- {
- if (open_) {
- open_ = 0;
- readPos_ = 0;
- readPosSample_ = 0;
- readSubTrack_ = NULL;
-
- reader.closeData();
- }
- }
- long TrackReader::readData(int encodingMode, long lba, char *buf, long len)
- {
- long err = 0;
- long b;
- long offset;
- assert(open_ != 0);
- if (readPos_ + len > track_->length_.lba()) {
- if ((len = track_->length_.lba() - readPos_) <= 0) {
- return 0;
- }
- }
- for (b = 0; b < len; b++) {
- if ((offset = readBlock(encodingMode, lba, (Sample*)buf)) == 0) {
- err = 1;
- break;
- }
- buf += offset;
- lba++;
- }
- readPos_ += b;
- return err == 0 ? b : -1;
- }
- // Reads one block from sub-tracks and performs the data encoding for the
- // block.
- // encodingMode: conrols how the data is encoded
- // 0: returned data is always an audio block (2352 bytes),
- // data blocks are completely encoded
- // 1: data is returned mostly unencoded, the block size
- // depends on the actual sub-track mode, MODE2_FORM1 and
- // MODE2_FORM2 blocks are extended by the sub header and
- // filled with 0 bytes to match the MODE2 block size
- // (2336 bytes).
- // lba: Logical block address that must be encoded into header of data blocks
- // Return: 0 if error occured, else length of block that has been filled
- //
- int TrackReader::readBlock(int encodingMode, long lba, Sample *buf)
- {
- TrackData::Mode dataMode; // actual data mode of sub-track
- long actLen;
- long count; // amount of data the must be read from sub track
- long nread = 0;
- long offset = 0; // block length of returned data
- while (reader.readLeft() == 0) {
- // skip to next sub track with available data
- readSubTrack_ = readSubTrack_->next_;
- // next sub-track must exist since requested length matches available data
- assert(readSubTrack_ != NULL);
- reader.init(readSubTrack_);
- if (reader.openData() != 0) {
- return 0;
- }
- }
- dataMode = readSubTrack_->mode(); // actual data mode
- if (dataMode == TrackData::AUDIO)
- count = SAMPLES_PER_BLOCK;
- else
- count = TrackData::dataBlockSize(dataMode);
- char *dataBuf = (char *)buf;
- if (encodingMode == 0) {
- offset = AUDIO_BLOCK_LEN;
- switch (dataMode) {
- case TrackData::AUDIO:
- case TrackData::MODE1_RAW:
- case TrackData::MODE2_RAW:
- break;
- case TrackData::MODE0:
- case TrackData::MODE1:
- case TrackData::MODE2:
- case TrackData::MODE2_FORM_MIX:
- dataBuf += 16;
- break;
- case TrackData::MODE2_FORM1:
- memset(dataBuf + 16, 0, 8); // clear sub-header
- dataBuf += 24;
- break;
- case TrackData::MODE2_FORM2:
- memset(dataBuf + 16, 0, 8); // clear sub-header
- dataBuf[16+2] = 0x20;
- dataBuf[16+6] = 0x20;
- dataBuf += 24;
- break;
- }
- }
- else if (encodingMode == 1) {
- switch (dataMode) {
- case TrackData::AUDIO:
- offset = AUDIO_BLOCK_LEN;
- break;
- case TrackData::MODE0:
- offset = MODE0_BLOCK_LEN;
- break;
- case TrackData::MODE1:
- offset = MODE1_BLOCK_LEN;
- break;
- case TrackData::MODE1_RAW:
- offset = MODE1_BLOCK_LEN;
- break;
- case TrackData::MODE2:
- case TrackData::MODE2_FORM_MIX:
- offset = MODE2_BLOCK_LEN;
- break;
- case TrackData::MODE2_FORM1:
- case TrackData::MODE2_FORM2:
- offset = MODE2_BLOCK_LEN;
- memset(dataBuf, 0, MODE2_BLOCK_LEN);
- dataBuf += 8; // reserve space for sub-header
- break;
- case TrackData::MODE2_RAW:
- offset = MODE2_BLOCK_LEN;
- break;
- }
- }
- // gather one block of data, block length depends on 'dataMode'
- while (count > 0) {
- if (dataMode == TrackData::AUDIO)
- actLen = reader.readData(buf + nread, count);
- else
- actLen = reader.readData((Sample *)(dataBuf + nread), count);
- if (actLen < 0) // indicates read error
- return 0;
- if (actLen != count) {
- // end of data in sub-track reached, skip to next sub-track
- readSubTrack_ = readSubTrack_->next_;
- // next sub-track must exist since requested length match available data
- assert(readSubTrack_ != NULL);
- // mode of next sub-track must match 'dataMode', this is ensured
- // in 'update()'.
- assert(readSubTrack_->mode() == dataMode);
- reader.init(readSubTrack_);
- if (reader.openData() != 0) {
- return 0;
- }
- }
- count -= actLen;
- nread += actLen;
- }
- unsigned char *encBuf = (unsigned char *)buf;
- if (encodingMode == 0) {
- // encode data block according to 'dataMode'
- switch (dataMode) {
- case TrackData::AUDIO:
- break;
- case TrackData::MODE0:
- do_encode_L2(encBuf, MODE_0, lba);
- scramble_L2(encBuf);
- break;
- case TrackData::MODE1:
- do_encode_L2(encBuf, MODE_1, lba);
- scramble_L2(encBuf);
- break;
- case TrackData::MODE1_RAW:
- {
- Msf m(lba);
- if (int2bcd(m.min()) != encBuf[12] ||
- int2bcd(m.sec()) != encBuf[13] ||
- int2bcd(m.frac()) != encBuf[14]) {
- // sector address mismatch -> rebuild L-EC since it covers the header
- do_encode_L2(encBuf, MODE_1, lba);
- }
- scramble_L2(encBuf);
- }
- break;
- case TrackData::MODE2:
- do_encode_L2(encBuf, MODE_2, lba);
- scramble_L2(encBuf);
- break;
- case TrackData::MODE2_FORM1:
- do_encode_L2(encBuf, MODE_2_FORM_1, lba);
- scramble_L2(encBuf);
- break;
- case TrackData::MODE2_FORM2:
- do_encode_L2(encBuf, MODE_2_FORM_2, lba);
- scramble_L2(encBuf);
- break;
- case TrackData::MODE2_FORM_MIX:
- if ((encBuf[16+2] & 0x20) != 0)
- do_encode_L2(encBuf, MODE_2_FORM_2, lba);
- else
- do_encode_L2(encBuf, MODE_2_FORM_1, lba);
- scramble_L2(encBuf);
- break;
- case TrackData::MODE2_RAW:
- {
- Msf m(lba);
- // L-EC does not cover sector header so it is relocatable
- // just update the sector address in the header
- encBuf[12] = int2bcd(m.min());
- encBuf[13] = int2bcd(m.sec());
- encBuf[14] = int2bcd(m.frac());
- scramble_L2(encBuf);
- }
- break;
- }
- }
- else if (encodingMode == 1) {
- switch (dataMode) {
- case TrackData::MODE2_FORM2:
- // add sub header for data form 2 sectors
- encBuf[2] = 0x20;
- encBuf[6] = 0x20;
- break;
- case TrackData::MODE1_RAW:
- // strip off sync and header
- memmove(encBuf, encBuf + 16, MODE1_BLOCK_LEN);
- break;
- case TrackData::MODE2_RAW:
- // strip off sync and header
- memmove(encBuf, encBuf + 16, MODE2_BLOCK_LEN);
- break;
- default:
- break;
- }
- }
-
- return offset;
- }
- long TrackReader::readTrackData(Sample *buf, long len)
- {
- long actLen;
- long count = len;
- long nread = 0;
- while (count > 0) {
- actLen = reader.readData(buf + nread, count);
- if (actLen < 0) {
- return -1;
- }
- if (actLen != count) {
- // end of audio data in sub-track reached, skip to next sub-track
- readSubTrack_ = readSubTrack_->next_;
- // next sub-track must exists since requested length match available data
- assert(readSubTrack_ != NULL);
- reader.init(readSubTrack_);
- if (reader.openData() != 0) {
- return -1;
- }
- }
- count -= actLen;
- nread += actLen;
- }
- return len;
- }
- // Seeks to specified sample.
- // return: 0: OK
- // 10: sample out of range
- // return code of 'TrackData::openData()'
- int TrackReader::seekSample(unsigned long sample)
- {
- int ret;
- assert(open_ != 0);
- // find sub track containing 'sample'
- SubTrack *st = track_->findSubTrack(sample);
- if (st == NULL)
- return 10;
- // open sub track if necessary
- if (readSubTrack_ != st) {
- readSubTrack_ = st;
- reader.init(readSubTrack_);
- if ((ret = reader.openData()) != 0)
- return ret;
- }
- assert(sample >= readSubTrack_->start());
- unsigned long offset = sample - readSubTrack_->start();
- // seek in sub track
- if ((ret = reader.seekSample(offset)) != 0)
- return ret;
- readPosSample_ = sample;
- return 0;
- }
- long TrackReader::readSamples(Sample *buf, long len)
- {
- long ret;
- long i;
- assert(open_ != 0);
- if (readPosSample_ + (unsigned long)len > track_->length_.samples()) {
- if ((len = track_->length_.samples() - readPosSample_) <= 0) {
- return 0;
- }
- }
- if (track_->type_ == TrackData::AUDIO) {
- if ((ret = readTrackData(buf, len)) > 0)
- readPosSample_ += ret;
- }
- else {
- for (i = 0; i < len; i++) {
- buf[i].left(16000);
- buf[i].right(16000);
- }
- readPosSample_ += len;
- ret = len;
- }
-
- return ret;
- }