|
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 |
}
|