shithub: sox

Download patch

ref: dc35efc0cb561002610c82a8f357eb812f396355
parent: 3ae511f8292579ff4aa0ec3a23ea9c18fd0f0994
author: robs <robs>
date: Sun Oct 26 05:34:06 EDT 2008

Improved handling of speed changes in the effects chain.
Fixes e.g. 'play -n synth speed 100' not working properly.

--- a/ChangeLog
+++ b/ChangeLog
@@ -38,7 +38,7 @@
 
 File formats:
 
-  o New unfiltered CVSD; supports any bit-rate.  (robs)
+  o New `.cvu' unfiltered CVSD; supports any bit-rate.  (robs)
   o New `.sox' native format intended for intermediate files.  (robs)
   o Fix WAV write on 64-bit arch.  (robs)
   o Fix writing PRC ADPCM files.  (Silas Brown)
@@ -65,6 +65,7 @@
   o Fix rare crash with `rate' effect.  (robs)
   o Fix [2190767] `norm' under-amplifying in some cases.  (George Yohng)
   o Trim will now skip past 2G point correctly. (cbagwell)
+  o Improved handling of speed changes in the effects chain.  (robs)
 
 Other new features:
 
--- a/sox.1
+++ b/sox.1
@@ -29,7 +29,7 @@
 .SP
 .fi
 ..
-.TH SoX 1 "September 22, 2008" "sox" "Sound eXchange"
+.TH SoX 1 "October 28, 2008" "sox" "Sound eXchange"
 .SH NAME
 SoX \- Sound eXchange, the Swiss Army knife of audio manipulation
 .SH SYNOPSIS
--- a/soxformat.7
+++ b/soxformat.7
@@ -29,7 +29,7 @@
 .SP
 .fi
 ..
-.TH SoX 7 "July 27, 2008" "soxformat" "Sound eXchange"
+.TH SoX 7 "October 28, 2008" "soxformat" "Sound eXchange"
 .SH NAME
 SoX \- Sound eXchange, the Swiss Army knife of audio manipulation
 .SH DESCRIPTION
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -13,7 +13,7 @@
   else(${ver} LESS 403)
     add_definitions(-Wtraditional-conversion)
   endif(${ver} LESS 403)
-  #add_definitions(-Werror)
+  add_definitions(-Werror)
 endif(CMAKE_COMPILER_IS_GNUCC)
 
 if (NOT EXTERNAL_GSM)
