shithub: sox

Download patch

ref: 65f3eca4990d29f08256ef7b72f07561062f7682
parent: d14f798ae9d14cc6192f3c764976820a288bd8af
author: rrt <rrt>
date: Mon Nov 13 20:32:09 EST 2006

Add files missing from earlier commit

--- /dev/null
+++ b/src/biquad.c
@@ -1,0 +1,32 @@
+#include "biquad.h"
+
+
+
+int st_biquad_flow(eff_t effp, st_sample_t *ibuf, st_sample_t *obuf, 
+                        st_size_t *isamp, st_size_t *osamp)
+{
+  biquad_t p = (biquad_t) effp->priv;
+  st_size_t len = (*isamp > *osamp)? *osamp : *isamp;
+  *isamp = *osamp = len;
+
+  while (len--)
+  {
+    double o0 = *ibuf*p->b0 +p->i1*p->b1 +p->i2*p->b2 -p->o1*p->a1 -p->o2*p->a2;
+    p->i2 = p->i1, p->i1 = *ibuf++;
+    p->o2 = p->o1, p->o1 = o0;
+    *obuf++ = ST_ROUND_CLIP_COUNT(o0, p->clippedCount);
+  }
+  return ST_SUCCESS;
+}
+
+
+
+int st_biquad_stop(eff_t effp) /* Stop processing, warn if overflows */
+{
+  biquad_t p = (biquad_t) effp->priv;
+  if (p->clippedCount != 0)
+  {
+    st_warn("%s: %d samples clipped", effp->name, p->clippedCount);
+  }
+  return ST_SUCCESS;
+}
--- /dev/null
+++ b/src/biquad.h
@@ -1,0 +1,32 @@
+#ifndef biquad_included
+#define biquad_included
+
+#include <math.h>
+#include "st_i.h"
+
+/* Private data for the biquad filter effects */
+typedef struct biquad
+{
+  double gain;
+  double fc;               /* Centre/corner/cutoff frequency */
+  double oomph;            /* Q, BW, or Slope */
+  bool dcNormalise;        /* A treble filter should normalise at DC */
+
+  double b2, b1, b0;       /* Filter coefficients */
+  double a2, a1;           /* Filter coefficients; a0 = 1 */
+
+  st_sample_t i1, i2;      /* Filter memory */
+  double o1, o2;           /* Filter memory */
+
+  unsigned clippedCount;
+} * biquad_t;
+
+int st_biquad_flow(eff_t effp, st_sample_t *ibuf, st_sample_t *obuf, 
+                        st_size_t *isamp, st_size_t *osamp);
+
+int st_biquad_stop(eff_t effp);
+
+assert_static(sizeof(struct biquad) <= ST_MAX_EFFECT_PRIVSIZE, 
+    /* else */ biquad_PRIVSIZE_too_big);
+
+#endif
--- /dev/null
+++ b/src/tone.c
@@ -1,0 +1,187 @@
+/*
+ * Sound Tools Tone Control Effects: bass & treble
+ *
+ * The bass and treble effects approximate to the venerable
+ * Baxandall circuit used in the analogue world.
+ *
+ * Filter design by Robert Bristow-Johnson  <rbj@audioimagination.com>
+ *
+ * This implementation (c) 2006 aquegg
+ *
+ * See LICENSE file for further copyright information.
+ */
+
+
+
+#include "biquad.h"
+
+#include <memory.h>
+
+
+
+static int getopts(eff_t effp, int n, char **argv, double fc, int dcNormalise)
+{
+  bool isFcSet = false;
+  double opt1 = HUGE_VAL, opt2 = HUGE_VAL;
+  biquad_t p = (biquad_t) effp->priv;
+  
+  /* Zero all numbers, set all bools to false: */
+  memset(p, 0, sizeof(*p));
+
+  /* Initialise non-zero numbers: */
+  p->dcNormalise = dcNormalise;
+  p->fc = fc;
+  p->oomph = 0.5;
+
+  /*
+   * This block is a little complicated -- all because I wanted
+   * to make it easy for the user i.e. order doesn't matter for
+   * optional arguments.
+   * This is made possible because slope (or oomph) <= 1 and by
+   * insisting that the centre-frequency is > 1 (Hz).
+   */
+  if (n > 0 &&
+     sscanf(argv[0], "%lf", &p->gain) &&
+     (n < 2 || sscanf(argv[1], "%lf", &opt1))  &&
+     (n < 3 || sscanf(argv[2], "%lf", &opt2))  &&
+     (n < 4))
+  do {
+    if (opt1 != HUGE_VAL)
+    {
+      if (opt1 > 1)
+      {
+        p->fc = opt1;
+        isFcSet = true;
+      }
+      else if (opt1 > 0)
+      {
+        p->oomph = opt1;
+      }
+      else break; /* error */
+      if (opt2 != HUGE_VAL)
+      {
+        if (opt2 > 1)
+        {
+          if (isFcSet) break; /* error */
+          p->fc = opt2;
+        }
+        else if (opt2 > 0)
+        {
+          if (!isFcSet) break; /* error */
+          p->oomph = opt2;
+        }
+        else break; /* error */
+      }
+    }
+    if (dcNormalise)
+    {
+      p->gain = -p->gain;
+    }
+    return ST_SUCCESS;
+  } while (0);
+
+  st_fail(effp->h->usage);
+  return ST_EOF;
+}
+
+
+
+static int st_bass_getopts  (eff_t e, int n, char **a) {return getopts(e, n, a,  100, 0);}
+static int st_treble_getopts(eff_t e, int n, char **a) {return getopts(e, n, a, 3000, 1);}
+
+
+
+static int st_biquad_shelf_start(eff_t effp)
+{
+  biquad_t p = (biquad_t) effp->priv;
+
+  /* Calculate intermediates: */
+  double A  = exp(p->gain / 40 * log(10));
+  double w0 = 2 * M_PI * p->fc / effp->ininfo.rate;
+  double alpha = sin(w0)/2 * sqrt( (A + 1/A)*(1/p->oomph - 1) + 2 );
+  double a0;
+
+  /* Calculate filter coefficients: */
+  p->b0 =    A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha );  /* Numerator. */
+  p->b1 =  2*A*( (A-1) - (A+1)*cos(w0)                   );
+  p->b2 =    A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha );
+     a0 =        (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha;    /* Denominator. */
+  p->a1 =   -2*( (A-1) + (A+1)*cos(w0)                   );
+  p->a2 =        (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha;
+
+  /* Simplify: */
+  p->b2 = p->b2/a0;
+  p->b1 = p->b1/a0;
+  p->b0 = p->b0/a0;
+  p->a2 = p->a2/a0;
+  p->a1 = p->a1/a0;
+
+  if (p->dcNormalise) /* Normalise to AV = 0dB at DC: */
+  {
+    double normalise = (1 + p->a1 + p->a2) / (p->b0 + p->b1 + p->b2);
+    p->b0 = normalise * p->b0;
+    p->b1 = normalise * p->b1;
+    p->b2 = normalise * p->b2;
+  }
+
+  if (effp->globalinfo.octave_plot_effect)
+  {
+    printf(
+      "title('SoX effect: %s gain=%g centre=%g slope=%g (rate=%u)')\n"
+      "xlabel('Frequency (Hz)')\n"
+      "ylabel('Amplitude Response (dB)')\n"
+      "Fs=%u;minF=10;maxF=Fs/2;\n"
+      "axis([minF maxF -25 25])\n"
+      "sweepF=logspace(log10(minF),log10(maxF),200);\n"
+      "grid on\n"
+      "[h,w]=freqz([%f %f %f],[1 %f %f],sweepF,Fs);\n"
+      "semilogx(w,20*log10(h),'b')\n"
+      "pause\n"
+      , effp->name, p->gain, p->fc, p->oomph
+      , effp->ininfo.rate, effp->ininfo.rate
+      , p->b0, p->b1, p->b2, p->a1, p->a2
+      );
+    exit(0);
+  }
+  return ST_SUCCESS;
+}
+
+
+
+static st_effect_t st_bass_effect = {
+  "bass",
+  "Usage: bass gain [frequency] [slope]",
+  0,
+  st_bass_getopts,
+  st_biquad_shelf_start,
+  st_biquad_flow,
+  st_effect_nothing_drain,
+  st_biquad_stop
+};
+
+
+
+st_effect_t const * st_bass_effect_fn(void)
+{
+  return &st_bass_effect;
+}
+
+
+
+static st_effect_t st_treble_effect = {
+  "treble",
+  "Usage: treble gain [frequency] [slope]",
+  0,
+  st_treble_getopts,
+  st_biquad_shelf_start,
+  st_biquad_flow,
+  st_effect_nothing_drain,
+  st_biquad_stop
+};
+
+
+
+st_effect_t const * st_treble_effect_fn(void)
+{
+  return &st_treble_effect;
+}