From 95e2d72759543b739a8faba7545fe6d9752fb4ef Mon Sep 17 00:00:00 2001 From: Jeffrey Goode Date: Wed, 4 Nov 2009 18:14:36 +0000 Subject: 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 --- apps/dsp.c | 38 +++++++------------ apps/dsp.h | 2 +- apps/menus/sound_menu.c | 6 +-- apps/settings.c | 2 +- apps/settings.h | 2 +- apps/settings_list.c | 34 ++++------------- manual/configure_rockbox/sound_settings.tex | 58 ++++++++++++++++++++++------- 7 files changed, 72 insertions(+), 70 deletions(-) diff --git a/apps/dsp.c b/apps/dsp.c index 7aab8f5c37..7292328212 100644 --- a/apps/dsp.c +++ b/apps/dsp.c @@ -137,8 +137,8 @@ struct eq_state 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 @@ void dsp_set_replaygain(void) /** 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 @@ void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain, c_menu.threshold, active ? "Yes" : "No"); } - if (c_menu.ratio != new_ratio) + if (c_menu.auto_gain != new_auto_gain) { changed = true; - c_menu.ratio = new_ratio; - if (c_menu.ratio) - { - logf(" Compressor Ratio: %d:1", c_menu.ratio); - } - else - { - logf(" Compressor Ratio: Limit"); - } + c_menu.auto_gain = new_auto_gain; + logf(" Compressor Makeup Gain: %s", + c_menu.auto_gain ? "Auto" : "Off"); } - if (c_menu.gain != c_gain) + if (c_menu.ratio != new_ratio) { changed = true; - c_menu.gain = c_gain; - if (c_menu.gain >= 0) - { - logf(" Compressor Makeup Gain: %d dB", c_menu.gain); - } + c_menu.ratio = new_ratio; + if (c_menu.ratio) + { logf(" Compressor Ratio: %d:1", c_menu.ratio); } else - { - logf(" Compressor Makeup Gain: Auto"); - } + { logf(" Compressor Ratio: Limit"); } } if (c_menu.soft_knee != new_knee) @@ -1731,9 +1722,8 @@ void dsp_set_compressor(int c_threshold, int c_ratio, int c_gain, #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 f87037d368..092a99f052 100644 --- a/apps/dsp.h +++ b/apps/dsp.h @@ -82,7 +82,7 @@ int32_t sound_get_pitch(void); 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 60315804a9..0ce860cb7c 100644 --- a/apps/menus/sound_menu.c +++ b/apps/menus/sound_menu.c @@ -109,16 +109,16 @@ static int timestretch_callback(int action,const struct menu_item_ex *this_item) /* 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 f12bd92bfd..2de4aa8c71 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -982,8 +982,8 @@ void settings_apply(bool read_disk) 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 6de820807f..5dfcc7cb14 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -792,8 +792,8 @@ struct user_settings #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 d9ca889458..c92772beb9 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -364,30 +364,12 @@ static void compressor_set(int val) { (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 @@ const struct settings_list settings[] = { 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 3e78dd65f5..53272afba1 100644 --- a/manual/configure_rockbox/sound_settings.tex +++ b/manual/configure_rockbox/sound_settings.tex @@ -445,18 +445,48 @@ experience with more complex audio. } \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. - -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. - -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. +\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. + +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. + +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. } -- cgit v1.2.3