ALSA: hda/ca0132 - Add bass redirection controls.

Add bass redirection controls for surround outputs. This uses the DSP to
redirect audio below the bass redirection crossover frequency to the LFE
channel from the front/rear L/R speakers. This only goes into effect if
the speakers aren't set as full range, and only if the surround
configuration has an LFE channel.

Signed-off-by: Connor McAdams <conmanx360@gmail.com>
Link: https://lore.kernel.org/r/20200825201040.30339-6-conmanx360@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Connor McAdams 2020-08-25 16:10:24 -04:00 committed by Takashi Iwai
parent 670c5f484a
commit f49b3063ad

View File

@ -149,6 +149,8 @@ enum {
SPEAKER_CHANNEL_CFG_ENUM,
SPEAKER_FULL_RANGE_FRONT,
SPEAKER_FULL_RANGE_REAR,
BASS_REDIRECTION,
BASS_REDIRECTION_XOVER,
#define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID)
};
@ -1123,6 +1125,8 @@ struct ca0132_spec {
unsigned char speaker_range_val[2];
unsigned char mic_boost_enum_val;
unsigned char smart_volume_setting;
unsigned char bass_redirection_val;
long bass_redirect_xover_freq;
long fx_ctl_val[EFFECT_LEVEL_SLIDERS];
long xbass_xover_freq;
long eq_preset_val;
@ -4324,6 +4328,35 @@ static int ca0132_alt_set_full_range_speaker(struct hda_codec *codec)
return 0;
}
static int ca0132_alt_surround_set_bass_redirection(struct hda_codec *codec,
bool val)
{
struct ca0132_spec *spec = codec->spec;
unsigned int tmp;
int err;
if (val && spec->channel_cfg_val != SPEAKER_CHANNELS_4_0 &&
spec->channel_cfg_val != SPEAKER_CHANNELS_2_0)
tmp = FLOAT_ONE;
else
tmp = FLOAT_ZERO;
err = dspio_set_uint_param(codec, 0x96, SPEAKER_BASS_REDIRECT, tmp);
if (err < 0)
return err;
/* If it is enabled, make sure to set the crossover frequency. */
if (tmp) {
tmp = float_xbass_xover_lookup[spec->xbass_xover_freq];
err = dspio_set_uint_param(codec, 0x96,
SPEAKER_BASS_REDIRECT_XOVER_FREQ, tmp);
if (err < 0)
return err;
}
return 0;
}
/*
* These are the commands needed to setup output on each of the different card
* types.
@ -4593,6 +4626,15 @@ static int ca0132_alt_select_out(struct hda_codec *codec)
ca0132_effects_set(codec, X_BASS,
spec->effects_switch[X_BASS - EFFECT_START_NID]);
if (spec->cur_out_type == SURROUND_OUT)
err = ca0132_alt_surround_set_bass_redirection(codec,
spec->bass_redirection_val);
else
err = ca0132_alt_surround_set_bass_redirection(codec, 0);
if (err < 0)
goto exit;
/* run through the output dsp commands for the selected output. */
for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) {
err = dspio_set_uint_param(codec,
@ -5282,6 +5324,18 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
return ret;
}
/* End of control change helpers. */
static void ca0132_alt_bass_redirection_xover_set(struct hda_codec *codec,
long idx)
{
snd_hda_power_up(codec);
dspio_set_param(codec, 0x96, 0x20, SPEAKER_BASS_REDIRECT_XOVER_FREQ,
&(float_xbass_xover_lookup[idx]), sizeof(unsigned int));
snd_hda_power_down(codec);
}
/*
* Below I've added controls to mess with the effect levels, I've only enabled
* them on the Sound Blaster Z, but they would probably also work on the
@ -5290,6 +5344,7 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
*/
/* Sets DSP effect level from the sliders above the controls */
static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid,
const unsigned int *lookup, int idx)
{
@ -5335,8 +5390,12 @@ static int ca0132_alt_xbass_xover_slider_ctl_get(struct snd_kcontrol *kcontrol,
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct ca0132_spec *spec = codec->spec;
long *valp = ucontrol->value.integer.value;
hda_nid_t nid = get_amp_nid(kcontrol);
*valp = spec->xbass_xover_freq;
if (nid == BASS_REDIRECTION_XOVER)
*valp = spec->bass_redirect_xover_freq;
else
*valp = spec->xbass_xover_freq;
return 0;
}
@ -5391,16 +5450,25 @@ static int ca0132_alt_xbass_xover_slider_put(struct snd_kcontrol *kcontrol,
struct ca0132_spec *spec = codec->spec;
hda_nid_t nid = get_amp_nid(kcontrol);
long *valp = ucontrol->value.integer.value;
long *cur_val;
int idx;
if (nid == BASS_REDIRECTION_XOVER)
cur_val = &spec->bass_redirect_xover_freq;
else
cur_val = &spec->xbass_xover_freq;
/* any change? */
if (spec->xbass_xover_freq == *valp)
if (*cur_val == *valp)
return 0;
spec->xbass_xover_freq = *valp;
*cur_val = *valp;
idx = *valp;
ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx);
if (nid == BASS_REDIRECTION_XOVER)
ca0132_alt_bass_redirection_xover_set(codec, *cur_val);
else
ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx);
return 0;
}
@ -5968,6 +6036,11 @@ static int ca0132_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
if (nid == BASS_REDIRECTION) {
*valp = spec->bass_redirection_val;
return 0;
}
return 0;
}
@ -6054,6 +6127,14 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
changed = 0;
}
if (nid == BASS_REDIRECTION) {
spec->bass_redirection_val = *valp;
if (spec->cur_out_type == SURROUND_OUT)
ca0132_alt_surround_set_bass_redirection(codec, *valp);
changed = 0;
}
exit:
snd_hda_power_down(codec);
return changed;
@ -6436,6 +6517,39 @@ static int ca0132_alt_add_rear_full_range_switch(struct hda_codec *codec)
snd_ctl_new1(&knew, codec));
}
/*
* Bass redirection redirects audio below the crossover frequency to the LFE
* channel on speakers that are set as not being full-range. On configurations
* without an LFE channel, it does nothing. Bass redirection seems to be the
* replacement for X-Bass on configurations with an LFE channel.
*/
static int ca0132_alt_add_bass_redirection_crossover(struct hda_codec *codec)
{
const char *namestr = "Bass Redirection Crossover";
struct snd_kcontrol_new knew =
HDA_CODEC_VOLUME_MONO(namestr, BASS_REDIRECTION_XOVER, 1, 0,
HDA_OUTPUT);
knew.tlv.c = NULL;
knew.info = ca0132_alt_xbass_xover_slider_info;
knew.get = ca0132_alt_xbass_xover_slider_ctl_get;
knew.put = ca0132_alt_xbass_xover_slider_put;
return snd_hda_ctl_add(codec, BASS_REDIRECTION_XOVER,
snd_ctl_new1(&knew, codec));
}
static int ca0132_alt_add_bass_redirection_switch(struct hda_codec *codec)
{
const char *namestr = "Bass Redirection";
struct snd_kcontrol_new knew =
CA0132_CODEC_MUTE_MONO(namestr, BASS_REDIRECTION, 1,
HDA_OUTPUT);
return snd_hda_ctl_add(codec, BASS_REDIRECTION,
snd_ctl_new1(&knew, codec));
}
/*
* Create an Input Source enumerated control for the alternate ca0132 codecs
* because the front microphone has no auto-detect, and Line-in has to be set
@ -6749,6 +6863,12 @@ static int ca0132_build_controls(struct hda_codec *codec)
if (err < 0)
return err;
err = ca0132_alt_add_rear_full_range_switch(codec);
if (err < 0)
return err;
err = ca0132_alt_add_bass_redirection_crossover(codec);
if (err < 0)
return err;
err = ca0132_alt_add_bass_redirection_switch(codec);
if (err < 0)
return err;
err = ca0132_alt_add_mic_boost_enum(codec);
@ -8102,6 +8222,8 @@ static void ca0132_init_chip(struct hda_codec *codec)
spec->xbass_xover_freq = 8;
for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
spec->fx_ctl_val[i] = effect_slider_defaults[i];
spec->bass_redirect_xover_freq = 8;
}
spec->voicefx_val = 0;