DSF2FLAC
|
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 }