summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp/crossfeed.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/dsp/crossfeed.c')
-rw-r--r--lib/rbcodec/dsp/crossfeed.c117
1 files changed, 79 insertions, 38 deletions
diff --git a/lib/rbcodec/dsp/crossfeed.c b/lib/rbcodec/dsp/crossfeed.c
index 36a98f1..fc40c6b 100644
--- a/lib/rbcodec/dsp/crossfeed.c
+++ b/lib/rbcodec/dsp/crossfeed.c
@@ -24,6 +24,7 @@
#include "fixedpoint.h"
#include "fracmul.h"
#include "replaygain.h"
+#include "dsp_misc.h"
#include "dsp_proc_entry.h"
#include "dsp_filter.h"
#include "crossfeed.h"
@@ -44,32 +45,40 @@ void crossfeed_meier_process(struct dsp_proc_entry *this,
* to listen to on headphones with no crossfeed.
*/
+#define DELAY_LEN(fs) ((300*(fs) / 1000000)*2) /* ~300 uS */
+
/* Crossfeed */
static struct crossfeed_state
{
- int32_t gain; /* 00h: Direct path gain */
- int32_t coefs[3]; /* 04h: Coefficients for the shelving filter */
union
{
- struct /* 10h: Data for meier crossfeed */
+ struct /* Data for meier crossfeed */
{
- int32_t vcl;
- int32_t vcr;
- int32_t vdiff;
- int32_t coef1;
- int32_t coef2;
+ int32_t reserved; /* 00h: Reserved: overlaps gain */
+ int32_t vcl; /* 04h: Left filter output */
+ int32_t vcr; /* 08h: Right filter output */
+ int32_t vdiff; /* 0ch: L-R difference signal */
+ int32_t coef1; /* 10h: Left/right filter coef */
+ int32_t coef2; /* 14h: Crossfeed filter coef */
};
- struct /* 10h: Data for custom crossfeed */
+ struct /* Data for custom crossfeed */
{
+ int32_t gain; /* 00h: Direct path gain */
+ int32_t coefs[3]; /* 04h: Filter coefficients: b0, b1, a1 */
int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */
- int32_t delay[13*2];/* 20h: Delay line buffer (L + R interleaved) */
+ int32_t *index; /* 20h: Current pointer into the delay line */
+ int32_t *index_max; /* 24h: Current max pointer of delay line */
+ /* 28h: Delay line buffer (L + R interleaved) */
+ int32_t delay[DELAY_LEN(DSP_OUT_MAX_HZ)]; /* Target-dependent size */
};
};
- int32_t *index; /* 88h: Current pointer into the delay line */
- /* 8ch */
} crossfeed_state IBSS_ATTR;
static int crossfeed_type = CROSSFEED_TYPE_NONE;
+/* Cached custom settings */
+static long crossfeed_lf_gain;
+static long crossfeed_hf_gain;
+static long crossfeed_cutoff;
/* Discard the sample histories */
static void crossfeed_flush(struct dsp_proc_entry *this)
@@ -82,12 +91,49 @@ static void crossfeed_flush(struct dsp_proc_entry *this)
}
else
{
- memset(state->history, 0,
- sizeof (state->history) + sizeof (state->delay));
+ memset(state->history, 0, sizeof (state->history));
+ memset(state->delay, 0, sizeof (state->delay));
state->index = state->delay;
}
}
+static void crossfeed_meier_update_filter(struct crossfeed_state *state,
+ unsigned int fout)
+{
+ /* 1 / (F.Rforward.C) */
+ state->coef1 = fp_div(2128, fout, 31);
+ /* 1 / (F.Rcross.C) */
+ state->coef2 = fp_div(1000, fout, 31);
+}
+
+static void crossfeed_custom_update_filter(struct crossfeed_state *state,
+ unsigned int fout)
+{
+ long lf_gain = crossfeed_lf_gain;
+ long hf_gain = crossfeed_hf_gain;
+ long cutoff = crossfeed_cutoff;
+ int32_t *c = state->coefs;
+
+ long scaler = get_replaygain_int(lf_gain * 10) << 7;
+
+ cutoff = fp_div(cutoff, fout, 32);
+ hf_gain -= lf_gain;
+ /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB
+ * point instead of shelf midpoint. This is for compatibility with the old
+ * crossfeed shelf filter and should be removed if crossfeed settings are
+ * ever made incompatible for any other good reason.
+ */
+ cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24);
+
+ filter_shelf_coefs(cutoff, hf_gain, false, c);
+ /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains
+ * over 1 and can do this safely
+ */
+ c[0] = FRACMUL_SHL(c[0], scaler, 4);
+ c[1] = FRACMUL_SHL(c[1], scaler, 4);
+ c[2] <<= 4;
+}
+
/** DSP interface **/
@@ -114,24 +160,13 @@ void dsp_set_crossfeed_direct_gain(int gain)
/* Both gains should be below 0 dB */
void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
{
- int32_t *c = crossfeed_state.coefs;
- long scaler = get_replaygain_int(lf_gain * 10) << 7;
+ crossfeed_lf_gain = lf_gain;
+ crossfeed_hf_gain = hf_gain;
+ crossfeed_cutoff = cutoff;
- cutoff = 0xffffffff / NATIVE_FREQUENCY * cutoff;
- hf_gain -= lf_gain;
- /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB
- * point instead of shelf midpoint. This is for compatibility with the old
- * crossfeed shelf filter and should be removed if crossfeed settings are
- * ever made incompatible for any other good reason.
- */
- cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24);
- filter_shelf_coefs(cutoff, hf_gain, false, c);
- /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains
- * over 1 and can do this safely
- */
- c[0] = FRACMUL_SHL(c[0], scaler, 4);
- c[1] = FRACMUL_SHL(c[1], scaler, 4);
- c[2] <<= 4;
+ struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
+ crossfeed_custom_update_filter(&crossfeed_state,
+ dsp_get_output_frequency(dsp));
}
#if !defined(CPU_COLDFIRE) && !defined(CPU_ARM)
@@ -147,6 +182,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p)
int32_t *coefs = &state->coefs[0];
int32_t gain = state->gain;
int32_t *di = state->index;
+ int32_t *di_max = state->index_max;
int count = buf->remcount;
@@ -176,7 +212,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p)
buf->p32[1][i] = FRACMUL(right, gain) + hist_l[1];
/* Wrap delay line index if bigger than delay line size */
- if (di >= delay + 13*2)
+ if (di >= di_max)
di = delay;
}
@@ -234,17 +270,21 @@ static void update_process_fn(struct dsp_proc_entry *this,
struct dsp_config *dsp)
{
struct crossfeed_state *state = (struct crossfeed_state *)this->data;
- dsp_proc_fn_type fn = crossfeed_process;
+ dsp_proc_fn_type fn;
+
+ unsigned int fout = dsp_get_output_frequency(dsp);
if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
{
- /* Set up for Meier */
- /* 1 / (F.Rforward.C) */
- state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
- /* 1 / (F.Rcross.C) */
- state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
+ crossfeed_meier_update_filter(state, fout);
fn = crossfeed_meier_process;
}
+ else
+ {
+ state->index_max = state->delay + DELAY_LEN(fout);
+ crossfeed_custom_update_filter(state, fout);
+ fn = crossfeed_process;
+ }
if (this->process != fn)
{
@@ -292,6 +332,7 @@ static intptr_t crossfeed_configure(struct dsp_proc_entry *this,
if (value == 0)
this->data = (intptr_t)&crossfeed_state;
+ case DSP_SET_OUT_FREQUENCY:
update_process_fn(this, dsp);
break;