Blame src/read-sound-file.c

Packit 3ae693
/*-*- Mode: C; c-basic-offset: 8 -*-*/
Packit 3ae693
Packit 3ae693
/***
Packit 3ae693
  This file is part of libcanberra.
Packit 3ae693
Packit 3ae693
  Copyright 2008 Lennart Poettering
Packit 3ae693
Packit 3ae693
  libcanberra is free software; you can redistribute it and/or modify
Packit 3ae693
  it under the terms of the GNU Lesser General Public License as
Packit 3ae693
  published by the Free Software Foundation, either version 2.1 of the
Packit 3ae693
  License, or (at your option) any later version.
Packit 3ae693
Packit 3ae693
  libcanberra is distributed in the hope that it will be useful, but
Packit 3ae693
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 3ae693
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit 3ae693
  Lesser General Public License for more details.
Packit 3ae693
Packit 3ae693
  You should have received a copy of the GNU Lesser General Public
Packit 3ae693
  License along with libcanberra. If not, see
Packit 3ae693
  <http://www.gnu.org/licenses/>.
Packit 3ae693
***/
Packit 3ae693
Packit 3ae693
#ifdef HAVE_CONFIG_H
Packit 3ae693
#include <config.h>
Packit 3ae693
#endif
Packit 3ae693
Packit 3ae693
#include <errno.h>
Packit 3ae693
Packit 3ae693
#include "read-sound-file.h"
Packit 3ae693
#include "read-wav.h"
Packit 3ae693
#include "read-vorbis.h"
Packit 3ae693
#include "macro.h"
Packit 3ae693
#include "malloc.h"
Packit 3ae693
#include "canberra.h"
Packit 3ae693
Packit 3ae693
struct ca_sound_file {
Packit 3ae693
        ca_wav *wav;
Packit 3ae693
        ca_vorbis *vorbis;
Packit 3ae693
        char *filename;
Packit 3ae693
Packit 3ae693
        unsigned nchannels;
Packit 3ae693
        unsigned rate;
Packit 3ae693
        ca_sample_type_t type;
Packit 3ae693
};
Packit 3ae693
Packit 3ae693
int ca_sound_file_open(ca_sound_file **_f, const char *fn) {
Packit 3ae693
        FILE *file;
Packit 3ae693
        ca_sound_file *f;
Packit 3ae693
        int ret;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(_f, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(fn, CA_ERROR_INVALID);
Packit 3ae693
Packit 3ae693
        if (!(f = ca_new0(ca_sound_file, 1)))
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
Packit 3ae693
        if (!(f->filename = ca_strdup(fn))) {
Packit 3ae693
                ret = CA_ERROR_OOM;
Packit 3ae693
                goto fail;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if (!(file = fopen(fn, "r"))) {
Packit 3ae693
                ret = errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
Packit 3ae693
                goto fail;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if ((ret = ca_wav_open(&f->wav, file)) == CA_SUCCESS) {
Packit 3ae693
                f->nchannels = ca_wav_get_nchannels(f->wav);
Packit 3ae693
                f->rate = ca_wav_get_rate(f->wav);
Packit 3ae693
                f->type = ca_wav_get_sample_type(f->wav);
Packit 3ae693
                *_f = f;
Packit 3ae693
                return CA_SUCCESS;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if (ret == CA_ERROR_CORRUPT) {
Packit 3ae693
Packit 3ae693
                if (fseek(file, 0, SEEK_SET) < 0) {
Packit 3ae693
                        ret = CA_ERROR_SYSTEM;
Packit 3ae693
                        goto fail;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                if ((ret = ca_vorbis_open(&f->vorbis, file)) == CA_SUCCESS)  {
Packit 3ae693
                        f->nchannels = ca_vorbis_get_nchannels(f->vorbis);
Packit 3ae693
                        f->rate = ca_vorbis_get_rate(f->vorbis);
Packit 3ae693
                        f->type = CA_SAMPLE_S16NE;
Packit 3ae693
                        *_f = f;
Packit 3ae693
                        return CA_SUCCESS;
Packit 3ae693
                }
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
fail:
Packit 3ae693
Packit 3ae693
        ca_free(f->filename);
Packit 3ae693
        ca_free(f);
Packit 3ae693
Packit 3ae693
        return ret;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
void ca_sound_file_close(ca_sound_file *f) {
Packit 3ae693
        ca_assert(f);
Packit 3ae693
Packit 3ae693
        if (f->wav)
Packit 3ae693
                ca_wav_close(f->wav);
Packit 3ae693
        if (f->vorbis)
Packit 3ae693
                ca_vorbis_close(f->vorbis);
Packit 3ae693
Packit 3ae693
        ca_free(f->filename);
Packit 3ae693
        ca_free(f);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
unsigned ca_sound_file_get_nchannels(ca_sound_file *f) {
Packit 3ae693
        ca_assert(f);
Packit 3ae693
        return f->nchannels;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
unsigned ca_sound_file_get_rate(ca_sound_file *f) {
Packit 3ae693
        ca_assert(f);
Packit 3ae693
        return f->rate;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
ca_sample_type_t ca_sound_file_get_sample_type(ca_sound_file *f) {
Packit 3ae693
        ca_assert(f);
Packit 3ae693
        return f->type;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
const ca_channel_position_t* ca_sound_file_get_channel_map(ca_sound_file *f) {
Packit 3ae693
        ca_assert(f);
Packit 3ae693
Packit 3ae693
        if (f->wav)
Packit 3ae693
                return ca_wav_get_channel_map(f->wav);
Packit 3ae693
        else
Packit 3ae693
                return ca_vorbis_get_channel_map(f->vorbis);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int ca_sound_file_read_int16(ca_sound_file *f, int16_t *d, size_t *n) {
Packit 3ae693
        ca_return_val_if_fail(f, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(d, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(n, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(f->wav || f->vorbis, CA_ERROR_STATE);
Packit 3ae693
        ca_return_val_if_fail(f->type == CA_SAMPLE_S16NE || f->type == CA_SAMPLE_S16RE, CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        if (f->wav)
Packit 3ae693
                return ca_wav_read_s16le(f->wav, d, n);
Packit 3ae693
        else
Packit 3ae693
                return ca_vorbis_read_s16ne(f->vorbis, d, n);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, size_t *n) {
Packit 3ae693
        ca_return_val_if_fail(f, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(d, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(n, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(f->wav && !f->vorbis, CA_ERROR_STATE);
Packit 3ae693
        ca_return_val_if_fail(f->type == CA_SAMPLE_U8, CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        if (f->wav)
Packit 3ae693
                return ca_wav_read_u8(f->wav, d, n);
Packit 3ae693
Packit 3ae693
        return CA_ERROR_STATE;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n) {
Packit 3ae693
        int ret;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(f, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(d, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(n, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(*n > 0, CA_ERROR_INVALID);
Packit 3ae693
Packit 3ae693
        switch (f->type) {
Packit 3ae693
        case CA_SAMPLE_S16NE:
Packit 3ae693
        case CA_SAMPLE_S16RE: {
Packit 3ae693
                size_t k;
Packit 3ae693
Packit 3ae693
                k = *n / sizeof(int16_t);
Packit 3ae693
                if ((ret = ca_sound_file_read_int16(f, d, &k)) == CA_SUCCESS)
Packit 3ae693
                        *n = k * sizeof(int16_t);
Packit 3ae693
Packit 3ae693
                break;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        case CA_SAMPLE_U8: {
Packit 3ae693
                size_t k;
Packit 3ae693
Packit 3ae693
                k = *n;
Packit 3ae693
                if ((ret = ca_sound_file_read_uint8(f, d, &k)) == CA_SUCCESS)
Packit 3ae693
                        *n = k;
Packit 3ae693
Packit 3ae693
                break;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        default:
Packit 3ae693
                ca_assert_not_reached();
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        return ret;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
off_t ca_sound_file_get_size(ca_sound_file *f) {
Packit 3ae693
        ca_return_val_if_fail(f, (off_t) -1);
Packit 3ae693
Packit 3ae693
        if (f->wav)
Packit 3ae693
                return ca_wav_get_size(f->wav);
Packit 3ae693
        else
Packit 3ae693
                return ca_vorbis_get_size(f->vorbis);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
size_t ca_sound_file_frame_size(ca_sound_file *f) {
Packit 3ae693
        unsigned c;
Packit 3ae693
Packit 3ae693
        ca_assert(f);
Packit 3ae693
Packit 3ae693
        c = ca_sound_file_get_nchannels(f);
Packit 3ae693
Packit 3ae693
        return c * (ca_sound_file_get_sample_type(f) == CA_SAMPLE_U8 ? 1U : 2U);
Packit 3ae693
}