diff options
Diffstat (limited to 'apps/audiofile.cc')
-rw-r--r-- | apps/audiofile.cc | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/apps/audiofile.cc b/apps/audiofile.cc new file mode 100644 index 0000000..ecf124b --- /dev/null +++ b/apps/audiofile.cc @@ -0,0 +1,326 @@ +// ------------------------------------------------------------------------- +// +// Copyright (C) 2009-2014 Fons Adriaensen <fons@linuxaudio.org> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// ------------------------------------------------------------------------- + + +#include <stdlib.h> +#include <string.h> +#include "audiofile.h" + + +const char *Audiofile::_typestr [] = { "other", "caf", "wav", "amb", "aiff", "flac" }; +const char *Audiofile::_formstr [] = { "other", "16bit", "24bit", "32bit", "float" }; +const char *Audiofile::_dithstr [] = { "none", "rect", "tri", "lips" }; + + + +Audiofile::Audiofile (void) : + _sndfile (0), + _dith_proc (0), + _dith_buff (0), + _data_buff (0) +{ + clear (); +} + + +Audiofile::~Audiofile (void) +{ + close (); +} + + +int Audiofile::enc_type (const char *s) +{ + for (int i = 1; i < 6; i++) if (!strcmp (s, _typestr [i])) return i; + return -1; +} + + +int Audiofile::enc_form (const char *s) +{ + for (int i = 1; i < 5; i++) if (!strcmp (s, _formstr [i])) return i; + return -1; +} + + +int Audiofile::enc_dith (const char *s) +{ + for (int i = 0; i < 4; i++) if (!strcmp (s, _dithstr [i])) return i; + return -1; +} + + +void Audiofile::clear (void) +{ + _mode = MODE_NONE; + _type = TYPE_OTHER; + _form = FORM_OTHER; + _rate = 0; + _chan = 0; + _size = 0; + _dith_type = 0; + delete[] _dith_proc; + delete[] _dith_buff; + delete[] _data_buff; + _dith_proc = 0; + _dith_buff = 0; + _data_buff = 0; +} + + +int Audiofile::open_read (const char *name) +{ + SF_INFO I; + + if (_mode) return ERR_MODE; + if ((_sndfile = sf_open (name, SFM_READ, &I)) == 0) return ERR_OPEN; + + _mode = MODE_READ; + switch (I.format & SF_FORMAT_TYPEMASK) + { + case SF_FORMAT_CAF: + _type = TYPE_CAF; + break; + case SF_FORMAT_WAV: + _type = TYPE_WAV; + break; + case SF_FORMAT_WAVEX: + if (sf_command (_sndfile, SFC_WAVEX_GET_AMBISONIC, 0, 0) == SF_AMBISONIC_B_FORMAT) + _type = TYPE_AMB; + else + _type = TYPE_WAV; + break; + case SF_FORMAT_AIFF: + _type = TYPE_AIFF; + break; + case SF_FORMAT_FLAC: + _type = TYPE_FLAC; + break; + default: + _type = TYPE_OTHER; + } + switch (I.format & SF_FORMAT_SUBMASK) + { + case SF_FORMAT_PCM_16: + _form = FORM_16BIT; + break; + case SF_FORMAT_PCM_24: + _form = FORM_24BIT; + break; + case SF_FORMAT_PCM_32: + _form = FORM_32BIT; + break; + case SF_FORMAT_FLOAT: + _form = FORM_FLOAT; + break; + default: + _form = FORM_OTHER; + } + _rate = I.samplerate; + _chan = I.channels; + _size = I.frames; + + return 0; +} + + +int Audiofile::open_write (const char *name, int type, int form, int rate, int chan) +{ + SF_INFO I; + + if (_mode) return ERR_MODE; + if ((rate < 1) || (chan < 1)) return ERR_OPEN; + + switch (type) + { + case TYPE_CAF: + I.format = SF_FORMAT_CAF; + break; + case TYPE_WAV: + case TYPE_AMB: + I.format = (chan > 2) ? SF_FORMAT_WAVEX : SF_FORMAT_WAV; + break; + case TYPE_AIFF: + I.format = SF_FORMAT_AIFF; + break; + case TYPE_FLAC: + I.format = SF_FORMAT_FLAC; + break; + default: + return ERR_TYPE; + } + switch (form) + { + case FORM_16BIT: + I.format |= SF_FORMAT_PCM_16; + break; + case FORM_24BIT: + I.format |= SF_FORMAT_PCM_24; + break; + case FORM_32BIT: + I.format |= SF_FORMAT_PCM_32; + break; + case FORM_FLOAT: + I.format |= SF_FORMAT_FLOAT; + break; + default: + return ERR_FORM; + } + I.samplerate = rate; + I.channels = chan; + I.sections = 1; + if ((_sndfile = sf_open (name, SFM_WRITE, &I)) == 0) return ERR_OPEN; + if (type == TYPE_AMB) + { + sf_command (_sndfile, SFC_WAVEX_SET_AMBISONIC, 0, SF_AMBISONIC_B_FORMAT); + } + + _mode = MODE_WRITE; + _type = type; + _form = form; + _rate = rate; + _chan = chan; + + return 0; +} + + +float *Audiofile::get_buffer (void) +{ + if (_mode == MODE_NONE) return 0; + if (_data_buff == 0) _data_buff = new float [_chan * BUFFSIZE]; + return _data_buff; +} + + +int Audiofile::set_dither (int type) +{ + if (_mode != MODE_WRITE) return ERR_MODE; + if (_form != FORM_16BIT) return ERR_FORM; + if (type == DITHER_NONE) + { + delete[] _dith_proc; + delete[] _dith_buff; + _dith_proc = 0; + _dith_buff = 0; + } + else if (_dith_type == DITHER_NONE) + { + _dith_proc = new Dither [_chan]; + _dith_buff = new int16_t [_chan * BUFFSIZE]; + } + _dith_type = type; + return 0; +} + + +int Audiofile::close (void) +{ + if (_sndfile) + { + sf_close (_sndfile); + _sndfile = 0; + } + clear (); + return 0; +} + + +int64_t Audiofile::seek (int64_t posit, int mode) +{ + if (!_sndfile) return ERR_MODE; + if (sf_seek (_sndfile, posit, mode) != posit) return ERR_SEEK; + return 0; +} + + +int Audiofile::read (float *data, uint64_t frames) +{ + if (_mode != MODE_READ) return ERR_MODE; + return sf_readf_float (_sndfile, data, frames); +} + + +int Audiofile::write (float *data, uint64_t frames) +{ + int i; + uint32_t k, n, r; + float *p, v; + int16_t *q; + Dither *D; + + if (_mode != MODE_WRITE) return ERR_MODE; + if (_dith_type == DITHER_NONE) + { + if (_form != FORM_FLOAT) + { + for (i = 0; i < _chan; i++) + { + p = data + i; + for (k = 0; k < frames; k++) + { + v = *p; + if (v > 1.0f) v = 1.0f; + else if (v < -1.0f) v = -1.0f; + *p = v; + p += _chan; + } + } + } + return sf_writef_float (_sndfile, data, frames); + } + else + { + n = 0; + while (frames) + { + k = (frames > BUFFSIZE) ? BUFFSIZE : frames; + p = data; + q = _dith_buff; + D = _dith_proc; + for (i = 0; i < _chan; i++) + { + switch (_dith_type) + { + case DITHER_RECT: + D->proc_rectangular (k, p, q, _chan, _chan); + break; + case DITHER_TRIA: + D->proc_triangular (k, p, q, _chan, _chan); + break; + case DITHER_LIPS: + D->proc_lipschitz (k, p, q, _chan, _chan); + break; + } + p++; + q++; + D++; + } + r = sf_writef_short (_sndfile, _dith_buff, k); + n += r; + if (r != k) return n; + data += k * _chan; + frames -= k; + } + } + return 0; +} + + |