Compressor: simplify makeup gain setting, expand release range, finally provide documention in the manual!

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23518 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/dsp.c b/apps/dsp.c
index 7aab8f5..7292328 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -137,8 +137,8 @@
 struct compressor_menu
 {
     int  threshold;     /* dB - from menu */
+    bool auto_gain;     /* 0 = off, 1 = auto */
     int  ratio;         /* from menu */
-    int  gain;          /* dB - from menu */
     bool soft_knee;     /* 0 = hard knee, 1 = soft knee */     
     int  release;       /* samples - from menu */
 };
@@ -1542,11 +1542,12 @@
 
 /** SET COMPRESSOR
  *  Called by the menu system to configure the compressor process */
-void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain,
+void dsp_set_compressor(int c_threshold, int c_gain, int c_ratio,
                         int c_knee, int c_release)
 {
     bool changed = false;
     bool active = (c_threshold < 0);
+    bool new_auto_gain = (c_gain == 1);
     const int comp_ratio[] = {2, 4, 6, 10, 0};
     int  new_ratio = comp_ratio[c_ratio];
     bool new_knee = (c_knee == 1);
@@ -1560,32 +1561,22 @@
             c_menu.threshold, active ? "Yes" : "No");
     }
 
+    if (c_menu.auto_gain != new_auto_gain)
+    {
+        changed = true;
+        c_menu.auto_gain = new_auto_gain;
+        logf("   Compressor Makeup Gain: %s",
+            c_menu.auto_gain ? "Auto" : "Off");
+    }
+    
     if (c_menu.ratio != new_ratio)
     {
         changed = true;
         c_menu.ratio = new_ratio;
         if (c_menu.ratio)
-        {
-            logf("   Compressor Ratio: %d:1", c_menu.ratio);
-        }
+            { logf("   Compressor Ratio: %d:1", c_menu.ratio); }
         else
-        {
-            logf("   Compressor Ratio: Limit");
-        }
-    }
-    
-    if (c_menu.gain != c_gain)
-    {
-        changed = true;
-        c_menu.gain = c_gain;
-        if (c_menu.gain >= 0)
-        {
-            logf("   Compressor Makeup Gain: %d dB", c_menu.gain);
-        }
-        else
-        {
-            logf("   Compressor Makeup Gain: Auto");
-        }
+            { logf("   Compressor Ratio: Limit"); }
     }
     
     if (c_menu.soft_knee != new_knee)
@@ -1731,9 +1722,8 @@
 #endif
         
         /* if using auto peak, then makeup gain is max offset - .1dB headroom */
-        int32_t db_makeup = (c_menu.gain == -1) ?
-            -(db_curve[3].offset) - 0x199A : c_menu.gain << 16;
-        comp_makeup_gain = fp_factor(db_makeup, 16) << 8;
+        comp_makeup_gain = c_menu.auto_gain ?
+            fp_factor(-(db_curve[3].offset) - 0x199A, 16) << 8 : UNITY;
         logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
 
         /* calculate per-sample gain change a rate of 10db over release time */
diff --git a/apps/dsp.h b/apps/dsp.h
index f87037d..092a99f 100644
--- a/apps/dsp.h
+++ b/apps/dsp.h
@@ -82,7 +82,7 @@
 void dsp_set_timestretch(int32_t percent);
 int32_t dsp_get_timestretch(void);
 int dsp_callback(int msg, intptr_t param);
-void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain,
+void dsp_set_compressor(int c_threshold, int c_gain, int c_ratio,
                         int c_knee, int c_release);
 
 #endif
diff --git a/apps/menus/sound_menu.c b/apps/menus/sound_menu.c
index 6031580..0ce860c 100644
--- a/apps/menus/sound_menu.c
+++ b/apps/menus/sound_menu.c
@@ -109,16 +109,16 @@
     /* compressor submenu */
     MENUITEM_SETTING(compressor_threshold,
                      &global_settings.compressor_threshold, lowlatency_callback);
-    MENUITEM_SETTING(compressor_ratio,
-                     &global_settings.compressor_ratio, lowlatency_callback);
     MENUITEM_SETTING(compressor_gain,
                      &global_settings.compressor_makeup_gain, lowlatency_callback);
