pcm_reader_t *wav_open(pcm_io_context_t *io, int ignore_length)
{
    wav_reader_t *reader = 0;
    int64_t data_length;
    unsigned bpf;

    if ((reader = calloc(1, sizeof(wav_reader_t))) == 0)
        return 0;
    memcpy(&reader->io, io, sizeof(pcm_io_context_t));
    reader->ignore_length = ignore_length;
    if (wav_parse(reader, &data_length) < 0) {
        free(reader);
        return 0;
    }
    bpf = reader->sample_format.bytes_per_frame;
    if (ignore_length || !data_length || data_length % bpf)
        reader->length = INT64_MAX;
    else
        reader->length = data_length / bpf;

    if (reader->length == INT64_MAX) {
        if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) {
            int64_t size = pcm_tell(&reader->io);
            if (size > 0)
                reader->length = (size - reader->data_offset) / bpf;
            pcm_seek(&reader->io, reader->data_offset, SEEK_SET);
        }
    }
    reader->vtbl = &wav_vtable;
    return (pcm_reader_t *)reader;
}
pcm_reader_t *wav_open(pcm_io_context_t *io, int ignore_length)
{
    wav_reader_t *reader = 0;
    int64_t data_length;
    unsigned bpf;

    if ((reader = calloc(1, sizeof(wav_reader_t))) == 0)
        return 0;
    memcpy(&reader->io, io, sizeof(pcm_io_context_t));
    reader->ignore_length = ignore_length;
    if (wav_parse(reader, &data_length) < 0) {
        free(reader);
        return 0;
    }
    bpf = reader->sample_format.bytes_per_frame;
    if (ignore_length || !data_length || data_length % bpf)
        reader->length = INT64_MAX;
    else
        reader->length = data_length / bpf;

    if (reader->length == INT64_MAX) {
        if (pcm_seek(&reader->io, 0, SEEK_END) >= 0) {
            int64_t size = pcm_tell(&reader->io);
            if (size > 0)
                reader->length = (size - reader->data_offset) / bpf;
            pcm_seek(&reader->io, reader->data_offset, SEEK_SET);
        }
    }
    reader->vtbl = &wav_vtable;
    return (pcm_reader_t *)reader;
}