ref: cce8fd8c57d58cac7e10d6bfc8a1ee89c87ff85c
dir: /src/sndfile.c/
/* * Sound Tools libsndfile formats. * * Copyright 2007 Reuben Thomas <rrt@sc3d.org> * Copyright 1999-2005 Erik de Castro Lopo <eridk@mega-nerd.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, write to the Free Software * Foundation, Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, * USA. */ #include "st_i.h" #ifdef HAVE_SNDFILE_H #include <stdio.h> #include <string.h> #include <sndfile.h> /* Private data for sndfile files */ typedef struct sndfile { SNDFILE *sf_file; SF_INFO *sf_info; } *sndfile_t; assert_static(sizeof(struct sndfile) <= ST_MAX_FILE_PRIVSIZE, /* else */ sndfile_PRIVSIZE_too_big); /* * Open file in sndfile. */ int st_sndfile_startread(ft_t ft) { sndfile_t sf = (sndfile_t)ft->priv; sf->sf_info = (SF_INFO *)xcalloc(1, sizeof(SF_INFO)); /* We'd like to use sf_open, but auto file typing has already invoked stdio buffering. */ if ((sf->sf_file = sf_open(ft->filename, SFM_READ, sf->sf_info)) == NULL) { st_fail("sndfile cannot open file for reading: %s %x", sf_strerror(sf->sf_file), sf->sf_info->format); free(sf->sf_file); return ST_EOF; } /* Copy format info */ ft->signal.rate = sf->sf_info->samplerate; ft->signal.size = ST_SIZE_32BIT; ft->signal.encoding = ST_ENCODING_UNSIGNED; ft->signal.channels = sf->sf_info->channels; ft->length = sf->sf_info->frames * sf->sf_info->channels; return ST_SUCCESS; } /* * Read up to len samples of type st_sample_t from file into buf[]. * Return number of samples read. */ st_size_t st_sndfile_read(ft_t ft, st_sample_t *buf, st_size_t len) { sndfile_t sf = (sndfile_t)ft->priv; /* FIXME: We assume int == st_sample_t here */ return (st_size_t)sf_read_int(sf->sf_file, (int *)buf, len); } /* * Close file for libsndfile (this doesn't close the file handle) */ int st_sndfile_stopread(ft_t ft) { sndfile_t sf = (sndfile_t)ft->priv; sf_close(sf->sf_file); return ST_SUCCESS; } static struct { const char *ext; int len; int format; } format_map[] = { { "aif", 3, SF_FORMAT_AIFF }, { "wav", 0, SF_FORMAT_WAV }, { "au", 0, SF_FORMAT_AU }, { "caf", 0, SF_FORMAT_CAF }, { "flac", 0, SF_FORMAT_FLAC }, { "snd", 0, SF_FORMAT_AU }, { "svx", 0, SF_FORMAT_SVX }, { "paf", 0, SF_ENDIAN_BIG | SF_FORMAT_PAF }, { "fap", 0, SF_ENDIAN_LITTLE | SF_FORMAT_PAF }, { "gsm", 0, SF_FORMAT_RAW }, { "nist", 0, SF_FORMAT_NIST }, { "ircam", 0, SF_FORMAT_IRCAM }, { "sf", 0, SF_FORMAT_IRCAM }, { "voc", 0, SF_FORMAT_VOC }, { "w64", 0, SF_FORMAT_W64 }, { "raw", 0, SF_FORMAT_RAW }, { "mat4", 0, SF_FORMAT_MAT4 }, { "mat5", 0, SF_FORMAT_MAT5 }, { "mat", 0, SF_FORMAT_MAT4 }, { "pvf", 0, SF_FORMAT_PVF }, { "sds", 0, SF_FORMAT_SDS }, { "sd2", 0, SF_FORMAT_SD2 }, { "vox", 0, SF_FORMAT_RAW }, { "xi", 0, SF_FORMAT_XI } }; static int guess_output_file_type(const char *type, int format) { int k; format &= SF_FORMAT_SUBMASK; if (strcmp(type, "gsm") == 0) return SF_FORMAT_RAW | SF_FORMAT_GSM610; if (strcmp(type, "vox") == 0) return SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM; for (k = 0; k < (int)(sizeof(format_map) / sizeof(format_map [0])); k++) { if (format_map[k].len > 0 && strncmp(type, format_map[k].ext, format_map[k].len) == 0) return format_map[k].format | format; else if (strcmp(type, format_map[k].ext) == 0) return format_map[k].format | format; } return 0; } int st_sndfile_startwrite(ft_t ft) { sndfile_t sf = (sndfile_t)ft->priv; sf->sf_info = (SF_INFO *)xmalloc(sizeof(SF_INFO)); /* Copy format info */ /* FIXME: Need to have a table of suitable default subtypes */ sf->sf_info->format = guess_output_file_type(ft->filetype, SF_FORMAT_PCM_16); sf->sf_info->samplerate = ft->signal.rate; sf->sf_info->channels = ft->signal.channels; sf->sf_info->frames = ft->length / ft->signal.channels; if (!sf_format_check(sf->sf_info)) { st_fail("invalid sndfile output format"); return ST_EOF; } if ((sf->sf_file = sf_open(ft->filename, SFM_WRITE, sf->sf_info)) == NULL) { st_fail("sndfile cannot open file for writing: %s", sf_strerror(sf->sf_file)); return ST_EOF; } return ST_SUCCESS; } /* * Write len samples of type st_sample_t from buf[] to file. * Return number of samples written. */ st_size_t st_sndfile_write(ft_t ft, const st_sample_t *buf, st_size_t len) { sndfile_t sf = (sndfile_t)ft->priv; /* FIXME: We assume int == st_sample_t here */ return (st_size_t)sf_write_int(sf->sf_file, (int *)buf, len); } /* * Close file for libsndfile (this doesn't close the file handle) */ int st_sndfile_stopwrite(ft_t ft) { sndfile_t sf = (sndfile_t)ft->priv; sf_close(sf->sf_file); return ST_SUCCESS; } int st_sndfile_seek(ft_t ft, st_size_t offset) { sndfile_t sf = (sndfile_t)ft->priv; sf_seek(sf->sf_file, offset / ft->signal.channels, SEEK_CUR); return ST_SUCCESS; } /* Format file suffixes */ /* For now, comment out formats built-in to SoX */ static const char *names[] = { /* "aif", */ /* "wav", */ /* "au", */ "caf", /* "flac", */ /* "snd", */ /* "svx", */ "paf", "fap", /* "gsm", */ "nist", /* "ircam", */ /* "sf", */ /* "voc", */ "w64", /* "raw", */ "mat4", "mat5", "mat", "pvf", "sds", "sd2", /* "vox", */ "xi", NULL }; /* Format descriptor */ static st_format_t st_sndfile_format = { names, NULL, ST_FILE_SEEK, st_sndfile_startread, st_sndfile_read, st_sndfile_stopread, st_sndfile_startwrite, st_sndfile_write, st_sndfile_stopwrite, st_sndfile_seek }; const st_format_t *st_sndfile_format_fn(void) { return &st_sndfile_format; } #endif