DSF2FLAC
dsdiff_file_reader.cpp
00001 /*
00002  * dsf2flac - http://code.google.com/p/dsf2flac/
00003  *
00004  * A file conversion tool for translating dsf dsd audio files into
00005  * flac pcm audio files.
00006  *
00007  * Copyright (c) 2013 by respective authors.
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  *
00024  * Acknowledgements
00025  *
00026  * Many thanks to the following authors and projects whose work has greatly
00027  * helped the development of this tool.
00028  *
00029  *
00030  * Sebastian Gesemann - dsd2pcm (http://code.google.com/p/dsd2pcm/)
00031  * SACD Ripper (http://code.google.com/p/sacd-ripper/)
00032  * Maxim V.Anisiutkin - foo_input_sacd (http://sourceforge.net/projects/sacddecoder/files/)
00033  * Vladislav Goncharov - foo_input_sacd_hq (http://vladgsound.wordpress.com)
00034  * Jesus R - www.sonore.us
00035  *
00036  */
00037 
00038 
00039 #include "dsdiff_file_reader.h"
00040 #include "iostream"
00041 #include "libdstdec/dst_init.h"
00042 #include "libdstdec/dst_fram.h"
00043 static bool chanIdentsAllocated = false;
00044 static bool sampleBufferAllocated = false;
00045 static ebunch dstEbunch;
00046 static bool dstEbunchAllocated = false;
00047 dsdiffFileReader::dsdiffFileReader(char* filePath) : DsdSampleReader()
00048 {
00049         // set some defaults
00050         ast.hours = 0;
00051         ast.minutes = 0;
00052         ast.seconds = 0;
00053         ast.samples = 0;
00054         samplesPerChar = 8; // always 8 samples per char (dsd wide not supported by dsdiff).
00055         sampleBufferLenPerChan = 1024;
00056         bufferMarker = 0;
00057         errorMsg = "";
00058         lsConfig=65535;
00059         isEm=false;
00060         // first let's open the file
00061         file.open(filePath, fstreamPlus::in | fstreamPlus::binary);
00062         // throw exception if that did not work.
00063         if (!file.is_open()) {
00064                 errorMsg = "could not open file";
00065                 valid = false;
00066                 return;
00067         }
00068         // try and read the header data
00069         if (!(valid = readHeaders()))
00070                 return;
00071                 
00072         // find the start and end of the tracks.
00073         processTracks();
00074                 
00075         // if DST data, then initialise the decoder
00076         if (checkIdent(compressionType,const_cast<dsf2flac_int8*>("DST "))) {
00077                 DST_InitDecoder(&dstEbunch, getNumChannels(), getSamplingFreq()/44100);
00078                 dstEbunchAllocated = true;
00079         }
00080         
00081         rewind(); // calls allocateBlockBuffer
00082         
00083         return;
00084 }
00085 dsdiffFileReader::~dsdiffFileReader()
00086 {
00087         // close the file
00088         file.close();
00089         // free mem in the chanIdents
00090         if (chanIdentsAllocated) {
00091                 for (dsf2flac_uint16 i=0; i<chanNum; i++)
00092                         delete[] chanIdents[i];
00093                 delete[] chanIdents;
00094         }
00095         // free sample buffer
00096         if (sampleBufferAllocated)
00097                 delete[] sampleBuffer;
00098         // free comments
00099         typename std::vector<DsdiffComment>::iterator c=comments.begin();
00100         while(c!=comments.end()) {
00101                 delete[] c->commentText;
00102                 ++c;
00103         }
00104         comments.clear();
00105         // free markers
00106         typename std::vector<DsdiffMarker>::iterator m=markers.begin();
00107         while(m!=markers.end()) {
00108                 delete[] m->markerText;
00109                 ++m;
00110         }
00111         markers.clear();
00112         // free emid
00113         if (isEm)
00114                 delete[] emid;
00115         
00116         // free the DST decoder (assuming one was used)
00117         if (dstEbunchAllocated) {
00118                 DST_CloseDecoder(&dstEbunch);
00119         }
00120 }
00127 void dsdiffFileReader::allocateSampleBuffer()
00128 {
00129         if (sampleBufferAllocated)
00130                 return;
00131         sampleBuffer = new dsf2flac_uint8[getNumChannels()*sampleBufferLenPerChan];
00132         sampleBufferAllocated = true;
00133 }
00140 void dsdiffFileReader::rewind()
00141 {
00142         // position the file at the start of the data chunk
00143         if (file.seekg(sampleDataPointer)) {
00144                 errorMsg = "dsfFileReader::rewind:file seek error";
00145         }
00146         allocateSampleBuffer();
00147         bufferCounter = 0;
00148         bufferMarker = 0;
00149         readNextBlock();
00150         bufferCounter = 0;
00151         posMarker = -1;
00152         clearBuffer();
00153 }
00154 
00161 bool dsdiffFileReader::readNextBlock() {
00162         
00163         bool ok = true;
00164         // return false if this is the end of the file
00165         if (!samplesAvailable()) {
00166                 errorMsg = "dsfFileReader::readNextBlock:no more data in file";
00167                 ok = false;
00168         }
00169         
00170         dsf2flac_int64 samplesLeft = getLength()-getPosition();
00171         
00172         if (ok && checkIdent(compressionType,const_cast<dsf2flac_int8*>("DSD "))) {
00173                 if (samplesLeft/samplesPerChar < sampleBufferLenPerChan) {
00174                         // fill the blockBuffer with the idle sample
00175                         for (dsf2flac_uint32 i=0; i<chanNum*sampleBufferLenPerChan; i++)
00176                                 sampleBuffer[i] = getIdleSample();
00177                         if (file.read_uint8(sampleBuffer,chanNum*samplesLeft/samplesPerChar)) {
00178                                 errorMsg = "dsfFileReader::readNextBlock:file read error";
00179                                 ok = false;
00180                         }
00181                 } else if (file.read_uint8(sampleBuffer,chanNum*sampleBufferLenPerChan)) {
00182                         errorMsg = "dsfFileReader::readNextBlock:file read error";
00183                         ok = false;
00184                 }
00185         } else if (ok && checkIdent(compressionType,const_cast<dsf2flac_int8*>("DST "))) {
00186                 
00187                 dsf2flac_uint64 chunkStart = file.tellg();
00188                 dsf2flac_uint64 chunkSz;
00189                 dsf2flac_int8 ident[5];
00190                 ident[4]='\0';
00191                 
00192                 if (chunkStart > dstChunkEnd)
00193                         ok = false;
00194                 
00195                 // read the chunk header
00196                 if (ok)
00197                         ok = readChunkHeader(ident,chunkStart,&chunkSz);
00198                 
00199                 // we might have a DSTC chunk, which we will ignore
00200                 if (ok)
00201                         if (checkIdent(ident,const_cast<dsf2flac_int8*>("DSTC")))
00202                                 ok = readChunkHeader(ident,chunkStart,&chunkSz);
00203                                 
00204                 // decode
00205                 if (ok)
00206                         ok = readChunk_DSTF(chunkStart);
00207 
00208                 // make sure we are in the right place for next time
00209                 file.seekg(chunkStart + chunkSz);
00210         } else
00211                 ok = false;
00212         
00213         
00214         if (!ok) {
00215                 // fill the blockBuffer with the idle sample
00216                 for (dsf2flac_uint32 i=0; i<chanNum*sampleBufferLenPerChan; i++)
00217                         sampleBuffer[i] = getIdleSample();
00218         }
00219         
00220         bufferCounter++;
00221         bufferMarker=0;
00222 
00223         return ok;
00224 }
00232 bool dsdiffFileReader::step()
00233 {
00234         bool ok = true;
00235         
00236         if (!samplesAvailable())
00237                 ok = false;
00238         else if (bufferMarker>=sampleBufferLenPerChan)
00239                 ok = readNextBlock();
00240         
00241         if (ok) {
00242                 for (dsf2flac_uint16 i=0; i<chanNum; i++)
00243                         circularBuffers[i].push_front(sampleBuffer[i+bufferMarker*chanNum]);
00244                 bufferMarker++;
00245         } else {
00246                 for (dsf2flac_uint16 i=0; i<chanNum; i++)
00247                         circularBuffers[i].push_front(getIdleSample());
00248         }
00249         
00250         posMarker++;
00251         return ok;
00252 }
00258 dsf2flac_uint64 dsdiffFileReader::getTrackStart(dsf2flac_uint32 trackNum) {
00259         if (trackNum >= numTracks)
00260                 return 0;
00261         return trackStartPositions[trackNum];
00262 }
00268 dsf2flac_uint64 dsdiffFileReader::getTrackEnd(dsf2flac_uint32 trackNum) {
00269         if (trackNum >= numTracks)
00270                 return getLength();
00271         return trackEndPositions[trackNum];
00272                 
00273 }
00280  ID3_Tag dsdiffFileReader::getID3Tag(dsf2flac_uint32 trackNum) {
00281         if (trackNum >= tags.size())
00282                 return NULL;
00283         return tags[trackNum];
00284 }
00291 bool dsdiffFileReader::readHeaders()
00292 {
00293         // look for the FRM8 chunk (probably at the start of the data).
00294         dsf2flac_int8 ident[5];
00295         ident[4]='\0';
00296         dsf2flac_uint64 chunkStart;
00297         dsf2flac_uint64 chunkSz;
00298         bool frm8read = false;
00299         bool frm8valid = false;
00300         // assum first chunk is at the start of the file.
00301         chunkStart = 0;
00302         // stop once one frm8 chunk is read
00303         while (!frm8read) {
00304                 // read the chunk header
00305                 if (!readChunkHeader(ident,chunkStart,&chunkSz))
00306                         return false;
00307                 // did we find a FRM8 chunk??
00308                 if ( checkIdent(ident,const_cast<dsf2flac_int8*>("FRM8")) ) {
00309                         frm8valid = readChunk_FRM8(chunkStart);
00310                         frm8read = true;
00311                 }
00312                 // otherwise, move to the next chunk
00313                 chunkStart +=chunkSz;
00314         }
00315         return frm8valid;
00316 }
00317 bool dsdiffFileReader::readChunk_FRM8(dsf2flac_uint64 chunkStart)
00318 {
00319         // read the header so that we are certain we are in the correct place.
00320         dsf2flac_int8 ident[5];
00321         ident[4]='\0';
00322         dsf2flac_uint64 chunkSz;
00323         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00324                 return false;
00325         // check the ident
00326         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("FRM8")) ) {
00327                 errorMsg = "dsdiffFileReader::readChunk_FRM8:chunk ident error";
00328                 return false;
00329         }
00330         // another ident which MUST be "DSD "
00331         if (file.read_int8_rev(ident,4)) {
00332                 errorMsg = "dsdiffFileReader::readChunk_FRM8:file read error";
00333                 return false;
00334         }
00335         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("DSD ")) ) {
00336                 errorMsg = "dsdiffFileReader::readChunk_FRM8:chunk ident error";
00337                 return false;
00338         }
00339         // read all sub chunks in the FRM8 chunk
00340         dsf2flac_uint64 subChunkStart = file.tellg();
00341         dsf2flac_uint64 subChunkSz;
00342         // keep track of the non-optional chunks
00343         bool found_fver = false;
00344         bool found_prop = false;
00345         bool found_dsdt = false; // either dsd or dst
00346         
00347         while (subChunkStart < chunkStart + chunkSz) {
00348                 // read the header
00349                 if (!readChunkHeader(ident,subChunkStart,&subChunkSz))
00350                         return false;
00351                 // see if we know how to read this chunk
00352                 if ( !found_fver && checkIdent(ident,const_cast<dsf2flac_int8*>("FVER")) ) {
00353                         found_fver = readChunk_FVER(subChunkStart);
00354                 } else if ( !found_prop && checkIdent(ident,const_cast<dsf2flac_int8*>("PROP")) ) {
00355                         found_prop = readChunk_PROP(subChunkStart);
00356                 } else if ( !found_dsdt && checkIdent(ident,const_cast<dsf2flac_int8*>("DSD ")) ) {
00357                         found_dsdt = readChunk_DSD(subChunkStart);
00358                 } else if ( !found_dsdt && checkIdent(ident,const_cast<dsf2flac_int8*>("DST ")) ) {
00359                         found_dsdt = readChunk_DST(subChunkStart);
00360                 } else if ( checkIdent(ident,const_cast<dsf2flac_int8*>("COMT")) ) {
00361                         readChunk_COMT(subChunkStart);
00362                 } else if ( checkIdent(ident,const_cast<dsf2flac_int8*>("ID3 ")) ) {
00363                         readChunk_ID3(subChunkStart);
00364                 } else if ( checkIdent(ident,const_cast<dsf2flac_int8*>("DIIN")) ) {
00365                         readChunk_DIIN(subChunkStart);
00366                 } else if ( checkIdent(ident,const_cast<dsf2flac_int8*>("DSTI")) ) {
00367                         readChunk_DSTI(subChunkStart);
00368                 } else
00369                         printf("WARNING: unknown chunk type: %s\n",ident);
00370                 // move to the next chunk
00371                 subChunkStart = subChunkStart + subChunkSz;
00372         }
00373         // return true if all required chunks are ok.
00374         if (!found_fver) {
00375                 errorMsg = "dsdiffFileReader::readChunk_FRM8:No valid FVER chunk found";
00376                 return false;
00377         } else if (!found_prop) {
00378                 errorMsg = "dsdiffFileReader::readChunk_FRM8:No valid PROP chunk found";
00379                 return false;
00380         } else if (!found_dsdt) {
00381                 errorMsg = "dsdiffFileReader::readChunk_FRM8:No valid DSD or DST chunk found";
00382                 return false;
00383         } else
00384                 return true;
00385 }
00386 bool dsdiffFileReader::readChunk_FVER(dsf2flac_uint64 chunkStart)
00387 {
00388         // read the header so that we are certain we are in the correct place.
00389         dsf2flac_int8 ident[5];
00390         ident[4]='\0';
00391         if (!readChunkHeader(ident,chunkStart))
00392                 return false;
00393         // check the ident
00394         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("FVER")) ) {
00395                 errorMsg = "dsdiffFileReader::readChunk_FVER:chunk ident error";
00396                 return false;
00397         }
00398         // read the file version
00399         if (file.read_uint32_rev(&dsdiffVersion,1)) {
00400                 errorMsg = "dsdiffFileReader::readChunk_FVER:file read error";
00401                 return false;
00402         };
00403         return true;
00404 }
00405 bool dsdiffFileReader::readChunk_PROP(dsf2flac_uint64 chunkStart)
00406 {
00407         // read the header so that we are certain we are in the correct place.
00408         dsf2flac_int8 ident[5];
00409         ident[4]='\0';
00410         dsf2flac_uint64 chunkSz;
00411         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00412                 return false;
00413         // check the ident
00414         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("PROP")) ) {
00415                 errorMsg = "dsdiffFileReader::readChunk_PROP:chunk ident error";
00416                 return false;
00417         }
00418         // another ident which MUST be "SND "
00419         if (file.read_int8(ident,4)) {
00420                 errorMsg = "dsdiffFileReader::readChunk_PROP:file read error";
00421                 return false;
00422         }
00423         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("SND ")) ) {
00424                 errorMsg = "dsdiffFileReader::readChunk_PROP:PROP chunk format error";
00425                 return false;
00426         }
00427         // read all sub chunks in the FRM8 chunk
00428         dsf2flac_uint64 subChunkStart = file.tellg();
00429         dsf2flac_uint64 subChunkSz;
00430         // keep track of the chunks we've read
00431         bool found_fs   = false;
00432         bool found_chnl = false;
00433         bool found_cmpr = false;
00434         bool found_abss = false;
00435         bool found_lsco = false;
00436         //
00437         while (subChunkStart < chunkStart + chunkSz) {
00438                 // read the header
00439                 if (!readChunkHeader(ident,subChunkStart,&subChunkSz))
00440                         return false;
00441                 // see if we know how to read this chunk
00442                 if ( !found_fs && checkIdent(ident,const_cast<dsf2flac_int8*>("FS  ")) ) {
00443                         found_fs = readChunk_FS(subChunkStart);
00444                 } else if ( !found_chnl && checkIdent(ident,const_cast<dsf2flac_int8*>("CHNL")) ) {
00445                         found_chnl = readChunk_CHNL(subChunkStart);
00446                 } else if ( !found_cmpr && checkIdent(ident,const_cast<dsf2flac_int8*>("CMPR")) ) {
00447                         found_cmpr = readChunk_CMPR(subChunkStart);
00448                 } else if ( !found_abss && checkIdent(ident,const_cast<dsf2flac_int8*>("ABSS")) ) {
00449                         found_abss = readChunk_ABSS(subChunkStart);
00450                 } else if ( !found_lsco && checkIdent(ident,const_cast<dsf2flac_int8*>("LSCO")) ) {
00451                         found_lsco = readChunk_LSCO(subChunkStart);
00452                 } else
00453                         printf("WARNING: unknown or repeated chunk type: %s\n",ident);
00454                 // move to the next chunk
00455                 subChunkStart = subChunkStart + subChunkSz;
00456         }
00457         // check that all the required chunks were read
00458         if (!found_fs) {
00459                 errorMsg = "dsdiffFileReader::readChunk_PROP: no valid FS chunk";
00460                 return false;
00461         } else if (!found_chnl) {
00462                 errorMsg = "dsdiffFileReader::readChunk_PROP: no valid CHNL chunk";
00463                 return false;
00464         } else if (!found_cmpr) {
00465                 errorMsg = "dsdiffFileReader::readChunk_PROP: no valid CMPR chunk";
00466                 return false;
00467         } else
00468                 return true;
00469 }
00470 bool dsdiffFileReader::readChunk_FS(dsf2flac_uint64 chunkStart)
00471 {
00472         // read the header so that we are certain we are in the correct place.
00473         dsf2flac_int8 ident[5];
00474         ident[4]='\0';
00475         if (!readChunkHeader(ident,chunkStart))
00476                 return false;
00477         // check the ident
00478         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("FS  ")) ) {
00479                 errorMsg = "dsdiffFileReader::readChunk_FS:chunk ident error";
00480                 return false;
00481         }
00482         if (file.read_uint32_rev(&samplingFreq,1)) {
00483                 errorMsg = "dsdiffFileReader::readChunk_FS:File read error";
00484                 return false;
00485         }
00486         return true;
00487 }
00488 bool dsdiffFileReader::readChunk_CHNL(dsf2flac_uint64 chunkStart)
00489 {
00490         // read the header so that we are certain we are in the correct place.
00491         dsf2flac_int8 ident[5];
00492         ident[4]='\0';
00493         if (!readChunkHeader(ident,chunkStart))
00494                 return false;
00495         // check the ident
00496         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("CHNL")) ) {
00497                 errorMsg = "dsdiffFileReader::readChunk_CHNL:chunk ident error";
00498                 return false;
00499         }
00500         // read number of channels
00501         if (file.read_uint16_rev(&chanNum,1)) {
00502                 errorMsg = "dsdiffFileReader::readChunk_CHNL:file read error";
00503                 return false;
00504         }
00505         // read channel identifiers
00506         chanIdents = new dsf2flac_int8*[chanNum];
00507         for (dsf2flac_uint16 i=0; i<chanNum; i++) {
00508                 chanIdents[i] = new dsf2flac_int8[5];
00509                 if (file.read_int8(chanIdents[i],4)) {
00510                         errorMsg = "dsdiffFileReader::readChunk_CHNL:file read error";
00511                         return false;
00512                 };
00513                 chanIdents[i][4] = '\0';
00514         }
00515         return true;
00516 }
00517 bool dsdiffFileReader::readChunk_CMPR(dsf2flac_uint64 chunkStart)
00518 {
00519         // read the header so that we are certain we are in the correct place.
00520         dsf2flac_int8 ident[5];
00521         ident[4]='\0';
00522         if (!readChunkHeader(ident,chunkStart))
00523                 return false;
00524         // check the ident
00525         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("CMPR")) ) {
00526                 errorMsg = "dsdiffFileReader::readChunk_CMPR:chunk ident error";
00527                 return false;
00528         }
00529         // type of compression
00530         compressionType[4] = '\0';
00531         if (file.read_int8(compressionType,4)) {
00532                 errorMsg = "dsdiffFileReader::readChunk_CMPR:file read error";
00533                 return false;
00534         }
00535         // read length of next entry
00536         dsf2flac_uint8 n;
00537         if (file.read_uint8(&n,1)) {
00538                 errorMsg = "dsdiffFileReader::readChunk_CMPR:file read error";
00539                 return false;
00540         }
00541         compressionName = new dsf2flac_int8[n+1];
00542         compressionName[n] = '\0';
00543         if (file.read_int8(compressionName,n)) {
00544                 errorMsg = "dsdiffFileReader::readChunk_CMPR:file read error";
00545                 return false;
00546         }
00547         return true;
00548 }
00549 bool dsdiffFileReader::readChunk_ABSS(dsf2flac_uint64 chunkStart)
00550 {
00551         // read the header so that we are certain we are in the correct place.
00552         dsf2flac_int8 ident[5];
00553         ident[4]='\0';
00554         if (!readChunkHeader(ident,chunkStart))
00555                 return false;
00556         // check the ident
00557         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("ABSS")) ) {
00558                 errorMsg = "dsdiffFileReader::readChunk_ABSS:chunk ident error";
00559                 return false;
00560         }
00561         // hours
00562         if (file.read_uint16_rev(&ast.hours,1)) {
00563                 errorMsg = "dsdiffFileReader::readChunk_ABSS:file read error";
00564                 return false;
00565         }
00566         // mins
00567         if (file.read_uint8(&ast.minutes,1)) {
00568                 errorMsg = "dsdiffFileReader::readChunk_ABSS:file read error";
00569                 return false;
00570         }
00571         // secs
00572         if (file.read_uint8(&ast.seconds,1)) {
00573                 errorMsg = "dsdiffFileReader::readChunk_ABSS:file read error";
00574                 return false;
00575         }
00576         // samples
00577         if (file.read_uint32_rev(&ast.samples,1)) {
00578                 errorMsg = "dsdiffFileReader::readChunk_ABSS:file read error";
00579                 return false;
00580         }
00581         return true;
00582 }
00583 bool dsdiffFileReader::readChunk_ID3(dsf2flac_uint64 chunkStart)
00584 {
00585         // read the header so that we are certain we are in the correct place.
00586         dsf2flac_int8 ident[5];
00587         ident[4]='\0';
00588         if (!readChunkHeader(ident,chunkStart))
00589                 return false;
00590         // check the ident
00591         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("ID3 ")) ) {
00592                 errorMsg = "dsdiffFileReader::readChunk_ID3:chunk ident error";
00593                 return false;
00594         }
00595         // read the first ID3_TAGHEADERSIZE bytes of the metadata (which should be the header).
00596         dsf2flac_uint8 id3header[ID3_TAGHEADERSIZE];
00597         if (file.read_uint8(id3header,ID3_TAGHEADERSIZE)) {
00598                 return false;
00599         }
00600         // check this is actually an id3 header
00601         dsf2flac_uint64 id3tagLen;
00602         if ( (id3tagLen = ID3_IsTagHeader(id3header)) > -1 )
00603                 return false;
00604         // read the tag
00605         dsf2flac_uint8* id3tag = new dsf2flac_uint8[ id3tagLen ];
00606         if (file.read_uint8(id3tag,id3tagLen)) {
00607                 return false;
00608         }
00609         ID3_Tag t;
00610         t.Parse (id3header, id3tag);
00611         tags.push_back(t);
00612         delete[] id3tag;
00613         return true;
00614 }
00615 bool dsdiffFileReader::readChunk_LSCO(dsf2flac_uint64 chunkStart)
00616 {
00617         // read the header so that we are certain we are in the correct place.
00618         dsf2flac_int8 ident[5];
00619         ident[4]='\0';
00620         if (!readChunkHeader(ident,chunkStart))
00621                 return false;
00622         // check the ident
00623         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("LSCO")) ) {
00624                 errorMsg = "dsdiffFileReader::readChunk_LSCO:chunk ident error";
00625                 return false;
00626         }
00627         if (file.read_uint16(&lsConfig,1)) {
00628                 errorMsg = "dsdiffFileReader::readChunk_LSCO:file read error";
00629                 return false;
00630         }
00631         return true;
00632 }
00633 bool dsdiffFileReader::readChunk_DIIN(dsf2flac_uint64 chunkStart)
00634 {
00635         // read the header so that we are certain we are in the correct place.
00636         dsf2flac_int8 ident[5];
00637         ident[4]='\0';
00638         dsf2flac_uint64 chunkSz;
00639         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00640                 return false;
00641         // check the ident
00642         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("DIIN")) ) {
00643                 errorMsg = "dsdiffFileReader::readChunk_DIIN:chunk ident error";
00644                 return false;
00645         }
00646         // read all sub chunks in the FRM8 chunk
00647         dsf2flac_uint64 subChunkStart = file.tellg();
00648         dsf2flac_uint64 subChunkSz;
00649         bool emidRead = false;
00650         while (subChunkStart < chunkStart + chunkSz) {
00651                 // read the header
00652                 if (!readChunkHeader(ident,subChunkStart,&subChunkSz))
00653                         return false;
00654                 // see if we know how to read this chunk
00655                 if ( !emidRead && checkIdent(ident,const_cast<dsf2flac_int8*>("EMID")) ) {
00656                         emidRead = readChunk_EMID(subChunkStart);
00657                 } else if ( checkIdent(ident,const_cast<dsf2flac_int8*>("MARK")) ) {
00658                         readChunk_MARK(subChunkStart);
00659                 } else
00660                         printf("WARNING: unknown chunk type: %s\n",ident);
00661                 // move to the next chunk
00662                 subChunkStart = subChunkStart + subChunkSz;
00663         }
00664         return true;
00665 }
00666 bool dsdiffFileReader::readChunk_EMID(dsf2flac_uint64 chunkStart)
00667 {
00668         // read the header so that we are certain we are in the correct place.
00669         dsf2flac_int8 ident[5];
00670         ident[4]='\0';
00671         dsf2flac_uint64 chunkSz;
00672         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00673                 return false;
00674         // check the ident
00675         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("EMID")) ) {
00676                 errorMsg = "dsdiffFileReader::readChunk_EMID:chunk ident error";
00677                 return false;
00678         }
00679         isEm = true;
00680         dsf2flac_uint64 n = chunkSz - 12;
00681         emid = new char[n + 1];
00682         emid[n] = '\0';
00683         if (file.read_int8(emid,n)) {
00684                 errorMsg = "dsdiffFileReader::readChunk_EMID:file read error";
00685                 return false;
00686         }
00687         return true;
00688 }
00689 bool dsdiffFileReader::readChunk_DSTI(dsf2flac_uint64 chunkStart)
00690 {
00691         // read the header so that we are certain we are in the correct place.
00692         dsf2flac_int8 ident[5];
00693         ident[4]='\0';
00694         dsf2flac_uint64 chunkSz;
00695         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00696                 return false;
00697         // check the ident
00698         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("DSTI")) ) {
00699                 errorMsg = "dsdiffFileReader::readChunk_DSTI:chunk ident error";
00700                 return false;
00701         }
00702         dsf2flac_uint64 n = (chunkSz - 12)/(32+64);
00703         for (dsf2flac_uint64 i=0; i<n; i++) {
00704                 DSTFrameIndex in;
00705                 if (file.read_uint64_rev(&in.offset,1)) {
00706                         errorMsg = "dsdiffFileReader::readChunk_DSTI:file read error";
00707                         return false;
00708                 }
00709                 if (file.read_uint32_rev(&in.length,1)) {
00710                         errorMsg = "dsdiffFileReader::readChunk_DSTI:file read error";
00711                         return false;
00712                 }
00713                 dstFrameIndices.push_back(in);
00714         }
00715         return true;
00716 }
00717 bool dsdiffFileReader::readChunk_MARK(dsf2flac_uint64 chunkStart)
00718 {
00719         // read the header so that we are certain we are in the correct place.
00720         dsf2flac_int8 ident[5];
00721         ident[4]='\0';
00722         dsf2flac_uint64 chunkSz;
00723         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00724                 return false;
00725         // check the ident
00726         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("MARK")) ) {
00727                 errorMsg = "dsdiffFileReader::readChunk_MARK:chunk ident error";
00728                 return false;
00729         }
00730         DsdiffMarker m;
00731         if (file.read_uint16_rev(&m.hours,1)) {
00732                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00733                 return false;
00734         }
00735         if (file.read_uint8_rev(&m.minutes,1)) {
00736                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00737                 return false;
00738         }
00739         if (file.read_uint8_rev(&m.seconds,1)) {
00740                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00741                 return false;
00742         }
00743         if (file.read_uint32_rev(&m.samples,1)) {
00744                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00745                 return false;
00746         }
00747         if (file.read_int32_rev(&m.offset,1)) {
00748                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00749                 return false;
00750         }
00751         if (file.read_uint16_rev(&m.markType,1)) {
00752                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00753                 return false;
00754         }
00755         if (file.read_uint16_rev(&m.markChannel,1)) {
00756                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00757                 return false;
00758         }
00759         if (file.read_uint16_rev(&m.trackFlags,1)) {
00760                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00761                 return false;
00762         }
00763         if (file.read_uint32_rev(&m.count,1)) {
00764                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00765                 return false;
00766         }
00767         m.markerText = new dsf2flac_int8[m.count+1];
00768         m.markerText[m.count] = '\0';
00769         if (file.read_int8_rev(m.markerText,m.count)) {
00770                 errorMsg = "dsdiffFileReader::readChunk_MARK:file read error";
00771                 return false;
00772         }
00773         if (m.count % 2)
00774                 file.seekg(1,fstreamPlus::cur);
00775         markers.push_back(m);
00776         //dispMarker(m);
00777         return true;
00778 }
00779 
00780 
00781 dsf2flac_uint64 decodeMarkerPosition(DsdiffAst ast, DsdiffMarker marker, dsf2flac_uint32 fs) {
00782         dsf2flac_int64 dhr = (dsf2flac_int64) marker.hours - (dsf2flac_int64) ast.hours;
00783         dsf2flac_int64 dmi = (dsf2flac_int64) marker.minutes - (dsf2flac_int64) ast.minutes;
00784         dsf2flac_int64 dse = (dsf2flac_int64) marker.seconds - (dsf2flac_int64) ast.seconds;
00785         dsf2flac_int64 dsa = (dsf2flac_int64) marker.samples - (dsf2flac_int64) ast.samples;
00786         dsf2flac_int64 pos = ( dhr*60*60 + dmi*60 + dse ) * fs + dsa;
00787         pos += marker.offset;
00788         return pos; // note div by 8 to give position in chars
00789 }
00790 
00791 
00792 void dsdiffFileReader::processTracks() {
00793         
00794         numTracks = 0;
00795         dsf2flac_uint64 thisTrackStart = 0;
00796         bool inTrack = false;
00797         
00798         for (unsigned int i = 0; i < markers.size(); i++) {
00799                 
00800                 // we only care about track markers
00801                 if (markers[i].markType != 0 && markers[i].markType != 1)
00802                         continue;
00803                         
00804                 // find the position of this marker in chars
00805                 dsf2flac_uint64 pos = decodeMarkerPosition(ast,markers[i],samplingFreq);
00806                 
00807                 // if we are inTrack then this marker must denote the end of the current track
00808                 if (inTrack) {
00809                         // add the track
00810                         numTracks ++;
00811                         trackStartPositions.push_back(thisTrackStart);
00812                         trackEndPositions.push_back(pos - 1);
00813                         inTrack = false;
00814                 }
00815                 
00816                 // if track start maker record pos and flag that we are inTrack.
00817                 if (markers[i].markType == 0) {
00818                         thisTrackStart = pos;
00819                         inTrack = true;
00820                 }
00821         }
00822         
00823         // if there are no markers then make a sensible default
00824         if ( numTracks ==0 ) {
00825                 numTracks = 1;
00826                 trackStartPositions.push_back(0);
00827                 trackEndPositions.push_back(getLength());
00828         }
00829         
00830         return;
00831 }
00832 void dsdiffFileReader::dispMarker(DsdiffMarker m)
00833 {
00834         printf("\nmarkType:\t%u\n",m.markType);
00835         printf("time:\t%u:%u:%u::%u + %u\n",m.hours,m.minutes,m.seconds,m.samples,m.offset);
00836         printf("markChannel:\t\t%u\n",m.markChannel);
00837         printf("trackFlags:\t\t%u\n",m.trackFlags);
00838         printf("markerText:\t%s\n",m.markerText);
00839         //printf("count:\t\t%u\n",m.count);
00840 }
00841 bool dsdiffFileReader::readChunk_COMT(dsf2flac_uint64 chunkStart)
00842 {
00843         // read the header so that we are certain we are in the correct place.
00844         dsf2flac_int8 ident[5];
00845         ident[4]='\0';
00846         if (!readChunkHeader(ident,chunkStart))
00847                 return false;
00848         // check the ident
00849         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("COMT")) ) {
00850                 errorMsg = "dsdiffFileReader::readChunk_COMT:chunk ident error";
00851                 return false;
00852         }
00853         dsf2flac_uint16 numComments;
00854         if (file.read_uint16_rev(&numComments,1)) {
00855                 errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00856                 return false;
00857         }
00858         for (short unsigned int i=0; i<numComments; i++) {
00859                 DsdiffComment c;
00860                 if (file.read_uint16_rev(&c.timeStampYear,1)) {
00861                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00862                         return false;
00863                 }
00864                 if (file.read_uint8_rev(&c.timeStampMonth,1)) {
00865                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00866                         return false;
00867                 }
00868                 if (file.read_uint8_rev(&c.timeStampDay,1)) {
00869                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00870                         return false;
00871                 }
00872                 if (file.read_uint8_rev(&c.timeStampHour,1)) {
00873                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00874                         return false;
00875                 }
00876                 if (file.read_uint8_rev(&c.timeStampMinutes,1)) {
00877                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00878                         return false;
00879                 }
00880                 if (file.read_uint16_rev(&c.cmtType,1)) {
00881                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00882                         return false;
00883                 }
00884                 if (file.read_uint16_rev(&c.cmtRef,1)) {
00885                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00886                         return false;
00887                 }
00888                 if (file.read_uint32_rev(&c.count,1)) {
00889                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00890                         return false;
00891                 }
00892                 c.commentText = new dsf2flac_int8[c.count+1];
00893                 c.commentText[c.count] = '\0';
00894                 if (file.read_int8_rev(c.commentText,c.count)) {
00895                         errorMsg = "dsdiffFileReader::readChunk_COMT:file read error";
00896                         return false;
00897                 }
00898                 if (c.count % 2)
00899                         file.seekg(1,fstreamPlus::cur);
00900                 comments.push_back(c);
00901         }
00902         return true;
00903 }
00904 void dsdiffFileReader::dispComment(DsdiffComment c)
00905 {
00906         printf("timeStampYear:\t%u\n",c.timeStampYear);
00907         printf("timeStampMonth:\t%u\n",c.timeStampMonth);
00908         printf("timeStampDay:\t%u\n",c.timeStampDay);
00909         printf("timeStampHour:\t%u\n",c.timeStampHour);
00910         printf("timeStampMinutes:\t%u\n",c.timeStampMinutes);
00911         printf("cmtType:\t%u\n",c.cmtType);
00912         printf("cmtRef:\t\t%u\n",c.cmtRef);
00913         printf("count:\t\t%u\n",c.count);
00914         printf("commentText:\t%s\n",c.commentText);
00915 }
00916 bool dsdiffFileReader::readChunk_DSD(dsf2flac_uint64 chunkStart)
00917 {
00918         // read the header so that we are certain we are in the correct place.
00919         dsf2flac_int8 ident[5];
00920         ident[4]='\0';
00921         dsf2flac_uint64 chunkLen;
00922         if (!readChunkHeader(ident,chunkStart,&chunkLen))
00923                 return false;
00924         // check the ident
00925         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("DSD ")) ) {
00926                 errorMsg = "dsdiffFileReader::readChunk_DSD:chunk ident error";
00927                 return false;
00928         }
00929         // we are now at the start of the dsd data, record the position
00930         sampleDataPointer = file.tellg();
00931         // chunkLen contains the number of samples
00932         sampleCountPerChan = (chunkLen - 12)/chanNum*samplesPerChar;
00933         return true;
00934 }
00935 bool dsdiffFileReader::readChunk_DSTF(dsf2flac_uint64 chunkStart)
00936 {
00937         // read the header so that we are certain we are in the correct place.
00938         dsf2flac_int8 ident[5];
00939         ident[4]='\0';
00940         dsf2flac_uint64 chunkLen;
00941         if (!readChunkHeader(ident,chunkStart,&chunkLen))
00942                 return false;
00943         // check the ident
00944         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("DSTF")) ) {
00945                 errorMsg = "dsdiffFileReader::readChunk_DSTF:chunk ident error";
00946                 return false;
00947         }
00948         dsf2flac_uint64 dst_framesize = chunkLen-12;
00949         dsf2flac_uint8* dst_data = new dsf2flac_uint8[dst_framesize];
00950         if (file.read_uint8_rev(dst_data,dst_framesize)) {
00951                 errorMsg = "dsdiffFileReader::readChunk_DSTF:file read error";
00952                 return false;
00953         }
00954         
00955         if (DST_FramDSTDecode(dst_data, sampleBuffer,dst_framesize, dstInfo.numFrames, &dstEbunch))
00956                 return false;
00957         
00958         return true;
00959 }
00960 bool dsdiffFileReader::readChunk_DST(dsf2flac_uint64 chunkStart)
00961 {
00962         // read the header so that we are certain we are in the correct place.
00963         dsf2flac_int8 ident[5];
00964         ident[4]='\0';
00965         dsf2flac_uint64 chunkSz;
00966         if (!readChunkHeader(ident,chunkStart,&chunkSz))
00967                 return false;
00968         // check the ident
00969         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("DST ")) ) {
00970                 errorMsg = "dsdiffFileReader::readChunk_DST:chunk ident error";
00971                 return false;
00972         }
00973         // record the end of the chunk
00974         dstChunkEnd = chunkStart + chunkSz -1;
00975         // read all sub chunks in the DST chunk
00976         dsf2flac_uint64 subChunkStart = file.tellg();
00977         dsf2flac_uint64 subChunkSz;
00978         bool found_frte = false;
00979         bool found_dstf = false;
00980         //
00981         while (!(found_frte && found_dstf) && subChunkStart < chunkStart + chunkSz) {
00982                 // read the header
00983                 if (!readChunkHeader(ident,subChunkStart,&subChunkSz))
00984                         return false;
00985                 // see if we know how to read this chunk
00986                 if ( !found_frte && checkIdent(ident,const_cast<dsf2flac_int8*>("FRTE")) ) {
00987                         found_frte = readChunk_FRTE(subChunkStart);
00988                 } else if ( !found_dstf && checkIdent(ident,const_cast<dsf2flac_int8*>("DSTF")) ) {
00989                         found_dstf = true;
00990                         sampleDataPointer = subChunkStart;
00991                 } else
00992                         printf("WARNING: unknown chunk type: %s\n",ident);
00993                 // move to the next chunk
00994                 subChunkStart = subChunkStart + subChunkSz;
00995         }
00996         if (found_frte) {
00997                 sampleCountPerChan = (dsf2flac_uint64)dstInfo.numFrames * (dsf2flac_uint64)dstInfo.frameSizeInSamplesPerChan;
00998                 sampleBufferLenPerChan = dstInfo.frameSizeInBytesPerChan;
00999         }
01000         return found_frte && found_dstf;
01001 }
01002 bool dsdiffFileReader::readChunk_FRTE(dsf2flac_uint64 chunkStart)
01003 {
01004         // read the header so that we are certain we are in the correct place.
01005         dsf2flac_int8 ident[5];
01006         ident[4]='\0';
01007         dsf2flac_uint64 chunkSz;
01008         if (!readChunkHeader(ident,chunkStart,&chunkSz))
01009                 return false;
01010         // check the ident
01011         if ( !checkIdent(ident,const_cast<dsf2flac_int8*>("FRTE")) ) {
01012                 errorMsg = "dsdiffFileReader::readChunk_FRTE:chunk ident error";
01013                 return false;
01014         }
01015         if (file.read_uint32_rev(&dstInfo.numFrames,1)) {
01016                 errorMsg = "dsdiffFileReader::readChunk_FRTE:file read error";
01017                 return false;
01018         }
01019         if (file.read_uint16_rev(&dstInfo.frameRate,1)) {
01020                 errorMsg = "dsdiffFileReader::readChunk_FRTE:file read error";
01021                 return false;
01022         }
01023         dstInfo.frameSizeInSamplesPerChan = getSamplingFreq()/dstInfo.frameRate;
01024         dstInfo.frameSizeInBytesPerChan = dstInfo.frameSizeInSamplesPerChan/samplesPerChar;
01025         return true;
01026 }
01033 bool dsdiffFileReader::readChunkHeader(dsf2flac_int8* ident, dsf2flac_uint64 chunkStart)
01034 {
01035         dsf2flac_uint64 chunkSz;
01036         return readChunkHeader(ident,chunkStart,&chunkSz);
01037 }
01038 bool dsdiffFileReader::readChunkHeader(dsf2flac_int8* ident, dsf2flac_uint64 chunkStart, dsf2flac_uint64* chunkSz)
01039 {
01040         // make sure we are at the start of the chunk
01041         if (file.seekg(chunkStart)) {
01042                 errorMsg = "dsdiffFileReader::readChunkHeader:File seek error";
01043                 return false;
01044         }
01045         // read the ident
01046         if (file.read_int8(ident,4)) {
01047                 errorMsg = "dsdiffFileReader::readChunkHeader:File read error";
01048                 return false;
01049         }
01050         // 8 bytes chunk size
01051         if (file.read_uint64_rev(chunkSz,1)) {
01052                 errorMsg = "dsdiffFileReader::readChunkHeader:File read error";
01053                 return false;
01054         }
01055         //printf("%s\n",ident);
01056         // if the chunk size is odd then add one... because for some stupid reason you have to do this....
01057         // also add the header length (12bytes).
01058         if ( chunkSz[0] & 1 )
01059                 chunkSz[0] += 13;
01060         else
01061                 chunkSz[0] += 12;
01062         return true;
01063 }
01064 bool dsdiffFileReader::checkIdent(dsf2flac_int8* a, dsf2flac_int8* b)
01065 {
01066         return ( a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3] );
01067 }
01068 void dsdiffFileReader::dispFileInfo()
01069 {
01070         printf("dsdiffVersion: %08x\n",dsdiffVersion);
01071         printf("samplingRate: %u\n",samplingFreq);
01072         printf("chanNum: %u\n",chanNum);
01073         for (int i=0; i<chanNum; i++)
01074                 printf("chanIdent%u: %s\n",i,chanIdents[i]);
01075         printf("compressionType: %s\n",compressionType);
01076         printf("compressionName: %s\n",compressionName);
01077         printf("ast_hours: %u\n",ast.hours);
01078         printf("ast_mins: %d\n",ast.minutes);
01079         printf("ast_secs: %d\n",ast.seconds);
01080         printf("ast_samples: %u\n",ast.samples);
01081         printf("sampleDataPointer: %lu\n",sampleDataPointer);
01082         printf("sampleCount: %lu\n",sampleCountPerChan);
01083 }
 All Classes Files Functions Variables