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 36a98f1f33..fc40c6b4d5 100644
--- a/lib/rbcodec/dsp/crossfeed.c
+++ b/lib/rbcodec/dsp/crossfeed.c
@@ -24,6 +24,7 @@
24#include "fixedpoint.h" 24#include "fixedpoint.h"
25#include "fracmul.h" 25#include "fracmul.h"
26#include "replaygain.h" 26#include "replaygain.h"
27#include "dsp_misc.h"
27#include "dsp_proc_entry.h" 28#include "dsp_proc_entry.h"
28#include "dsp_filter.h" 29#include "dsp_filter.h"
29#include "crossfeed.h" 30#include "crossfeed.h"
@@ -44,32 +45,40 @@ void crossfeed_meier_process(struct dsp_proc_entry *this,
44 * to listen to on headphones with no crossfeed. 45 * to listen to on headphones with no crossfeed.
45 */ 46 */
46 47
48#define DELAY_LEN(fs) ((300*(fs) / 1000000)*2) /* ~300 uS */
49
47/* Crossfeed */ 50/* Crossfeed */
48static struct crossfeed_state 51static struct crossfeed_state
49{ 52{
50 int32_t gain; /* 00h: Direct path gain */
51 int32_t coefs[3]; /* 04h: Coefficients for the shelving filter */
52 union 53 union
53 { 54 {
54 struct /* 10h: Data for meier crossfeed */ 55 struct /* Data for meier crossfeed */
55 { 56 {
56 int32_t vcl; 57 int32_t reserved; /* 00h: Reserved: overlaps gain */
57 int32_t vcr; 58 int32_t vcl; /* 04h: Left filter output */
58 int32_t vdiff; 59 int32_t vcr; /* 08h: Right filter output */
59 int32_t coef1; 60 int32_t vdiff; /* 0ch: L-R difference signal */
60 int32_t coef2; 61 int32_t coef1; /* 10h: Left/right filter coef */
62 int32_t coef2; /* 14h: Crossfeed filter coef */
61 }; 63 };
62 struct /* 10h: Data for custom crossfeed */ 64 struct /* Data for custom crossfeed */
63 { 65 {
66 int32_t gain; /* 00h: Direct path gain */
67 int32_t coefs[3]; /* 04h: Filter coefficients: b0, b1, a1 */
64 int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */ 68 int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */
65 int32_t delay[13*2];/* 20h: Delay line buffer (L + R interleaved) */ 69 int32_t *index; /* 20h: Current pointer into the delay line */
70 int32_t *index_max; /* 24h: Current max pointer of delay line */
71 /* 28h: Delay line buffer (L + R interleaved) */
72 int32_t delay[DELAY_LEN(DSP_OUT_MAX_HZ)]; /* Target-dependent size */
66 }; 73 };
67 }; 74 };
68 int32_t *index; /* 88h: Current pointer into the delay line */
69 /* 8ch */
70} crossfeed_state IBSS_ATTR; 75} crossfeed_state IBSS_ATTR;
71 76
72static int crossfeed_type = CROSSFEED_TYPE_NONE; 77static int crossfeed_type = CROSSFEED_TYPE_NONE;
78/* Cached custom settings */
79static long crossfeed_lf_gain;
80static long crossfeed_hf_gain;
81static long crossfeed_cutoff;
73 82
74/* Discard the sample histories */ 83/* Discard the sample histories */
75static void crossfeed_flush(struct dsp_proc_entry *this) 84static void crossfeed_flush(struct dsp_proc_entry *this)
@@ -82,12 +91,49 @@ static void crossfeed_flush(struct dsp_proc_entry *this)
82 } 91 }
83 else 92 else
84 { 93 {
85 memset(state->history, 0, 94 memset(state->history, 0, sizeof (state->history));
86 sizeof (state->history) + sizeof (state->delay)); 95 memset(state->delay, 0, sizeof (state->delay));
87 state->index = state->delay; 96 state->index = state->delay;
88 } 97 }
89} 98}
90 99
100static void crossfeed_meier_update_filter(struct crossfeed_state *state,
101 unsigned int fout)
102{
103 /* 1 / (F.Rforward.C) */
104 state->coef1 = fp_div(2128, fout, 31);
105 /* 1 / (F.Rcross.C) */
106 state->coef2 = fp_div(1000, fout, 31);
107}
108
109static void crossfeed_custom_update_filter(struct crossfeed_state *state,
110 unsigned int fout)
111{
112 long lf_gain = crossfeed_lf_gain;
113 long hf_gain = crossfeed_hf_gain;
114 long cutoff = crossfeed_cutoff;
115 int32_t *c = state->coefs;
116
117 long scaler = get_replaygain_int(lf_gain * 10) << 7;
118
119 cutoff = fp_div(cutoff, fout, 32);
120 hf_gain -= lf_gain;
121 /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB
122 * point instead of shelf midpoint. This is for compatibility with the old
123 * crossfeed shelf filter and should be removed if crossfeed settings are
124 * ever made incompatible for any other good reason.
125 */
126 cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24);
127
128 filter_shelf_coefs(cutoff, hf_gain, false, c);
129 /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains
130 * over 1 and can do this safely
131 */
132 c[0] = FRACMUL_SHL(c[0], scaler, 4);
133 c[1] = FRACMUL_SHL(c[1], scaler, 4);
134 c[2] <<= 4;
135}
136
91 137
92/** DSP interface **/ 138/** DSP interface **/
93 139
@@ -114,24 +160,13 @@ void dsp_set_crossfeed_direct_gain(int gain)
114/* Both gains should be below 0 dB */ 160/* Both gains should be below 0 dB */
115void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) 161void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
116{ 162{
117 int32_t *c = crossfeed_state.coefs; 163 crossfeed_lf_gain = lf_gain;
118 long scaler = get_replaygain_int(lf_gain * 10) << 7; 164 crossfeed_hf_gain = hf_gain;
165 crossfeed_cutoff = cutoff;
119 166
120 cutoff = 0xffffffff / NATIVE_FREQUENCY * cutoff; 167 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
121 hf_gain -= lf_gain; 168 crossfeed_custom_update_filter(&crossfeed_state,
122 /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB 169 dsp_get_output_frequency(dsp));
123 * point instead of shelf midpoint. This is for compatibility with the old
124 * crossfeed shelf filter and should be removed if crossfeed settings are
125 * ever made incompatible for any other good reason.
126 */
127 cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24);
128 filter_shelf_coefs(cutoff, hf_gain, false, c);
129 /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains
130 * over 1 and can do this safely
131 */
132 c[0] = FRACMUL_SHL(c[0], scaler, 4);
133 c[1] = FRACMUL_SHL(c[1], scaler, 4);
134 c[2] <<= 4;
135} 170}
136 171
137#if !defined(CPU_COLDFIRE) && !defined(CPU_ARM) 172#if !defined(CPU_COLDFIRE) && !defined(CPU_ARM)
@@ -147,6 +182,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p)
147 int32_t *coefs = &state->coefs[0]; 182 int32_t *coefs = &state->coefs[0];
148 int32_t gain = state->gain; 183 int32_t gain = state->gain;
149 int32_t *di = state->index; 184 int32_t *di = state->index;
185 int32_t *di_max = state->index_max;
150 186
151 int count = buf->remcount; 187 int count = buf->remcount;
152 188
@@ -176,7 +212,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p)
176 buf->p32[1][i] = FRACMUL(right, gain) + hist_l[1]; 212 buf->p32[1][i] = FRACMUL(right, gain) + hist_l[1];
177 213
178 /* Wrap delay line index if bigger than delay line size */ 214 /* Wrap delay line index if bigger than delay line size */
179 if (di >= delay + 13*2) 215 if (di >= di_max)
180 di = delay; 216 di = delay;
181 } 217 }
182 218
@@ -234,17 +270,21 @@ static void update_process_fn(struct dsp_proc_entry *this,
234 struct dsp_config *dsp) 270 struct dsp_config *dsp)
235{ 271{
236 struct crossfeed_state *state = (struct crossfeed_state *)this->data; 272 struct crossfeed_state *state = (struct crossfeed_state *)this->data;
237 dsp_proc_fn_type fn = crossfeed_process; 273 dsp_proc_fn_type fn;
274
275 unsigned int fout = dsp_get_output_frequency(dsp);
238 276
239 if (crossfeed_type != CROSSFEED_TYPE_CUSTOM) 277 if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
240 { 278 {
241 /* Set up for Meier */ 279 crossfeed_meier_update_filter(state, fout);
242 /* 1 / (F.Rforward.C) */
243 state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
244 /* 1 / (F.Rcross.C) */
245 state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
246 fn = crossfeed_meier_process; 280 fn = crossfeed_meier_process;
247 } 281 }
282 else
283 {
284 state->index_max = state->delay + DELAY_LEN(fout);
285 crossfeed_custom_update_filter(state, fout);
286 fn = crossfeed_process;
287 }
248 288
249 if (this->process != fn) 289 if (this->process != fn)
250 { 290 {
@@ -292,6 +332,7 @@ static intptr_t crossfeed_configure(struct dsp_proc_entry *this,
292 if (value == 0) 332 if (value == 0)
293 this->data = (intptr_t)&crossfeed_state; 333 this->data = (intptr_t)&crossfeed_state;
294 334
335 case DSP_SET_OUT_FREQUENCY:
295 update_process_fn(this, dsp); 336 update_process_fn(this, dsp);
296 break; 337 break;
297 338