@@ -28,16 +28,16 @@
 
 # Format with: !xargs echo|tr ' ' '\n'|sort|column|expand|sed 's/^/  /'
 set(effects_srcs
-  bend            earwax          mixer           rate            stat
-  biquad          echo            noiseprof       remix           stretch
-  biquads         echos           noisered        repeat          swap
-  chorus          fade            normalise       resample        synth
-  compand         fft4g           output          reverb          tempo
-  compandt        filter          pad             reverse         tremolo
-  contrast        flanger         pan             silence         trim
-  dcshift         input           phaser          skeleff         vol
-  delay           loudness        pitch           speed
-  dither          mcompand        polyphas        splice
+  bend            earwax          mixer           remix           stretch
+  biquad          echo            noiseprof       repeat          swap
+  biquads         echos           noisered        resample        synth
+  chorus          fade            normalise       reverb          tempo
+  compand         fft4g           output          reverse         tremolo
+  compandt        filter          pad             silence         trim
+  contrast        flanger         pan             skeleff         vol
+  dcshift         input           phaser          speed
+  delay           loudness        polyphas        splice
+  dither          mcompand        rate            stat
 )
 set(formats_srcs
   8svx            dat             ima-fmt         s3-fmt          u3-fmt
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -267,7 +267,7 @@
 	echo.c echos.c effects.c effects.h effects_i.c fade.c fft4g.c fft4g.h \
 	fifo.h filter.c flanger.c input.c ladspa.c loudness.c mcompand.c \
 	mixer.c noiseprof.c noisered.c noisered.h normalise.c output.c pad.c \
-	pan.c phaser.c pitch.c polyphas.c rabbit.c rate.c \
+	pan.c phaser.c polyphas.c rabbit.c rate.c \
 	rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \
 	remix.c repeat.c resample.c reverb.c reverse.c silence.c skeleff.c \
 	speed.c	splice.c stat.c swap.c stretch.c synth.c tempo.c tremolo.c \
--- a/src/effects.c
+++ b/src/effects.c
@@ -33,7 +33,7 @@
 
 /* FIXME: Not thread safe using globals */
 sox_effects_globals_t sox_effects_globals =
-    {sox_plot_off, 1, &sox_globals};
+    {sox_plot_off, &sox_globals};
 
 /* Default effect handler functions for do-nothing situations: */
 
@@ -137,10 +137,6 @@
   unsigned f;
   sox_effect_t eff0;  /* Copy of effect for flow 0 before calling start */
 
-  if (effp->handler.flags & SOX_EFF_NULL) {
-    lsx_report("has no effect (is a proxy effect)");
-    return SOX_SUCCESS;
-  }
   effp->global_info = &chain->global_info;
   effp->in_signal = *in;
   effp->out_signal = *out;
--- a/src/pitch.c
+++ /dev/null
@@ -1,63 +1,0 @@
-/* libSoX effect: change the audio pitch (i.e. change pitch but not tempo)
- * Copyright (c) 2007 robs@users.sourceforge.net
- *
- * 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.1 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,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- *
- * 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 "sox_i.h"
-#include <string.h>
-
-static int getopts(sox_effect_t * effp, int argc, char **argv)
-{
-  double d;
-  char dummy, arg[100], **argv2 = malloc(argc * sizeof(*argv2));
-  int ret, pos = (argc > 1 && !strcmp(argv[1], "-q"))? 2 : 1;
-
-  if (argc <= pos || sscanf(argv[pos], "%lf %c", &d, &dummy) != 1)
-    return lsx_usage(effp);
-
-  effp->global_info->speed *= d = pow(2., d / 1200);  /* cents --> factor */
-  sprintf(arg, "%g", 1 / d);
-  memcpy(argv2, argv, argc * sizeof(*argv2));
-  argv2[pos] = arg;
-  ret = sox_tempo_effect_fn()->getopts(effp, argc, argv2);
-  free(argv2);
-  return ret;
-}
-
-sox_effect_handler_t const * sox_pitch_effect_fn(void)
-{
-  static sox_effect_handler_t handler;
-  handler = *sox_tempo_effect_fn();
-  handler.name = "pitch";
-  handler.usage = "[-q] shift-in-cents [segment-ms [search-ms [overlap-ms]]]",
-  handler.getopts = getopts;
-  handler.flags &= ~SOX_EFF_LENGTH;
-  return &handler;
-}
-
-sox_effect_handler_t const * sox_key_effect_fn(void) /* old name for pitch */
-{
-  static sox_effect_handler_t handler;
-  handler = *sox_pitch_effect_fn();
-  handler.name = "key";
-  handler.flags |= SOX_EFF_DEPRECATED;
-  return &handler;
-}
--- a/src/sox.c
+++ b/src/sox.c
@@ -1456,13 +1456,6 @@
   calculate_combiner_signal_parameters();
   set_combiner_and_output_encoding_parameters();
   calculate_output_signal_parameters();
-
-  /* Now take account of any net speed change specified by user effects by
-   * adjusting the nominal sample rate at the output of the combiner.  This
-   * cannot be done inside calculate_combiner_signal_parameters since
-   * it must be done after calculate_output_signal_parameters. */
-  combiner_signal.rate *= sox_effects_globals.speed;
-
   open_output_file();
 
   if (!effects_chain)
--- a/src/sox.h
+++ b/src/sox.h
@@ -448,7 +448,6 @@
 typedef struct sox_effect sox_effect_t;
 struct sox_effects_globals { /* Global parameters (for effects) */
   sox_plot_t plot;         /* To help the user choose effect & options */
-  double speed;            /* Gather up all speed changes here, then resample */
   sox_globals_t * global_info;
 };
 typedef struct sox_effects_globals sox_effects_globals_t;
