summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/Makefile73
-rw-r--r--apps/audiofile.cc326
-rw-r--r--apps/audiofile.h137
-rw-r--r--apps/dither.cc127
-rw-r--r--apps/dither.h59
-rw-r--r--apps/zresample.190
-rw-r--r--apps/zresample.cc302
-rw-r--r--apps/zretune.179
-rw-r--r--apps/zretune.cc265
9 files changed, 1458 insertions, 0 deletions
diff --git a/apps/Makefile b/apps/Makefile
new file mode 100644
index 0000000..f009937
--- /dev/null
+++ b/apps/Makefile
@@ -0,0 +1,73 @@
+# ----------------------------------------------------------------------------
+#
+# Copyright (C) 2006-2011 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 3 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, see <http:#www.gnu.org/licenses/>.
+#
+# ----------------------------------------------------------------------------
+
+
+PREFIX = /usr/local
+SUFFIX := $(shell uname -m | sed -e 's/^unknown/$//' -e 's/^i.86/$//' -e 's/^x86_64/$/64/')
+LIBDIR = lib$(SUFFIX)
+DISTDIR = zresample-$(VERSION)
+VERSION = 1.6.0
+MANDIR = /usr/share/man/man1
+LDFLAGS += -L$(PREFIX)/$(LIBDIR)
+CPPFLAGS += -MMD -MP -DVERSION=\"$(VERSION)\"
+CXXFLAGS += -O3 -ffast-math -Wall
+CXXFLAGS += -march=native
+
+
+all: zresample zretune zresample.1.gz zretune.1.gz
+
+
+ZRESAMPLE_O = zresample.o audiofile.o dither.o
+zresample: LDLIBS += -lzita-resampler -lsndfile -lrt
+zresample: $(ZRESAMPLE_O)
+ g++ $(LDFLAGS) -o $@ $(ZRESAMPLE_O) $(LDLIBS)
+$(ZRESAMPLE_O):
+-include $(ZRESAMPLE_O:%.o=%.d)
+
+
+ZRETUNE_O = zretune.o audiofile.o dither.o
+zretune: LDLIBS += -lzita-resampler -lsndfile -lrt
+zretune: $(ZRETUNE_O)
+ g++ $(LDFLAGS) -o $@ $(ZRETUNE_O) $(LDLIBS)
+$(ZRETUNE_O):
+-include $(ZRETUNE_O:%.o=%.d)
+
+
+zresample.1.gz: zresample.1
+ gzip -c zresample.1 > zresample.1.gz
+
+zretune.1.gz: zretune.1
+ gzip -c zretune.1 > zretune.1.gz
+
+
+install: all
+ install -Dm 755 zresample $(DESTDIR)$(PREFIX)/bin/zresample
+ install -Dm 755 zretune $(DESTDIR)$(PREFIX)/bin/zretune
+ install -Dm 644 zresample.1.gz $(DESTDIR)$(MANDIR)/zresample.1.gz
+ install -Dm 644 zretune.1.gz $(DESTDIR)$(MANDIR)/zretune.1.gz
+
+uninstall:
+ /bin/rm -f $(DESTDIR)$(PREFIX)/bin/zresample
+ /bin/rm -f $(DESTDIR)$(PREFIX)/bin/zretune
+ /bin/rm -f $(MANDIR)/zresample.1.gz
+ /bin/rm -f $(MANDIR)/zretune.1.gz
+
+clean:
+ /bin/rm -f *~ *.o *.a *.d *.so *.gz zresample zretune
+
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;
+}
+
+
diff --git a/apps/audiofile.h b/apps/audiofile.h
new file mode 100644
index 0000000..aaf7ec0
--- /dev/null
+++ b/apps/audiofile.h
@@ -0,0 +1,137 @@
+// -------------------------------------------------------------------------
+//
+// 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.
+//
+// -------------------------------------------------------------------------
+
+
+#ifndef __AUDIOFILE_H
+#define __AUDIOFILE_H
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sndfile.h>
+#include "dither.h"
+
+
+class Audiofile
+{
+public:
+
+ enum
+ {
+ MODE_NONE,
+ MODE_READ,
+ MODE_WRITE
+ };
+
+ enum
+ {
+ TYPE_OTHER,
+ TYPE_CAF,
+ TYPE_WAV,
+ TYPE_AMB,
+ TYPE_AIFF,
+ TYPE_FLAC
+ };
+
+ enum
+ {
+ FORM_OTHER,
+ FORM_16BIT,
+ FORM_24BIT,
+ FORM_32BIT,
+ FORM_FLOAT,
+ };
+
+ enum
+ {
+ DITHER_NONE,
+ DITHER_RECT,
+ DITHER_TRIA,
+ DITHER_LIPS,
+ };
+
+ enum
+ {
+ ERR_NONE = 0,
+ ERR_MODE = -1,
+ ERR_TYPE = -2,
+ ERR_FORM = -3,
+ ERR_OPEN = -4,
+ ERR_SEEK = -5,
+ ERR_DATA = -6,
+ ERR_READ = -7,
+ ERR_WRITE = -8
+ };
+
+ enum { BUFFSIZE = 1024 };
+
+ Audiofile (void);
+ ~Audiofile (void);
+
+ int mode (void) const { return _mode; }
+ int type (void) const { return _type; }
+ int form (void) const { return _form; }
+ int rate (void) const { return _rate; }
+ int chan (void) const { return _chan; }
+ uint64_t size (void) const { return _size; }
+
+ const char *typestr (void) const { return _typestr [_type]; }
+ const char *formstr (void) const { return _formstr [_form]; }
+ const char *dithstr (void) const { return _dithstr [_dith_type]; }
+
+ int enc_type (const char *s);
+ int enc_form (const char *s);
+ int enc_dith (const char *s);
+
+ int open_read (const char *name);
+ int open_write (const char *name, int type, int form, int rate, int chan);
+ int close (void);
+ int set_dither (int type);
+ float *get_buffer (void);
+
+ int64_t seek (int64_t posit, int mode = SEEK_SET);
+ int read (float *data, uint64_t frames);
+ int write (float *data, uint64_t frames);
+
+
+private:
+
+ void clear (void);
+
+ SNDFILE *_sndfile;
+ int _mode;
+ int _type;
+ int _form;
+ int _rate;
+ int _chan;
+ uint64_t _size;
+ int _dith_type;
+ Dither *_dith_proc;
+ int16_t *_dith_buff;
+ float *_data_buff;
+
+ static const char *_typestr [];
+ static const char *_formstr [];
+ static const char *_dithstr [];
+};
+
+
+#endif
+
diff --git a/apps/dither.cc b/apps/dither.cc
new file mode 100644
index 0000000..c85b296
--- /dev/null
+++ b/apps/dither.cc
@@ -0,0 +1,127 @@
+// -------------------------------------------------------------------------
+//
+// Copyright (C) 2010-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 <string.h>
+#include <math.h>
+#include "dither.h"
+
+
+float Dither::_div = 0;
+
+#define SCALE 32768.0f
+#define LIMIT 32767
+
+
+
+Dither::Dither (void)
+{
+ reset ();
+ _div = ldexpf (1.0f, 32);
+}
+
+
+void Dither::reset (void)
+{
+ memset (_err, 0, (SIZE + 4) * sizeof(float));
+ _ind = SIZE - 1;
+ _ran = 1234567;
+}
+
+
+void Dither::proc_rectangular (int nsam, const float *srce, int16_t *dest, int ds, int dd)
+{
+ float v, r;
+ int16_t k;
+
+ while (nsam--)
+ {
+ r = genrand () - 0.5f;
+ v = *srce * SCALE + r;
+ k = lrintf (v);
+ if (k < -LIMIT) k = -LIMIT;
+ else if (k > LIMIT) k = LIMIT;
+ *dest = k;
+ srce += ds;
+ dest += dd;
+ }
+}
+
+
+void Dither::proc_triangular (int nsam, const float *srce, int16_t *dest, int ds, int dd)
+{
+ float v, r0, r1;
+ int16_t k;
+
+ r1 = *_err;
+ while (nsam--)
+ {
+ r0 = genrand ();
+ v = *srce * SCALE + r0 - r1;
+ r1 = r0;
+ k = lrintf (v);
+ if (k < -LIMIT) k = -LIMIT;
+ else if (k > LIMIT) k = LIMIT;
+ *dest = k;
+ srce += ds;
+ dest += dd;
+ }
+ *_err = r1;
+}
+
+
+void Dither::proc_lipschitz (int nsam, const float *srce, int16_t *dest, int ds, int dd)
+{
+ float e, u, v, *p;
+ int i;
+ int16_t k;
+
+ i = _ind;
+ while (nsam--)
+ {
+ p = _err + i;
+ u = *srce * SCALE
+ - 2.033f * p [0]
+ + 2.165f * p [1]
+ - 1.959f * p [2]
+ + 1.590f * p [3]
+ - 0.615f * p [4];
+ v = u + genrand () - genrand ();
+ k = lrintf (v);
+ e = k - u;
+ if (k < -LIMIT) k = -LIMIT;
+ else if (k > LIMIT) k = LIMIT;
+ *dest = k;
+ if (--i < 0)
+ {
+ _err [SIZE + 0] = _err [0];
+ _err [SIZE + 1] = _err [1];
+ _err [SIZE + 2] = _err [2];
+ _err [SIZE + 3] = _err [3];
+ i += SIZE;
+ }
+ _err [i] = e;
+ srce += ds;
+ dest += dd;
+ }
+ _ind = i;
+}
+
+
diff --git a/apps/dither.h b/apps/dither.h
new file mode 100644
index 0000000..d03ca8c
--- /dev/null
+++ b/apps/dither.h
@@ -0,0 +1,59 @@
+// -------------------------------------------------------------------------
+//
+// Copyright (C) 2010-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.
+//
+// -------------------------------------------------------------------------
+
+
+#ifndef __DITHER_H
+#define __DITHER_H
+
+
+#include <stdint.h>
+
+
+class Dither
+{
+public:
+
+ Dither (void);
+ void reset (void);
+ void proc_rectangular (int nsam, const float *srce, int16_t *dest, int ds, int dd);
+ void proc_triangular (int nsam, const float *srce, int16_t *dest, int ds, int dd);
+ void proc_lipschitz (int nsam, const float *srce, int16_t *dest, int ds, int dd);
+
+private:
+
+ enum { SIZE = 64 };
+
+ float genrand (void)
+ {
+ _ran *= 1103515245;
+ _ran += 12345;
+ return _ran / _div;
+ }
+
+ float _err [SIZE + 4];
+ int _ind;
+ uint32_t _ran;
+
+ static float _div;
+};
+
+
+#endif
+
diff --git a/apps/zresample.1 b/apps/zresample.1
new file mode 100644
index 0000000..70cc7cf
--- /dev/null
+++ b/apps/zresample.1
@@ -0,0 +1,90 @@
+.TH zresample 1 "May 2010" "version 0.0.1" "USER COMMANDS"
+.SH NAME
+zresample \- resample and change sample format of audio files
+.SH SYNOPSIS
+.B zresample
+[options] input-file output-file
+.SH DESCRIPTION
+.B zresample
+copies an audio file, changing the sample rate and/or the
+sample format. For 16-bit output it can also dither the
+audio signal. Input can be any audio file readable by the
+libsndfile library. The output file type is either WAV, WAVEX,
+CAF, AIFF or FLAC.
+.SH OPTIONS
+.TP
+.B --help
+Display a short help text.
+.TP
+.B --rate sample-rate
+Set the output sample rate.
+.B Zresample
+uses the zita-resampler library which means that not all
+combinations of input/output sample rate will be accepted.
+The resample ratio must be a reducable to a fraction
+.B a/b
+with both
+.B a
+and
+.B b
+less than or equal to 1000.
+.TP
+.B --gain gain
+Gain in dB, default zero.
+.SS Output file type
+.TP
+.B --wav
+Produce a WAV file, or for more than 2 channels, a WAVEX file.
+This is the default.
+.TP
+.B --amb
+Produce a WAVEX file with the Ambisonic GUID. Such files should
+have the
+.B .amb
+filename extension.
+.TP
+.B --caf
+Produce a Core Audio file.
+.TP
+.B --aiff
+Produce an AIFF file.
+.TP
+.B --flac
+Produce a FLAC file.
+.SS Output sample format
+.TP
+.B --16bit
+Output sample format is signed 16-bit. This option also
+enables the use of dithering, described below.
+.TP
+.B --24bit
+Output sample format is 24-bit. This is the default.
+.TP
+.B --float
+Output sample format is 32-bit floating point.
+.SS Dithering
+.TP
+.B --rec
+Add white dithering noise with a rectangular distribution. This
+is the best option if the output data is going to processed again,
+but in that case it would be advisable to use 24-bit or float.
+.TP
+.B --tri
+Add filtered noise with a triangular distribution. Compared to the
+rectangular dither this reduces the noise density in the lower
+frequency range.
+.TP
+.B --lips
+This uses the optimal error feedback filter described by
+Stanley Lipschitz. This is recommended is the output is the
+final distribution format, e.g. for a CD.
+.SS Timing
+.TP
+.B --pad
+Insert zero valued input samples at the start and end so that the output
+includes the full symmetric filter response even for the first and last
+samples.
+.SH EXIT STATUS
+Zero in case there are no errors, non-zero otherwise.
+.SH AUTHOR
+Fons Adriaensen (fons (at) linuxaudio.org)
diff --git a/apps/zresample.cc b/apps/zresample.cc
new file mode 100644
index 0000000..474bee8
--- /dev/null
+++ b/apps/zresample.cc
@@ -0,0 +1,302 @@
+// ----------------------------------------------------------------------------
+//
+// Copyright (C) 2006-2011 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 3 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, see <http://www.gnu.org/licenses/>.
+//
+// ----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <math.h>
+#include <zita-resampler/resampler.h>
+#include "audiofile.h"
+
+
+enum { HELP, CAF, WAV, AMB, AIFF, FLAC, BIT16, BIT24, FLOAT, RATE, GAIN, REC, TRI, LIPS, PAD };
+enum { BUFFSIZE = 0x4000, FILTSIZE = 96 };
+
+
+static unsigned int type = Audiofile::TYPE_WAV;
+static unsigned int form = Audiofile::FORM_24BIT;
+static unsigned int rout = 0;
+static unsigned int dith = Audiofile::DITHER_NONE;
+static float gain = 0.0f;
+static bool zpad = false;
+
+
+static void help (void)
+{
+ fprintf (stderr, "\nzresample %s\n", VERSION);
+ fprintf (stderr, "(C) 2007-2015 Fons Adriaensen <fons@linuxaudio.org>\n");
+ fprintf (stderr, "Usage: zresample <options> <input file> <output file>.\n");
+ fprintf (stderr, "Options:\n");
+ fprintf (stderr, " Display this text: --help\n");
+ fprintf (stderr, " Output file type: --caf, --wav, --amb, --aiff, --flac\n");
+ fprintf (stderr, " Output sample rate: --rate <sample rate>\n");
+ fprintf (stderr, " Additional gain (dB): --gain [0.0]\n");
+ fprintf (stderr, " Output sample format: --16bit, --24bit, --float\n");
+ fprintf (stderr, " Dither type (16 bit): --rec, --tri, --lips\n");
+ fprintf (stderr, " Add zero padding : --pad\n");
+ fprintf (stderr, "The default output file format is wav, 24-bit, no dithering.\n");
+ fprintf (stderr, "Integer output formats are clipped, float output is not.\n\n");
+ exit (1);
+}
+
+
+static struct option options [] =
+{
+ { "help", 0, 0, HELP },
+ { "caf", 0, 0, CAF },
+ { "wav", 0, 0, WAV },
+ { "amb", 0, 0, AMB },
+ { "aiff", 0, 0, AIFF },
+ { "flac", 0, 0, FLAC },
+ { "16bit", 0, 0, BIT16 },
+ { "24bit", 0, 0, BIT24 },
+ { "float", 0, 0, FLOAT },
+ { "rate", 1, 0, RATE },
+ { "gain", 1, 0, GAIN },
+ { "rec", 0, 0, REC },
+ { "tri", 0, 0, TRI },
+ { "lips", 0, 0, LIPS },
+ { "pad", 0, 0, PAD },
+ { 0, 0, 0, 0 }
+};
+
+
+static void procoptions (int ac, char *av [])
+{
+ int k;
+
+ while ((k = getopt_long (ac, av, "", options, 0)) != -1)
+ {
+ switch (k)
+ {
+ case '?':
+ case HELP:
+ help ();
+ break;
+ case CAF:
+ type = Audiofile::TYPE_CAF;
+ break;
+ case WAV:
+ type = Audiofile::TYPE_WAV;
+ break;
+ case AMB:
+ type = Audiofile::TYPE_AMB;
+ break;
+ case AIFF:
+ type = Audiofile::TYPE_AIFF;
+ break;
+ case FLAC:
+ type = Audiofile::TYPE_FLAC;
+ break;
+ case BIT16:
+ form = Audiofile::FORM_16BIT;
+ break;
+ case BIT24:
+ form = Audiofile::FORM_24BIT;
+ break;
+ case FLOAT:
+ form = Audiofile::FORM_FLOAT;
+ break;
+ case RATE:
+ if (sscanf (optarg, "%d", &rout) != 1)
+ {
+ fprintf (stderr, "Illegal value for --rate option: '%s'.\n", optarg);
+ exit (1);
+ }
+ break;
+ case GAIN:
+ if (sscanf (optarg, "%f", &gain) != 1)
+ {
+ fprintf (stderr, "Illegal value for --gain option: '%s'.\n", optarg);
+ exit (1);
+ }
+ break;
+ case REC:
+ dith = Audiofile::DITHER_RECT;
+ break;
+ case TRI:
+ dith = Audiofile::DITHER_TRIA;
+ break;
+ case LIPS:
+ dith = Audiofile::DITHER_LIPS;
+ break;
+ case PAD:
+ zpad = true;
+ break;
+ }
+ }
+}
+
+
+int main (int ac, char *av [])
+{
+ Audiofile Ainp;
+ Audiofile Aout;
+ Resampler R;
+ unsigned int i, k, chan, rinp, z1, z2;
+ float *inpb, *outb;
+ bool done;
+
+ procoptions (ac, av);
+ if (ac - optind < 2)
+ {
+ fprintf (stderr, "Missing arguments, try --help.\n");
+ return 1;
+ }
+ if (ac - optind > 2 )
+ {
+ fprintf (stderr, "Too many arguments, try --help.\n");
+ return 1;
+ }
+
+ if (Ainp.open_read (av [optind]))
+ {
+ fprintf (stderr, "Can't open input file '%s'.\n", av [optind]);
+ return 1;
+ }
+
+ chan = Ainp.chan ();
+ rinp = Ainp.rate ();
+ if (rout == 0) rout = rinp;
+
+ if (rout != rinp)
+ {
+ if ((rinp < 8000) || (rinp > 192000))
+ {
+ fprintf (stderr, "Input sample %d rate is out of range.\n", rinp);
+ Ainp.close ();
+ return 1;
+ }
+ if ((rout < 8000) || (rout > 192000))
+ {
+ fprintf (stderr, "Output sample rate %d is out of range.\n", rout);
+ Ainp.close ();
+ return 1;
+ }
+ if (R.setup (rinp, rout, chan, FILTSIZE))
+ {
+ fprintf (stderr, "Sample rate ratio %d/%d is not supported.\n", rout, rinp);
+ Ainp.close ();
+ return 1;
+ }
+ }
+
+ optind++;
+ if (Aout.open_write (av [optind], type, form, rout, chan))
+ {
+ fprintf (stderr, "Can't open output file '%s'.\n", av [optind]);
+ Ainp.close ();
+ return 1;
+ }
+ if (dith != Audiofile::DITHER_NONE)
+ {
+ Aout.set_dither (dith);
+ }
+
+ if (zpad)
+ {
+ z1 = R.inpsize () - 1;
+ z2 = R.inpsize () - 1;
+ }
+ else
+ {
+ z1 = R.inpsize () / 2 - 1;
+ z2 = R.inpsize () / 2;
+ }
+
+ gain = powf (10.0f, 0.05f * gain);
+ inpb = new float [chan * BUFFSIZE];
+ if (rout != rinp)
+ {
+ outb = new float [chan * BUFFSIZE];
+ // Insert zero samples at start.
+ R.inp_count = z1;
+ R.inp_data = 0;
+ R.out_count = BUFFSIZE;
+ R.out_data = outb;
+ done = false;
+ while (true)
+ {
+ R.process ();
+ if (R.inp_count == 0)
+ {
+ // Input buffer empty, read more samples, insert
+ // zeros at the end, or terminate.
+ if (done)
+ {
+ // We already inserted final zero samples.
+ // Write out any remaining output samples and terminate.
+ Aout.write (outb, BUFFSIZE - R.out_count);
+ break;
+ }
+ k = Ainp.read (inpb, BUFFSIZE);
+ if (k)
+ {
+ if (fabsf (gain - 1.0f) > 1e-3f)
+ {
+ for (i = 0; i < k; i++) inpb [i] *= gain;
+ }
+ // Process next 'k' input samples.
+ R.inp_count = k;
+ R.inp_data = inpb;
+ }
+ else
+ {
+ // At end of input, insert zero samples.
+ R.inp_count = z2;
+ R.inp_data = 0;
+ done = true;
+ }
+ }
+ if (R.out_count == 0)
+ {
+ // Output buffer full, write to file.
+ Aout.write (outb, BUFFSIZE);
+ R.out_count = BUFFSIZE;
+ R.out_data = outb;
+ }
+ }
+ delete[] outb;
+ }
+ else
+ {
+ // No resampling, just copy.
+ while (1)
+ {
+ k = Ainp.read (inpb, BUFFSIZE);
+ if (k)
+ {
+ if (fabsf (gain - 1.0f) > 1e-3f)
+ {
+ for (i = 0; i < k; i++) inpb [i] *= gain;
+ }
+ Aout.write (inpb, k);
+ }
+ else break;
+ }
+ }
+
+ Ainp.close ();
+ Aout.close ();
+ delete[] inpb;
+
+ return 0;
+}
diff --git a/apps/zretune.1 b/apps/zretune.1
new file mode 100644
index 0000000..f4147cd
--- /dev/null
+++ b/apps/zretune.1
@@ -0,0 +1,79 @@
+.TH zretune 1 "Sect 2012" "version 0.0.1" "USER COMMANDS"
+.SH NAME
+zretune \- resample an audio file in order to change its pitch
+.SH SYNOPSIS
+.B zretune
+[options] input-file output-file
+.SH DESCRIPTION
+.B zretune
+resamples an audio file by a the inverse of a ratio expressed in cents,
+without changing the nominal sample rate. The result is to change the
+musical pitch and lenght of the file. Input can be any audio file
+readable by the libsndfile library. The output file type is either
+WAV, WAVEX, CAF, AIFF or FLAC.
+.SH OPTIONS
+.TP
+.B --help
+Display a short help text.
+.TP
+.B --cent pitch change in cents
+The number of cents by which the pitch is changed. The accepted
+range is +/- 1200 cents, the useful range in practice will be
+something like +/- 100 cents.
+.SS Output file type
+.TP
+.B --wav
+Produce a WAV file, or for more than 2 channels, a WAVEX file.
+This is the default.
+.TP
+.B --amb
+Produce a WAVEX file with the Ambisonic GUID. Such files should
+have the
+.B .amb
+filename extension.
+.TP
+.B --caf
+Produce a Core Audio file.
+.TP
+.B --aiff
+Produce an AIFF file.
+.TP
+.B --flac
+Produce a FLAC file.
+.SS Output sample format
+.TP
+.B --16bit
+Output sample format is signed 16-bit. This option also
+enables the use of dithering, described below.
+.TP
+.B --24bit
+Output sample format is 24-bit. This is the default.
+.TP
+.B --float
+Output sample format is 32-bit floating point.
+.SS Dithering
+.TP
+.B --rec
+Add white dithering noise with a rectangular distribution. This
+is the best option if the output data is going to processed again,
+but in that case it would be advisable to use 24-bit or float.
+.TP
+.B --tri
+Add filtered noise with a triangular distribution. Compared to the
+rectangular dither this reduces the noise density in the lower
+frequency range.
+.TP
+.B --lips
+This uses the optimal error feedback filter described by
+Stanley Lipschitz. This is recommended is the output is the
+final distribution format, e.g. for a CD.
+.SS Timing
+.TP
+.B --pad
+Insert zero valued input samples at the start and end so that the output
+includes the full symmetric filter response even for the first and last
+samples.
+.SH EXIT STATUS
+Zero in case there are no errors, non-zero otherwise.
+.SH AUTHOR
+Fons Adriaensen (fons (at) linuxaudio.org)
diff --git a/apps/zretune.cc b/apps/zretune.cc
new file mode 100644
index 0000000..a605a01
--- /dev/null
+++ b/apps/zretune.cc
@@ -0,0 +1,265 @@
+// ----------------------------------------------------------------------------
+//
+// Copyright (C) 2006-2011 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 3 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, see <http://www.gnu.org/licenses/>.
+//
+// ----------------------------------------------------------------------------
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <math.h>
+#include <zita-resampler/vresampler.h>
+#include "audiofile.h"
+
+
+enum { HELP, CAF, WAV, AMB, AIFF, FLAC, BIT16, BIT24, FLOAT, CENT, REC, TRI, LIPS, PAD };
+enum { BUFFSIZE = 0x4000, FILTSIZE = 96 };
+
+
+static unsigned int type = Audiofile::TYPE_WAV;
+static unsigned int form = Audiofile::FORM_24BIT;
+static double cent = 0;
+static unsigned int dith = Audiofile::DITHER_NONE;
+static bool zpad = false;
+
+
+static void help (void)
+{
+ fprintf (stderr, "\nzretune %s\n", VERSION);
+ fprintf (stderr, "(C) 2007-2012 Fons Adriaensen <fons@linuxaudio.org>\n");
+ fprintf (stderr, "Usage: zretune <options> <input file> <output file>.\n");
+ fprintf (stderr, "Options:\n");
+ fprintf (stderr, " Display this text: --help\n");
+ fprintf (stderr, " Output file type: --caf, --wav, --amb, --aiff, --flac\n");
+ fprintf (stderr, " Resampling ratio: --cent <pitch change>\n");
+ fprintf (stderr, " Output sample format: --16bit, --24bit, --float\n");
+ fprintf (stderr, " Dither type (16 bit): --rec, --tri, --lips\n");
+ fprintf (stderr, " Add zero padding : --pad\n");
+ fprintf (stderr, "The default output file format is wav, 24-bit, no dithering.\n");
+ fprintf (stderr, "Integer output formats are clipped, float output is not.\n\n");
+ exit (1);
+}
+
+
+static struct option options [] =
+{
+ { "help", 0, 0, HELP },
+ { "caf", 0, 0, CAF },
+ { "wav", 0, 0, WAV },
+ { "amb", 0, 0, AMB },
+ { "aiff", 0, 0, AIFF },
+ { "flac", 0, 0, FLAC },
+ { "16bit", 0, 0, BIT16 },
+ { "24bit", 0, 0, BIT24 },
+ { "float", 0, 0, FLOAT },
+ { "cent", 1, 0, CENT },
+ { "rec", 0, 0, REC },
+ { "tri", 0, 0, TRI },
+ { "lips", 0, 0, LIPS },
+ { "pad", 0, 0, PAD },
+ { 0, 0, 0, 0 }
+};
+
+
+static void procoptions (int ac, char *av [])
+{
+ int k;
+
+ while ((k = getopt_long (ac, av, "", options, 0)) != -1)
+ {
+ switch (k)
+ {
+ case '?':
+ case HELP:
+ help ();
+ break;
+ case CAF:
+ type = Audiofile::TYPE_CAF;
+ break;
+ case WAV:
+ type = Audiofile::TYPE_WAV;
+ break;
+ case AMB:
+ type = Audiofile::TYPE_AMB;
+ break;
+ case AIFF:
+ type = Audiofile::TYPE_AIFF;
+ break;
+ case FLAC:
+ type = Audiofile::TYPE_FLAC;
+ break;
+ case BIT16:
+ form = Audiofile::FORM_16BIT;
+ break;
+ case BIT24:
+ form = Audiofile::FORM_24BIT;
+ break;
+ case FLOAT:
+ form = Audiofile::FORM_FLOAT;
+ break;
+ case CENT:
+ if (sscanf (optarg, "%lf", &cent) != 1)
+ {
+ fprintf (stderr, "Illegal value for --rate option: '%s'.\n", optarg);
+ exit (1);
+ }
+ break;
+ case REC:
+ dith = Audiofile::DITHER_RECT;
+ break;
+ case TRI:
+ dith = Audiofile::DITHER_TRIA;
+ break;
+ case LIPS:
+ dith = Audiofile::DITHER_LIPS;
+ break;
+ case PAD:
+ zpad = true;
+ break;
+ }
+ }
+}
+
+
+int main (int ac, char *av [])
+{
+ Audiofile Ainp;
+ Audiofile Aout;
+ VResampler R;
+ unsigned int k, chan, z1, z2;
+ float *inpb, *outb;
+ bool done;
+ double ratio;
+
+ procoptions (ac, av);
+ if (ac - optind < 2)
+ {
+ fprintf (stderr, "Missing arguments, try --help.\n");
+ return 1;
+ }
+ if (ac - optind > 2 )
+ {
+ fprintf (stderr, "Too many arguments, try --help.\n");
+ return 1;
+ }
+
+ if (Ainp.open_read (av [optind]))
+ {
+ fprintf (stderr, "Can't open input file '%s'.\n", av [optind]);
+ return 1;
+ }
+
+ if ((cent < -1200) || (cent > 1200))
+ {
+ fprintf (stderr, "Pitch change %3.1lf is out of range.\n", cent);
+ Ainp.close ();
+ return 1;
+ }
+ ratio = pow (2.0, -cent / 1200.0);
+ R.setup (ratio, Ainp.chan (), FILTSIZE);
+
+ optind++;
+ if (Aout.open_write (av [optind], type, form, Ainp.rate(), Ainp.chan ()))
+ {
+ fprintf (stderr, "Can't open output file '%s'.\n", av [optind]);
+ Ainp.close ();
+ return 1;
+ }
+ if (dith != Audiofile::DITHER_NONE)
+ {
+ Aout.set_dither (dith);
+ }
+
+ if (zpad)
+ {
+ z1 = R.inpsize () - 1;
+ z2 = R.inpsize () - 1;
+ }
+ else
+ {
+ z1 = R.inpsize () / 2 - 1;
+ z2 = R.inpsize () / 2;
+ }
+
+ chan = Ainp.chan ();
+ inpb = new float [chan * BUFFSIZE];
+ if (cent != 0.0)
+ {
+ outb = new float [chan * BUFFSIZE];
+ // Insert zero samples at start.
+ R.inp_count = z1;
+ R.inp_data = 0;
+ R.out_count = BUFFSIZE;
+ R.out_data = outb;
+ done = false;
+ while (true)
+ {
+ R.process ();
+ if (R.inp_count == 0)
+ {
+ // Input buffer empty, read more samples, insert
+ // zeros at the end, or terminate.
+ if (done)
+ {
+ // We already inserted final zero samples.
+ // Write out any remaining output samples and terminate.
+ Aout.write (outb, BUFFSIZE - R.out_count);
+ break;
+ }
+ k = Ainp.read (inpb, BUFFSIZE);
+ if (k)
+ {
+ // Process next 'k' input samples.
+ R.inp_count = k;
+ R.inp_data = inpb;
+ }
+ else
+ {
+ // At end of input, insert zero samples.
+ R.inp_count = z2;
+ R.inp_data = 0;
+ done = true;
+ }
+ }
+ if (R.out_count == 0)
+ {
+ // Output buffer full, write to file.
+ Aout.write (outb, BUFFSIZE);
+ R.out_count = BUFFSIZE;
+ R.out_data = outb;
+ }
+ }
+ delete[] outb;
+ }
+ else
+ {
+ // No resampling, just copy.
+ while (1)
+ {
+ k = Ainp.read (inpb, BUFFSIZE);
+ if (k) Aout.write (inpb, k);
+ else break;
+ }
+ }
+
+ Ainp.close ();
+ Aout.close ();
+ delete[] inpb;
+
+ return 0;
+}