summaryrefslogtreecommitdiff
path: root/apps/zresample.cc
diff options
context:
space:
mode:
Diffstat (limited to 'apps/zresample.cc')
-rw-r--r--apps/zresample.cc302
1 files changed, 302 insertions, 0 deletions
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;
+}