diff options
Diffstat (limited to 'lib/rbcodec/dsp/crossfeed.c')
-rw-r--r-- | lib/rbcodec/dsp/crossfeed.c | 117 |
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 */ |
48 | static struct crossfeed_state | 51 | static 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 | ||
72 | static int crossfeed_type = CROSSFEED_TYPE_NONE; | 77 | static int crossfeed_type = CROSSFEED_TYPE_NONE; |
78 | /* Cached custom settings */ | ||
79 | static long crossfeed_lf_gain; | ||
80 | static long crossfeed_hf_gain; | ||
81 | static long crossfeed_cutoff; | ||
73 | 82 | ||
74 | /* Discard the sample histories */ | 83 | /* Discard the sample histories */ |
75 | static void crossfeed_flush(struct dsp_proc_entry *this) | 84 | static 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 | ||
100 | static 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 | |||
109 | static 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 */ |
115 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) | 161 | void 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 | ||