mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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
This commit is contained in:
parent
a06feaa7ec
commit
95e2d72759
7 changed files with 71 additions and 69 deletions
40
apps/dsp.c
40
apps/dsp.c
|
@ -137,8 +137,8 @@ struct eq_state
|
||||||
struct compressor_menu
|
struct compressor_menu
|
||||||
{
|
{
|
||||||
int threshold; /* dB - from menu */
|
int threshold; /* dB - from menu */
|
||||||
|
bool auto_gain; /* 0 = off, 1 = auto */
|
||||||
int ratio; /* from menu */
|
int ratio; /* from menu */
|
||||||
int gain; /* dB - from menu */
|
|
||||||
bool soft_knee; /* 0 = hard knee, 1 = soft knee */
|
bool soft_knee; /* 0 = hard knee, 1 = soft knee */
|
||||||
int release; /* samples - from menu */
|
int release; /* samples - from menu */
|
||||||
};
|
};
|
||||||
|
@ -1542,11 +1542,12 @@ void dsp_set_replaygain(void)
|
||||||
|
|
||||||
/** SET COMPRESSOR
|
/** SET COMPRESSOR
|
||||||
* Called by the menu system to configure the compressor process */
|
* 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)
|
int c_knee, int c_release)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
bool active = (c_threshold < 0);
|
bool active = (c_threshold < 0);
|
||||||
|
bool new_auto_gain = (c_gain == 1);
|
||||||
const int comp_ratio[] = {2, 4, 6, 10, 0};
|
const int comp_ratio[] = {2, 4, 6, 10, 0};
|
||||||
int new_ratio = comp_ratio[c_ratio];
|
int new_ratio = comp_ratio[c_ratio];
|
||||||
bool new_knee = (c_knee == 1);
|
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");
|
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)
|
if (c_menu.ratio != new_ratio)
|
||||||
{
|
{
|
||||||
changed = true;
|
changed = true;
|
||||||
c_menu.ratio = new_ratio;
|
c_menu.ratio = new_ratio;
|
||||||
if (c_menu.ratio)
|
if (c_menu.ratio)
|
||||||
{
|
{ logf(" Compressor Ratio: %d:1", c_menu.ratio); }
|
||||||
logf(" Compressor Ratio: %d:1", c_menu.ratio);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{ logf(" Compressor Ratio: Limit"); }
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c_menu.soft_knee != new_knee)
|
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
|
#endif
|
||||||
|
|
||||||
/* if using auto peak, then makeup gain is max offset - .1dB headroom */
|
/* if using auto peak, then makeup gain is max offset - .1dB headroom */
|
||||||
int32_t db_makeup = (c_menu.gain == -1) ?
|
comp_makeup_gain = c_menu.auto_gain ?
|
||||||
-(db_curve[3].offset) - 0x199A : c_menu.gain << 16;
|
fp_factor(-(db_curve[3].offset) - 0x199A, 16) << 8 : UNITY;
|
||||||
comp_makeup_gain = fp_factor(db_makeup, 16) << 8;
|
|
||||||
logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
|
logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
|
||||||
|
|
||||||
/* calculate per-sample gain change a rate of 10db over release time */
|
/* calculate per-sample gain change a rate of 10db over release time */
|
||||||
|
|
|
@ -82,7 +82,7 @@ int32_t sound_get_pitch(void);
|
||||||
void dsp_set_timestretch(int32_t percent);
|
void dsp_set_timestretch(int32_t percent);
|
||||||
int32_t dsp_get_timestretch(void);
|
int32_t dsp_get_timestretch(void);
|
||||||
int dsp_callback(int msg, intptr_t param);
|
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);
|
int c_knee, int c_release);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -109,16 +109,16 @@ static int timestretch_callback(int action,const struct menu_item_ex *this_item)
|
||||||
/* compressor submenu */
|
/* compressor submenu */
|
||||||
MENUITEM_SETTING(compressor_threshold,
|
MENUITEM_SETTING(compressor_threshold,
|
||||||
&global_settings.compressor_threshold, lowlatency_callback);
|
&global_settings.compressor_threshold, lowlatency_callback);
|
||||||
MENUITEM_SETTING(compressor_ratio,
|
|
||||||
&global_settings.compressor_ratio, lowlatency_callback);
|
|
||||||
MENUITEM_SETTING(compressor_gain,
|
MENUITEM_SETTING(compressor_gain,
|
||||||
&global_settings.compressor_makeup_gain, lowlatency_callback);
|
&global_settings.compressor_makeup_gain, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(compressor_ratio,
|
||||||
|
&global_settings.compressor_ratio, lowlatency_callback);
|
||||||
MENUITEM_SETTING(compressor_knee,
|
MENUITEM_SETTING(compressor_knee,
|
||||||
&global_settings.compressor_knee, lowlatency_callback);
|
&global_settings.compressor_knee, lowlatency_callback);
|
||||||
MENUITEM_SETTING(compressor_release,
|
MENUITEM_SETTING(compressor_release,
|
||||||
&global_settings.compressor_release_time, lowlatency_callback);
|
&global_settings.compressor_release_time, lowlatency_callback);
|
||||||
MAKE_MENU(compressor_menu,ID2P(LANG_COMPRESSOR), NULL, Icon_NOICON,
|
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);
|
&compressor_knee, &compressor_release);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -982,8 +982,8 @@ void settings_apply(bool read_disk)
|
||||||
dsp_dither_enable(global_settings.dithering_enabled);
|
dsp_dither_enable(global_settings.dithering_enabled);
|
||||||
dsp_timestretch_enable(global_settings.timestretch_enabled);
|
dsp_timestretch_enable(global_settings.timestretch_enabled);
|
||||||
dsp_set_compressor(global_settings.compressor_threshold,
|
dsp_set_compressor(global_settings.compressor_threshold,
|
||||||
global_settings.compressor_ratio,
|
|
||||||
global_settings.compressor_makeup_gain,
|
global_settings.compressor_makeup_gain,
|
||||||
|
global_settings.compressor_ratio,
|
||||||
global_settings.compressor_knee,
|
global_settings.compressor_knee,
|
||||||
global_settings.compressor_release_time);
|
global_settings.compressor_release_time);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -792,8 +792,8 @@ struct user_settings
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
int compressor_threshold;
|
int compressor_threshold;
|
||||||
int compressor_ratio;
|
|
||||||
int compressor_makeup_gain;
|
int compressor_makeup_gain;
|
||||||
|
int compressor_ratio;
|
||||||
int compressor_knee;
|
int compressor_knee;
|
||||||
int compressor_release_time;
|
int compressor_release_time;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -364,30 +364,12 @@ static void compressor_set(int val)
|
||||||
{
|
{
|
||||||
(void)val;
|
(void)val;
|
||||||
dsp_set_compressor(global_settings.compressor_threshold,
|
dsp_set_compressor(global_settings.compressor_threshold,
|
||||||
global_settings.compressor_ratio,
|
|
||||||
global_settings.compressor_makeup_gain,
|
global_settings.compressor_makeup_gain,
|
||||||
|
global_settings.compressor_ratio,
|
||||||
global_settings.compressor_knee,
|
global_settings.compressor_knee,
|
||||||
global_settings.compressor_release_time);
|
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,
|
static const char* db_format(char* buffer, size_t buffer_size, int value,
|
||||||
const char* unit)
|
const char* unit)
|
||||||
{
|
{
|
||||||
|
@ -1293,24 +1275,24 @@ const struct settings_list settings[] = {
|
||||||
LANG_COMPRESSOR_THRESHOLD, 0,
|
LANG_COMPRESSOR_THRESHOLD, 0,
|
||||||
"compressor threshold", UNIT_DB, 0, -24,
|
"compressor threshold", UNIT_DB, 0, -24,
|
||||||
-3, formatter_unit_0_is_off, getlang_unit_0_is_off, compressor_set),
|
-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,
|
CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_ratio,
|
||||||
LANG_COMPRESSOR_RATIO, 1, "compressor ratio",
|
LANG_COMPRESSOR_RATIO, 1, "compressor ratio",
|
||||||
"2:1,4:1,6:1,10:1,limit", compressor_set, 5,
|
"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_2), ID2P(LANG_COMPRESSOR_RATIO_4),
|
||||||
ID2P(LANG_COMPRESSOR_RATIO_6), ID2P(LANG_COMPRESSOR_RATIO_10),
|
ID2P(LANG_COMPRESSOR_RATIO_6), ID2P(LANG_COMPRESSOR_RATIO_10),
|
||||||
ID2P(LANG_COMPRESSOR_RATIO_LIMIT)),
|
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,
|
CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, compressor_knee,
|
||||||
LANG_COMPRESSOR_KNEE, 1, "compressor knee",
|
LANG_COMPRESSOR_KNEE, 1, "compressor knee",
|
||||||
"hard knee,soft knee", compressor_set, 2,
|
"hard knee,soft knee", compressor_set, 2,
|
||||||
ID2P(LANG_COMPRESSOR_HARD_KNEE), ID2P(LANG_COMPRESSOR_SOFT_KNEE)),
|
ID2P(LANG_COMPRESSOR_HARD_KNEE), ID2P(LANG_COMPRESSOR_SOFT_KNEE)),
|
||||||
INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_release_time,
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_release_time,
|
||||||
LANG_COMPRESSOR_RELEASE, 100,
|
LANG_COMPRESSOR_RELEASE, 500,
|
||||||
"compressor release time", UNIT_MS, 20, 200,
|
"compressor release time", UNIT_MS, 100, 1000,
|
||||||
10, NULL, NULL, compressor_set),
|
100, NULL, NULL, compressor_set),
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_WM8758
|
#ifdef HAVE_WM8758
|
||||||
SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
|
SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
|
||||||
|
|
|
@ -445,18 +445,48 @@ experience with more complex audio.
|
||||||
}
|
}
|
||||||
|
|
||||||
\opt{swcodec}{
|
\opt{swcodec}{
|
||||||
\section{Limiter Preamp}
|
\section{Compressor}
|
||||||
The limiter preamp raises the gain of the audio by the selected amount. The associated
|
The \setting{Compressor} reduces, or compresses, the dynamic range of the audio
|
||||||
limiter function works on the resulting louder signal to reduce any peaks to below the
|
signal. This makes the quieter and louder sections closer to the same volume
|
||||||
maximum level. The default selection of 0dB turns all limiter processing off.
|
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
|
There are several settings associated with the compressor. The first, and most
|
||||||
loud sections are kept just under maximum gain. This allows listening to the quiet sections
|
important, is the \setting{Threshold}. The threshold is the audio input level
|
||||||
of dynamic material in noisy environments while preventing sudden loud sections from being
|
at which the compressor begins to act. Any level louder than the threshold
|
||||||
overbearing.
|
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
|
The \setting{Makeup Gain} setting has two options: Off and Auto. Off means
|
||||||
amount you select so that you can hear quiet passages. But it senses when a loud section is
|
that the compressed audio will not be amplified after compression. The default
|
||||||
about to play and quickly and smoothly lowers the volume as necessary to keep the audio
|
of Auto will amplify the signal so that the loudest possible signal after
|
||||||
under the maximum limit. As the loud section fades, the volume is turned back up.
|
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.
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue