int wav_fmt(wav_reader_t *reader, uint32_t size)
{
    uint16_t wFormatTag, nChannels, nBlockAlign, wBitsPerSample, cbSize;
    uint32_t nSamplesPerSec, nAvgBytesPerSec, dwChannelMask = 0;
    uint16_t wValidBitsPerSample;
    uint8_t guid[16];
    int is_float = 0;

    ENSURE(size >= 16);
    TRY_IO(pcm_scanl(&reader->io, "SSLLSS", &wFormatTag, &nChannels,
                     &nSamplesPerSec, &nAvgBytesPerSec, &nBlockAlign,
                     &wBitsPerSample) != 6);
    wValidBitsPerSample = wBitsPerSample;

    ENSURE(wFormatTag == 1 || wFormatTag == 3 || wFormatTag == 0xfffe);
    ENSURE(nChannels && nSamplesPerSec && nAvgBytesPerSec &&
           nBlockAlign && wBitsPerSample && !(wBitsPerSample & 7) &&
           nBlockAlign == nChannels * wBitsPerSample / 8);

    if (wFormatTag == 3)
        is_float = 1;

    if (wFormatTag != 0xfffe)
        TRY_IO(pcm_skip(&reader->io, (size - 15) & ~1));
    else {
        ENSURE(size >= 40);
        TRY_IO(pcm_scanl(&reader->io, "SSL",
                         &cbSize, &wValidBitsPerSample, &dwChannelMask) != 3);
        TRY_IO(pcm_read(&reader->io, guid, 16) != 16);

        if (memcmp(guid, WAV_GUID_FLOAT, 16) == 0)
            is_float = 1;
        else if (memcmp(guid, WAV_GUID_PCM, 16) != 0)
            goto FAIL;
        ENSURE(wValidBitsPerSample && wValidBitsPerSample <= wBitsPerSample);
        TRY_IO(pcm_skip(&reader->io, (size - 39) & ~1));
    }
    reader->sample_format.sample_rate = nSamplesPerSec;
    reader->sample_format.bits_per_channel = wValidBitsPerSample;
    reader->sample_format.bytes_per_frame = nBlockAlign;
    reader->sample_format.channels_per_frame = nChannels;
    reader->sample_format.channel_mask = dwChannelMask;
    if (is_float)
        reader->sample_format.sample_type = PCM_TYPE_FLOAT;
    else if (wBitsPerSample == 8)
        reader->sample_format.sample_type = PCM_TYPE_UINT;
    else
        reader->sample_format.sample_type = PCM_TYPE_SINT;
    return 0;
FAIL:
    return -1;
}
int wav_fmt(wav_reader_t *reader, uint32_t size)
{
    uint16_t wFormatTag, nChannels, nBlockAlign, wBitsPerSample, cbSize;
    uint32_t nSamplesPerSec, nAvgBytesPerSec, dwChannelMask = 0;
    uint16_t wValidBitsPerSample;
    uint8_t guid[16];
    int is_float = 0;

    ENSURE(size >= 16);
    TRY_IO(pcm_scanl(&reader->io, "SSLLSS", &wFormatTag, &nChannels,
                     &nSamplesPerSec, &nAvgBytesPerSec, &nBlockAlign,
                     &wBitsPerSample) != 6);
    wValidBitsPerSample = wBitsPerSample;

    ENSURE(wFormatTag == 1 || wFormatTag == 3 || wFormatTag == 0xfffe);
    ENSURE(nChannels && nSamplesPerSec && nAvgBytesPerSec &&
           nBlockAlign && wBitsPerSample && !(wBitsPerSample & 7) &&
           nBlockAlign == nChannels * wBitsPerSample / 8);

    if (wFormatTag == 3)
        is_float = 1;

    if (wFormatTag != 0xfffe)
        TRY_IO(pcm_skip(&reader->io, (size - 15) & ~1));
    else {
        ENSURE(size >= 40);
        TRY_IO(pcm_scanl(&reader->io, "SSL",
                         &cbSize, &wValidBitsPerSample, &dwChannelMask) != 3);
        TRY_IO(pcm_read(&reader->io, guid, 16) != 16);

        if (memcmp(guid, WAV_GUID_FLOAT, 16) == 0)
            is_float = 1;
        else if (memcmp(guid, WAV_GUID_PCM, 16) != 0)
            goto FAIL;
        ENSURE(wValidBitsPerSample && wValidBitsPerSample <= wBitsPerSample);
        TRY_IO(pcm_skip(&reader->io, (size - 39) & ~1));
    }
    reader->sample_format.sample_rate = nSamplesPerSec;
    reader->sample_format.bits_per_channel = wValidBitsPerSample;
    reader->sample_format.bytes_per_frame = nBlockAlign;
    reader->sample_format.channels_per_frame = nChannels;
    reader->sample_format.channel_mask = dwChannelMask;
    if (is_float)
        reader->sample_format.sample_type = PCM_TYPE_FLOAT;
    else if (wBitsPerSample == 8)
        reader->sample_format.sample_type = PCM_TYPE_UINT;
    else
        reader->sample_format.sample_type = PCM_TYPE_SINT;
    return 0;
FAIL:
    return -1;
}