--- a/src/speed.c
+++ b/src/speed.c
@@ -1,5 +1,5 @@
 /* libSoX Effect: Adjust the audio speed (pitch and tempo together)
- * (c) 2006 robs@users.sourceforge.net
+ * (c) 2006,8 robs@users.sourceforge.net
  *
  * 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
@@ -24,22 +24,22 @@
 #include "sox_i.h"
 #include <string.h>
 
+typedef struct {
+  double factor;
+} priv_t;
+
 static int getopts(sox_effect_t * effp, int n, char * * argv)
 {
+  priv_t * p = (priv_t *) effp->priv;
   sox_bool is_cents = sox_false;
-  double speed;
 
-  /* Be quietly compatible with the old speed effect: */
-  if (n != 0 && strcmp(*argv, "-c") == 0)
-    is_cents = sox_true, ++argv, --n;
-
   if (n == 1) {
     char c, dummy;
-    int scanned = sscanf(*argv, "%lf%c %c", &speed, &c, &dummy);
+    int scanned = sscanf(*argv, "%lf%c %c", &p->factor, &c, &dummy);
     if (scanned == 1 || (scanned == 2 && c == 'c')) {
       is_cents |= scanned == 2;
-      if (is_cents || speed > 0) {
-        effp->global_info->speed *= is_cents? pow(2., speed/1200) : speed;
+      if (is_cents || p->factor > 0) {
+        p->factor = is_cents? pow(2., p->factor / 1200) : p->factor;
         return SOX_SUCCESS;
       }
     }
@@ -47,10 +47,30 @@
   return lsx_usage(effp);
 }
 
+static int start(sox_effect_t * effp)
+{
+  priv_t * p = (priv_t *) effp->priv;
+
+  if (p->factor == 1)
+    return SOX_EFF_NULL;
+
+  effp->out_signal.rate = effp->in_signal.rate * p->factor;
+  return SOX_SUCCESS;
+}
+
+static int flow(sox_effect_t * effp, const sox_sample_t * ibuf,
+                sox_sample_t * obuf, size_t * isamp, size_t * osamp)
+{
+  size_t len = *isamp = *osamp = min(*isamp, *osamp);
+  memcpy(obuf, ibuf, len * sizeof(*osamp));
+  (void)effp;
+  return SOX_SUCCESS;
+}
+
 sox_effect_handler_t const * sox_speed_effect_fn(void)
 {
   static sox_effect_handler_t handler = {
-    "speed", "factor[c]", SOX_EFF_NULL | SOX_EFF_LENGTH,
-    getopts, 0, 0, 0, 0, 0, 0};
+    "speed", "factor[c]",SOX_EFF_NULL|SOX_EFF_MCHAN|SOX_EFF_RATE|SOX_EFF_LENGTH,
+    getopts, start, flow, 0, 0, 0, sizeof(priv_t)};
   return &handler;
 }
--- a/src/tempo.c
+++ b/src/tempo.c
@@ -1,5 +1,5 @@
-/* libSoX effect: change tempo (alter duration, maintain pitch)
- * Copyright (c) 2007 robs@users.sourceforge.net
+/* libSoX effect: change tempo (and duration) or pitch (maintain duration)
+ * Copyright (c) 2007,8 robs@users.sourceforge.net
  * Based on ideas from Olli Parviainen's SoundTouch Library.
  *
  * This library is free software; you can redistribute it and/or modify it
@@ -302,5 +302,57 @@
     SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_GETOPT,
     getopts, start, flow, drain, stop, NULL, sizeof(priv_t)
   };
+  return &handler;
+}
+
+/*---------------------------------- pitch -----------------------------------*/
+
+static int pitch_getopts(sox_effect_t * effp, int argc, char **argv)
+{
+  double d;
+  char dummy, arg[100], **argv2 = malloc(argc * sizeof(*argv2));
+  int result, pos = (argc > 1 && !strcmp(argv[1], "-q"))? 2 : 1;
+
+  if (argc <= pos || sscanf(argv[pos], "%lf %c", &d, &dummy) != 1)
+    return lsx_usage(effp);
+
+  d = pow(2., d / 1200);  /* cents --> factor */
+  sprintf(arg, "%g", 1 / d);
+  memcpy(argv2, argv, argc * sizeof(*argv2));
+  argv2[pos] = arg;
+  result = getopts(effp, argc, argv2);
+  free(argv2);
+  return result;
+}
+
+static int pitch_start(sox_effect_t * effp)
+{
+  priv_t * p = (priv_t *) effp->priv;
+  int result = start(effp);
+
+  effp->out_signal.rate = effp->in_signal.rate / p->factor;
+  return result;
+}
+
+sox_effect_handler_t const * sox_pitch_effect_fn(void)
+{
+  static sox_effect_handler_t handler;
+  handler = *sox_tempo_effect_fn();
+  handler.name = "pitch";
+  handler.usage = "[-q] shift-in-cents [segment-ms [search-ms [overlap-ms]]]",
+  handler.getopts = pitch_getopts;
+  handler.start = pitch_start;
+  handler.flags &= ~SOX_EFF_LENGTH;
+  return &handler;
+}
+
+/*------------------------- key (old name for pitch) -------------------------*/
+
+sox_effect_handler_t const * sox_key_effect_fn(void)
+{
+  static sox_effect_handler_t handler;
+  handler = *sox_pitch_effect_fn();
+  handler.name = "key";
+  handler.flags |= SOX_EFF_DEPRECATED;
   return &handler;
 }