+    MENUITEM_SETTING(compressor_ratio,
+                     &global_settings.compressor_ratio, lowlatency_callback);
     MENUITEM_SETTING(compressor_knee,
                      &global_settings.compressor_knee, lowlatency_callback);
     MENUITEM_SETTING(compressor_release,
                      &global_settings.compressor_release_time, lowlatency_callback);
     MAKE_MENU(compressor_menu,ID2P(LANG_COMPRESSOR), NULL, Icon_NOICON,
-              &compressor_threshold, &compressor_ratio, &compressor_gain,
+              &compressor_threshold, &compressor_gain, &compressor_ratio,
               &compressor_knee, &compressor_release);
 #endif
 
diff --git a/apps/settings.c b/apps/settings.c
index f12bd92..2de4aa8 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -982,8 +982,8 @@
     dsp_dither_enable(global_settings.dithering_enabled);
     dsp_timestretch_enable(global_settings.timestretch_enabled);
     dsp_set_compressor(global_settings.compressor_threshold,
-                       global_settings.compressor_ratio,
                        global_settings.compressor_makeup_gain,
+                       global_settings.compressor_ratio,
                        global_settings.compressor_knee,
                        global_settings.compressor_release_time);
 #endif
diff --git a/apps/settings.h b/apps/settings.h
index 6de8208..5dfcc7c 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -792,8 +792,8 @@
 
 #if CONFIG_CODEC == SWCODEC
     int compressor_threshold;
-    int compressor_ratio;
     int compressor_makeup_gain;
+    int compressor_ratio;
     int compressor_knee;
     int compressor_release_time;
 #endif
diff --git a/apps/settings_list.c b/apps/settings_list.c
index d9ca889..c92772b 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -364,30 +364,12 @@
 {
     (void)val;
     dsp_set_compressor(global_settings.compressor_threshold,
-                       global_settings.compressor_ratio,
                        global_settings.compressor_makeup_gain,
+                       global_settings.compressor_ratio,
                        global_settings.compressor_knee,
                        global_settings.compressor_release_time);
 }
 
-static const char* auto_formatter(char *buffer, size_t buffer_size,
-                                int val, const char *unit)
-{
-    if (val == -1)
-        return str(LANG_AUTO);
-    else
-        snprintf(buffer, buffer_size, "%d %s", val, unit);
-    return buffer;
-}
-
-static int32_t auto_getlang(int value, int unit)
-{
-    if (value == -1)
-        return LANG_AUTO;
-    else
-        return TALK_ID(value, unit);
-}
-
 static const char* db_format(char* buffer, size_t buffer_size, int value,
                       const char* unit)
 {
@@ -1293,24 +1275,24 @@
                        LANG_COMPRESSOR_THRESHOLD, 0,
                        "compressor threshold", UNIT_DB, 0, -24,
                        -3, formatter_unit_0_is_off, getlang_unit_0_is_off, compressor_set),
+    CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_makeup_gain,
+                   LANG_COMPRESSOR_GAIN, 1, "compressor makeup gain",
+                   "off,auto", compressor_set, 2,
+                   ID2P(LANG_OFF), ID2P(LANG_AUTO)),
     CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_ratio,
                    LANG_COMPRESSOR_RATIO, 1, "compressor ratio",
                    "2:1,4:1,6:1,10:1,limit", compressor_set, 5,
                    ID2P(LANG_COMPRESSOR_RATIO_2), ID2P(LANG_COMPRESSOR_RATIO_4),
                    ID2P(LANG_COMPRESSOR_RATIO_6), ID2P(LANG_COMPRESSOR_RATIO_10),
                    ID2P(LANG_COMPRESSOR_RATIO_LIMIT)),
-    INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_makeup_gain,
-                       LANG_COMPRESSOR_GAIN, -1,
-                       "compressor makeup gain", UNIT_DB, -1, 20,
-                       1, auto_formatter, auto_getlang, compressor_set),
     CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_knee,
                    LANG_COMPRESSOR_KNEE, 1, "compressor knee",
                    "hard knee,soft knee", compressor_set, 2,
                    ID2P(LANG_COMPRESSOR_HARD_KNEE), ID2P(LANG_COMPRESSOR_SOFT_KNEE)),
     INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_release_time,
