forked from len0rd/rockbox
Add software based bass/treble controls for targets which have no such functionality in hardware (currently only X5). They can also be used on any other SWCODEC target by adding #define HAVE_SW_TONE_CONTROLS in the relevant config-*.h file. Also remove some now unneeded zero checks when using get_replaygain_int(). Comments on sound quality are welcome as some parameters can still be fine-tuned.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12489 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1915c10994
commit
a7fabf0741
9 changed files with 175 additions and 45 deletions
71
apps/dsp.c
71
apps/dsp.c
|
@ -116,9 +116,10 @@ struct crossfeed_data
|
||||||
/* 8ch */
|
/* 8ch */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Current setup is one lowshelf filters, three peaking filters and one
|
/* Current setup is one lowshelf filters three peaking filters and one
|
||||||
highshelf filter. Varying the number of shelving filters make no sense,
|
* highshelf filter. Varying the number of shelving filters make no sense,
|
||||||
but adding peaking filters is possible. */
|
* but adding peaking filters is possible.
|
||||||
|
*/
|
||||||
struct eq_state
|
struct eq_state
|
||||||
{
|
{
|
||||||
char enabled[5]; /* 00h - Flags for active filters */
|
char enabled[5]; /* 00h - Flags for active filters */
|
||||||
|
@ -171,6 +172,13 @@ static long dither_bias IBSS_ATTR;
|
||||||
struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */
|
struct crossfeed_data crossfeed_data IBSS_ATTR; /* A */
|
||||||
/* Equalizer */
|
/* Equalizer */
|
||||||
static struct eq_state eq_data; /* A/V */
|
static struct eq_state eq_data; /* A/V */
|
||||||
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
|
static int prescale;
|
||||||
|
static int bass;
|
||||||
|
static int treble;
|
||||||
|
/* Filter struct for software bass/treble controls */
|
||||||
|
static struct eqfilter tone_filter;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Settings applicable to audio codec only */
|
/* Settings applicable to audio codec only */
|
||||||
static int pitch_ratio = 1000;
|
static int pitch_ratio = 1000;
|
||||||
|
@ -704,11 +712,7 @@ void dsp_set_crossfeed(bool enable)
|
||||||
|
|
||||||
void dsp_set_crossfeed_direct_gain(int gain)
|
void dsp_set_crossfeed_direct_gain(int gain)
|
||||||
{
|
{
|
||||||
/* Work around bug in get_replaygain_int which returns 0 for 0 dB */
|
crossfeed_data.gain = get_replaygain_int(gain * -10) << 7;
|
||||||
if (gain == 0)
|
|
||||||
crossfeed_data.gain = 0x7fffffff;
|
|
||||||
else
|
|
||||||
crossfeed_data.gain = get_replaygain_int(gain * -10) << 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
|
void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
|
||||||
|
@ -716,8 +720,8 @@ void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
|
||||||
long g1 = get_replaygain_int(lf_gain * -10) << 3;
|
long g1 = get_replaygain_int(lf_gain * -10) << 3;
|
||||||
long g2 = get_replaygain_int(hf_gain * -10) << 3;
|
long g2 = get_replaygain_int(hf_gain * -10) << 3;
|
||||||
|
|
||||||
filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*cutoff, g1, g2,
|
filter_shelf_coefs(0xffffffff/NATIVE_FREQUENCY*cutoff, g1, g2,
|
||||||
crossfeed_data.coefs);
|
crossfeed_data.coefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Applies crossfeed to the stereo signal in src.
|
/* Applies crossfeed to the stereo signal in src.
|
||||||
|
@ -985,6 +989,36 @@ static void channels_process_sound_chan_mono(int count, int32_t *buf[])
|
||||||
}
|
}
|
||||||
#endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */
|
#endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */
|
||||||
|
|
||||||
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
|
static void set_tone_controls(void)
|
||||||
|
{
|
||||||
|
filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*200,
|
||||||
|
0xffffffff/NATIVE_FREQUENCY*3500,
|
||||||
|
bass, treble, -prescale, tone_filter.coefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dsp_callback(int msg, intptr_t param)
|
||||||
|
{
|
||||||
|
switch (msg) {
|
||||||
|
case DSP_CALLBACK_SET_PRESCALE:
|
||||||
|
prescale = param;
|
||||||
|
set_tone_controls();
|
||||||
|
break;
|
||||||
|
/* prescaler is always set after calling any of these, so we wait with
|
||||||
|
* calculating coefs until the above case is hit.
|
||||||
|
*/
|
||||||
|
case DSP_CALLBACK_SET_BASS:
|
||||||
|
bass = param;
|
||||||
|
break;
|
||||||
|
case DSP_CALLBACK_SET_TREBLE:
|
||||||
|
treble = param;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
|
#ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
|
||||||
static void channels_process_sound_chan_custom(int count, int32_t *buf[])
|
static void channels_process_sound_chan_custom(int count, int32_t *buf[])
|
||||||
{
|
{
|
||||||
|
@ -1068,12 +1102,12 @@ int dsp_process(char *dst, const char *src[], int count)
|
||||||
int written = 0;
|
int written = 0;
|
||||||
int samples;
|
int samples;
|
||||||
|
|
||||||
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
||||||
/* set emac unit for dsp processing, and save old macsr, we're running in
|
/* set emac unit for dsp processing, and save old macsr, we're running in
|
||||||
codec thread context at this point, so can't clobber it */
|
codec thread context at this point, so can't clobber it */
|
||||||
unsigned long old_macsr = coldfire_get_macsr();
|
unsigned long old_macsr = coldfire_get_macsr();
|
||||||
coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
|
coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (count > 0)
|
while (count > 0)
|
||||||
{
|
{
|
||||||
|
@ -1085,8 +1119,17 @@ int dsp_process(char *dst, const char *src[], int count)
|
||||||
break; /* I'm pretty sure we're downsampling here */
|
break; /* I'm pretty sure we're downsampling here */
|
||||||
if (dsp->apply_crossfeed)
|
if (dsp->apply_crossfeed)
|
||||||
dsp->apply_crossfeed(tmp, samples);
|
dsp->apply_crossfeed(tmp, samples);
|
||||||
|
/* TODO: EQ and tone controls need separate structs for audio and voice
|
||||||
|
* DSP processing thanks to filter history. isn't really audible now, but
|
||||||
|
* might be the day we start handling voice more delicately.
|
||||||
|
*/
|
||||||
if (eq_enabled)
|
if (eq_enabled)
|
||||||
eq_process(samples, tmp);
|
eq_process(samples, tmp);
|
||||||
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
|
if ((bass | treble) != 0)
|
||||||
|
eq_filter(tmp, &tone_filter, samples, dsp->data.num_channels,
|
||||||
|
FILTER_BISHELF_SHIFT);
|
||||||
|
#endif
|
||||||
if (dsp->channels_process)
|
if (dsp->channels_process)
|
||||||
dsp->channels_process(samples, tmp);
|
dsp->channels_process(samples, tmp);
|
||||||
dsp->output_samples(samples, &dsp->data, tmp, (int16_t *)dst);
|
dsp->output_samples(samples, &dsp->data, tmp, (int16_t *)dst);
|
||||||
|
@ -1095,10 +1138,10 @@ int dsp_process(char *dst, const char *src[], int count)
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
||||||
/* set old macsr again */
|
/* set old macsr again */
|
||||||
coldfire_set_macsr(old_macsr);
|
coldfire_set_macsr(old_macsr);
|
||||||
#endif
|
#endif
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,12 @@ enum
|
||||||
DSP_CROSSFEED
|
DSP_CROSSFEED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DSP_CALLBACK_SET_PRESCALE = 0,
|
||||||
|
DSP_CALLBACK_SET_BASS,
|
||||||
|
DSP_CALLBACK_SET_TREBLE
|
||||||
|
};
|
||||||
|
|
||||||
/* A bunch of fixed point assembler helper macros */
|
/* A bunch of fixed point assembler helper macros */
|
||||||
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
|
||||||
/* These macros use the Coldfire EMAC extension and need the MACSR flags set
|
/* These macros use the Coldfire EMAC extension and need the MACSR flags set
|
||||||
|
@ -209,6 +215,7 @@ void dsp_set_eq_precut(int precut);
|
||||||
void dsp_set_eq_coefs(int band);
|
void dsp_set_eq_coefs(int band);
|
||||||
void sound_set_pitch(int r);
|
void sound_set_pitch(int r);
|
||||||
int sound_get_pitch(void);
|
int sound_get_pitch(void);
|
||||||
|
int dsp_callback(int msg, intptr_t param);
|
||||||
void channels_set(int value);
|
void channels_set(int value);
|
||||||
void stereo_width_set(int value);
|
void stereo_width_set(int value);
|
||||||
void dsp_dither_enable(bool enable);
|
void dsp_dither_enable(bool enable);
|
||||||
|
|
60
apps/eq.c
60
apps/eq.c
|
@ -7,7 +7,7 @@
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Thom Johansen
|
* Copyright (C) 2006-2007 Thom Johansen
|
||||||
*
|
*
|
||||||
* All files in this archive are subject to the GNU General Public License.
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
* See the file COPYING in the source tree root for full license agreement.
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
@ -127,7 +127,7 @@ static long fsincos(unsigned long phase, long *cos) {
|
||||||
* @param an gain at Nyquist frequency. s3.27 fixed point.
|
* @param an gain at Nyquist frequency. s3.27 fixed point.
|
||||||
* @param c pointer to coefficient storage. The coefs are s0.31 format.
|
* @param c pointer to coefficient storage. The coefs are s0.31 format.
|
||||||
*/
|
*/
|
||||||
void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c)
|
void filter_shelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c)
|
||||||
{
|
{
|
||||||
const long one = 1 << 27;
|
const long one = 1 << 27;
|
||||||
long a0, a1;
|
long a0, a1;
|
||||||
|
@ -137,7 +137,7 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c)
|
||||||
cs = one + (cs >> 4);
|
cs = one + (cs >> 4);
|
||||||
|
|
||||||
/* For max A = 4 (24 dB) */
|
/* For max A = 4 (24 dB) */
|
||||||
b0 = FRACMUL_SHL(an, cs, 4) + FRACMUL_SHL(ad, s, 4);
|
b0 = FRACMUL_SHL(ad, s, 4) + FRACMUL_SHL(an, cs, 4);
|
||||||
b1 = FRACMUL_SHL(ad, s, 4) - FRACMUL_SHL(an, cs, 4);
|
b1 = FRACMUL_SHL(ad, s, 4) - FRACMUL_SHL(an, cs, 4);
|
||||||
a0 = s + cs;
|
a0 = s + cs;
|
||||||
a1 = s - cs;
|
a1 = s - cs;
|
||||||
|
@ -147,6 +147,58 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c)
|
||||||
c[2] = -DIV64(a1, a0, 31);
|
c[2] = -DIV64(a1, a0, 31);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate second order section filter consisting of one low-shelf and one
|
||||||
|
* high-shelf section.
|
||||||
|
* @param cutoff_low low-shelf midpoint frequency. See eq_pk_coefs for format.
|
||||||
|
* @param cutoff_high high-shelf midpoint frequency.
|
||||||
|
* @param A_low decibel value multiplied by ten, describing gain/attenuation of
|
||||||
|
* low-shelf part. Max value is 24 dB.
|
||||||
|
* @param A_high decibel value multiplied by ten, describing gain/attenuation of
|
||||||
|
* high-shelf part. Max value is 24 dB.
|
||||||
|
* @param A decibel value multiplied by ten, describing additional overall gain.
|
||||||
|
* @param c pointer to coefficient storage. Coefficients are s4.27 format.
|
||||||
|
*/
|
||||||
|
void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high,
|
||||||
|
long A_low, long A_high, long A, int32_t *c)
|
||||||
|
{
|
||||||
|
long sin1, cos2; /* s0.31 */
|
||||||
|
long cos1, sin2; /* s3.28 */
|
||||||
|
int32_t b0, b1, b2, b3; /* s3.28 */
|
||||||
|
int32_t a0, a1, a2, a3;
|
||||||
|
const long gd = get_replaygain_int(A_low*5) << 4; /* 10^(db/40), s3.28 */
|
||||||
|
const long gn = get_replaygain_int(A_high*5) << 4; /* 10^(db/40), s3.28 */
|
||||||
|
const long g = get_replaygain_int(A*10) << 7; /* 10^(db/20), s0.31 */
|
||||||
|
|
||||||
|
sin1 = fsincos(cutoff_low/2, &cos1);
|
||||||
|
sin2 = fsincos(cutoff_high/2, &cos2) >> 3;
|
||||||
|
cos1 >>= 3;
|
||||||
|
|
||||||
|
/* lowshelf filter, ranges listed are for all possible cutoffs */
|
||||||
|
b0 = FRACMUL(sin1, gd) + cos1; /* 0.25 .. 4.10 */
|
||||||
|
b1 = FRACMUL(sin1, gd) - cos1; /* -1 .. 3.98 */
|
||||||
|
a0 = DIV64(sin1, gd, 25) + cos1; /* 0.25 .. 4.10 */
|
||||||
|
a1 = DIV64(sin1, gd, 25) - cos1; /* -1 .. 3.98 */
|
||||||
|
|
||||||
|
/* highshelf filter */
|
||||||
|
b2 = sin2 + FRACMUL(cos2, gn); /* 0.25 .. 4.10 */
|
||||||
|
b3 = sin2 - FRACMUL(cos2, gn); /* -3.98 .. 1 */
|
||||||
|
a2 = sin2 + DIV64(cos2, gn, 25); /* 0.25 .. 4.10 */
|
||||||
|
a3 = sin2 - DIV64(cos2, gn, 25); /* -3.98 .. 1 */
|
||||||
|
|
||||||
|
/* now we cascade the two first order filters to one second order filter
|
||||||
|
* which can be used by eq_filter(). these resulting coefficients have a
|
||||||
|
* really wide numerical range, so we use a fixed point format which will
|
||||||
|
* work for the selected cutoff frequencies (in dsp.c) only.
|
||||||
|
*/
|
||||||
|
const int32_t rcp_a0 = DIV64(1, FRACMUL(a0, a2), 53); /* s3.28 */
|
||||||
|
*c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b0, b2), rcp_a0, 5));
|
||||||
|
*c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b0, b3) + FRACMUL(b1, b2), rcp_a0, 5));
|
||||||
|
*c++ = FRACMUL(g, FRACMUL_SHL(FRACMUL(b1, b3), rcp_a0, 5));
|
||||||
|
*c++ = -FRACMUL_SHL(FRACMUL(a0, a3) + FRACMUL(a1, a2), rcp_a0, 5);
|
||||||
|
*c++ = -FRACMUL_SHL(FRACMUL(a1, a3), rcp_a0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
/* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson.
|
/* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson.
|
||||||
* Slightly faster calculation can be done by deriving forms which use tan()
|
* Slightly faster calculation can be done by deriving forms which use tan()
|
||||||
* instead of cos() and sin(), but the latter are far easier to use when doing
|
* instead of cos() and sin(), but the latter are far easier to use when doing
|
||||||
|
@ -162,7 +214,7 @@ void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c)
|
||||||
* @param Q Q factor value multiplied by ten. Lower bound is artificially set
|
* @param Q Q factor value multiplied by ten. Lower bound is artificially set
|
||||||
* at 0.5.
|
* at 0.5.
|
||||||
* @param db decibel value multiplied by ten, describing gain/attenuation at
|
* @param db decibel value multiplied by ten, describing gain/attenuation at
|
||||||
* peak freq.
|
* peak freq. Max value is 24 dB.
|
||||||
* @param c pointer to coefficient storage. Coefficients are s3.28 format.
|
* @param c pointer to coefficient storage. Coefficients are s3.28 format.
|
||||||
*/
|
*/
|
||||||
void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c)
|
void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* \/ \/ \/ \/ \/
|
* \/ \/ \/ \/ \/
|
||||||
* $Id$
|
* $Id$
|
||||||
*
|
*
|
||||||
* Copyright (C) 2006 Thom Johansen
|
* Copyright (C) 2006-2007 Thom Johansen
|
||||||
*
|
*
|
||||||
* All files in this archive are subject to the GNU General Public License.
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
* See the file COPYING in the source tree root for full license agreement.
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
/* These depend on the fixed point formats used by the different filter types
|
/* These depend on the fixed point formats used by the different filter types
|
||||||
and need to be changed when they change.
|
and need to be changed when they change.
|
||||||
*/
|
*/
|
||||||
|
#define FILTER_BISHELF_SHIFT 5
|
||||||
#define EQ_PEAK_SHIFT 4
|
#define EQ_PEAK_SHIFT 4
|
||||||
#define EQ_SHELF_SHIFT 6
|
#define EQ_SHELF_SHIFT 6
|
||||||
|
|
||||||
|
@ -33,7 +34,9 @@ struct eqfilter {
|
||||||
int32_t history[2][4];
|
int32_t history[2][4];
|
||||||
};
|
};
|
||||||
|
|
||||||
void filter_bishelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c);
|
void filter_shelf_coefs(unsigned long cutoff, long ad, long an, int32_t *c);
|
||||||
|
void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high,
|
||||||
|
long A_low, long A_high, long A, int32_t *c);
|
||||||
void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
|
void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
|
||||||
void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
|
void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
|
||||||
void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
|
void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
|
||||||
|
|
|
@ -55,12 +55,8 @@ int soundmenu_callback(int action,const struct menu_item_ex *this_item)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MENUITEM_SETTING(volume, &global_settings.volume, soundmenu_callback);
|
MENUITEM_SETTING(volume, &global_settings.volume, soundmenu_callback);
|
||||||
|
MENUITEM_SETTING(bass, &global_settings.bass, soundmenu_callback);
|
||||||
#ifndef HAVE_TLV320
|
MENUITEM_SETTING(treble, &global_settings.treble, soundmenu_callback);
|
||||||
MENUITEM_SETTING(bass, &global_settings.bass, soundmenu_callback);
|
|
||||||
MENUITEM_SETTING(treble, &global_settings.treble, soundmenu_callback);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
MENUITEM_SETTING(balance, &global_settings.balance, soundmenu_callback);
|
MENUITEM_SETTING(balance, &global_settings.balance, soundmenu_callback);
|
||||||
MENUITEM_SETTING(channel_config, &global_settings.channel_config, soundmenu_callback);
|
MENUITEM_SETTING(channel_config, &global_settings.channel_config, soundmenu_callback);
|
||||||
MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback);
|
MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback);
|
||||||
|
@ -99,9 +95,7 @@ MENUITEM_SETTING(stereo_width, &global_settings.stereo_width, soundmenu_callback
|
||||||
|
|
||||||
MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, bitmap_icons_6x8[Icon_Audio],
|
MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, bitmap_icons_6x8[Icon_Audio],
|
||||||
&volume,
|
&volume,
|
||||||
#ifndef HAVE_TLV320
|
|
||||||
&bass,&treble,
|
&bass,&treble,
|
||||||
#endif
|
|
||||||
&balance,&channel_config,&stereo_width
|
&balance,&channel_config,&stereo_width
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
,&crossfeed_menu, &equalizer_menu, &dithering_enabled
|
,&crossfeed_menu, &equalizer_menu, &dithering_enabled
|
||||||
|
|
|
@ -642,6 +642,9 @@ void settings_apply_pm_range(void)
|
||||||
|
|
||||||
void sound_settings_apply(void)
|
void sound_settings_apply(void)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
|
sound_set_dsp_callback(dsp_callback);
|
||||||
|
#endif
|
||||||
sound_set(SOUND_BASS, global_settings.bass);
|
sound_set(SOUND_BASS, global_settings.bass);
|
||||||
sound_set(SOUND_TREBLE, global_settings.treble);
|
sound_set(SOUND_TREBLE, global_settings.treble);
|
||||||
sound_set(SOUND_BALANCE, global_settings.balance);
|
sound_set(SOUND_BALANCE, global_settings.balance);
|
||||||
|
@ -967,7 +970,7 @@ bool set_sound(const unsigned char * string,
|
||||||
talkunit = UNIT_PERCENT;
|
talkunit = UNIT_PERCENT;
|
||||||
else if (*unit == 'H')
|
else if (*unit == 'H')
|
||||||
talkunit = UNIT_HERTZ;
|
talkunit = UNIT_HERTZ;
|
||||||
if(!numdec)
|
if (!numdec)
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
/* We need to hijack this one and send it off to apps/dsp.c instead of
|
/* We need to hijack this one and send it off to apps/dsp.c instead of
|
||||||
firmware/sound.c */
|
firmware/sound.c */
|
||||||
|
@ -975,7 +978,7 @@ bool set_sound(const unsigned char * string,
|
||||||
return set_int(string, unit, talkunit, variable, &stereo_width_set,
|
return set_int(string, unit, talkunit, variable, &stereo_width_set,
|
||||||
steps, min, max, NULL );
|
steps, min, max, NULL );
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
return set_int(string, unit, talkunit, variable, sound_callback,
|
return set_int(string, unit, talkunit, variable, sound_callback,
|
||||||
steps, min, max, NULL );
|
steps, min, max, NULL );
|
||||||
else
|
else
|
||||||
|
|
|
@ -84,6 +84,9 @@
|
||||||
|
|
||||||
#define HAVE_TLV320
|
#define HAVE_TLV320
|
||||||
|
|
||||||
|
/* TLV320 has no tone controls, so we use the software ones */
|
||||||
|
#define HAVE_SW_TONE_CONTROLS
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
|
|
||||||
/* Define this if your LCD can set contrast */
|
/* Define this if your LCD can set contrast */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#ifndef SOUND_H
|
#ifndef SOUND_H
|
||||||
#define SOUND_H
|
#define SOUND_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
#ifdef HAVE_UDA1380
|
#ifdef HAVE_UDA1380
|
||||||
#include "uda1380.h"
|
#include "uda1380.h"
|
||||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8751)
|
#elif defined(HAVE_WM8975) || defined(HAVE_WM8751)
|
||||||
|
@ -76,6 +77,7 @@ int sound_max(int setting);
|
||||||
int sound_default(int setting);
|
int sound_default(int setting);
|
||||||
sound_set_type* sound_get_fn(int setting);
|
sound_set_type* sound_get_fn(int setting);
|
||||||
|
|
||||||
|
void sound_set_dsp_callback(int (*func)(int, intptr_t));
|
||||||
void sound_set_volume(int value);
|
void sound_set_volume(int value);
|
||||||
void sound_set_balance(int value);
|
void sound_set_balance(int value);
|
||||||
void sound_set_bass(int value);
|
void sound_set_bass(int value);
|
||||||
|
|
|
@ -86,6 +86,11 @@ static const struct sound_settings_info sound_settings_table[] = {
|
||||||
[SOUND_VOLUME] = {"dB", 0, 1, -78, 18, -18, sound_set_volume},
|
[SOUND_VOLUME] = {"dB", 0, 1, -78, 18, -18, sound_set_volume},
|
||||||
[SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass},
|
[SOUND_BASS] = {"dB", 0, 1, -15, 15, 7, sound_set_bass},
|
||||||
[SOUND_TREBLE] = {"dB", 0, 1, -15, 15, 7, sound_set_treble},
|
[SOUND_TREBLE] = {"dB", 0, 1, -15, 15, 7, sound_set_treble},
|
||||||
|
#endif
|
||||||
|
/* Override any other potentially existing treble/bass controllers if wanted */
|
||||||
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
|
[SOUND_BASS] = {"dB", 0, 1, -24, 24, 0, sound_set_bass},
|
||||||
|
[SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0, sound_set_treble},
|
||||||
#endif
|
#endif
|
||||||
[SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0, sound_set_balance},
|
[SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0, sound_set_balance},
|
||||||
[SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0, sound_set_channels},
|
[SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0, sound_set_channels},
|
||||||
|
@ -166,6 +171,22 @@ sound_set_type* sound_get_fn(int setting)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
|
/* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
|
||||||
|
enum {
|
||||||
|
DSP_CALLBACK_SET_PRESCALE = 0,
|
||||||
|
DSP_CALLBACK_SET_BASS,
|
||||||
|
DSP_CALLBACK_SET_TREBLE
|
||||||
|
};
|
||||||
|
|
||||||
|
static int (*dsp_callback)(int, intptr_t) = NULL;
|
||||||
|
|
||||||
|
void sound_set_dsp_callback(int (*func)(int, intptr_t))
|
||||||
|
{
|
||||||
|
dsp_callback = func;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef SIMULATOR
|
#ifndef SIMULATOR
|
||||||
#if CONFIG_CODEC == MAS3507D /* volume/balance/treble/bass interdependency */
|
#if CONFIG_CODEC == MAS3507D /* volume/balance/treble/bass interdependency */
|
||||||
#define VOLUME_MIN -780
|
#define VOLUME_MIN -780
|
||||||
|
@ -293,10 +314,9 @@ int current_bass = 0; /* -150..+150 0..+240 */
|
||||||
|
|
||||||
static void set_prescaled_volume(void)
|
static void set_prescaled_volume(void)
|
||||||
{
|
{
|
||||||
int prescale = 0;
|
int prescale;
|
||||||
int l, r;
|
int l, r;
|
||||||
|
|
||||||
#ifndef HAVE_TLV320
|
|
||||||
prescale = MAX(current_bass, current_treble);
|
prescale = MAX(current_bass, current_treble);
|
||||||
if (prescale < 0)
|
if (prescale < 0)
|
||||||
prescale = 0; /* no need to prescale if we don't boost
|
prescale = 0; /* no need to prescale if we don't boost
|
||||||
|
@ -307,13 +327,12 @@ static void set_prescaled_volume(void)
|
||||||
* instead (might cause clipping). */
|
* instead (might cause clipping). */
|
||||||
if (current_volume + prescale > VOLUME_MAX)
|
if (current_volume + prescale > VOLUME_MAX)
|
||||||
prescale = VOLUME_MAX - current_volume;
|
prescale = VOLUME_MAX - current_volume;
|
||||||
#endif
|
|
||||||
|
#if defined(HAVE_SW_TONE_CONTROLS)
|
||||||
#if CONFIG_CODEC == MAS3507D
|
dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
|
||||||
|
#elif CONFIG_CODEC == MAS3507D
|
||||||
mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]);
|
mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]);
|
||||||
#elif defined(HAVE_UDA1380)
|
#elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
||||||
audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale));
|
|
||||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
|
||||||
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751)
|
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751)
|
||||||
audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale));
|
audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale));
|
||||||
#endif
|
#endif
|
||||||
|
@ -338,9 +357,7 @@ static void set_prescaled_volume(void)
|
||||||
|
|
||||||
#if CONFIG_CODEC == MAS3507D
|
#if CONFIG_CODEC == MAS3507D
|
||||||
dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
|
dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
|
||||||
#elif defined(HAVE_UDA1380)
|
#elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
||||||
audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
|
|
||||||
#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|
|
||||||
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751)
|
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751)
|
||||||
audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
|
audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
|
||||||
#if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751)
|
#if defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8751)
|
||||||
|
@ -484,12 +501,15 @@ void sound_set_balance(int value)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_TLV320
|
|
||||||
void sound_set_bass(int value)
|
void sound_set_bass(int value)
|
||||||
{
|
{
|
||||||
if(!audio_is_initialized)
|
if(!audio_is_initialized)
|
||||||
return;
|
return;
|
||||||
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
#if defined(HAVE_SW_TONE_CONTROLS)
|
||||||
|
current_bass = value * 10;
|
||||||
|
dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
|
||||||
|
set_prescaled_volume();
|
||||||
|
#elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
||||||
unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8;
|
unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8;
|
||||||
mas_codec_writereg(0x14, tmp);
|
mas_codec_writereg(0x14, tmp);
|
||||||
#elif CONFIG_CODEC == MAS3507D
|
#elif CONFIG_CODEC == MAS3507D
|
||||||
|
@ -515,7 +535,11 @@ void sound_set_treble(int value)
|
||||||
{
|
{
|
||||||
if(!audio_is_initialized)
|
if(!audio_is_initialized)
|
||||||
return;
|
return;
|
||||||
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
#if defined(HAVE_SW_TONE_CONTROLS)
|
||||||
|
current_treble = value * 10;
|
||||||
|
dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
|
||||||
|
set_prescaled_volume();
|
||||||
|
#elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
|
||||||
unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8;
|
unsigned tmp = ((unsigned)(value * 8) & 0xff) << 8;
|
||||||
mas_codec_writereg(0x15, tmp);
|
mas_codec_writereg(0x15, tmp);
|
||||||
#elif CONFIG_CODEC == MAS3507D
|
#elif CONFIG_CODEC == MAS3507D
|
||||||
|
@ -536,7 +560,6 @@ void sound_set_treble(int value)
|
||||||
(void)value;
|
(void)value;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* HAVE_TLV320 */
|
|
||||||
|
|
||||||
void sound_set_channels(int value)
|
void sound_set_channels(int value)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue