avfilter/af_stereotools: introduce different balance modes
authorPaul B Mahol <onemda@gmail.com>
Mon, 15 May 2017 17:56:55 +0000 (19:56 +0200)
committerPaul B Mahol <onemda@gmail.com>
Mon, 15 May 2017 17:58:15 +0000 (19:58 +0200)
Signed-off-by: Paul B Mahol <onemda@gmail.com>
doc/filters.texi
libavfilter/af_stereotools.c

index 0ea4e26..a86127f 100644 (file)
@@ -3669,6 +3669,23 @@ Set S/C level. Default is 1. Allowed range is from 1 to 100.
 
 @item phase
 Set the stereo phase in degrees. Default is 0. Allowed range is from 0 to 360.
+
+@item bmode_in, bmode_out
+Set balance mode for balance_in/balance_out option.
+
+Can be one of the following:
+
+@table @samp
+@item balance
+Classic balance mode. Attenuate one channel at time.
+Gain is raised up to 1.
+
+@item amplitude
+Similar as classic mode above but gain is raised up to 2.
+
+@item power
+Equal power distribution, from -6dB to +6dB range.
+@end table
 @end table
 
 @subsection Examples
index 8ab184d..2d2a9bd 100644 (file)
@@ -33,6 +33,8 @@ typedef struct StereoToolsContext {
     int phase_l;
     int phase_r;
     int mode;
+    int bmode_in;
+    int bmode_out;
     double slev;
     double sbal;
     double mlev;
@@ -83,6 +85,11 @@ static const AVOption stereotools_options[] = {
     { "delay",       "set delay",        OFFSET(delay),       AV_OPT_TYPE_DOUBLE, {.dbl=0}, -20,         20, A },
     { "sclevel",     "set S/C level",    OFFSET(sc_level),    AV_OPT_TYPE_DOUBLE, {.dbl=1},   1,        100, A },
     { "phase",       "set stereo phase", OFFSET(phase),       AV_OPT_TYPE_DOUBLE, {.dbl=0},   0,        360, A },
+    { "bmode_in",    "set balance in mode", OFFSET(bmode_in), AV_OPT_TYPE_INT,    {.i64=0},   0,          2, A, "bmode" },
+    {     "balance",   0,                0,                   AV_OPT_TYPE_CONST,  {.i64=0},   0,          0, A, "bmode" },
+    {     "amplitude", 0,                0,                   AV_OPT_TYPE_CONST,  {.i64=1},   0,          0, A, "bmode" },
+    {     "power",     0,                0,                   AV_OPT_TYPE_CONST,  {.i64=2},   0,          0, A, "bmode" },
+    { "bmode_out", "set balance out mode", OFFSET(bmode_out), AV_OPT_TYPE_INT,    {.i64=0},   0,          2, A, "bmode" },
     { NULL }
 };
 
@@ -167,13 +174,31 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     dst = (double *)out->data[0];
 
     for (n = 0; n < in->nb_samples; n++, src += 2, dst += 2) {
-        double L = src[0], R = src[1], l, r, m, S;
+        double L = src[0], R = src[1], l, r, m, S, gl, gr, gd;
 
         L *= level_in;
         R *= level_in;
 
-        L *= 1. - FFMAX(0., balance_in);
-        R *= 1. + FFMIN(0., balance_in);
+        gl = 1. - FFMAX(0., balance_in);
+        gr = 1. + FFMIN(0., balance_in);
+        switch (s->bmode_in) {
+        case 1:
+            gd = gl - gr;
+            gl = 1. + gd;
+            gr = 1. - gd;
+            break;
+        case 2:
+            if (balance_in < 0.) {
+                gr = FFMAX(0.5, gr);
+                gl = 1. / gr;
+            } else if (balance_in > 0.) {
+                gl = FFMAX(0.5, gl);
+                gr = 1. / gl;
+            }
+            break;
+        }
+        L *= gl;
+        R *= gr;
 
         if (s->softclip) {
             R = s->inv_atan_shape * atan(R * sc_level);
@@ -253,8 +278,27 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 
         s->pos = (s->pos + 2) % s->length;
 
-        L *= 1. - FFMAX(0., balance_out);
-        R *= 1. + FFMIN(0., balance_out);
+        gl = 1. - FFMAX(0., balance_out);
+        gr = 1. + FFMIN(0., balance_out);
+        switch (s->bmode_out) {
+        case 1:
+            gd = gl - gr;
+            gl = 1. + gd;
+            gr = 1. - gd;
+            break;
+        case 2:
+            if (balance_out < 0.) {
+                gr = FFMAX(0.5, gr);
+                gl = 1. / gr;
+            } else if (balance_out > 0.) {
+                gl = FFMAX(0.5, gl);
+                gr = 1. / gl;
+            }
+            break;
+        }
+        L *= gl;
+        R *= gr;
+
 
         L *= level_out;
         R *= level_out;