WWPcmData * WWReadWavFile(const char *path, WWPcmDataStreamAllocType t) { unsigned char buff[12]; WWPcmData *result = nullptr; WaveFormatInfo wfi; memset(&wfi, 0, sizeof wfi); FILE *fp = nullptr; fopen_s(&fp, path, "rb"); if (nullptr == fp) { return nullptr; } size_t rv = fread(buff, 1, 12, fp); if (rv != 12) { printf("E: flie size is too small\n"); goto end; } if (0 != (strncmp("RIFF", (const char*)buff, 4))) { goto end; } if (0 != (strncmp("WAVE", (const char*)&buff[8], 4))) { printf("E: WAVE not found\n"); goto end; } for (;;) { if (!ReadWaveChunk(fp, wfi)) { break; } } if (wfi.data) { result = new WWPcmData(); if (nullptr == result) { goto end; } result->Init(t); result->bitsPerSample = wfi.bitsPerSample; result->validBitsPerSample = wfi.bitsPerSample; result->nChannels = wfi.nChannels; result->nSamplesPerSec = wfi.nSamplesPerSec; result->nFrames = wfi.nFrames; result->posFrame = 0; int64_t bytes = (int64_t)result->nFrames * result->nChannels * result->bitsPerSample / 8; if (!result->StoreStream(wfi.data, bytes)) { printf("memory allocation failed\n"); goto end; } } end: fclose(fp); return result; }
WWPcmData * WWReadDsfFile(const char *path, WWBitsPerSampleType bitsPerSampleType, WWPcmDataStreamAllocType allocType) { WWPcmData *pcmData = nullptr; char fourCC[4]; DsfDsdChunk dsdChunk; DsfFmtChunk fmtChunk; DsfDataChunk dataChunk; int64_t streamBytes; int64_t writePos; uint32_t blockNum; unsigned char *blockData = nullptr; unsigned char *stream = nullptr; int result = -1; if (bitsPerSampleType == WWBpsNone) { printf("E: device does not support DoP\n"); return nullptr; } FILE *fp = nullptr; fopen_s(&fp, path, "rb"); if (nullptr == fp) { return nullptr; } if (fread(fourCC, 1, 4, fp) < 4 || 0 != memcmp(fourCC, DSD_CHUNK_FOURCC, 4) || dsdChunk.ReadFromFile(fp) < 0) { goto end; } if (fread(fourCC, 1, 4, fp) < 4 || 0 != memcmp(fourCC, FMT_CHUNK_FOURCC, 4) || fmtChunk.ReadFromFile(fp) < 0) { goto end; } if (fread(fourCC, 1, 4, fp) < 4 || 0 != memcmp(fourCC, DATA_CHUNK_FOURCC, 4) || dataChunk.ReadFromFile(fp) < 0) { goto end; } pcmData = new WWPcmData(); if (nullptr == pcmData) { goto end; } pcmData->Init(allocType); pcmData->bitsPerSample = bitsPerSampleType == WWBps32v24 ? 32 : 24; pcmData->validBitsPerSample = 24; pcmData->nChannels = fmtChunk.channelNum; // DSD 16bit == 1 frame pcmData->nFrames = fmtChunk.sampleCount/16; pcmData->nSamplesPerSec = 176400; pcmData->posFrame = 0; streamBytes = (pcmData->bitsPerSample/8) * pcmData->nFrames * pcmData->nChannels; stream = new unsigned char[streamBytes]; if (nullptr == stream) { goto end; } memset(stream, 0, streamBytes); blockNum = (uint32_t)((dataChunk.chunkBytes-12)/fmtChunk.blockSizePerChannel); blockData = new unsigned char[fmtChunk.blockSizePerChannel * fmtChunk.channelNum]; if (nullptr == blockData) { goto end; } writePos = 0; for (uint32_t block = 0; block < blockNum; ++block) { // data is stored in following order: // L channel 4096bytes consecutive data, R channel 4096bytes consecutive data, L channel 4096bytes consecutive data, ... // // read 4096 x numChannels bytes. if (fread(blockData, fmtChunk.blockSizePerChannel * fmtChunk.channelNum, 1, fp) < 1) { goto end; } switch (bitsPerSampleType) { case WWBps32v24: for (uint32_t i=0; i<fmtChunk.blockSizePerChannel/2; ++i) { for (uint32_t ch=0; ch<fmtChunk.channelNum; ++ch) { stream[writePos+0] = 0; stream[writePos+1] = gBitReverse[blockData[i*2+1 + ch*fmtChunk.blockSizePerChannel]]; stream[writePos+2] = gBitReverse[blockData[i*2+0 + ch*fmtChunk.blockSizePerChannel]]; stream[writePos+3] = i & 1 ? 0xfa : 0x05; writePos += 4; if (streamBytes <= writePos) { // recorded sample is ended on part of the way of the block result = 0; goto end; } } } break; case WWBps24: for (uint32_t i=0; i<fmtChunk.blockSizePerChannel/2; ++i) { for (uint32_t ch=0; ch<fmtChunk.channelNum; ++ch) { stream[writePos+0] = gBitReverse[blockData[i*2+1 + ch*fmtChunk.blockSizePerChannel]]; stream[writePos+1] = gBitReverse[blockData[i*2+0 + ch*fmtChunk.blockSizePerChannel]]; stream[writePos+2] = i & 1 ? 0xfa : 0x05; writePos += 3; if (streamBytes <= writePos) { // recorded sample is ended on part of the way of the block result = 0; goto end; } } } break; } } // coincidentally block size == recorded sample size result = 0; end: if (result == 0) { // succeeded if (!pcmData->StoreStream(stream, streamBytes)) { printf("pcmData->StoreStream() failed\n"); result = -1; } } delete [] blockData; blockData = nullptr; delete [] stream; stream = nullptr; if (result < 0) { if (pcmData) { pcmData->Term(); delete pcmData; pcmData = nullptr; } } fclose(fp); return pcmData; }