three new DSPs
perceptual bass enhancement - a bbe-ish group delay corrction with Biophonic EQ boost. - precut auditory fatigue reduction -reduce signal in frequency that may trigger temporary threshold shift haas surround -frequency between f(x1) and f(x2) is always bypassed. -can apply to side only. Change-Id: Icb6355ce9b1c99bf2c58c9385c3c411c0ae209d3
This commit is contained in:
parent
2cdfc43f10
commit
3ae0f32ac3
17 changed files with 1084 additions and 6 deletions
|
@ -13254,3 +13254,122 @@
|
||||||
swcodec: "Q"
|
swcodec: "Q"
|
||||||
</voice>
|
</voice>
|
||||||
</phrase>
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_PBE
|
||||||
|
desc: in sound settings
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "Perceptual Bass Enhancement"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "Perceptual Bass Enhancement"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "Perceptual Bass Enhancement"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_AFR
|
||||||
|
desc: in sound settings
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "Auditory Fatigue Reduction"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "Auditory Fatigue Reduction"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "Auditory Fatigue Reduction"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_SURROUND
|
||||||
|
desc: in the sound settings menu
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "Haas Surround"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "Haas Surround"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "Haas Surround"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_SURROUND_FX1
|
||||||
|
desc: in sound settings
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "f(x1)"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "f(x1)"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "f(x1)"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_SURROUND_FX2
|
||||||
|
desc: in sound settings
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "f(x2)"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "f(x2)"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "f(x2)"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_SURROUND_METHOD2
|
||||||
|
desc: in sound settings
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "SIDE ONLY"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "SIDE ONLY"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "SIDE ONLY"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
<phrase>
|
||||||
|
id: LANG_SURROUND_MIX
|
||||||
|
desc: in sound settings
|
||||||
|
user: core
|
||||||
|
<source>
|
||||||
|
*: none
|
||||||
|
swcodec: "Dry / Wet Mix"
|
||||||
|
</source>
|
||||||
|
<dest>
|
||||||
|
*: none
|
||||||
|
swcodec: "Dry / Wet Mix"
|
||||||
|
</dest>
|
||||||
|
<voice>
|
||||||
|
*: none
|
||||||
|
swcodec: "Dry / Wet Mix"
|
||||||
|
</voice>
|
||||||
|
</phrase>
|
||||||
|
|
|
@ -166,6 +166,28 @@ static int timestretch_callback(int action,const struct menu_item_ex *this_item)
|
||||||
|
|
||||||
MENUITEM_SETTING(dithering_enabled,
|
MENUITEM_SETTING(dithering_enabled,
|
||||||
&global_settings.dithering_enabled, lowlatency_callback);
|
&global_settings.dithering_enabled, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(afr_enabled,
|
||||||
|
&global_settings.afr_enabled, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(pbe,
|
||||||
|
&global_settings.pbe, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(pbe_precut,
|
||||||
|
&global_settings.pbe_precut, lowlatency_callback);
|
||||||
|
MAKE_MENU(pbe_menu,ID2P(LANG_PBE), NULL, Icon_NOICON,
|
||||||
|
&pbe,&pbe_precut);
|
||||||
|
MENUITEM_SETTING(surround_enabled,
|
||||||
|
&global_settings.surround_enabled, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(surround_balance,
|
||||||
|
&global_settings.surround_balance, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(surround_fx1,
|
||||||
|
&global_settings.surround_fx1, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(surround_fx2,
|
||||||
|
&global_settings.surround_fx2, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(surround_method2,
|
||||||
|
&global_settings.surround_method2, lowlatency_callback);
|
||||||
|
MENUITEM_SETTING(surround_mix,
|
||||||
|
&global_settings.surround_mix, lowlatency_callback);
|
||||||
|
MAKE_MENU(surround_menu,ID2P(LANG_SURROUND), NULL, Icon_NOICON,
|
||||||
|
&surround_enabled,&surround_balance,&surround_fx1,&surround_fx2,&surround_method2,&surround_mix);
|
||||||
|
|
||||||
/* compressor submenu */
|
/* compressor submenu */
|
||||||
MENUITEM_SETTING(compressor_threshold,
|
MENUITEM_SETTING(compressor_threshold,
|
||||||
|
@ -236,6 +258,7 @@ MAKE_MENU(sound_settings, ID2P(LANG_SOUND_SETTINGS), NULL, Icon_Audio,
|
||||||
#endif
|
#endif
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
,&crossfeed_menu, &equalizer_menu, &dithering_enabled
|
,&crossfeed_menu, &equalizer_menu, &dithering_enabled
|
||||||
|
,&surround_menu, &pbe_menu, &afr_enabled
|
||||||
#ifdef HAVE_PITCHCONTROL
|
#ifdef HAVE_PITCHCONTROL
|
||||||
,×tretch_enabled
|
,×tretch_enabled
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1034,6 +1034,13 @@ void settings_apply(bool read_disk)
|
||||||
}
|
}
|
||||||
|
|
||||||
dsp_dither_enable(global_settings.dithering_enabled);
|
dsp_dither_enable(global_settings.dithering_enabled);
|
||||||
|
dsp_surround_set_balance(global_settings.surround_balance);
|
||||||
|
dsp_surround_set_cutoff(global_settings.surround_fx1, global_settings.surround_fx2);
|
||||||
|
dsp_surround_mix(global_settings.surround_mix);
|
||||||
|
dsp_surround_enable(global_settings.surround_enabled);
|
||||||
|
dsp_afr_enable(global_settings.afr_enabled);
|
||||||
|
dsp_pbe_precut(global_settings.pbe_precut);
|
||||||
|
dsp_pbe_enable(global_settings.pbe);
|
||||||
#ifdef HAVE_PITCHCONTROL
|
#ifdef HAVE_PITCHCONTROL
|
||||||
dsp_timestretch_enable(global_settings.timestretch_enabled);
|
dsp_timestretch_enable(global_settings.timestretch_enabled);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -838,6 +838,18 @@ struct user_settings
|
||||||
int play_frequency; /* core audio output frequency selection */
|
int play_frequency; /* core audio output frequency selection */
|
||||||
#endif
|
#endif
|
||||||
int volume_limit; /* maximum volume limit */
|
int volume_limit; /* maximum volume limit */
|
||||||
|
|
||||||
|
int surround_enabled;
|
||||||
|
int surround_balance;
|
||||||
|
int surround_fx1;
|
||||||
|
int surround_fx2;
|
||||||
|
bool surround_method2;
|
||||||
|
int surround_mix;
|
||||||
|
|
||||||
|
int pbe;
|
||||||
|
int pbe_precut;
|
||||||
|
|
||||||
|
int afr_enabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** global variables **/
|
/** global variables **/
|
||||||
|
|
|
@ -446,6 +446,12 @@ static void crossfeed_cross_set(int val)
|
||||||
global_settings.crossfeed_hf_cutoff);
|
global_settings.crossfeed_hf_cutoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void surround_set_factor(int val)
|
||||||
|
{
|
||||||
|
(void)val;
|
||||||
|
dsp_surround_set_cutoff(global_settings.surround_fx1, global_settings.surround_fx2);
|
||||||
|
}
|
||||||
|
|
||||||
static void compressor_set(int val)
|
static void compressor_set(int val)
|
||||||
{
|
{
|
||||||
(void)val;
|
(void)val;
|
||||||
|
@ -1667,7 +1673,44 @@ const struct settings_list settings[] = {
|
||||||
/* dithering */
|
/* dithering */
|
||||||
OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false,
|
OFFON_SETTING(F_SOUNDSETTING, dithering_enabled, LANG_DITHERING, false,
|
||||||
"dithering enabled", dsp_dither_enable),
|
"dithering enabled", dsp_dither_enable),
|
||||||
|
/* surround */
|
||||||
|
TABLE_SETTING(F_SOUNDSETTING, surround_enabled,
|
||||||
|
LANG_SURROUND, 0, "surround enabled", "off",
|
||||||
|
UNIT_MS, formatter_unit_0_is_off, getlang_unit_0_is_off,
|
||||||
|
dsp_surround_enable, 6,
|
||||||
|
0,5,8,10,15,30),
|
||||||
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, surround_balance,
|
||||||
|
LANG_BALANCE, 35,
|
||||||
|
"surround balance", UNIT_PERCENT, 0, 99,
|
||||||
|
1, NULL, NULL, dsp_surround_set_balance),
|
||||||
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, surround_fx1,
|
||||||
|
LANG_SURROUND_FX1, 3400,
|
||||||
|
"surround_fx1", UNIT_HERTZ, 600, 8000,
|
||||||
|
200, NULL, NULL, surround_set_factor),
|
||||||
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, surround_fx2,
|
||||||
|
LANG_SURROUND_FX2, 320,
|
||||||
|
"surround_fx2", UNIT_HERTZ, 40, 400,
|
||||||
|
40, NULL, NULL, surround_set_factor),
|
||||||
|
OFFON_SETTING(F_SOUNDSETTING, surround_method2, LANG_SURROUND_METHOD2, false,
|
||||||
|
"side only", dsp_surround_side_only),
|
||||||
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, surround_mix,
|
||||||
|
LANG_SURROUND_MIX, 50,
|
||||||
|
"surround mix", UNIT_PERCENT, 0, 100,
|
||||||
|
5, NULL, NULL, dsp_surround_mix),
|
||||||
|
/* auditory fatigue reduction */
|
||||||
|
CHOICE_SETTING(F_SOUNDSETTING|F_NO_WRAP, afr_enabled,
|
||||||
|
LANG_AFR, 0,"afr enabled",
|
||||||
|
"off,weak,moderate,strong", dsp_afr_enable, 4,
|
||||||
|
ID2P(LANG_OFF), ID2P(LANG_WEAK),ID2P(LANG_MODERATE),ID2P(LANG_STRONG)),
|
||||||
|
/* PBE */
|
||||||
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, pbe,
|
||||||
|
LANG_PBE, 0,
|
||||||
|
"pbe", UNIT_PERCENT, 0, 100,
|
||||||
|
25, NULL, NULL, dsp_pbe_enable),
|
||||||
|
INT_SETTING_NOWRAP(F_SOUNDSETTING, pbe_precut,
|
||||||
|
LANG_EQUALIZER_PRECUT, -25,
|
||||||
|
"pbe precut", UNIT_DB, -45, 0,
|
||||||
|
1, db_format, NULL, dsp_pbe_precut),
|
||||||
#ifdef HAVE_PITCHCONTROL
|
#ifdef HAVE_PITCHCONTROL
|
||||||
/* timestretch */
|
/* timestretch */
|
||||||
OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false,
|
OFFON_SETTING(F_SOUNDSETTING, timestretch_enabled, LANG_TIMESTRETCH, false,
|
||||||
|
|
|
@ -7,6 +7,9 @@ dsp/channel_mode.c
|
||||||
dsp/compressor.c
|
dsp/compressor.c
|
||||||
dsp/crossfeed.c
|
dsp/crossfeed.c
|
||||||
dsp/dsp_core.c
|
dsp/dsp_core.c
|
||||||
|
dsp/pbe.c
|
||||||
|
dsp/afr.c
|
||||||
|
dsp/surround.c
|
||||||
dsp/dsp_filter.c
|
dsp/dsp_filter.c
|
||||||
dsp/dsp_misc.c
|
dsp/dsp_misc.c
|
||||||
dsp/dsp_sample_input.c
|
dsp/dsp_sample_input.c
|
||||||
|
|
147
lib/rbcodec/dsp/afr.c
Normal file
147
lib/rbcodec/dsp/afr.c
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Chiwen Chang
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "afr.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "fixedpoint.h"
|
||||||
|
#include "fracmul.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "dsp_proc_entry.h"
|
||||||
|
#include "dsp_filter.h"
|
||||||
|
|
||||||
|
/* Auditory fatigue reduction */
|
||||||
|
|
||||||
|
static int afr_strength = 0;
|
||||||
|
static struct dsp_filter afr_filters[4];
|
||||||
|
|
||||||
|
static void dsp_afr_flush(void)
|
||||||
|
{
|
||||||
|
for (int i = 0 ;i < 4;i++)
|
||||||
|
filter_flush(&afr_filters[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strength_update(unsigned int fout)
|
||||||
|
{
|
||||||
|
int hs=0, ls=0, drop3k=0;
|
||||||
|
|
||||||
|
switch (afr_strength)
|
||||||
|
{
|
||||||
|
/* not called if afr_strength == 0 (disabled) */
|
||||||
|
case 1:
|
||||||
|
hs=-29; ls=0; drop3k=-13;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
hs=-58; ls=-5; drop3k=-29;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
hs=-72; ls=-5; drop3k=-48;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter_bishelf_coefs(fp_div(8000, fout, 32),
|
||||||
|
fp_div(20000, fout, 32),
|
||||||
|
0, (hs/2), 0,
|
||||||
|
&afr_filters[0]);
|
||||||
|
|
||||||
|
filter_pk_coefs(fp_div(8000, fout, 32), 28, hs,
|
||||||
|
&afr_filters[1]);
|
||||||
|
|
||||||
|
filter_pk_coefs(fp_div(3150, fout, 32), 28, drop3k,
|
||||||
|
&afr_filters[2]);
|
||||||
|
|
||||||
|
filter_bishelf_coefs(fp_div(200, fout, 32),
|
||||||
|
fp_div(1280, fout, 32),
|
||||||
|
ls, 0, 0,
|
||||||
|
&afr_filters[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_afr_enable(int var)
|
||||||
|
{
|
||||||
|
if (var == afr_strength)
|
||||||
|
return; /* No setting change */
|
||||||
|
|
||||||
|
bool was_enabled = afr_strength > 0;
|
||||||
|
afr_strength = var;
|
||||||
|
|
||||||
|
bool now_enabled = var > 0;
|
||||||
|
|
||||||
|
if (was_enabled == now_enabled && !now_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If changing status, enable or disable it; if already enabled push
|
||||||
|
additional DSP_PROC_INIT messages with value = 1 to force-update the
|
||||||
|
filters */
|
||||||
|
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
|
||||||
|
dsp_proc_enable(dsp, DSP_PROC_AFR, now_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void afr_reduce_process(struct dsp_proc_entry *this,
|
||||||
|
struct dsp_buffer **buf_p)
|
||||||
|
{
|
||||||
|
struct dsp_buffer *buf = *buf_p;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
filter_process(&afr_filters[i], buf->p32, buf->remcount,
|
||||||
|
buf->format.num_channels);
|
||||||
|
|
||||||
|
(void)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DSP message hook */
|
||||||
|
static intptr_t afr_configure(struct dsp_proc_entry *this,
|
||||||
|
struct dsp_config *dsp,
|
||||||
|
unsigned int setting,
|
||||||
|
intptr_t value)
|
||||||
|
{
|
||||||
|
/* This only attaches to the audio (codec) DSP */
|
||||||
|
|
||||||
|
switch (setting)
|
||||||
|
{
|
||||||
|
case DSP_PROC_INIT:
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
/* Coming online; was disabled */
|
||||||
|
this->process = afr_reduce_process;
|
||||||
|
dsp_afr_flush();
|
||||||
|
dsp_proc_activate(dsp, DSP_PROC_AFR, true);
|
||||||
|
}
|
||||||
|
/* else additional forced messages */
|
||||||
|
|
||||||
|
strength_update(dsp_get_output_frequency(dsp));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSP_FLUSH:
|
||||||
|
/* Discontinuity; clear filters */
|
||||||
|
dsp_afr_flush();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSP_SET_OUT_FREQUENCY:
|
||||||
|
/* New output frequency */
|
||||||
|
strength_update(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Database entry */
|
||||||
|
DSP_PROC_DB_ENTRY(
|
||||||
|
AFR,
|
||||||
|
afr_configure);
|
27
lib/rbcodec/dsp/afr.h
Normal file
27
lib/rbcodec/dsp/afr.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Chiwen Chang
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef AFR_H
|
||||||
|
#define AFR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
void dsp_afr_enable(int var);
|
||||||
|
|
||||||
|
#endif /* AFR_H */
|
|
@ -72,7 +72,7 @@ void filter_shelf_coefs(unsigned long cutoff, long A, bool low, int32_t *c)
|
||||||
*c++ = -FRACMUL_SHL(a1, rcp_a0, 1); /* -1 .. 1 */
|
*c++ = -FRACMUL_SHL(a1, rcp_a0, 1); /* -1 .. 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_SW_TONE_CONTROLS
|
|
||||||
/**
|
/**
|
||||||
* Calculate second order section filter consisting of one low-shelf and one
|
* Calculate second order section filter consisting of one low-shelf and one
|
||||||
* high-shelf section.
|
* high-shelf section.
|
||||||
|
@ -114,7 +114,7 @@ void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high,
|
||||||
|
|
||||||
f->shift = FILTER_BISHELF_SHIFT;
|
f->shift = FILTER_BISHELF_SHIFT;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_SW_TONE_CONTROLS */
|
|
||||||
|
|
||||||
/* 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()
|
||||||
|
@ -303,3 +303,23 @@ void filter_process(struct dsp_filter *f, int32_t * const buf[], int count,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CPU */
|
#endif /* CPU */
|
||||||
|
|
||||||
|
/* ring buffer */
|
||||||
|
int32_t dequeue(int32_t* buffer, int *head, int boundary)
|
||||||
|
{
|
||||||
|
int32_t var = buffer[*head];
|
||||||
|
if (*head +1 >= boundary)
|
||||||
|
*head = 0;
|
||||||
|
else
|
||||||
|
*head += 1;
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enqueue(int32_t var, int32_t* buffer, int *head, int boundary)
|
||||||
|
{
|
||||||
|
buffer[*head] = var;
|
||||||
|
if (*head +1 >= boundary)
|
||||||
|
*head = 0;
|
||||||
|
else
|
||||||
|
*head += 1;
|
||||||
|
}
|
||||||
|
|
|
@ -37,12 +37,10 @@ struct dsp_filter
|
||||||
};
|
};
|
||||||
|
|
||||||
void filter_shelf_coefs(unsigned long cutoff, long A, bool low, int32_t *c);
|
void filter_shelf_coefs(unsigned long cutoff, long A, bool low, int32_t *c);
|
||||||
#ifdef HAVE_SW_TONE_CONTROLS
|
|
||||||
void filter_bishelf_coefs(unsigned long cutoff_low,
|
void filter_bishelf_coefs(unsigned long cutoff_low,
|
||||||
unsigned long cutoff_high,
|
unsigned long cutoff_high,
|
||||||
long A_low, long A_high, long A,
|
long A_low, long A_high, long A,
|
||||||
struct dsp_filter *f);
|
struct dsp_filter *f);
|
||||||
#endif /* HAVE_SW_TONE_CONTROLS */
|
|
||||||
void filter_pk_coefs(unsigned long cutoff, unsigned long Q, long db,
|
void filter_pk_coefs(unsigned long cutoff, unsigned long Q, long db,
|
||||||
struct dsp_filter *f);
|
struct dsp_filter *f);
|
||||||
void filter_ls_coefs(unsigned long cutoff, unsigned long Q, long db,
|
void filter_ls_coefs(unsigned long cutoff, unsigned long Q, long db,
|
||||||
|
@ -53,5 +51,7 @@ void filter_copy(struct dsp_filter *dst, const struct dsp_filter *src);
|
||||||
void filter_flush(struct dsp_filter *f);
|
void filter_flush(struct dsp_filter *f);
|
||||||
void filter_process(struct dsp_filter *f, int32_t * const buf[], int count,
|
void filter_process(struct dsp_filter *f, int32_t * const buf[], int count,
|
||||||
unsigned int channels);
|
unsigned int channels);
|
||||||
|
/* ring buffer */
|
||||||
|
void enqueue(int32_t var, int32_t* buffer, int *head, int boundary);
|
||||||
|
int32_t dequeue(int32_t* buffer, int *head, int boundary);
|
||||||
#endif /* DSP_FILTER_H */
|
#endif /* DSP_FILTER_H */
|
||||||
|
|
|
@ -46,6 +46,9 @@ DSP_PROC_DB_START
|
||||||
#ifdef HAVE_SW_TONE_CONTROLS
|
#ifdef HAVE_SW_TONE_CONTROLS
|
||||||
DSP_PROC_DB_ITEM(TONE_CONTROLS) /* bass and treble */
|
DSP_PROC_DB_ITEM(TONE_CONTROLS) /* bass and treble */
|
||||||
#endif
|
#endif
|
||||||
|
DSP_PROC_DB_ITEM(PBE) /* perceptual bass enhancement */
|
||||||
|
DSP_PROC_DB_ITEM(AFR) /* auditory fatigue reduction */
|
||||||
|
DSP_PROC_DB_ITEM(SURROUND) /* haas surround */
|
||||||
DSP_PROC_DB_ITEM(CHANNEL_MODE) /* channel modes */
|
DSP_PROC_DB_ITEM(CHANNEL_MODE) /* channel modes */
|
||||||
DSP_PROC_DB_ITEM(COMPRESSOR) /* dynamic-range compressor */
|
DSP_PROC_DB_ITEM(COMPRESSOR) /* dynamic-range compressor */
|
||||||
DSP_PROC_DB_STOP
|
DSP_PROC_DB_STOP
|
||||||
|
|
|
@ -28,6 +28,9 @@
|
||||||
#include "dsp_misc.h"
|
#include "dsp_misc.h"
|
||||||
#include "eq.h"
|
#include "eq.h"
|
||||||
#include "pga.h"
|
#include "pga.h"
|
||||||
|
#include "surround.h"
|
||||||
|
#include "afr.h"
|
||||||
|
#include "pbe.h"
|
||||||
#ifdef HAVE_PITCHCONTROL
|
#ifdef HAVE_PITCHCONTROL
|
||||||
#include "tdspeed.h"
|
#include "tdspeed.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
251
lib/rbcodec/dsp/pbe.c
Normal file
251
lib/rbcodec/dsp/pbe.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Chiwen Chang
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "config.h"
|
||||||
|
#include "fixedpoint.h"
|
||||||
|
#include "fracmul.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "dsp_proc_entry.h"
|
||||||
|
#include "dsp_misc.h"
|
||||||
|
#include "dsp_filter.h"
|
||||||
|
#include "core_alloc.h"
|
||||||
|
|
||||||
|
/* Perceptual bass enhancement */
|
||||||
|
|
||||||
|
#define B3_DLY 72 /* ~800 uS */
|
||||||
|
#define B2_DLY 180 /* ~2000 uS*/
|
||||||
|
#define B0_DLY 276 /* ~3050 uS */
|
||||||
|
|
||||||
|
#define B3_SIZE (B3_DLY+1)
|
||||||
|
#define B2_SIZE (B2_DLY+1)
|
||||||
|
#define B0_SIZE (B0_DLY+1)
|
||||||
|
|
||||||
|
static int pbe_strength = 100;
|
||||||
|
static int pbe_precut = 0;
|
||||||
|
static int32_t tcoef1, tcoef2, tcoef3;
|
||||||
|
static int32_t *b0[2], *b2[2], *b3[2];
|
||||||
|
static int b0_r[2],b2_r[2],b3_r[2],b0_w[2],b2_w[2],b3_w[2];
|
||||||
|
int32_t temp_buffer;
|
||||||
|
static struct dsp_filter pbe_filter[5];
|
||||||
|
static int handle = -1;
|
||||||
|
|
||||||
|
static void pbe_buffer_alloc(void)
|
||||||
|
{
|
||||||
|
if (handle > 0)
|
||||||
|
return; /* already-allocated */
|
||||||
|
|
||||||
|
unsigned int total_len = (B0_SIZE + B2_SIZE + B3_SIZE) * 2;
|
||||||
|
handle = core_alloc("dsp_pbe_buffer",sizeof(int32_t) * total_len);
|
||||||
|
|
||||||
|
if (handle < 0)
|
||||||
|
{
|
||||||
|
pbe_strength = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(core_get_data(handle),0,sizeof(int32_t) * total_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbe_buffer_get_data(void)
|
||||||
|
{
|
||||||
|
if (handle < 0)
|
||||||
|
return;
|
||||||
|
b0[0] = core_get_data(handle);
|
||||||
|
b0[1] = b0[0] + B0_SIZE;
|
||||||
|
b2[0] = b0[1] + B0_SIZE;
|
||||||
|
b2[1] = b2[0] + B2_SIZE;
|
||||||
|
b3[0] = b2[1] + B2_SIZE;
|
||||||
|
b3[1] = b3[0] + B3_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsp_pbe_flush(void)
|
||||||
|
{
|
||||||
|
if (pbe_strength == 0)
|
||||||
|
return; /* Not currently enabled */
|
||||||
|
|
||||||
|
pbe_buffer_get_data();
|
||||||
|
|
||||||
|
memset(b0[0], 0, B0_DLY * sizeof(int32_t));
|
||||||
|
memset(b0[1], 0, B0_DLY * sizeof(int32_t));
|
||||||
|
memset(b2[0], 0, B2_DLY * sizeof(int32_t));
|
||||||
|
memset(b2[1], 0, B2_DLY * sizeof(int32_t));
|
||||||
|
memset(b3[0], 0, B3_DLY * sizeof(int32_t));
|
||||||
|
memset(b3[1], 0, B3_DLY * sizeof(int32_t));
|
||||||
|
b0_r[0] = 0; b0_w[0] = B0_DLY;
|
||||||
|
b0_r[1] = 0; b0_w[1] = B0_DLY;
|
||||||
|
b2_r[0] = 0; b2_w[0] = B2_DLY;
|
||||||
|
b2_r[1] = 0; b2_w[1] = B2_DLY;
|
||||||
|
b3_r[0] = 0; b3_w[0] = B3_DLY;
|
||||||
|
b3_r[1] = 0; b3_w[1] = B3_DLY;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
filter_flush(&pbe_filter[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbe_update_filter(unsigned int fout)
|
||||||
|
{
|
||||||
|
tcoef1 = fp_div(160, fout, 31);
|
||||||
|
tcoef2 = fp_div(500, fout, 31);
|
||||||
|
tcoef3 = fp_div(1150, fout, 31);
|
||||||
|
/* Biophonic EQ */
|
||||||
|
filter_bishelf_coefs(fp_div(20, fout, 32),
|
||||||
|
fp_div(16000, fout, 32),
|
||||||
|
0, 53, -5 + pbe_precut,
|
||||||
|
&pbe_filter[0]);
|
||||||
|
filter_pk_coefs(fp_div(64, fout, 32), 28, 53,
|
||||||
|
&pbe_filter[1]);
|
||||||
|
filter_pk_coefs(fp_div(2000, fout, 32), 28, 58,
|
||||||
|
&pbe_filter[2]);
|
||||||
|
filter_pk_coefs(fp_div(7500, fout, 32), 43, -82,
|
||||||
|
&pbe_filter[3]);
|
||||||
|
filter_pk_coefs(fp_div(10000, fout, 32), 43, -29,
|
||||||
|
&pbe_filter[4]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_pbe_precut(int var)
|
||||||
|
{
|
||||||
|
if (var == pbe_precut)
|
||||||
|
return; /* No change */
|
||||||
|
|
||||||
|
pbe_precut = var;
|
||||||
|
|
||||||
|
if (pbe_strength == 0)
|
||||||
|
return; /* Not currently enabled */
|
||||||
|
|
||||||
|
/* Push more DSP_PROC_INIT messages to force filter updates
|
||||||
|
(with value = 1) */
|
||||||
|
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
|
||||||
|
dsp_proc_enable(dsp, DSP_PROC_PBE, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dsp_pbe_enable(int var)
|
||||||
|
{
|
||||||
|
if (var == pbe_strength)
|
||||||
|
return; /* No change */
|
||||||
|
bool was_enabled = pbe_strength > 0;
|
||||||
|
pbe_strength = var;
|
||||||
|
|
||||||
|
bool now_enabled = var > 0;
|
||||||
|
|
||||||
|
if (now_enabled == was_enabled)
|
||||||
|
return; /* No change in enabled status */
|
||||||
|
|
||||||
|
if (now_enabled == false && handle > 0)
|
||||||
|
{
|
||||||
|
core_free(handle);
|
||||||
|
handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
|
||||||
|
dsp_proc_enable(dsp, DSP_PROC_PBE, now_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pbe_process(struct dsp_proc_entry *this,
|
||||||
|
struct dsp_buffer **buf_p)
|
||||||
|
{
|
||||||
|
struct dsp_buffer *buf = *buf_p;
|
||||||
|
int count = buf->remcount;
|
||||||
|
int num_channels = buf->format.num_channels;
|
||||||
|
int b2_level = (B2_DLY * pbe_strength) / 100;
|
||||||
|
int b0_level = (B0_DLY * pbe_strength) / 100;
|
||||||
|
int32_t x;
|
||||||
|
|
||||||
|
pbe_buffer_get_data();
|
||||||
|
|
||||||
|
for(int ch = 0; ch < num_channels; ch++)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
/* 160hz - 500hz no delay */
|
||||||
|
temp_buffer = FRACMUL(buf->p32[ch][i], tcoef1) -
|
||||||
|
FRACMUL(buf->p32[ch][i], tcoef2);
|
||||||
|
|
||||||
|
/* delay below 160hz*/
|
||||||
|
x = buf->p32[ch][i] -
|
||||||
|
FRACMUL(buf->p32[ch][i], tcoef1);
|
||||||
|
temp_buffer += dequeue(b0[ch], &b0_r[ch], b0_level);
|
||||||
|
enqueue(x, b0[ch], &b0_w[ch], b0_level );
|
||||||
|
|
||||||
|
/* delay 500-1150hz */
|
||||||
|
x = FRACMUL(buf->p32[ch][i], tcoef2) -
|
||||||
|
FRACMUL(buf->p32[ch][i], tcoef3);
|
||||||
|
temp_buffer += dequeue(b2[ch], &b2_r[ch], b2_level);
|
||||||
|
enqueue(x, b2[ch], &b2_w[ch], b2_level );
|
||||||
|
|
||||||
|
/* delay anything beyond 1150hz */
|
||||||
|
x = FRACMUL(buf->p32[ch][i], tcoef3);
|
||||||
|
temp_buffer += dequeue(b3[ch], &b3_r[ch], B3_DLY);
|
||||||
|
enqueue(x, b3[ch], &b3_w[ch], B3_DLY );
|
||||||
|
|
||||||
|
buf->p32[ch][i] = temp_buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* apply Biophonic EQ */
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
filter_process(&pbe_filter[i], buf->p32, buf->remcount,
|
||||||
|
buf->format.num_channels);
|
||||||
|
|
||||||
|
(void)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DSP message hook */
|
||||||
|
static intptr_t pbe_configure(struct dsp_proc_entry *this,
|
||||||
|
struct dsp_config *dsp,
|
||||||
|
unsigned int setting,
|
||||||
|
intptr_t value)
|
||||||
|
{
|
||||||
|
/* This only attaches to the audio (codec) DSP */
|
||||||
|
|
||||||
|
switch (setting)
|
||||||
|
{
|
||||||
|
case DSP_PROC_INIT:
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
/* Coming online; was disabled */
|
||||||
|
this->process = pbe_process;
|
||||||
|
pbe_buffer_alloc();
|
||||||
|
dsp_pbe_flush();
|
||||||
|
dsp_proc_activate(dsp, DSP_PROC_PBE, true);
|
||||||
|
}
|
||||||
|
/* else additional forced messages */
|
||||||
|
|
||||||
|
pbe_update_filter(dsp_get_output_frequency(dsp));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSP_FLUSH:
|
||||||
|
/* Discontinuity; clear filters */
|
||||||
|
dsp_pbe_flush();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DSP_SET_OUT_FREQUENCY:
|
||||||
|
/* New output frequency */
|
||||||
|
pbe_update_filter(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Database entry */
|
||||||
|
DSP_PROC_DB_ENTRY(
|
||||||
|
PBE,
|
||||||
|
pbe_configure);
|
29
lib/rbcodec/dsp/pbe.h
Normal file
29
lib/rbcodec/dsp/pbe.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Chiwen Chang
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef PBE_H
|
||||||
|
#define PBE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
void dsp_pbe_enable(int var);
|
||||||
|
void dsp_pbe_precut(int var);
|
||||||
|
|
||||||
|
#endif /* PBE_H */
|
||||||
|
|
333
lib/rbcodec/dsp/surround.c
Normal file
333
lib/rbcodec/dsp/surround.c
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Chiwen Chang
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "surround.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "fixedpoint.h"
|
||||||
|
#include "fracmul.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "dsp_proc_entry.h"
|
||||||
|
#include "dsp_filter.h"
|
||||||
|
#include "core_alloc.h"
|
||||||
|
|
||||||
|
static bool surround_enabled = false;
|
||||||
|
static int surround_balance = 0;
|
||||||
|
static bool surround_side_only = false;
|
||||||
|
static int surround_mix = 100;
|
||||||
|
static int surround_strength = 0;
|
||||||
|
/*1 sample ~ 11ns */
|
||||||
|
#define DLY_5MS 454
|
||||||
|
#define DLY_8MS 727
|
||||||
|
#define DLY_10MS 909
|
||||||
|
#define DLY_15MS 1363
|
||||||
|
#define DLY_30MS 2727
|
||||||
|
#define MAX_DLY DLY_30MS
|
||||||
|
|
||||||
|
#define B0_DLY (MAX_DLY/8 + 1)
|
||||||
|
#define B2_DLY (MAX_DLY + 1)
|
||||||
|
#define BB_DLY (MAX_DLY/4 + 1)
|
||||||
|
#define HH_DLY (MAX_DLY/2 + 1)
|
||||||
|
#define CL_DLY B2_DLY
|
||||||
|
/*only need to buffer right channel */
|
||||||
|
static int32_t *b0, *b2, *bb, *hh, *cl;
|
||||||
|
static int32_t temp_buffer[2];
|
||||||
|
static int32_t mid, side;
|
||||||
|
|
||||||
|
/*voice from 300hz - 3400hz ?*/
|
||||||
|
static int32_t tcoef1,tcoef2,bcoef,hcoef;
|
||||||
|
|
||||||
|
static int dly_size = MAX_DLY;
|
||||||
|
static int cutoff_l = 320;
|
||||||
|
static int cutoff_h = 3400;
|
||||||
|
|
||||||
|
static int b0_r=0,b0_w=0,
|
||||||
|
b2_r=0,b2_w=0,
|
||||||
|
bb_r=0,bb_w=0,
|
||||||
|
hh_r=0,hh_w=0,
|
||||||
|
cl_r=0,cl_w=0;
|
||||||
|
static int handle = -1;
|
||||||
|
|
||||||
|
static void surround_buffer_alloc(void)
|
||||||
|
{
|
||||||
|
if (handle > 0)
|
||||||
|
return; /* already-allocated */
|
||||||
|
|
||||||
|
unsigned int total_len = B0_DLY + B2_DLY + BB_DLY + HH_DLY + CL_DLY;
|
||||||
|
handle = core_alloc("dsp_surround_buffer",sizeof(int32_t) * total_len);
|
||||||
|
|
||||||
|
if (handle < 0)
|
||||||
|
{
|
||||||
|
surround_enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(core_get_data(handle),0,sizeof(int32_t) * total_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void surround_buffer_get_data(void)
|
||||||
|
{
|
||||||
|
if (handle < 0)
|
||||||
|
return;
|
||||||
|
b0 = core_get_data(handle);
|
||||||
|
b2 = b0 + B0_DLY;
|
||||||
|
bb = b2 + B2_DLY;
|
||||||
|
hh = bb + BB_DLY;
|
||||||
|
cl = hh + HH_DLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsp_surround_flush(void)
|
||||||
|
{
|
||||||
|
if (!surround_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
surround_buffer_get_data();
|
||||||
|
|
||||||
|
memset(b0,0,MAX_DLY/8 * sizeof(int32_t));
|
||||||
|
memset(b2,0,MAX_DLY * sizeof(int32_t));
|
||||||
|
memset(bb,0,MAX_DLY/4 * sizeof(int32_t));
|
||||||
|
memset(hh,0,MAX_DLY/2 * sizeof(int32_t));
|
||||||
|
memset(cl,0,MAX_DLY * sizeof(int32_t));
|
||||||
|
b0_r = 0;b0_w = dly_size/8 - 1;
|
||||||
|
b2_r = 0;b2_w = dly_size - 1;
|
||||||
|
bb_r = 0;bb_w = dly_size/4 - 1;
|
||||||
|
hh_r = 0;hh_w = dly_size/2 - 1;
|
||||||
|
cl_r = 0;cl_w = dly_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void surround_update_filter(unsigned int fout)
|
||||||
|
{
|
||||||
|
tcoef1 = fp_div(cutoff_l, fout, 31);
|
||||||
|
tcoef2 = fp_div(cutoff_h, fout, 31);
|
||||||
|
bcoef = fp_div(cutoff_l / 2, fout, 31);
|
||||||
|
hcoef = fp_div(cutoff_h * 2, fout, 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_surround_set_balance(int var)
|
||||||
|
{
|
||||||
|
surround_balance = var;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_surround_side_only(bool var)
|
||||||
|
{
|
||||||
|
dsp_surround_flush();
|
||||||
|
surround_side_only = var;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_surround_mix(int var)
|
||||||
|
{
|
||||||
|
surround_mix = var;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_surround_set_cutoff(int frq_l, int frq_h)
|
||||||
|
{
|
||||||
|
cutoff_l = frq_l;/*fx2*/
|
||||||
|
cutoff_h = frq_h;/*fx1*/
|
||||||
|
|
||||||
|
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
|
||||||
|
unsigned int fout = dsp_get_output_frequency(dsp);
|
||||||
|
surround_update_filter(fout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void surround_set_stepsize(int surround_strength)
|
||||||
|
{
|
||||||
|
dsp_surround_flush();
|
||||||
|
switch(surround_strength)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
dly_size = DLY_5MS;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
dly_size = DLY_8MS;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
dly_size = DLY_10MS;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
dly_size = DLY_15MS;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
dly_size = DLY_30MS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dsp_surround_enable(int var)
|
||||||
|
{
|
||||||
|
if (var == surround_strength)
|
||||||
|
return; /* No setting change */
|
||||||
|
|
||||||
|
bool was_enabled = surround_strength > 0;
|
||||||
|
surround_strength = var;
|
||||||
|
surround_set_stepsize(surround_strength);
|
||||||
|
|
||||||
|
bool now_enabled = var > 0;
|
||||||
|
|
||||||
|
if (was_enabled == now_enabled && !now_enabled)
|
||||||
|
return; /* No change in enabled status */
|
||||||
|
|
||||||
|
if (now_enabled == false && handle > 0)
|
||||||
|
{
|
||||||
|
core_free(handle);
|
||||||
|
handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
|
||||||
|
dsp_proc_enable(dsp, DSP_PROC_SURROUND, now_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void surround_process(struct dsp_proc_entry *this,
|
||||||
|
struct dsp_buffer **buf_p)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct dsp_buffer *buf = *buf_p;
|
||||||
|
int count = buf->remcount;
|
||||||
|
|
||||||
|
int dly_shift3 = dly_size/8;
|
||||||
|
int dly_shift2 = dly_size/4;
|
||||||
|
int dly_shift1 = dly_size/2;
|
||||||
|
int dly = dly_size;
|
||||||
|
int i;
|
||||||
|
int32_t x;
|
||||||
|
|
||||||
|
surround_buffer_get_data();
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
mid = buf->p32[0][i] /2 + buf->p32[1][i] /2;
|
||||||
|
side = buf->p32[0][i] - buf->p32[1][i];
|
||||||
|
|
||||||
|
if (!surround_side_only)
|
||||||
|
{
|
||||||
|
/*clone the left channal*/
|
||||||
|
temp_buffer[0]= buf->p32[0][i];
|
||||||
|
/*keep the middle band of right channel*/
|
||||||
|
temp_buffer[1]= FRACMUL(buf->p32[1][i], tcoef1) -
|
||||||
|
FRACMUL(buf->p32[1][i], tcoef2);
|
||||||
|
}
|
||||||
|
else /* apply haas to side only*/
|
||||||
|
{
|
||||||
|
temp_buffer[0] = side / 2;
|
||||||
|
temp_buffer[1] = FRACMUL(-side,tcoef1)/2 -
|
||||||
|
FRACMUL(-side, tcoef2)/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inverted crossfeed delay (left channel) to make sound wider*/
|
||||||
|
x = temp_buffer[1]/100 * 35;
|
||||||
|
temp_buffer[0] += dequeue(cl, &cl_r, dly);
|
||||||
|
enqueue(-x, cl, &cl_w, dly);
|
||||||
|
|
||||||
|
/* apply 1/8 delay to frequency below fx2 */
|
||||||
|
x = buf->p32[1][i] - FRACMUL(buf->p32[1][i], tcoef1);
|
||||||
|
temp_buffer[1] += dequeue(b0, &b0_r, dly_shift3);
|
||||||
|
enqueue(x, b0, &b0_w, dly_shift3 );
|
||||||
|
|
||||||
|
/* cut frequency below half fx2*/
|
||||||
|
temp_buffer[1] = FRACMUL(temp_buffer[1], bcoef);
|
||||||
|
|
||||||
|
/* apply 1/4 delay to frequency below half fx2 */
|
||||||
|
/* use different delay to fake the sound direction*/
|
||||||
|
x = buf->p32[1][i] - FRACMUL(buf->p32[1][i], bcoef);
|
||||||
|
temp_buffer[1] += dequeue(bb, &bb_r, dly_shift2);
|
||||||
|
enqueue(x, bb, &bb_w, dly_shift2 );
|
||||||
|
|
||||||
|
/* apply full delay to higher band */
|
||||||
|
x = FRACMUL(buf->p32[1][i], tcoef2);
|
||||||
|
temp_buffer[1] += dequeue(b2, &b2_r, dly);
|
||||||
|
enqueue(x, b2, &b2_w, dly );
|
||||||
|
|
||||||
|
/* do the same direction trick again */
|
||||||
|
temp_buffer[1] -= FRACMUL(temp_buffer[1], hcoef);
|
||||||
|
|
||||||
|
x = FRACMUL(buf->p32[1][i], hcoef);
|
||||||
|
temp_buffer[1] += dequeue(hh, &hh_r, dly_shift1);
|
||||||
|
enqueue(x, hh, &hh_w, dly_shift1 );
|
||||||
|
/*balance*/
|
||||||
|
if (surround_balance > 0 && !surround_side_only)
|
||||||
|
{
|
||||||
|
temp_buffer[0] -= temp_buffer[0]/200 * surround_balance;
|
||||||
|
temp_buffer[1] += temp_buffer[1]/200 * surround_balance;
|
||||||
|
}
|
||||||
|
else if (surround_balance > 0)
|
||||||
|
{
|
||||||
|
temp_buffer[0] += temp_buffer[0]/200 * surround_balance;
|
||||||
|
temp_buffer[1] -= temp_buffer[1]/200 * surround_balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surround_side_only)
|
||||||
|
{
|
||||||
|
temp_buffer[0] += mid;
|
||||||
|
temp_buffer[1] += mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surround_mix == 100)
|
||||||
|
{
|
||||||
|
buf->p32[0][i] = temp_buffer[0];
|
||||||
|
buf->p32[1][i] = temp_buffer[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*dry wet mix*/
|
||||||
|
buf->p32[0][i] = buf->p32[0][i]/100 * (100-surround_mix) +
|
||||||
|
temp_buffer[0]/100 * surround_mix;
|
||||||
|
buf->p32[1][i] = buf->p32[1][i]/100 * (100-surround_mix) +
|
||||||
|
temp_buffer[1]/100 * surround_mix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void)this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DSP message hook */
|
||||||
|
static intptr_t surround_configure(struct dsp_proc_entry *this,
|
||||||
|
struct dsp_config *dsp,
|
||||||
|
unsigned int setting,
|
||||||
|
intptr_t value)
|
||||||
|
{
|
||||||
|
unsigned int fout = dsp_get_output_frequency(dsp);
|
||||||
|
switch (setting)
|
||||||
|
{
|
||||||
|
case DSP_PROC_INIT:
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
this->process = surround_process;
|
||||||
|
surround_buffer_alloc();
|
||||||
|
dsp_surround_flush();
|
||||||
|
dsp_proc_activate(dsp, DSP_PROC_SURROUND, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
surround_update_filter(fout);
|
||||||
|
break;
|
||||||
|
case DSP_FLUSH:
|
||||||
|
dsp_surround_flush();
|
||||||
|
break;
|
||||||
|
case DSP_SET_OUT_FREQUENCY:
|
||||||
|
surround_update_filter(value);
|
||||||
|
break;
|
||||||
|
case DSP_PROC_CLOSE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
(void)dsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Database entry */
|
||||||
|
DSP_PROC_DB_ENTRY(
|
||||||
|
SURROUND,
|
||||||
|
surround_configure);
|
||||||
|
|
31
lib/rbcodec/dsp/surround.h
Normal file
31
lib/rbcodec/dsp/surround.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 by Chiwen Chang
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef SURROUND_H
|
||||||
|
#define SURROUND_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
void dsp_surround_enable(int var);
|
||||||
|
void dsp_surround_set_balance(int var);
|
||||||
|
void dsp_surround_set_cutoff(int frq_l, int frq_h);
|
||||||
|
void dsp_surround_side_only(bool var);
|
||||||
|
void dsp_surround_mix(int var);
|
||||||
|
|
||||||
|
#endif /* SURROUND_H */
|
|
@ -590,6 +590,33 @@ details about how to use the feature.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
\opt{swcodec}{
|
||||||
|
\section{Haas Surround}
|
||||||
|
This setting does Haas effect with adjustable delay time to enhance the stereo stage
|
||||||
|
of the sound. A full range haas effect may sounds like everything starts from left channel ends at right.
|
||||||
|
Therefore, four additional functions are provided to move the stage back to the center:
|
||||||
|
First is a \setting{Balance} setting for change left-right channel output ratio. Second
|
||||||
|
is a bypass band for frequency mostly contain vocals, using \setting{f(x1)}, \setting{f(x2)} to reserved the
|
||||||
|
frequncy range. The \setting{SIDE ONLY} setting uses mid-side
|
||||||
|
processing to determine and apply effect to side only. And finally, a \setting{Dry/Wet Mix}
|
||||||
|
to adjust the proportion of mix between the original (dry) and 'effected' (wet) signals.
|
||||||
|
}
|
||||||
|
|
||||||
|
\opt{swcodec}{
|
||||||
|
\section{Perceptual Bass Enhancement}
|
||||||
|
This setting dose a group delay correction and an additional Biophonic EQ to
|
||||||
|
emphasize the clarity of the sounds. The \setting{Precut} setting provides
|
||||||
|
negative overall gain to prevent possible audio distortion due to the EQ
|
||||||
|
gain. The defult precut value is set to -2.5 dB and can be adjust from 0 dB to -4.5 dB.
|
||||||
|
}
|
||||||
|
|
||||||
|
\opt{swcodec}{
|
||||||
|
\section{Auditory Fatigue Reduction}
|
||||||
|
Human hearing are most senstive to some frequency bands, and this setting applies custom presets
|
||||||
|
of equalization and bi-shelf filter to reduce signals in those bands to minimize
|
||||||
|
the chance that temporary threshold shift (Auditory Fatigue) occurs.
|
||||||
|
}
|
||||||
|
|
||||||
\opt{swcodec}{
|
\opt{swcodec}{
|
||||||
\section{Compressor}
|
\section{Compressor}
|
||||||
The \setting{Compressor} reduces, or compresses, the dynamic range of the audio
|
The \setting{Compressor} reduces, or compresses, the dynamic range of the audio
|
||||||
|
|
Loading…
Reference in a new issue