Ejemplo n.º 1
0
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;
}