shithub: sox

Download patch

ref: 3e7c1e463cc93eb7b8f3aae049a20c6dc1ac3e0b
parent: 4c789efcd4c3d37ea7ca2fbc833f54dc28f11d85
author: robs <robs>
date: Fri Sep 12 16:24:39 EDT 2008

riaa effect

--- a/AUTHORS
+++ b/AUTHORS
@@ -14,10 +14,10 @@
                 FORMATS: M3U, PLS, FLAC, AMR, HTK, WavPack, VOX/IMA/VOC ADPCM
                 support, 24bit support for popular formats, MP3 tags & duration
                 support.
-		EFFECTS: key, tempo, pad, bass, treble, delay, new reverb, new
+		EFFECTS: tempo, pad, bass, treble, delay, new reverb, new
 		flanger, soft-knee companding, speed via resampling, filters
 		makeover inc. gnuplot & octave plotting, splice, remix, norm,
-		contrast, new rate, spectrogram;
+		contrast, new rate, spectrogram, new pitch, riaa;
                 new effects chain with buffering and any # channels.
                 OTHERS: open input files via URL, file merge, play
                 multiple files with mixed format types, play with replay-gain,
--- a/ChangeLog
+++ b/ChangeLog
@@ -37,15 +37,19 @@
   14.1.1   E key                   pitch                   14.1.1 + 6 months
   14.1.1   E pan                   ~= mixer/remix          14.1.1 + 6 months
 
-Other new features:
+Effects:
 
-  o New --output option to write to multiple files in one run.
-    Only useful with certain effects like trim and silence. (cbagwell)
-  o Display SoX build environment information with -V -V.  (robs)
+  o New `riaa' effect; RIAA vinyl playback EQ.  (robs)
   o For `rate' effect, change default phase to intermediate; phase,
     band-width and aliasing now configurable.  (robs)
   o New -b option for the norm effect; can be used to fix stereo
     imbalance.  (robs)
+
+Other new features:
+
+  o New --output option to write to multiple files in one run.
+    Only useful with certain effects like trim and silence. (cbagwell)
+  o Display SoX build environment information with -V -V.  (robs)
 
 Other bug fixes:
 
--- a/README
+++ b/README
@@ -156,6 +156,7 @@
     o earwax		Process CD audio to best effect for headphone use
     o noisered		Filter out noise from the audio
     o oops		Out Of Phase Stereo (or `Karaoke') effect
+    o riaa		RIAA vinyl playback equalisation
 
   o Analysis `effects'
     o noiseprof		Produce a DFT profile of the audio (use with noisered)
--- a/soxeffect.7
+++ b/soxeffect.7
@@ -1238,6 +1238,9 @@
 Reverse the audio completely.
 Requires temporary file space to store the audio to be reversed.
 .TP
+\fBriaa\fR
+Apply RIAA vinyl playback equalisation.
+.TP
 \fBsilence \fR[\fB\-l\fR] \fIabove-periods\fR [\fIduration
 threshold\fR[\fBd\fR\^|\^\fB%\fR] [\fIbelow-periods duration
 threshold\fR[\fBd\fR\^|\^\fB%\fR]]
--- a/src/biquad.h
+++ b/src/biquad.h
@@ -36,7 +36,8 @@
   filter_BPF_SPK_N,
   filter_AP1,
   filter_AP2,
-  filter_deemph
+  filter_deemph,
+  filter_riaa
 } filter_t;
 
 typedef enum {
@@ -59,8 +60,8 @@
 
   filter_t filter_type;
 
-  double b2, b1, b0;       /* Filter coefficients */
-  double a2, a1, a0;       /* Filter coefficients */
+  double b0, b1, b2;       /* Filter coefficients */
+  double a0, a1, a2;       /* Filter coefficients */
 
   sox_sample_t i1, i2;     /* Filter memory */
   double      o1, o2;      /* Filter memory */
--- a/src/biquads.c
+++ b/src/biquads.c
@@ -139,6 +139,26 @@
 }
 
 
+static int riaa_getopts(sox_effect_t * effp, int argc, char **argv) {
+  priv_t * p = (priv_t *)effp->priv;
+  p->filter_type = filter_riaa;
+  (void)argv;
+  return argc? lsx_usage(effp) : SOX_SUCCESS;
+}
+
+
+static void make_poly_from_roots(
+    double const * roots, size_t num_roots, double * poly)
+{
+  size_t i, j;
+  poly[0] = 1;
+  poly[1] = -roots[0];
+  memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly));
+  for (i = 1; i < num_roots; ++i)
+    for (j = num_roots; j > 0; --j)
+      poly[j] -= poly[j - 1] * roots[i];
+}
+
 static int start(sox_effect_t * effp)
 {
   priv_t * p = (priv_t *)effp->priv;
@@ -309,6 +329,40 @@
       p->a1 = -2 * cos(w0);
       p->a2 = 1 - sin(w0);
       break;
+
+    case filter_riaa: /* http://www.dsprelated.com/showmessage/73300/3.php */
+      if (effp->in_signal.rate == 44100) {
+        static const double zeros[] = {-0.2014898, 0.9233820};
+        static const double poles[] = {0.7083149, 0.9924091};
+        make_poly_from_roots(zeros, 2, &p->b0);
+        make_poly_from_roots(poles, 2, &p->a0);
+      }
+      else if (effp->in_signal.rate == 48000) {
+        static const double zeros[] = {-0.1766069, 0.9321590};
+        static const double poles[] = {0.7396325, 0.9931330};
+        make_poly_from_roots(zeros, 2, &p->b0);
+        make_poly_from_roots(poles, 2, &p->a0);
+      }
+      else if (effp->in_signal.rate == 88200) {
+        static const double zeros[] = {-0.1168735, 0.9648312};
+        static const double poles[] = {0.8590646, 0.9964002};
+        make_poly_from_roots(zeros, 2, &p->b0);
+        make_poly_from_roots(poles, 2, &p->a0);
+      }
+      else if (effp->in_signal.rate == 96000) {
+        static const double zeros[] = {-0.1141486, 0.9676817};
+        static const double poles[] = {0.8699137, 0.9966946};
+        make_poly_from_roots(zeros, 2, &p->b0);
+        make_poly_from_roots(poles, 2, &p->a0);
+      }
+      else {
+        sox_fail("Sample rate must be 44.1k, 48k, 88.2k, or 96k");
+        return SOX_EOF;
+      }
+      {double g = dB_to_linear(19.9 - linear_to_dB(
+            (p->b0 + p->b1 + p->b2) / (p->a0 + p->a1 + p->a2)));
+      p->b0 *= g; p->b1 *= g; p->b2 *= g;}
+      break;
   }
   return sox_biquad_start(effp);
 }
@@ -333,3 +387,4 @@
 BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h|k] gain", 0)
 BIQUAD_EFFECT(band,      band,     "[-n] center [width[h|k|q|o]]", 0)
 BIQUAD_EFFECT(deemph,    deemph,   NULL, 0)
+BIQUAD_EFFECT(riaa,      riaa,     NULL, 0)
--- a/src/effects.h
+++ b/src/effects.h
@@ -63,6 +63,7 @@
   EFFECT(resample)
   EFFECT(reverb)
   EFFECT(reverse)
+  EFFECT(riaa)
   EFFECT(silence)
 #ifdef HAVE_PNG
   EFFECT(spectrogram)