Index: apps/settings.c
===================================================================
--- apps/settings.c (revision 21906)
+++ apps/settings.c (working copy)
@@ -940,6 +940,7 @@
dsp_dither_enable(global_settings.dithering_enabled);
dsp_timestretch_enable(global_settings.timestretch_enabled);
+ dsp_set_compressor(global_settings.compressor_level);
#endif
#ifdef HAVE_SPDIF_POWER
Index: apps/lang/english.lang
===================================================================
--- apps/lang/english.lang (revision 21906)
+++ apps/lang/english.lang (working copy)
@@ -12655,3 +12655,20 @@
pitchscreen: "Rate"
+
+ id: LANG_COMPRESSOR
+ desc: in sound settings
+ user: core
+
+ *: none
+ swcodec: "Compressor Preamp"
+
+
+ *: none
+ swcodec: "Compressor Preamp"
+
+
+ *: none
+ swcodec: "Compressor Preamp"
+
+
Index: apps/settings.h
===================================================================
--- apps/settings.h (revision 21906)
+++ apps/settings.h (working copy)
@@ -744,6 +744,7 @@
bool pitch_mode_semitone;
#if CONFIG_CODEC == SWCODEC
bool pitch_mode_timestretch;
+ int compressor_level;
#endif
#endif
/* If values are just added to the end, no need to bump plugin API
Index: apps/menus/sound_menu.c
===================================================================
--- apps/menus/sound_menu.c (revision 21906)
+++ apps/menus/sound_menu.c (working copy)
@@ -105,6 +105,8 @@
&global_settings.timestretch_enabled, timestretch_callback);
MENUITEM_SETTING(dithering_enabled,
&global_settings.dithering_enabled, lowlatency_callback);
+ MENUITEM_SETTING(compressor_level,
+ &global_settings.compressor_level, lowlatency_callback);
#endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
@@ -138,6 +140,7 @@
#if CONFIG_CODEC == SWCODEC
,&crossfeed_menu, &equalizer_menu, &dithering_enabled
,×tretch_enabled
+ ,&compressor_level
#endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
,&loudness,&avc,&superbass,&mdb_enable,&mdb_strength
Index: apps/fixedpoint.c
===================================================================
--- apps/fixedpoint.c (revision 21906)
+++ apps/fixedpoint.c (working copy)
@@ -400,4 +400,5 @@
/* factor = 10 ^ (decibels / 20) */
return fp_exp10(FP_DIV_FRAC(decibels, (20L << fracbits)), fracbits);
}
+
#endif /* !PLUGIN and !CODEC */
Index: apps/dsp.c
===================================================================
--- apps/dsp.c (revision 21906)
+++ apps/dsp.c (working copy)
@@ -36,6 +36,10 @@
#include "fixedpoint.h"
#include "fracmul.h"
+/* Define LOGF_ENABLE to enable logf output in this file */
+#define LOGF_ENABLE
+#include "logf.h"
+
/* 16-bit samples are scaled based on these constants. The shift should be
* no more than 15.
*/
@@ -165,6 +169,7 @@
int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */
bool tdspeed_active; /* Timestretch is in use */
int frac_bits;
+ long compressor_preamp; /* compressor amp gain in S7.24 format */
#ifdef HAVE_SW_TONE_CONTROLS
/* Filter struct for software bass/treble controls */
struct eqfilter tone_filter;
@@ -180,6 +185,7 @@
channels_process_fn_type apply_crossfeed;
channels_process_fn_type eq_process;
channels_process_fn_type channels_process;
+ channels_process_fn_type compressor_process;
};
/* General DSP config */
@@ -890,6 +896,13 @@
(long) (((int64_t) dsp->data.gain * eq_precut) >> 24);
}
+ /* only preamp for the compressor if the compressor is active and sample
+ * depth allows safe pre-amping (12 dB is OK with 29 or less frac bits) */
+ if ((dsp->compressor_preamp) && (dsp->frac_bits <= 29))
+ {
+ dsp->data.gain = fp_mul(dsp->data.gain, dsp->compressor_preamp, 24);
+ }
+
if (dsp->data.gain == DEFAULT_GAIN)
{
dsp->data.gain = 0;
@@ -1015,6 +1028,138 @@
dsp_sw_cross = cross << 8;
}
+static void compressor_process(int count, int32_t *buf[])
+{
+ bool neg[2];
+ int i, larger;
+ int32_t *ext_buf[2], sample[2], x;
+ const int fracbits = AUDIO_DSP.frac_bits;
+ const long one_half = 1L << (fracbits - 1);
+ long gain;
+
+ /* don't process if calculation might overflow */
+ if (AUDIO_DSP.frac_bits > 29) return;
+
+ for (i = 0; i < 2; i++)
+ ext_buf[i] = buf[i];
+
+ while (count-- > 0)
+ {
+ /*
+ if (sample < -0.5)
+ sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
+ else if (sample > 0.5)
+ sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
+ */
+ for (i = 0; i < 2; i++)
+ {
+ sample[i] = *ext_buf[i];
+ if ((neg[i] = (sample[i] < 0)))
+ sample[i] = -(sample[i] + 1);
+ }
+ larger = (sample[1] > sample[0]) ? 1 : 0;
+ x = sample[larger];
+
+ /* large gains will overflow so just clip */
+ if (x >= (3L << fracbits))
+ x = (1L << fracbits) - 1;
+
+ /* compress samples above -6dB using
+ tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5 */
+ else if (x > one_half)
+ {
+ /* scale to 16 frac bits */
+ if (fracbits > 16)
+ x >>= (fracbits - 16);
+ else if (fracbits < 16)
+ x <<= (16 - fracbits);
+
+ /* calculate (x - 0.5) * 2, then double again for
+ use in tanh(x/2) function below */
+ x = (x - (1L << 15)) << 2;
+
+ /* Calculate exp(x) using 16 frac bits. Code taken from
+ http://www.quinapalus.com/efunc.html*/
+ long t,y;
+ const long one = (1L << 16);
+ y=0x00010000;
+ t=x-0x58B91; if(t>=0) x=t,y<<=8;
+ t=x-0x2C5C8; if(t>=0) x=t,y<<=4;
+ t=x-0x162E4; if(t>=0) x=t,y<<=2;
+ t=x-0x0B172; if(t>=0) x=t,y<<=1;
+ t=x-0x067CD; if(t>=0) x=t,y+=y>>1;
+ t=x-0x03920; if(t>=0) x=t,y+=y>>2;
+ t=x-0x01E27; if(t>=0) x=t,y+=y>>3;
+ t=x-0x00F85; if(t>=0) x=t,y+=y>>4;
+ t=x-0x007E1; if(t>=0) x=t,y+=y>>5;
+ t=x-0x003F8; if(t>=0) x=t,y+=y>>6;
+ t=x-0x001FE; if(t>=0) x=t,y+=y>>7;
+ if(x&0x000100) y+=y>>8;
+ if(x&0x000080) y+=y>>9;
+ if(x&0x000040) y+=y>>10;
+ if(x&0x000020) y+=y>>11;
+ if(x&0x000010) y+=y>>12;
+ if(x&0x000008) y+=y>>13;
+ if(x&0x000004) y+=y>>14;
+ if(x&0x000002) y+=y>>15;
+ if(x&0x000001) y+=y>>16;
+ x = fp_mul(x + one, y, 16);
+
+ /* tanh(x) = (exp(2x)-1)/(exp(2x)+1)
+ x was already doubled above */
+ x = fp_div(x - one, x + one, 16);
+
+ /* scale back to fracbits */
+ if (fracbits > 16)
+ x <<= (fracbits - 16);
+ else if (fracbits < 16)
+ x >>= (16 - fracbits);
+
+ /* x = x/2 + 0.5 */
+ x = (x >> 1) + one_half;
+
+ /* guard against rounding error overflows */
+ if (x >= (1L << fracbits))
+ x = (1L << fracbits) - 1;
+
+ }
+
+ gain = fp_div(x, sample[larger], fracbits);
+
+ for (i = 0; i < 2; i++)
+ {
+ sample[i] = fp_mul(sample[i], gain, fracbits);
+ if (neg[i])
+ sample[i] = -sample[i] - 1;
+ *ext_buf[i]++ = sample[i];
+ }
+ }
+}
+
+void dsp_set_compressor(int compressor_level)
+{
+ if (compressor_level > 0)
+ {
+ /* enable compressor process */
+ AUDIO_DSP.compressor_process = compressor_process;
+ /* compressor preamp is a gain factor in S7.24 format */
+ AUDIO_DSP.compressor_preamp =
+ fp_factor((((long)compressor_level << 24) / 10), 24);
+ }
+ else
+ {
+ /* disable compressor process*/
+ AUDIO_DSP.compressor_process = NULL;
+ AUDIO_DSP.compressor_preamp = 0;
+ }
+
+ set_gain(&AUDIO_DSP);
+
+ logf("Compressor enable: %s\tCompressor amp: %.8f",
+ AUDIO_DSP.compressor_process ? "Yes" : "No",
+ (float)AUDIO_DSP.compressor_preamp / (1 << 24));
+}
+
/**
* Implements the different channel configurations and stereo width.
*/
@@ -1236,6 +1381,9 @@
if (dsp->channels_process)
dsp->channels_process(chunk, t2);
+ if (dsp->compressor_process)
+ dsp->compressor_process(chunk, t2);
+
dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst);
written += chunk;
Index: apps/settings_list.c
===================================================================
--- apps/settings_list.c (revision 21906)
+++ apps/settings_list.c (working copy)
@@ -1236,6 +1236,12 @@
/* timestretch */
OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false,
"timestretch enabled", dsp_timestretch_enable),
+
+ /* compressor */
+ INT_SETTING_NOWRAP(F_SOUNDSETTING, compressor_level,
+ LANG_COMPRESSOR, 0,
+ "compressor level", UNIT_DB, 0, MAX_COMPRESSOR_GAIN,
+ 5, db_format, get_dec_talkid, dsp_set_compressor),
#endif
#ifdef HAVE_WM8758
SOUND_SETTING(F_NO_WRAP, bass_cutoff, LANG_BASS_CUTOFF,
Index: apps/dsp.h
===================================================================
--- apps/dsp.h (revision 21906)
+++ apps/dsp.h (working copy)
@@ -26,6 +26,7 @@
#include
#define NATIVE_FREQUENCY 44100
+#define MAX_COMPRESSOR_GAIN 80 /* 8 dB */
enum
{
STEREO_INTERLEAVED = 0,
@@ -88,5 +89,6 @@
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 compressor_level);
#endif