ref: a94ba4b564483866ad151cd6c9496603f191c2c9
parent: e8388c3697d0cd52a7d2108c4940cd5a610a30c2
author: robs <robs>
date: Tue Jul 3 17:11:43 EDT 2007
Trying out soundtouch; same as stretch & pitch but much better audio performance. A few niggles still to iron out.
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,5 @@
include(CheckIncludeFiles)
+include(CheckIncludeFileCXX)
include(CheckFunctionExists)
include(CheckLibraryExists)
include(TestBigEndian)
@@ -41,6 +42,13 @@
check_include_files("sys/timeb.h" HAVE_SYS_TIMEB_H)
check_include_files("unistd.h" HAVE_UNISTD_H)
+check_include_file_cxx("soundtouch/SoundTouch.h" HAVE_LIBSOUNDTOUCH)
+if (HAVE_LIBSOUNDTOUCH)
+ set(optional_srcs ${optional_srcs} tempo)
+ set(optional_libs ${optional_libs} SoundTouch)
+endif (HAVE_LIBSOUNDTOUCH)
+
+
check_function_exists("fseeko" HAVE_FSEEKO)
check_function_exists("getopt_long" HAVE_GETOPT_LONG)
check_function_exists("gettimeofday" HAVE_GETTIMEOFDAY)
@@ -210,6 +218,9 @@
)
add_executable(${PROJECT_NAME} ${PROJECT_NAME}.c)
target_link_libraries(${PROJECT_NAME} lib${PROJECT_NAME} lpc10 ${optional_libs})
+if (HAVE_LIBSOUNDTOUCH)
+ set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
+endif (HAVE_LIBSOUNDTOUCH)
add_executable(sox_sample_test sox_sample_test.c)
add_custom_target(rec ALL ln -sf sox rec DEPENDS sox)
add_custom_target(play ALL ln -sf sox play DEPENDS sox)
--- a/src/effects.h
+++ b/src/effects.h
@@ -20,6 +20,9 @@
EFFECT(flanger)
EFFECT(highpass)
EFFECT(highp)
+#ifdef HAVE_LIBSOUNDTOUCH
+ EFFECT(key)
+#endif
#ifdef HAVE_LADSPA_H
EFFECT(ladspa)
#endif
@@ -51,6 +54,9 @@
EFFECT(stretch)
EFFECT(swap)
EFFECT(synth)
+#ifdef HAVE_LIBSOUNDTOUCH
+ EFFECT(tempo)
+#endif
EFFECT(treble)
EFFECT(tremolo)
EFFECT(trim)
--- a/src/sox_i.h
+++ b/src/sox_i.h
@@ -273,7 +273,7 @@
*/
/* Psion record header check, defined in misc.c and used in prc.c and auto.c */
-const char prc_header[41];
+extern const char prc_header[41];
int prc_checkheader(sox_format_t * ft, char *head);
typedef const sox_format_handler_t *(*sox_format_fn_t)(void);
--- /dev/null
+++ b/src/tempo.c++
@@ -1,0 +1,156 @@
+/*
+ * 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.
+ */
+
+/*
+ * (c) 2007 robs@users.sourceforge.net
+ *
+ * libSoX tempo effect: adjust the audio tempo (but not key)
+ *
+ * Adjustment is given as the ratio of the new tempo to the old tempo.
+ *
+ * libSoX key effect: adjust the audio pitch (but not tempo)
+ *
+ * Adjustment is given as a number of cents (100ths of a semitone) to
+ * change. Implementation comprises a tempo change (performed by tempo)
+ * and a speed change performed by whichever resampling effect is in effect.
+ */
+
+#include <soundtouch/SoundTouch.h>
+
+extern "C" {
+
+#include "sox_i.h"
+#include <math.h>
+#include <string.h>
+
+typedef struct tempo
+{
+ soundtouch::SAMPLETYPE * buffer;
+ soundtouch::SoundTouch * sound_touch;
+ double factor;
+} * tempo_t;
+
+assert_static(sizeof(struct tempo) <= SOX_MAX_EFFECT_PRIVSIZE,
+ /* else */ tempo_PRIVSIZE_too_big);
+
+static int create(sox_effect_t * effp, int n, char * * argv)
+{
+ tempo_t p = (tempo_t) effp->priv;
+ char dummy;
+
+ if (n == 1 && sscanf(*argv, "%lf %c", &p->factor, &dummy) == 1 && p->factor >=0.05 && p->factor <= 20)
+ return SOX_SUCCESS;
+ return sox_usage(effp);
+}
+
+static int start(sox_effect_t * effp)
+{
+ tempo_t p = (tempo_t) effp->priv;
+
+ if (!p->factor)
+ return SOX_EFF_NULL;
+
+ p->buffer = new soundtouch::SAMPLETYPE[effp->global_info->global_info->bufsiz];
+
+ p->sound_touch = new soundtouch::SoundTouch;
+ p->sound_touch->setSampleRate(static_cast<uint>(effp->ininfo.rate + 0.5));
+ p->sound_touch->setTempoChange(100 / p->factor - 100);
+
+ p->sound_touch->setChannels(1);
+ p->sound_touch->setPitchSemiTones(0);
+ p->sound_touch->setRateChange(0);
+ p->sound_touch->setSetting(SETTING_USE_AA_FILTER, 0);
+ return SOX_SUCCESS;
+}
+
+static int flow(sox_effect_t * effp, const sox_ssample_t * ibuf, sox_ssample_t * obuf,
+ sox_size_t * isamp, sox_size_t * osamp)
+{
+ tempo_t p = (tempo_t) effp->priv;
+ sox_size_t i;
+ sox_size_t idone = 0;
+ sox_size_t odone = p->sound_touch->receiveSamples(p->buffer, *osamp);
+
+ for (i = 0; i < odone; ++i)
+ obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE(p->buffer[i], effp->clips);
+
+ if (odone < *osamp)
+ if (*isamp && odone < *osamp) {
+ for (i = 0; i < *isamp; ++i)
+ p->buffer[i] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips);
+ p->sound_touch->putSamples(p->buffer, idone = *isamp);
+ }
+
+ *isamp = idone;
+ *osamp = odone;
+ return SOX_SUCCESS;
+}
+
+static int drain(sox_effect_t * effp, sox_ssample_t * obuf, sox_size_t * osamp)
+{
+ static sox_size_t isamp = 0;
+ tempo_t p = (tempo_t) effp->priv;
+ p->sound_touch->flush();
+ return flow(effp, 0, obuf, &isamp, osamp);
+}
+
+static int stop(sox_effect_t * effp)
+{
+ tempo_t p = (tempo_t) effp->priv;
+ delete p->sound_touch;
+ delete[] p->buffer;
+ return SOX_SUCCESS;
+}
+
+sox_effect_handler_t const *sox_tempo_effect_fn(void)
+{
+ static sox_effect_handler_t handler = {
+ "tempo", "factor", SOX_EFF_LENGTH,
+ create, start, flow, drain, stop, 0};
+ return &handler;
+}
+
+static int key_create(sox_effect_t * effp, int argc, char * * argv)
+{
+ double d;
+ char dummy, arg[100];
+ char * args[10];
+ sox_size_t nargs = 0;
+
+ if (!argc || sscanf(*argv, "%lf %c", &d, &dummy) != 1)
+ return sox_usage(effp);
+
+ d = pow(2., d/1200);
+ effp->global_info->speed *= d;
+ sprintf(arg, "%g", d);
+ args[nargs++] = arg;
+ ++argv, --argc;
+
+ return argc ? sox_usage(effp) :
+ sox_tempo_effect_fn()->getopts(effp, nargs, args);
+}
+
+sox_effect_handler_t const * sox_key_effect_fn(void)
+{
+ static sox_effect_handler_t handler;
+ handler = *sox_tempo_effect_fn();
+ handler.name = "key";
+ handler.usage = "shift-in-cents";
+ handler.getopts = key_create;
+ return &handler;
+}
+
+} // extern "C"