-                       LANG_COMPRESSOR_RELEASE, 100,
-                       "compressor release time", UNIT_MS, 20, 200,
-                       10, NULL, NULL, compressor_set),
+                       LANG_COMPRESSOR_RELEASE, 500,
+                       "compressor release time", UNIT_MS, 100, 1000,
+                       100, NULL, NULL, compressor_set),
 #endif
 #ifdef HAVE_WM8758
     SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
diff --git a/manual/configure_rockbox/sound_settings.tex b/manual/configure_rockbox/sound_settings.tex
index 3e78dd6..53272af 100644
--- a/manual/configure_rockbox/sound_settings.tex
+++ b/manual/configure_rockbox/sound_settings.tex
@@ -445,18 +445,48 @@
 }
 
 \opt{swcodec}{
-\section{Limiter Preamp}
-The limiter preamp raises the gain of the audio by the selected amount.  The associated
-limiter function works on the resulting louder signal to reduce any peaks to below the
-maximum level.  The default selection of 0dB turns all limiter processing off.
+\section{Compressor}
+The \setting{Compressor} reduces, or compresses, the dynamic range of the audio
+signal.  This makes the quieter and louder sections closer to the same volume
+level by progressively reducing the gain of louder signals.  When subsequently
+amplified, this has the effect of making the quieter sections louder while
+keeping the louder sections from clipping.  This allows listening to the quiet
+sections of dynamic material in noisy environments while preventing sudden loud
+sections from being overbearing.
 
-The limiter has the effect of reducing dynamic range by amplifying quiet sections while
-loud sections are kept just under maximum gain.  This allows listening to the quiet sections
-of dynamic material in noisy environments while preventing sudden loud sections from being
-overbearing.
+There are several settings associated with the compressor.  The first, and most
+important, is the \setting{Threshold}.  The threshold is the audio input level
+at which the compressor begins to act.  Any level louder than the threshold
+will be compressed to some extent.  The maximum amount of compression, or the
+quietest level at which the compressor will operate, is -24db.  The default of
+Off disables the compressor.
 
-Think of this as a smart volume control.  The preamp in effect turns up the volume by the
-amount you select so that you can hear quiet passages.  But it senses when a loud section is
-about to play and quickly and smoothly lowers the volume as necessary to keep the audio
-under the maximum limit.  As the loud section fades, the volume is turned back up.
+The \setting{Makeup Gain} setting has two options: Off and Auto.  Off means
+that the compressed audio will not be amplified after compression.  The default
+of Auto will amplify the signal so that the loudest possible signal after
+compression will be just under the clipping limit.  This is desirable because
+the compressed signal without makeup gain is quieter than the input signal.
+Makeup Gain in Auto restores the signal to the maximum possible level and
+brings the quieter audio up with it.  This is what makes it possible to hear
+the quieter audio in noisy environments.
+
+The \setting{Ratio} setting determines how aggressively the compressor reduces
+gain above the threshold.  For example, the 2:1 setting means that for each
+two decibels of input signal above the threshold, the compressor will only
+allow the output to appear as one decibel.  The higher the ratio, the harder
+the signal is compressed.  The ratio setting of Limit means essentially a ratio
+of infinity to one.  In this case, the output signal is not allowed to exceed
+the threshold at all.
+
+The \setting{Knee} setting determines how abrupt the transition is from a
+non-compressed signal to a compressed signal.  Hard Knee means that the
+transition occurs precisely at the threshold.  The Soft Knee setting smoothes
+the transition from plus or minus three decibels around the threshold.
+
+The \setting{Release Time} setting sets the recovery time after the signal is
+compressed.  Once the compressor determines that compression is necessary,
+the input signal is reduced appropriately, but the gain isn't allowed to
+immediately return to normal levels.  This is necessary to reduce artifacts
+such as "pumping."  Instead, the gain is allowed to return to normal at the
+chosen rate.  Release Time is the time for the gain to recover by 10dB.
 }