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

SCSI/ASPI

开发平台:

MultiPlatform

  1. /*  cdrdao - write audio CD-Rs in disc-at-once mode
  2.  *
  3.  *  Copyright (C) 1998, 1999  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: TrackData.cc,v $
  21.  * Revision 1.12  1999/04/02 20:36:21  mueller
  22.  * Created implementation class that contains all mutual member data.
  23.  *
  24.  * Revision 1.11  1999/03/27 19:49:29  mueller
  25.  * Added data file support.
  26.  *
  27.  * Revision 1.10  1999/01/24 15:59:52  mueller
  28.  * Added static member functions 'waveLength()', 'audioDataLength()' and
  29.  * 'audioFileType()'.
  30.  * Fixed handling of WAVE files as indicated by Eberhard Mattes. The length
  31.  * of audio data is now taken from the WAVE header instead assuming that
  32.  * the audio data reaches until the end of the file.
  33.  *
  34.  * Revision 1.9  1999/01/10 15:13:02  mueller
  35.  * Added function 'checkAudioFile()'.
  36.  *
  37.  * Revision 1.8  1998/11/21 18:07:55  mueller
  38.  * Added on-the-fly writing patch from Michael Weber <Michael.Weber@Post.RWTH-AAchen.DE>
  39.  *
  40.  * Revision 1.7  1998/11/15 12:15:18  mueller
  41.  * Added member functions 'split()' and 'merge()'.
  42.  *
  43.  * Revision 1.6  1998/09/23 17:55:59  mueller
  44.  * Improved error message about short audio file.
  45.  *
  46.  * Revision 1.5  1998/09/22 19:17:19  mueller
  47.  * Added seeking to and reading of samples for GUI.
  48.  *
  49.  * Revision 1.4  1998/09/06 12:00:26  mueller
  50.  * Used 'message' function for messages.
  51.  *
  52.  * Revision 1.3  1998/07/28 13:47:48  mueller
  53.  * Automatic length determination of audio files is now done in 'AudioData'.
  54.  *
  55.  */
  56. static char rcsid[] = "$Id: TrackData.cc,v 1.12 1999/04/02 20:36:21 mueller Exp mueller $";
  57. #include <config.h>
  58. #include <stdio.h>
  59. #include <sys/types.h>
  60. #include <sys/stat.h>
  61. #include <fcntl.h>
  62. #include <unistd.h>
  63. #include <assert.h>
  64. #include <string.h>
  65. #include <errno.h>
  66. #include "TrackData.h"
  67. #include "Msf.h"
  68. #include "util.h"
  69. // creates an object representing a portion of an audio data file
  70. TrackData::TrackData(const char *filename, long offset,
  71.      unsigned long start, unsigned long length)
  72. {
  73.   init(filename, offset, start, length);
  74. }
  75. TrackData::TrackData(const char *filename, unsigned long start,
  76.      unsigned long length)
  77. {
  78.   init(filename, 0, start, length);
  79. }
  80. void TrackData::init(const char *filename, long offset,
  81.      unsigned long start, unsigned long length)
  82. {
  83.   assert(offset >= 0);
  84.   length_ = length;
  85.   if (strcmp(filename, "-") == 0) {
  86.     type_ = STDIN;
  87.     fileType_ = RAW; // currently only raw data
  88.     filename_ = strdupCC("STDIN");
  89.   }
  90.   else {
  91.     type_ = DATAFILE;
  92.     filename_ = strdupCC(filename);
  93.     fileType_ = audioFileType(filename);
  94.   }
  95.   
  96.   offset_ = offset;
  97.   startPos_ = start;
  98.   swapSamples_ = 0;
  99.   mode_ = AUDIO;
  100. }
  101. // creates an object that contains constant data with specified mode
  102. TrackData::TrackData(Mode m, unsigned long length)
  103. {
  104.   type_ = ZERODATA;
  105.   mode_ = m;
  106.   filename_ = NULL;
  107.   fileType_ = RAW;
  108.   startPos_ = 0;
  109.   offset_ = 0;
  110.   length_ = length;
  111.   swapSamples_ = 0;
  112. }
  113. // creates a file object  with given mode
  114. TrackData::TrackData(Mode m, const char *filename, long offset,
  115.      unsigned long length)
  116. {
  117.   init(m, filename, offset, length);
  118. }
  119. TrackData::TrackData(Mode m, const char *filename, unsigned long length)
  120. {
  121.   init(m, filename, 0, length);
  122. }
  123. void TrackData::init(Mode m, const char *filename, long offset,
  124.      unsigned long length)
  125. {
  126.   assert(offset >= 0);
  127.   mode_ = m;
  128.   if (strcmp(filename, "-") == 0) {
  129.     type_ = STDIN;
  130.     fileType_ = RAW; // currently only raw data
  131.     filename_ = strdupCC("STDIN");
  132.   }
  133.   else {
  134.     type_ = DATAFILE;
  135.     filename_ = strdupCC(filename);
  136.     if (mode_ == AUDIO)
  137.       fileType_ = audioFileType(filename);
  138.     else
  139.       fileType_ = RAW; // data files are always raw
  140.   }
  141.   offset_ = offset;
  142.   length_ = length;
  143.   startPos_ = 0;
  144.   swapSamples_ = 0;
  145. }
  146. // copy constructor
  147. TrackData::TrackData(const TrackData &obj)
  148. {
  149.   type_ = obj.type_;
  150.   mode_ = obj.mode_;
  151.   offset_ = obj.offset_;
  152.   if (type_ == DATAFILE) {
  153.     filename_ = strdupCC(obj.filename_);
  154.     startPos_ = obj.startPos_;
  155.     fileType_ = obj.fileType_;
  156.   }
  157.   else if (type_ == STDIN) {
  158.     filename_ = strdupCC("STDIN");
  159.     startPos_ = obj.startPos_;
  160.     fileType_ = obj.fileType_;
  161.   }
  162.   else {
  163.     filename_ = NULL;
  164.     startPos_ = 0;
  165.     fileType_ = RAW;
  166.   }
  167.   length_ = obj.length_;
  168.   swapSamples_ = obj.swapSamples_;
  169. }
  170.     
  171. TrackData::~TrackData()
  172. {
  173.   if (filename_ != NULL) {
  174.     delete[] filename_;
  175.     filename_ = NULL;
  176.   }
  177. }
  178. unsigned long TrackData::length() const
  179. {
  180.   return length_;
  181. }
  182. // Determines length of data by inspecting the data file. The available data
  183. // from the specified start point up to the end of file is stored in 'length_'.
  184. // Return: 0: OK
  185. //         1: cannot open or access the file (see 'errno')
  186. //         2: start pos or offset exceeds length of file
  187. int TrackData::determineLength()
  188. {
  189.   unsigned long len;
  190.   if (type_ == DATAFILE) {
  191.     if (mode_ == AUDIO) {
  192.       switch (audioDataLength(filename_, offset_, &len)) {
  193.       case 1:
  194. message(-2, "Cannot open audio file "%s": %s", filename_,
  195. strerror(errno));
  196. return 1;
  197. break;
  198.       case 2:
  199. message(-2, "Cannot determine length of audio file "%s": %s",
  200. filename_, strerror(errno));
  201. return 1;
  202. break;
  203.       case 3:
  204. message(-2, "Header of audio file "%s" is corrupted.",
  205. filename_);
  206. return 1;
  207. break;
  208.       case 4:
  209. message(-2, "Invalid offset %ld for audio file "%s".", offset_,
  210. filename_);
  211. return 2;
  212. break;
  213.       }
  214.       if (startPos_ < len) {
  215. length_ = len - startPos_;
  216.       }
  217.       else {
  218. message(-2,
  219. "Start position %lu exceeds available data of file "%s".",
  220. startPos_, filename_);
  221. return 2;
  222.       }
  223.     }
  224.     else {
  225.       switch (dataFileLength(filename_, offset_, &len)) {
  226.       case 1:
  227. message(-2, "Cannot open data file "%s": %s", filename_,
  228. strerror(errno));
  229. return 1;
  230. break;
  231.       case 2:
  232. message(-2, "Invalid offset %ld for audio file "%s".", offset_,
  233. filename_);
  234. return 2;
  235. break;
  236.       }
  237.       length_ = len;
  238.     }
  239.   }
  240.   return 0;
  241. }
  242. // checks the consistency of object
  243. // return: 0: OK
  244. //         1: DATAFILE: file cannot be opened or 'stat()' failed
  245. //         2: DATAFILE: file length  does not match requested portion
  246. //         3: DATAFILE: file length is not a multiple of 'sizeof(Sample)'
  247. //         4: DATAFILE: length is zero
  248. int TrackData::check() const
  249. {
  250.   switch (type_) {
  251.   case ZERODATA:
  252.     // always OK
  253.     break;
  254.   case STDIN:
  255.     // cannot do much here...
  256.     break;
  257.   case DATAFILE:
  258.     if (mode_ == AUDIO) {
  259.       unsigned long len = 0;
  260.       switch (audioDataLength(filename_, offset_, &len)) {
  261.       case 1:
  262. message(-2, "Cannot open audio file "%s": %s", filename_,
  263. strerror(errno));
  264. return 1;
  265. break;
  266.       case 2:
  267. message(-2, "Cannot access audio file "%s": %s", filename_,
  268. strerror(errno));
  269. return 1;
  270. break;
  271.       case 3:
  272. message(-2, "%s: Unacceptable WAVE file.", filename_);
  273. return 1;
  274. break;
  275.       case 4:
  276. message(-2, "Invalid offset %ld for audio file "%s".", offset_,
  277. filename_);
  278. return 2;
  279. break;
  280.       }
  281.       if (length() == 0) {
  282. message(-2, "Requested length for audio file "%s" is 0.", filename_);
  283. return 4;
  284.       }
  285.       if (startPos_ + length() > len) {
  286. // requested part exceeds file size
  287. message(-2,
  288. "Requested length (%lu + %lu samples) exceeds length of audio file "%s" (%lu samples at offset %ld).",
  289. startPos_, length(), filename_, len, offset_);
  290. return 2;
  291.       }
  292.     }
  293.     else {
  294.       // data mode
  295.       unsigned long len;
  296.       switch (dataFileLength(filename_, offset_, &len) != 0) {
  297.       case 1:
  298. message(-2, "Cannot open data file "%s": %s", filename_,
  299. strerror(errno));
  300. return 1;
  301. break;
  302.       case 2:
  303. message(-2, "Invalid offset %ld for data file "%s".", offset_,
  304. filename_);
  305. return 2;
  306. break;
  307.       }
  308.       if (length() == 0) {
  309. message(-2, "Requested length for data file "%s" is 0.", filename_);
  310. return 4;
  311.       }
  312.       if (length() > len) {
  313. message(-2, "Requested length (%lu bytes) exceeds length of file "%s" (%lu bytes at offset %ld).",
  314. length(), filename_, len, offset_);
  315. return 2;
  316.       }
  317.     }
  318.     break;
  319.   }
  320.   return 0;
  321. }
  322. // writes out contents of object in TOC file syntax
  323. void TrackData::print(ostream &out) const
  324. {
  325.   unsigned long blen;
  326.   if (mode() == AUDIO) {
  327.     // we're calculating in samples and not in bytes for audio data
  328.     blen = SAMPLES_PER_BLOCK;
  329.   }
  330.   else {
  331.     blen  = dataBlockSize(mode());
  332.   }
  333.   switch (type()) {
  334.   case STDIN:
  335.   case DATAFILE:
  336.     if (mode() == AUDIO) {
  337.       if (type() == STDIN)
  338. out << "FILE "-" ";
  339.       else
  340. out << "FILE "" << filename_ << "" ";
  341.       if (swapSamples_)
  342. out << "SWAP ";
  343.       if (offset_ > 0)
  344. out << "#" << offset_ << " ";
  345.       if (startPos() != 0 && (startPos() % blen) == 0)
  346. out << Msf(startPos() / blen).str();
  347.       else
  348. out << startPos();
  349.     
  350.       out << " ";
  351.     }
  352.     else {
  353.       // data mode
  354.       if (type() == STDIN)
  355. out << "DATAFILE "-" ";
  356.       else
  357. out << "DATAFILE "" << filename_ << "" ";
  358.       //out <<  mode2String(mode()) << " ";
  359.       if (offset_ > 0)
  360. out << "#" << offset_ << " ";
  361.     }
  362.     if ((length() % blen) == 0)
  363.       out << Msf(length() / blen).str();
  364.     else
  365.       out << length();
  366.     if (mode() != AUDIO)
  367.       out << " // length in bytes: " << length();
  368.     out << endl;
  369.     break;
  370.   case ZERODATA:
  371.     if (mode_ == AUDIO) {
  372.       out << "SILENCE ";
  373.     }
  374.     else {
  375.       out << "ZERO " << mode2String(mode()) << " ";
  376.     }
  377.     
  378.     if ((length() % blen) == 0)
  379.       out << Msf(length() / blen).str();
  380.     else
  381.       out << length();
  382.     out << endl;
  383.     break;
  384.   }
  385. }
  386. void TrackData::split(unsigned long pos, TrackData **part1, TrackData **part2)
  387. {
  388.   assert(mode_ == AUDIO);
  389.   assert(pos > 0 && pos < length_);
  390.   *part1 = new TrackData(*this);
  391.   *part2 = new TrackData(*this);
  392.   (*part1)->length_ = pos;
  393.   (*part2)->length_ = length_ - pos;
  394.   if (type_ == DATAFILE)
  395.     (*part2)->startPos_ = startPos_ + pos;
  396. }
  397. TrackData *TrackData::merge(const TrackData *obj) const
  398. {
  399.   if (type_ != obj->type_ || mode_ != obj->mode_ || mode_ != AUDIO ||
  400.       offset_ != obj->offset_)
  401.     return NULL;
  402.   TrackData *data = NULL;
  403.   switch (type_) {
  404.   case ZERODATA:
  405.     data = new TrackData(*this);
  406.     data->length_ += obj->length_;
  407.     break;
  408.   case DATAFILE:
  409.     if (strcmp(filename_, obj->filename_) == 0 &&
  410. startPos_ + length_ == obj->startPos_) {
  411.       data = new TrackData(*this);
  412.       data->length_ += obj->length_;
  413.     }
  414.     break;
  415.   case STDIN:
  416.     // can't merge this type at all
  417.     break;
  418.   }
  419.   
  420.   return data;
  421. }
  422. // Checks if given audio file is suitable for cdrdao. 'length' is filled
  423. // with number of samples in audio file on success.
  424. // return: 0: file is suitable
  425. //         1: cannot open or access file
  426. //         2: file has wrong format
  427. int TrackData::checkAudioFile(const char *fn, unsigned long *length)
  428. {
  429.   int fd;
  430.   int ret;
  431.   struct stat buf;
  432.   long headerLength = 0;
  433.   
  434.   if ((fd = open(fn, O_RDONLY)) < 0)
  435.     return 1;
  436.   ret = fstat(fd, &buf);
  437.   close(fd);
  438.   if (ret != 0)
  439.     return 1;
  440.   if (audioFileType(fn) == WAVE) {
  441.     if (waveLength(fn, 0, &headerLength, length) != 0)
  442.       return 2;
  443.   }
  444.   else {
  445.     if (buf.st_size % sizeof(Sample) != 0) {
  446.       message(-1, "%s: Length is not a multiple of sample size (4).", fn);
  447.     }
  448.     *length = buf.st_size / sizeof(Sample);
  449.   }
  450.   return 0;
  451. }
  452. // Determines length of header and audio data for WAVE files. 'hdrlen' is
  453. // filled with length of WAVE header in bytes. 'datalen' is filled with
  454. // length of audio data in samples (if != NULL).
  455. // return: 0: OK
  456. //         1: error occured
  457. //         2: illegal WAVE file
  458. int TrackData::waveLength(const char *filename, long offset,
  459.   long *hdrlen, unsigned long *datalen)
  460. {
  461.   FILE *fp;
  462.   char magic[4];
  463.   long headerLen = 0;
  464.   long len;
  465.   short waveFormat;
  466.   short waveChannels;
  467.   long waveRate;
  468.   short waveBits;
  469.   struct stat sbuf;
  470. #ifdef _WIN32
  471.   if ((fp = fopen(filename, "rb")) == NULL)
  472. #else
  473.   if ((fp = fopen(filename, "r")) == NULL)
  474. #endif
  475.   {
  476.     message(-2, "Cannot open audio file "%s" for reading: %s",
  477.     filename, strerror(errno));
  478.     return 1;
  479.   }
  480.   if (offset != 0) {
  481.     if (fseek(fp, offset, SEEK_SET) != 0) {
  482.       message(-2, "Cannot seek to offset %ld in file "%s": %s",
  483.       offset, filename, strerror(errno));
  484.       return 1;
  485.     }
  486.   }
  487.   if (fread(magic, sizeof(char), 4, fp) != 4 ||
  488.       strncmp("RIFF", magic, 4) != 0) {
  489.     message(-2, "%s: not a WAVE file.", filename);
  490.     fclose(fp);
  491.     return 2;
  492.   }
  493.   readLong(fp);
  494.   if (fread(magic, sizeof(char), 4, fp) != 4 ||
  495.       strncmp("WAVE", magic, 4) != 0) {
  496.     message(-2, "%s: not a WAVE file.", filename);
  497.     fclose(fp);
  498.     return 2;
  499.   }
  500.   // search for format chunk
  501.   for (;;) {
  502.     if (fread(magic, sizeof(char), 4, fp) != 4) {
  503.       message(-2, "%s: corrupted WAVE file.", filename);
  504.       fclose(fp);
  505.       return 1;
  506.     }
  507.     len = readLong(fp);
  508.     len += len & 1; // round to multiple of 2
  509.     if (strncmp("fmt ", magic, 4) == 0) {
  510.       // format chunk found
  511.       break;
  512.     }
  513.     // skip chunk data
  514.     if (fseek(fp, len, SEEK_CUR) != 0) {
  515.       message(-2, "%s: corrupted WAVE file.", filename);
  516.       fclose(fp);
  517.       return 1;
  518.     }
  519.   }
  520.   if (len < 16) {
  521.     message(-2, "%s: corrupted WAVE file.", filename);
  522.     fclose(fp);
  523.     return 1;
  524.   }
  525.   waveFormat = readShort(fp);
  526.   if (waveFormat != 1) {
  527.     // not PCM format
  528.     message(-2, "%s: not in PCM format.", filename);
  529.     fclose(fp);
  530.     return 2;
  531.   }
  532.   waveChannels = readShort(fp);
  533.   if (waveChannels != 2) {
  534.     message(-2, "%s: found %d channel(s), require 2 channels.",
  535.     filename, waveChannels);
  536.     fclose(fp);
  537.     return 2;
  538.   }
  539.   waveRate = readLong(fp);
  540.   if (waveRate != 44100) {
  541.      message(-2, "%s: found sampling rate %ld, require 44100.",
  542.     filename, waveRate);
  543.      fclose(fp);
  544.      return 2;
  545.   }
  546.   
  547.   readLong(fp); // average bytes/second
  548.   readShort(fp); // block align
  549.   
  550.   waveBits = readShort(fp);
  551.   if (waveBits != 16) {
  552.     message(-2, "%s: found %d bits per sample, require 16.",
  553.     filename, waveBits);
  554.     fclose(fp);
  555.     return 2;
  556.   }
  557.   
  558.   len -= 16;
  559.   // skip chunk data
  560.   if (fseek(fp, len, SEEK_CUR) != 0) {
  561.     message(-2, "%s: corrupted WAVE file.", filename);
  562.     fclose(fp);
  563.     return 1;
  564.   }
  565.   // search wave data chunk
  566.   for (;;) {
  567.     if (fread(magic, sizeof(char), 4, fp) != 4) {
  568.       message(-2, "%s: corrupted WAVE file.", filename);
  569.       fclose(fp);
  570.       return 1;
  571.     }
  572.     
  573.     len = readLong(fp);
  574.     if (strncmp("data", magic, 4) == 0) {
  575.       // found data chunk
  576.       break;
  577.     }
  578.     len += len & 1; // round to multiple of 2
  579.      
  580.     // skip chunk data
  581.     if (fseek(fp, len, SEEK_CUR) != 0) {
  582.       message(-2, "%s: corrupted WAVE file.", filename);
  583.       fclose(fp);
  584.       return 1;
  585.     }
  586.   }
  587.   if ((headerLen = ftell(fp)) < 0) {
  588.     message(-2, "%s: cannot determine file position: %s",
  589.     filename, strerror(errno));
  590.     fclose(fp);
  591.     return 1;
  592.   }
  593.   headerLen -= offset;
  594.   if (fstat(fileno(fp), &sbuf) != 0) {
  595.     message(-2, "Cannot fstat audio file "%s": %s", filename,
  596.     strerror(errno));
  597.     fclose(fp);
  598.     return 1;
  599.   }
  600.   fclose(fp);
  601.   if (len + headerLen + offset > sbuf.st_size) {
  602.     message(-1, "%s: file length does not match length from WAVE header - using actual length.", filename);
  603.     len = sbuf.st_size - offset - headerLen;
  604.   }
  605.   if (len % sizeof(Sample) != 0) {
  606.     message(-1,
  607.     "%s: length of data chunk is not a multiple of sample size (4).",
  608.     filename);
  609.   }
  610.   *hdrlen = headerLen;
  611.   
  612.   if (datalen != NULL) 
  613.     *datalen = len / sizeof(Sample);
  614.   return 0;
  615. }
  616. // Returns length in samples for given audio file.
  617. // return: 1: file cannot be opened
  618. //         2: 'fstat' failed
  619. //         3: file header corruption
  620. //         4: invalid offset
  621. //         0: OK
  622. int TrackData::audioDataLength(const char *fname, long offset, 
  623.        unsigned long *length)
  624. {
  625.   int fd;
  626.   struct stat buf;
  627.   long headerLength = 0;
  628.   int ret;
  629.   *length = 0;
  630.   if ((fd = open(fname, O_RDONLY)) < 0)
  631.     return 1;
  632.   ret = fstat(fd, &buf);
  633.   close(fd);
  634.   if (ret != 0)
  635.     return 2;
  636.   if (offset > buf.st_size)
  637.     return 4;
  638.   if (audioFileType(fname) == WAVE) {
  639.     if (waveLength(fname, offset, &headerLength, length) != 0)
  640.       return 3;
  641.   }
  642.   else {
  643.     if (((buf.st_size - offset) % sizeof(Sample)) != 0) {
  644.       message(-1,
  645.       "Length of file "%s" is not a multiple of sample size (4).",
  646.       fname);
  647.     }
  648.     *length = (buf.st_size - offset) / sizeof(Sample);
  649.   }
  650.   return 0;
  651. }
  652. // Sets 'length' to length of given data file.
  653. // return: 0: OK
  654. //         1: file cannot be opened or accessed
  655. //         2: invalid offset
  656. int TrackData::dataFileLength(const char *fname, long offset,
  657.       unsigned long *length)
  658. {
  659.   int fd;
  660.   struct stat buf;
  661.   int ret;
  662.   *length = 0;
  663.   if ((fd = open(fname, O_RDONLY)) < 0)
  664.     return 1;
  665.   ret = fstat(fd, &buf);
  666.   close(fd);
  667.   if (ret != 0)
  668.     return 1;
  669.   if (offset > buf.st_size)
  670.     return 2;
  671.   *length = buf.st_size - offset;
  672.   return 0;
  673. }
  674. // determines type of audio file
  675. // return: RAW: raw samples
  676. //         WAVE: wave file
  677. TrackData::FileType TrackData::audioFileType(const char *filename)
  678. {
  679.   char *p;
  680.   if ((p = strrchr(filename, '.')) != NULL) {
  681.     if (strcasecmp(p, ".wav") == 0) {
  682.       return WAVE;
  683.     }
  684.   }
  685.   return RAW;
  686. }
  687. unsigned long TrackData::dataBlockSize(Mode m)
  688. {
  689.   unsigned long b = 0;
  690.   switch (m) {
  691.   case AUDIO:
  692.   case MODE1_RAW:
  693.   case MODE2_RAW:
  694.     b = AUDIO_BLOCK_LEN;
  695.     break;
  696.   case MODE0:
  697.     b = MODE0_BLOCK_LEN;
  698.     break;
  699.   case MODE1:
  700.     b = MODE1_BLOCK_LEN;
  701.     break;
  702.   case MODE2:
  703.   case MODE2_FORM_MIX:
  704.     b = MODE2_BLOCK_LEN;
  705.     break;
  706.   case MODE2_FORM1:
  707.     b = MODE2_FORM1_DATA_LEN;
  708.     break;
  709.   case MODE2_FORM2:
  710.     b = MODE2_FORM2_DATA_LEN;
  711.     break;
  712.   }
  713.   return b;
  714. }
  715. const char *TrackData::mode2String(Mode m)
  716. {
  717.   const char *ret = NULL;
  718.   switch (m) {
  719.   case AUDIO:
  720.     ret = "AUDIO";
  721.     break;
  722.   case MODE0:
  723.     ret = "MODE0";
  724.     break;
  725.   case MODE1:
  726.     ret = "MODE1";
  727.     break;
  728.   case MODE1_RAW:
  729.     ret = "MODE1_RAW";
  730.     break;
  731.   case MODE2:
  732.     ret = "MODE2";
  733.     break;
  734.   case MODE2_RAW:
  735.     ret = "MODE2_RAW";
  736.     break;
  737.   case MODE2_FORM1:
  738.     ret = "MODE2_FORM1";
  739.     break;
  740.   case MODE2_FORM2:
  741.     ret = "MODE2_FORM2";
  742.     break;
  743.   case MODE2_FORM_MIX:
  744.     ret = "MODE2_FORM_MIX";
  745.     break;
  746.   }
  747.   return ret;
  748. }
  749. TrackDataReader::TrackDataReader(const TrackData *d)
  750. {
  751.   trackData_ = d;
  752.   open_ = 0;
  753.   fd_ = -1;
  754.   readPos_ = 0;
  755.   headerLength_ = 0;
  756.   readUnderRunMsgGiven_ = 0;
  757. }
  758. TrackDataReader::~TrackDataReader()
  759. {
  760.   if (open_) {
  761.     closeData();
  762.   }
  763.   trackData_ = NULL;
  764. }
  765. void TrackDataReader::init(const TrackData *d)
  766. {
  767.   if (open_) {
  768.     closeData();
  769.   }
  770.   trackData_ = d;
  771. }
  772. // initiates reading audio data, an audio data file is opened
  773. // return: 0: OK
  774. //         1: file could not be opened
  775. //         2: could not seek to start position
  776. int TrackDataReader::openData()
  777. {
  778.   assert(open_ == 0);
  779.   assert(trackData_ != NULL);
  780.   if (trackData_->type_ == TrackData::DATAFILE) {
  781.     if (trackData_->mode_ == TrackData::AUDIO) {
  782.       long headerLength = 0;
  783. #ifdef _WIN32
  784.       if ((fd_ = open(trackData_->filename_, O_RDONLY | O_BINARY)) < 0)
  785. #else
  786.       if ((fd_ = open(trackData_->filename_, O_RDONLY)) < 0)
  787. #endif
  788.       {
  789. message(-2, "Cannot open audio file "%s": %s", trackData_->filename_,
  790. strerror(errno));
  791. return 1;
  792.       }
  793.       if (trackData_->fileType_ == TrackData::WAVE) {
  794. if (TrackData::waveLength(trackData_->filename_, trackData_->offset_,
  795.   &headerLength) != 0) {
  796.   message(-2, "%s: Unacceptable WAVE file.", trackData_->filename_);
  797.   return 1;
  798. }
  799.       }
  800.       
  801.       if (lseek(fd_, trackData_->offset_ + headerLength + (trackData_->startPos_ * sizeof(Sample)), SEEK_SET) < 0) {
  802. message(-2, "Cannot seek in audio file "%s": %s",
  803. trackData_->filename_, strerror(errno));
  804. return 2;
  805.       }
  806.       headerLength_ = headerLength;
  807.     }
  808.     else {
  809.       // data mode
  810.       headerLength_ = 0;
  811. #ifdef _WIN32
  812.       if ((fd_ = open(trackData_->filename_, O_RDONLY | O_BINARY)) < 0)
  813. #else
  814.       if ((fd_ = open(trackData_->filename_, O_RDONLY)) < 0)
  815. #endif
  816.       {
  817. message(-2, "Cannot open data file "%s": %s", trackData_->filename_,
  818. strerror(errno));
  819. return 1;
  820.       }
  821.       if (trackData_->offset_ > 0) {
  822. if (lseek(fd_, trackData_->offset_ , SEEK_SET) < 0) {
  823.   message(-2, "Cannot seek to offset %ld in file "%s": %s",
  824.   trackData_->offset_, trackData_->filename_, strerror(errno));
  825.   return 2;
  826. }
  827.       }
  828.     }
  829.   }
  830.   else if (trackData_->type_ == TrackData::STDIN) {
  831.     headerLength_ = 0;
  832.     fd_ = fileno(stdin);
  833.   }
  834.   readPos_ = 0;
  835.   open_ = 1;
  836.   readUnderRunMsgGiven_ = 0;
  837.   return 0;
  838. }
  839. // ends reading audio data, an audio data file is closed
  840. void TrackDataReader::closeData()
  841. {
  842.   if (open_ != 0) {
  843.     if (trackData_->type_ == TrackData::DATAFILE) {
  844.       close(fd_);
  845.     }
  846.     fd_ = -1;
  847.     open_ = 0;
  848.     readPos_ = 0;
  849.   }
  850. }
  851. // fills 'buffer' with 'len' samples
  852. // return: number of samples written to buffer
  853. long TrackDataReader::readData(Sample *buffer, long len)
  854. {
  855.   long readLen = 0;
  856.   assert(open_ != 0);
  857.   if (len == 0) {
  858.     return 0;
  859.   }
  860.   if (readPos_ + len > trackData_->length()) {
  861.     if ((len = trackData_->length() - readPos_) <= 0) {
  862.       return 0;
  863.     }
  864.   }
  865.   switch (trackData_->type_) {
  866.   case TrackData::ZERODATA:
  867.     if (trackData_->mode_ == TrackData::AUDIO)
  868.       memset(buffer, 0, len * sizeof(Sample));
  869.     else
  870.       memset(buffer, 0, len);
  871.     
  872.     readLen = len;
  873.     break;
  874.   case TrackData::STDIN:
  875.   case TrackData::DATAFILE:
  876.     if (trackData_->mode_ == TrackData::AUDIO) {
  877.       readLen = fullRead(fd_, buffer, len * sizeof(Sample));
  878.       if (readLen < 0) {
  879. message(-2, "Read error while reading audio data from file "%s": %s",
  880. trackData_->filename_, strerror(errno));
  881.       }
  882.       else if (readLen != (long)(len * sizeof(Sample))) {
  883. long pad = len * sizeof(Sample) - readLen;
  884. if (readUnderRunMsgGiven_ == 0) {
  885.   message(-1, "Could not read expected amount of audio data from file "%s".", trackData_->filename_);
  886.   message(-1, "Padding with zeros.");
  887.   readUnderRunMsgGiven_ = 1;
  888. }
  889. // Adding zeros to the 'buffer'
  890. memset(buffer + readLen, 0, pad);
  891. readLen = len;
  892.       }
  893.       else {
  894. readLen = len;
  895.       }
  896.     }
  897.     else {
  898.       readLen = fullRead(fd_, buffer, len);
  899.       if (readLen < 0) {
  900. message(-2, "Read error while reading data from file "%s": %s",
  901. trackData_->filename_, strerror(errno));
  902.       }
  903.       else if (readLen != len) {
  904. message(-2, "Could not read expected amount of data from file "%s".",
  905. trackData_->filename_);
  906. readLen = -1;
  907.       }
  908.     }
  909.     break;
  910.   }
  911.   if (readLen > 0) {
  912.     if (trackData_->mode_ == TrackData::AUDIO) {
  913.       int swap = 0;
  914.       if (trackData_->fileType_ == TrackData::WAVE) {
  915. // WAVE files contain little endian samples
  916. swap = 1;
  917.       }
  918.       if (trackData_->swapSamples_) 
  919. swap = !swap;
  920.       if (swap) {
  921. // swap samples 
  922. swapSamples(buffer, readLen);
  923.       }
  924.     }
  925.     readPos_ += readLen;
  926.   }
  927.   return readLen;
  928. }
  929. // Seeks to specified sample.
  930. // return: 0: OK
  931. //        10: sample out of range
  932. int TrackDataReader::seekSample(unsigned long sample)
  933. {
  934.   assert(open_ != 0);
  935.   if (sample >= trackData_->length()) 
  936.     return 10;
  937.   if (trackData_->type_ == TrackData::DATAFILE) {
  938.     if (lseek(fd_,
  939.       trackData_->offset_ + headerLength_ +
  940.       (sample * sizeof(Sample)) + 
  941.       (trackData_->startPos_ * sizeof(Sample)),
  942.       SEEK_SET) < 0) {
  943.       message(-2, "Cannot seek in audio file "%s": %s",
  944.       trackData_->filename_, strerror(errno));
  945.       return 10;
  946.     }
  947.   }
  948.   readPos_ = sample;
  949.   
  950.   return 0;
  951. }
  952. // Returns number of bytes that are still available for reading.
  953. unsigned long TrackDataReader::readLeft() const
  954. {
  955.   assert(open_ != 0);
  956.   assert(trackData_ != NULL);
  957.   return trackData_->length() - readPos_;
  958. }