# HG changeset patch # User Eugene Zagidullin # Date 1202326952 -10800 # Node ID b0ca963fd965127e7a9385ebcecc5100fc1161c3 # Parent 70f379ff23adf857dde3db335ff4f82dd09fddb4 adaptive scaler added, disabled hard limiter diff -r 70f379ff23ad -r b0ca963fd965 src/audacious/main.c --- a/src/audacious/main.c Tue Feb 05 00:09:07 2008 +0300 +++ b/src/audacious/main.c Wed Feb 06 22:42:32 2008 +0300 @@ -236,7 +236,7 @@ TRUE, /* enable clipping prevention */ TRUE, /* track mode */ FALSE, /* album mode */ - FALSE, /* enable hard limiter */ + FALSE, /* enable adaptive scaler */ 0.0, /* preamp */ -9.0, /* default gain */ }; @@ -354,7 +354,7 @@ {"enable_clipping_prevention", &cfg.enable_clipping_prevention, TRUE}, {"replay_gain_track", &cfg.replay_gain_track, TRUE}, {"replay_gain_album", &cfg.replay_gain_album, TRUE}, - {"enable_hard_limiter", &cfg.enable_hard_limiter, TRUE}, + {"enable_adaptive_scaler", &cfg.enable_adaptive_scaler, TRUE}, }; static gint ncfgbent = G_N_ELEMENTS(bmp_boolents); diff -r 70f379ff23ad -r b0ca963fd965 src/audacious/main.h --- a/src/audacious/main.h Tue Feb 05 00:09:07 2008 +0300 +++ b/src/audacious/main.h Wed Feb 06 22:42:32 2008 +0300 @@ -147,7 +147,7 @@ gboolean enable_clipping_prevention; gboolean replay_gain_track; gboolean replay_gain_album; - gboolean enable_hard_limiter; + gboolean enable_adaptive_scaler; gfloat replay_gain_preamp; gfloat default_gain; }; diff -r 70f379ff23ad -r b0ca963fd965 src/audacious/output.c --- a/src/audacious/output.c Tue Feb 05 00:09:07 2008 +0300 +++ b/src/audacious/output.c Wed Feb 06 22:42:32 2008 +0300 @@ -495,9 +495,9 @@ if(replay_gain_info.album_peak == 0.0 && replay_gain_info.track_peak == 0.0) { AUDDBG("RG info isn't set yet. Filling replay_gain_info with default values.\n"); replay_gain_info.track_gain = cfg.default_gain; - replay_gain_info.track_peak = 1.0; + replay_gain_info.track_peak = 0.01; replay_gain_info.album_gain = cfg.default_gain; - replay_gain_info.album_peak = 1.0; + replay_gain_info.album_peak = 0.01; } apply_replaygain_info(&replay_gain_info); @@ -779,7 +779,8 @@ rg_enabled = cfg.enable_replay_gain; album_mode = cfg.replay_gain_album; mode.clipping_prevention = cfg.enable_clipping_prevention; - mode.hard_limit = cfg.enable_hard_limiter; + mode.hard_limit = FALSE; + mode.adaptive_scaler = cfg.enable_adaptive_scaler; if(!rg_enabled) return; @@ -795,7 +796,7 @@ AUDDBG("Applying Replay Gain settings:\n"); AUDDBG("* mode: %s\n", mode.mode == SAD_RG_ALBUM ? "album" : "track"); AUDDBG("* clipping prevention: %s\n", mode.clipping_prevention ? "yes" : "no"); - AUDDBG("* hard limit: %s\n", mode.hard_limit ? "yes" : "no"); + AUDDBG("* adaptive scaler %s\n", mode.adaptive_scaler ? "yes" : "no"); AUDDBG("* preamp: %+f dB\n", mode.preamp); AUDDBG("Replay Gain info for current track:\n"); AUDDBG("* track gain: %+f dB\n", info.track_gain); diff -r 70f379ff23ad -r b0ca963fd965 src/audacious/ui_preferences.c --- a/src/audacious/ui_preferences.c Tue Feb 05 00:09:07 2008 +0300 +++ b/src/audacious/ui_preferences.c Wed Feb 06 22:42:32 2008 +0300 @@ -233,8 +233,10 @@ {WIDGET_RADIO_BTN, N_("Track gain/peak"), &cfg.replay_gain_track, NULL, NULL, TRUE}, {WIDGET_RADIO_BTN, N_("Album gain/peak"), &cfg.replay_gain_album, NULL, NULL, TRUE}, {WIDGET_LABEL, N_("Miscellaneous"), NULL, NULL, NULL, TRUE}, - {WIDGET_CHK_BTN, N_("Enable clipping prevention"), &cfg.enable_clipping_prevention, NULL, NULL, TRUE}, - {WIDGET_CHK_BTN, N_("Enable 6 dB hard limiter"), &cfg.enable_hard_limiter, NULL, NULL, TRUE}, + {WIDGET_CHK_BTN, N_("Enable peak info clipping prevention"), &cfg.enable_clipping_prevention, NULL, + N_("Use peak value from Replay Gain info for clipping prevention"), TRUE}, + {WIDGET_CHK_BTN, N_("Dynamically adjust scale factor to prevent clipping"), &cfg.enable_adaptive_scaler, NULL, + N_("Decrease scale factor (gain) if clipping nevertheless occurred"), TRUE}, {WIDGET_CUSTOM, NULL, NULL, NULL, NULL, TRUE, ui_preferences_rg_params}, }; @@ -1728,7 +1730,7 @@ GtkWidget *spin = gtk_spin_button_new_with_range(-15, 15, 0.01); gtk_table_attach(GTK_TABLE(table), spin, 1, 2, 0, 1, - (GtkAttachOptions) (0), + (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), cfg.replay_gain_preamp); g_signal_connect(G_OBJECT(spin), "value_changed", G_CALLBACK(on_rg_spin_changed), &cfg.replay_gain_preamp); @@ -1747,7 +1749,7 @@ spin = gtk_spin_button_new_with_range(-15, 15, 0.01); gtk_table_attach(GTK_TABLE(table), spin, 1, 2, 1, 2, - (GtkAttachOptions) (0), + (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), cfg.default_gain); g_signal_connect(G_OBJECT(spin), "value_changed", G_CALLBACK(on_rg_spin_changed), &cfg.default_gain); @@ -1761,6 +1763,20 @@ gtk_container_add(GTK_CONTAINER(alignment), table); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0); + + GtkWidget *image = gtk_image_new_from_stock ("gtk-info", GTK_ICON_SIZE_BUTTON); + gtk_table_attach (GTK_TABLE (table), image, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + label = gtk_label_new (_("Please remember that the most efficient way to prevent signal clipping is not to use " + "positive values above.")); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_label_set_use_markup (GTK_LABEL (label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); return alignment; } diff -r 70f379ff23ad -r b0ca963fd965 src/libSAD/common.h --- a/src/libSAD/common.h Tue Feb 05 00:09:07 2008 +0300 +++ b/src/libSAD/common.h Wed Feb 06 22:42:32 2008 +0300 @@ -146,6 +146,7 @@ int mode; int clipping_prevention; int hard_limit; + int adaptive_scaler; float preamp; /* in dB ! */ } SAD_replaygain_mode; diff -r 70f379ff23ad -r b0ca963fd965 src/libSAD/dither.c --- a/src/libSAD/dither.c Tue Feb 05 00:09:07 2008 +0300 +++ b/src/libSAD/dither.c Wed Feb 06 22:42:32 2008 +0300 @@ -17,8 +17,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* #define CLIPPING_DEBUG */ -/* #define DITHER_DEBUG */ +/* #define CLIPPING_DEBUG +#define DEBUG +#define DITHER_DEBUG */ #include "common.h" #include "dither_ops.h" @@ -51,6 +52,8 @@ #define MAXINT(a) (1L << ((a)-1)) #define CLIP(x,m) (x > m-1 ? m-1 : (x < -m ? -m : x)) +#define ADJUSTMENT_COEFFICIENT 0.1 + /* private object */ typedef struct { SAD_sample_format input_sample_format; @@ -66,15 +69,16 @@ SAD_put_sample_proc put_sample; int dither; int hardlimit; - float scale; - float rg_scale; + double scale; + double rg_scale; + int adaptive_scaler; } SAD_state_priv; /* error code */ //static SAD_error SAD_last_error = SAD_ERROR_OK; -static inline double compute_hardlimit (double sample, float scale) { +static inline double compute_hardlimit (double sample, double scale) { sample *= scale; const double k = 0.5; /* -6dBFS */ if (sample > k) { @@ -91,8 +95,8 @@ * samples < -1 and > 1 will be clipped */ -static inline int32_t __dither_sample_fixed_to_int (int32_t sample, int inbits, int fracbits, int outbits, float scale, int dither, - int hardlimit) +static inline int32_t __dither_sample_fixed_to_int (int32_t sample, int inbits, int fracbits, int outbits, double *scale, int dither, + int hardlimit, int adaptive_scale) { int n_bits_to_loose, bitwidth, precision_loss; int32_t maxint = MAXINT(outbits); @@ -131,18 +135,34 @@ } assert(n_bits_to_loose >=0 ); - + + /* adaptive scaler */ + if (adaptive_scale) { + int sam = sample >> n_bits_to_loose; + double d_sam = fabs((double)sam) / (double)(maxint - 1); + if (d_sam * *scale > 1.0) { +#ifdef CLIPPING_DEBUG + printf("sample val %d, scale factor adjusted %f --> ", sam, *scale); +#endif + *scale -= (*scale - 1.0 / d_sam) * ADJUSTMENT_COEFFICIENT; +#ifdef CLIPPING_DEBUG + printf("%f\n", *scale); +#endif + } + sample = SCALE(sample, *scale); + } else + /*****************/ if (hardlimit) { - sample = (int32_t)(compute_hardlimit((double)sample/(double)MAXINT(bitwidth), scale) * (double)MAXINT(bitwidth)); + sample = (int32_t)(compute_hardlimit((double)sample/(double)MAXINT(bitwidth), *scale) * (double)MAXINT(bitwidth)); #ifdef PRECISION_DEBUG printf("Precision loss, reason: hard limiter\n", inbits, outbits); #endif precision_loss = TRUE; } else { - sample = SCALE(sample, scale); + sample = SCALE(sample, *scale); } - if (scale != 1.0){ + if (*scale != 1.0){ precision_loss = TRUE; #ifdef PRECISION_DEBUG printf("Precision loss, reason: scale\n", inbits, outbits); @@ -182,18 +202,32 @@ * Dither floating-point normalized sample to n-bits integer * samples < -1 and > 1 will be clipped */ -static inline int32_t __dither_sample_float_to_int (float sample, int nbits, float scale, int dither, int hardlimit) { +static inline int32_t __dither_sample_float_to_int (float sample, int nbits, double *scale, int dither, int hardlimit, int adaptive_scale) { #ifdef DEEP_DEBUG printf("f: __dither_sample_float_to_int\n"); #endif int32_t maxint = MAXINT(nbits); - + + /* adaptive scaler */ + if (adaptive_scale) { + if (fabs(sample) * *scale > 1.0) { +#ifdef CLIPPING_DEBUG + printf("sample val %f, scale factor adjusted %f --> ", sample, *scale); +#endif + *scale -= (*scale - 1.0 / sample) * ADJUSTMENT_COEFFICIENT; +#ifdef CLIPPING_DEBUG + printf("%f\n", *scale); +#endif + } + sample = SCALE(sample, *scale); + } else + /*****************/ if (hardlimit) { - sample = compute_hardlimit((double)sample, scale); + sample = compute_hardlimit((double)sample, *scale); } else { - sample = SCALE(sample, scale); + sample = SCALE(sample, *scale); } sample *= maxint; @@ -205,7 +239,7 @@ val_wo_dither = CLIP(val_wo_dither, maxint); #endif if (dither) { - float dither_num = triangular_dither_noise_f(); + double dither_num = triangular_dither_noise_f(); sample += dither_num; } @@ -227,7 +261,7 @@ return value; } -static inline float __dither_sample_float_to_float (float sample, float scale, int hardlimit) { +static inline float __dither_sample_float_to_float (float sample, double scale, int hardlimit) { #ifdef DEEP_DEBUG printf("f: __dither_sample_float_to_float\n"); #endif @@ -239,16 +273,16 @@ return sample; } -static inline float __dither_sample_fixed_to_float (int32_t sample, int inbits, int fracbits, float scale, int hardlimit) { +static inline float __dither_sample_fixed_to_float (int32_t sample, int inbits, int fracbits, double scale, int hardlimit) { float fsample; #ifdef DEEP_DEBUG printf("f: __dither_sample_fixed_to_float\n"); #endif if (fracbits == 0) { - fsample = (float)sample / (float)MAXINT(inbits); + fsample = (double)sample / (double)MAXINT(inbits); } else { - fsample = (float)sample / (float)MAXINT(fracbits+1); + fsample = (double)sample / (double)MAXINT(fracbits+1); } return __dither_sample_float_to_float (fsample, scale, hardlimit); } @@ -300,6 +334,7 @@ priv->rg_scale = 1.0; priv->dither = TRUE; priv->hardlimit = FALSE; + priv->adaptive_scaler = FALSE; switch(outbuf_format->sample_format){ case SAD_SAMPLE_S8: @@ -393,9 +428,11 @@ int inbits = priv->input_bits; int outbits = priv->output_bits; int fracbits = priv->input_fracbits; - float scale = priv->scale * priv->rg_scale; + double scale = priv->scale * priv->rg_scale; + double oldscale = scale; int dither = priv->dither; int hardlimit = priv->hardlimit; + int adaptive_scale = priv->adaptive_scaler; SAD_channels_order input_chorder = priv->input_chorder; SAD_channels_order output_chorder = priv->output_chorder; @@ -422,7 +459,7 @@ for(i=0; irg_scale = scale / priv->scale; + return SAD_ERROR_OK; } int SAD_dither_apply_replaygain (SAD_dither_t *state, SAD_replaygain_info *rg_info, SAD_replaygain_mode *mode) { SAD_state_priv *priv = (SAD_state_priv*) state; - float scale = -1.0, peak = 0.0; + double scale = -1.0, peak = 0.0; DEBUG_MSG("f: SAD_dither_apply_replaygain\n",0); @@ -498,13 +538,16 @@ if(scale * peak > 1.0) DEBUG_MSG("f: SAD_dither_apply_replaygain: clipping prevented\n",0); #endif scale = scale * peak > 1.0 ? 1.0 / peak : scale; + DEBUG_MSG("f: SAD_dither_apply_replaygain: new scale %f\n", scale); } scale = scale > 15.0 ? 15.0 : scale; // safety priv->rg_scale = scale; priv->hardlimit = mode->hard_limit; // apply settings + priv->adaptive_scaler = mode->adaptive_scaler; } else { priv->rg_scale = 1.0; priv->hardlimit = FALSE; + priv->adaptive_scaler = FALSE; // apply settings } return SAD_ERROR_OK; diff -r 70f379ff23ad -r b0ca963fd965 src/libSAD/noicegen.c --- a/src/libSAD/noicegen.c Tue Feb 05 00:09:07 2008 +0300 +++ b/src/libSAD/noicegen.c Wed Feb 06 22:42:32 2008 +0300 @@ -35,10 +35,10 @@ return v; } -float triangular_dither_noise_f() { +double triangular_dither_noise_f() { // Сonditionally assume we have 16 bits in fractional part // Please, check it thoroughly: is this assumption correct in floatin-point arithmetic? - return (float) triangular_dither_noise(17) / 65536.0; + return (double) triangular_dither_noise(17) / 65536.0; } void noicegen_init_rand(uint32_t seed) { diff -r 70f379ff23ad -r b0ca963fd965 src/libSAD/noicegen.h --- a/src/libSAD/noicegen.h Tue Feb 05 00:09:07 2008 +0300 +++ b/src/libSAD/noicegen.h Wed Feb 06 22:42:32 2008 +0300 @@ -4,7 +4,7 @@ #include int triangular_dither_noise(int nbits); -float triangular_dither_noise_f(void); +double triangular_dither_noise_f(void); void noicegen_init_rand(uint32_t seed); #endif /*NOICEGEN_H*/