summaryrefslogtreecommitdiff
path: root/lib/rbcodec
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec')
-rw-r--r--lib/rbcodec/dsp/compressor.c18
-rw-r--r--lib/rbcodec/dsp/crossfeed.c117
-rw-r--r--lib/rbcodec/dsp/dsp_arm.S84
-rw-r--r--lib/rbcodec/dsp/dsp_cf.S102
-rw-r--r--lib/rbcodec/dsp/dsp_core.c29
-rw-r--r--lib/rbcodec/dsp/dsp_core.h4
-rw-r--r--lib/rbcodec/dsp/dsp_misc.c15
-rw-r--r--lib/rbcodec/dsp/dsp_misc.h7
-rw-r--r--lib/rbcodec/dsp/dsp_proc_database.h2
-rw-r--r--lib/rbcodec/dsp/dsp_proc_entry.h4
-rw-r--r--lib/rbcodec/dsp/dsp_sample_input.c30
-rw-r--r--lib/rbcodec/dsp/dsp_sample_io.h5
-rw-r--r--lib/rbcodec/dsp/eq.c77
-rw-r--r--lib/rbcodec/dsp/resample.c41
-rw-r--r--lib/rbcodec/dsp/tone_controls.c29
-rw-r--r--lib/rbcodec/rbcodecconfig-example.h4
-rw-r--r--lib/rbcodec/test/warble.c5
17 files changed, 377 insertions, 196 deletions
diff --git a/lib/rbcodec/dsp/compressor.c b/lib/rbcodec/dsp/compressor.c
index fc73f761a7..a222caed7f 100644
--- a/lib/rbcodec/dsp/compressor.c
+++ b/lib/rbcodec/dsp/compressor.c
@@ -28,6 +28,7 @@
28#include "logf.h" 28#include "logf.h"
29#include "dsp_proc_entry.h" 29#include "dsp_proc_entry.h"
30#include "compressor.h" 30#include "compressor.h"
31#include "dsp_misc.h"
31 32
32static struct compressor_settings curr_set; /* Cached settings */ 33static struct compressor_settings curr_set; /* Cached settings */
33 34
@@ -40,7 +41,8 @@ static int32_t release_gain IBSS_ATTR; /* S7.24 format */
40 41
41/** COMPRESSOR UPDATE 42/** COMPRESSOR UPDATE
42 * Called via the menu system to configure the compressor process */ 43 * Called via the menu system to configure the compressor process */
43static bool compressor_update(const struct compressor_settings *settings) 44static bool compressor_update(struct dsp_config *dsp,
45 const struct compressor_settings *settings)
44{ 46{
45 /* make settings values useful */ 47 /* make settings values useful */
46 int threshold = settings->threshold; 48 int threshold = settings->threshold;
@@ -48,9 +50,10 @@ static bool compressor_update(const struct compressor_settings *settings)
48 static const int comp_ratios[] = { 2, 4, 6, 10, 0 }; 50 static const int comp_ratios[] = { 2, 4, 6, 10, 0 };
49 int ratio = comp_ratios[settings->ratio]; 51 int ratio = comp_ratios[settings->ratio];
50 bool soft_knee = settings->knee == 1; 52 bool soft_knee = settings->knee == 1;
51 int release = settings->release_time * NATIVE_FREQUENCY / 1000; 53 int release = settings->release_time *
54 dsp_get_output_frequency(dsp) / 1000;
52 55
53 bool changed = false; 56 bool changed = settings == &curr_set; /* If frequency change */
54 bool active = threshold < 0; 57 bool active = threshold < 0;
55 58
56 if (memcmp(settings, &curr_set, sizeof (curr_set))) 59 if (memcmp(settings, &curr_set, sizeof (curr_set)))
@@ -300,8 +303,8 @@ static inline int32_t get_compression_gain(struct sample_format *format,
300void dsp_set_compressor(const struct compressor_settings *settings) 303void dsp_set_compressor(const struct compressor_settings *settings)
301{ 304{
302 /* enable/disable the compressor depending upon settings */ 305 /* enable/disable the compressor depending upon settings */
303 bool enable = compressor_update(settings);
304 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); 306 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
307 bool enable = compressor_update(dsp, settings);
305 dsp_proc_enable(dsp, DSP_PROC_COMPRESSOR, enable); 308 dsp_proc_enable(dsp, DSP_PROC_COMPRESSOR, enable);
306 dsp_proc_activate(dsp, DSP_PROC_COMPRESSOR, true); 309 dsp_proc_activate(dsp, DSP_PROC_COMPRESSOR, true);
307} 310}
@@ -386,15 +389,20 @@ static intptr_t compressor_configure(struct dsp_proc_entry *this,
386 break; /* Already enabled */ 389 break; /* Already enabled */
387 390
388 this->process = compressor_process; 391 this->process = compressor_process;
392 /* Won't have been getting frequency updates */
393 compressor_update(dsp, &curr_set);
389 /* Fall-through */ 394 /* Fall-through */
390 case DSP_RESET: 395 case DSP_RESET:
391 case DSP_FLUSH: 396 case DSP_FLUSH:
392 release_gain = UNITY; 397 release_gain = UNITY;
393 break; 398 break;
399
400 case DSP_SET_OUT_FREQUENCY:
401 compressor_update(dsp, &curr_set);
402 break;
394 } 403 }
395 404
396 return 0; 405 return 0;
397 (void)dsp;
398} 406}
399 407
400/* Database entry */ 408/* Database entry */
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
diff --git a/lib/rbcodec/dsp/dsp_arm.S b/lib/rbcodec/dsp/dsp_arm.S
index ed58bed340..16394b8690 100644
--- a/lib/rbcodec/dsp/dsp_arm.S
+++ b/lib/rbcodec/dsp/dsp_arm.S
@@ -196,55 +196,56 @@ crossfeed_process:
196 @ to keep the count on the stack :/ 196 @ to keep the count on the stack :/
197 ldr r1, [r1] @ r1 = buf = *buf_p; 197 ldr r1, [r1] @ r1 = buf = *buf_p;
198 stmfd sp!, { r4-r11, lr } @ stack modified regs 198 stmfd sp!, { r4-r11, lr } @ stack modified regs
199 ldr r12, [r1] @ r12 = buf->remcount 199 ldr r0, [r0] @ r0 = this->data = &crossfeed_state
200 ldr r14, [r0] @ r14 = this->data = &crossfeed_state 200 ldmia r1, { r1-r3 } @ r1 = buf->remcount, r2 = buf->p32[0],
201 ldmib r1, { r2-r3 } @ r2 = buf->p32[0], r3 = buf->p32[1] 201 @ r3 = buf->p32[1]
202 ldmia r14!, { r4-r11 } @ load direct gain and filter data 202 ldmia r0, { r4-r12, r14 } @ r4 = gain, r5-r7 = coeffs,
203 add r0, r14, #13*2*4 @ calculate end of delay 203 @ r8-r11 = history, r12 = index,
204 stmfd sp!, { r0, r12 } @ stack end of delay adr, count and state 204 @ r14 = index_max
205 ldr r0, [r0] @ fetch current delay line address 205 add r0, r0, #0x28 @ r0 = state->delay
206 206 stmfd sp!, { r0-r1, r14 } @ stack state->delay, count, index_max
207 /* Register usage in loop: 207
208 * r0 = &delay[index][0], r1 = accumulator high, r2 = buf->p32[0], 208 /* Register usage in loop:
209 * r0 = acc low/count, r1 = acc high, r2 = buf->p32[0],
209 * r3 = buf->p32[1], r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs), 210 * r3 = buf->p32[1], r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs),
210 * r8-r11 = filter history, r12 = temp, r14 = accumulator low 211 * r8 = dr[n-1], r9 = y_r[n-1], r10 = dl[n-1], r11 = y_l[n-1],
212 * r12 = index, r14 = scratch/index_max
211 */ 213 */
212.cfloop: 214.cfloop:
213 smull r14, r1, r6, r8 @ acc = b1*dr[n - 1] 215 smull r0, r1, r6, r8 @ acc = b1*dr[n - 1]
214 smlal r14, r1, r7, r9 @ acc += a1*y_l[n - 1] 216 ldr r8, [r12, #4] @ r8 = dr[n]
215 ldr r8, [r0, #4] @ r8 = dr[n] 217 smlal r0, r1, r7, r9 @ acc += a1*y_r[n - 1]
216 smlal r14, r1, r5, r8 @ acc += b0*dr[n] 218 smlal r0, r1, r5, r8 @ acc += b0*dr[n]
217 mov r9, r1, lsl #1 @ fix format for filter history 219 ldr r14, [r2] @ load left input: x_l[n]
218 ldr r12, [r2] @ load left input 220 mov r9, r1, asl #1 @ fix format for filter history
219 smlal r14, r1, r4, r12 @ acc += gain*x_l[n] 221 smlal r0, r1, r4, r14 @ acc += gain*x_l[n]
220 mov r1, r1, lsl #1 @ fix format 222 mov r1, r1, asl #1 @ fix format
221 str r1, [r2], #4 @ save result 223 str r1, [r2], #4 @ save result
222 224 smull r0, r1, r6, r10 @ acc = b1*dl[n - 1]
223 smull r14, r1, r6, r10 @ acc = b1*dl[n - 1] 225 ldr r10, [r12] @ r10 = dl[n]
224 smlal r14, r1, r7, r11 @ acc += a1*y_r[n - 1] 226 smlal r0, r1, r7, r11 @ acc += a1*y_l[n - 1]
225 ldr r10, [r0] @ r10 = dl[n] 227 smlal r0, r1, r5, r10 @ acc += b0*dl[n]
226 str r12, [r0], #4 @ save left input to delay line 228 str r14, [r12], #4 @ save left input to delay line
227 smlal r14, r1, r5, r10 @ acc += b0*dl[n] 229 ldr r14, [r3] @ load right input: x_r[n]
228 mov r11, r1, lsl #1 @ fix format for filter history 230 mov r11, r1, asl #1 @ fix format for filter history
229 ldr r12, [r3] @ load right input 231 smlal r0, r1, r4, r14 @ acc += gain*x_r[n]
230 smlal r14, r1, r4, r12 @ acc += gain*x_r[n] 232 str r14, [r12], #4 @ save right input to delay line
231 str r12, [r0], #4 @ save right input to delay line 233 ldmib sp, { r0, r14 } @ fetch count and delay end
232 mov r1, r1, lsl #1 @ fix format 234 mov r1, r1, asl #1 @ fix format
233 ldmia sp, { r12, r14 } @ fetch delay line end addr and count from stack
234 str r1, [r3], #4 @ save result 235 str r1, [r3], #4 @ save result
235 236
236 cmp r0, r12 @ need to wrap to start of delay? 237 cmp r12, r14 @ need to wrap to start of delay?
237 subhs r0, r12, #13*2*4 @ wrap back delay line ptr to start 238 ldrhs r12, [sp] @ wrap delay index
238 239
239 subs r14, r14, #1 @ are we finished? 240 subs r0, r0, #1 @ are we finished?
240 strgt r14, [sp, #4] @ nope, save count back to stack 241 strgt r0, [sp, #4] @ save count to stack
241 bgt .cfloop 242 bgt .cfloop
242 243
243 @ save data back to struct 244 @ save data back to struct
244 str r0, [r12] @ save delay line index 245 ldr r0, [sp] @ fetch state->delay
245 sub r12, r12, #13*2*4 + 4*4 @ r12 = data->history 246 sub r0, r0, #0x18 @ save filter history and delay index
246 stmia r12, { r8-r11 } @ save filter history 247 stmia r0, { r8-r12 } @
247 add sp, sp, #8 @ remove temp variables from stack 248 add sp, sp, #12 @ remove temp variables from stack
248 ldmpc regs=r4-r11 249 ldmpc regs=r4-r11
249 .size crossfeed_process, .-crossfeed_process 250 .size crossfeed_process, .-crossfeed_process
250 251
@@ -260,8 +261,7 @@ crossfeed_meier_process:
260 ldr r0, [r0] @ r0 = this->data = &crossfeed_state 261 ldr r0, [r0] @ r0 = this->data = &crossfeed_state
261 stmfd sp!, { r4-r10, lr } @ stack non-volatile context 262 stmfd sp!, { r4-r10, lr } @ stack non-volatile context
262 ldmia r1, { r1-r3 } @ r1 = buf->remcout, r2=p32[0], r3=p32[1] 263 ldmia r1, { r1-r3 } @ r1 = buf->remcout, r2=p32[0], r3=p32[1]
263 add r0, r0, #16 @ r0 = &state->vcl 264 ldmib r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff
264 ldmia r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff
265 @ r7 = coef1, r8 = coef2 265 @ r7 = coef1, r8 = coef2
266.cfm_loop: 266.cfm_loop:
267 ldr r12, [r2] @ r12 = lout 267 ldr r12, [r2] @ r12 = lout
@@ -285,7 +285,7 @@ crossfeed_meier_process:
285 sub r5, r5, r12 @ r5 = vcr -= res2 285 sub r5, r5, r12 @ r5 = vcr -= res2
286 bgt .cfm_loop @ more samples? 286 bgt .cfm_loop @ more samples?
287 287
288 stmia r0, { r4-r6 } @ save vcl, vcr, vdiff 288 stmib r0, { r4-r6 } @ save vcl, vcr, vdiff
289 ldmpc regs=r4-r10 @ restore non-volatile context, return 289 ldmpc regs=r4-r10 @ restore non-volatile context, return
290 .size crossfeed_meier_process, .-crossfeed_meier_process 290 .size crossfeed_meier_process, .-crossfeed_meier_process
291 291
diff --git a/lib/rbcodec/dsp/dsp_cf.S b/lib/rbcodec/dsp/dsp_cf.S
index 02db8f61b6..e34075ef9a 100644
--- a/lib/rbcodec/dsp/dsp_cf.S
+++ b/lib/rbcodec/dsp/dsp_cf.S
@@ -81,58 +81,60 @@ crossfeed_process:
81 movem.l %d2-%d7/%a2-%a6, (%sp) | save all regs 81 movem.l %d2-%d7/%a2-%a6, (%sp) | save all regs
82 movem.l 48(%sp), %a1/%a4 | %a1 = this, %a4 = buf_p 82 movem.l 48(%sp), %a1/%a4 | %a1 = this, %a4 = buf_p
83 move.l (%a4), %a4 | %a4 = buf = *buf_p 83 move.l (%a4), %a4 | %a4 = buf = *buf_p
84 movem.l (%a4), %d7/%a4-%a5 | %d7 = buf->remcount, %a4 = buf->p32[0], 84 movem.l (%a4), %d0/%a4-%a5 | %d0 = buf->remcount, %a4 = buf->p32[0],
85 | %a5 = buf->p32[1] 85 | %a5 = buf->p32[1]
86 move.l (%a1), %a1 | %a1 = &crossfeed_state 86 move.l (%a1), %a6 | %d7 = state = &crossfeed_state
87 move.l (%a1)+, %d6 | %d6 = direct gain 87 movem.l (%a6), %d1-%d6/%a0-%a3 | %d1 = gain, %d2-%d4 = coefs,
88 movem.l 12(%a1), %d0-%d3 | fetch filter history samples 88 | %d5..%d6 = history[0..1],
89 lea.l 132(%a1), %a6 | %a6 = delay line wrap limit 89 | %a0..%a1 = history[2..3],
90 move.l (%a6), %a0 | fetch delay line address 90 | %a2 = index, %a3 = index_max
91 movem.l (%a1), %a1-%a3 | load filter coefs 91 lea.l 0x28(%a6), %a6 | %a6 = state->delay
92 bra.b 20f | loop start | go to loop start point 92 move.l %a6, -(%sp) | push state->delay
93 bra.b .cfp_loop_start
93 /* Register usage in loop: 94 /* Register usage in loop:
94 * %a0 = delay_p, %a1..%a3 = b0, b1, a1 (filter coefs), 95 * %d0 = count, %d1 = direct gain, %d2..%d4 = b0, b1, a1 (filter coefs),
95 * %a4 = buf[0], %a5 = buf[1], 96 * %d5..%d6 = history[0..1], %d7 = scratch
96 * %a6 = delay line pointer wrap limit, 97 * %a0..%a1 = history[2..3], %a2 = index, %a3 = index_max,
97 * %d0..%d3 = history 98 * %a4 = buf[0], %a5 = buf[1], %a6 = scratch
98 * %d4..%d5 = temp.
99 * %d6 = direct gain,
100 * %d7 = count
101 */ 99 */
10210: | loop | 100.cfp_loop:
103 movclr.l %acc0, %d4 | write outputs 101 movclr.l %acc0, %d7 | write outputs
104 move.l %d4, (%a4)+ | . 102 move.l %d7, (%a4)+ | .
105 movclr.l %acc1, %d5 | . 103 movclr.l %acc1, %a6 | .
106 move.l %d5, (%a5)+ | . 104 move.l %a6, (%a5)+ | .
10720: | loop start | 105.cfp_loop_start:
108 mac.l %a2, %d0, (%a0)+, %d0, %acc0 | %acc0 = b1*dl[n - 1], %d0 = dl[n] 106 mac.l %d3, %d5, (%a2)+, %d5, %acc1 | %acc1 = b1*dl[n - 1], %d5 = dl[n]
109 mac.l %a1, %d0 , %acc0 | %acc0 += b0*dl[n] 107 mac.l %d2, %d5 , %acc1 | %acc1 += b0*dl[n]
110 mac.l %a3, %d1, (%a5), %d5, %acc0 | %acc0 += a1*y_r[n - 1], load R 108 mac.l %d4, %d6, (%a4), %d7, %acc1 | %acc1 += a1*y_l[n - 1], %d7 = x_l[n]
111 mac.l %a2, %d2, (%a0)+, %d2, %acc1 | %acc1 = b1*dr[n - 1], %d2 = dr[n] 109 mac.l %d3, %a0, (%a2)+, %a0, %acc0 | %acc0 = b1*dr[n - 1], %a0 = dr[n]
112 mac.l %a1, %d2 , %acc1 | %acc1 += b0*dr[n] 110 mac.l %a2, %a0 , %acc0 | %acc0 += b0*dr[n]
113 mac.l %a3, %d3, (%a4), %d4, %acc1 | %acc1 += a1*y_l[n - 1], load L 111 mac.l %d4, %a1, (%a5), %a6, %acc0 | %acc0 += a1*y_r[n - 1], %a6 = x_r[n]
114 movem.l %d4-%d5, -8(%a0) | save left & right inputs to delay line 112 movem.l %d7/%a6, -8(%a2) | save x_l[n] and x_r[n] to delay line
115 move.l %acc0, %d3 | get filtered delayed left sample (y_l[n]) 113 move.l %acc1, %d6 | get filtered delayed left sample (y_l[n])
116 move.l %acc1, %d1 | get filtered delayed right sample (y_r[n]) 114 move.l %acc0, %a1 | get filtered delayed right sample (y_r[n])
117 mac.l %d6, %d4, %acc0 | %acc0 += gain*x_l[n] 115 mac.l %d1, %d7, %acc0 | %acc0 = gain*x_l[n] + y_r[n]
118 mac.l %d6, %d5, %acc1 | %acc1 += gain*x_r[n] 116 mac.l %d1, %a6, %acc1 | %acc1 = gain*x_r[n] + y_l[n]
119 cmp.l %a6, %a0 | wrap %a0 if passed end 117
120 bhs.b 30f | wrap buffer | 118 cmp.l %a3, %a2 | wrap index if past end
121 tpf.l | trap the buffer wrap 119 bhs.b 1f |
12230: | wrap buffer | ...fwd taken branches more costly 120 tpf.w | trap the buffer wrap
123 lea.l -104(%a6), %a0 | wrap it up 1211: | ...fwd taken branches more costly
124 subq.l #1, %d7 | --count > 0 ? 122 move.l (%sp), %a2 | 2b | wrap it up
125 bgt.b 10b | loop | yes? do more 123
126 movclr.l %acc0, %d4 | write last outputs 124 subq.l #1, %d0 | --count > 0 ?
127 move.l %d4, (%a4) | . 125 bgt.b .cfp_loop | yes? do more
128 movclr.l %acc1, %d5 | . 126
129 move.l %d5, (%a5) | . 127 movclr.l %acc0, %d7 | write last outputs
130 movem.l %d0-%d3, -120(%a6) | ...history 128 move.l %d7, (%a4) | .
131 move.l %a0, (%a6) | ...delay_p 129 movclr.l %acc1, %a6 | .
130 move.l %a6, (%a5) | .
131
132 move.l (%sp)+, %a6 | pop state->delay
133 movem.l %d5-%d6/%a0-%a2, -0x18(%a6) | save history, index
132 movem.l (%sp), %d2-%d7/%a2-%a6 | restore all regs 134 movem.l (%sp), %d2-%d7/%a2-%a6 | restore all regs
133 lea.l 44(%sp), %sp | 135 lea.l 44(%sp), %sp |
134 rts | 136 rts |
135 .size crossfeed_process,.-crossfeed_process 137 .size crossfeed_process, .-crossfeed_process
136 138
137/**************************************************************************** 139/****************************************************************************
138 * void crossfeed_meier_process(struct dsp_proc_entry *this, 140 * void crossfeed_meier_process(struct dsp_proc_entry *this,
@@ -147,7 +149,7 @@ crossfeed_meier_process:
147 movem.l %d2-%d6/%a2, (%sp) | . 149 movem.l %d2-%d6/%a2, (%sp) | .
148 move.l (%a0), %a0 | %a0 = &this->data = &crossfeed_state 150 move.l (%a0), %a0 | %a0 = &this->data = &crossfeed_state
149 move.l (%a1), %a1 | %a1 = buf = *buf_p 151 move.l (%a1), %a1 | %a1 = buf = *buf_p
150 movem.l 16(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff, 152 movem.l 4(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff,
151 | %d4 = coef1, %d5 = coef2 153 | %d4 = coef1, %d5 = coef2
152 movem.l (%a1), %d0/%a1-%a2 | %d0 = count = buf->remcount 154 movem.l (%a1), %d0/%a1-%a2 | %d0 = count = buf->remcount
153 | %a1 = p32[0], %a2 = p32[1] 155 | %a1 = p32[0], %a2 = p32[1]
@@ -155,7 +157,7 @@ crossfeed_meier_process:
155 | %d0 = count, %d1 = vcl, %d2 = vcr, %d3 = vdiff/lout, 157 | %d0 = count, %d1 = vcl, %d2 = vcr, %d3 = vdiff/lout,
156 | %d4 = coef1, %d5 = coef2, %d6 = rout/scratch 158 | %d4 = coef1, %d5 = coef2, %d6 = rout/scratch
157 | %a1 = p32[0], %a2 = p32[1] 159 | %a1 = p32[0], %a2 = p32[1]
15810: | loop 160.cfmp_loop:
159 mac.l %d5, %d3, %acc0 | %acc0 = common = coef2*vdiff 161 mac.l %d5, %d3, %acc0 | %acc0 = common = coef2*vdiff
160 move.l %acc0, %acc1 | copy common 162 move.l %acc0, %acc1 | copy common
161 mac.l %d4, %d1, (%a1), %d3, %acc0 | %acc0 += coef1*vcl, %d3 = lout 163 mac.l %d4, %d1, (%a1), %d3, %acc0 | %acc0 += coef1*vcl, %d3 = lout
@@ -170,9 +172,9 @@ crossfeed_meier_process:
170 movclr.l %acc1, %d6 | %d5 = fetch -res2 in s0.31 172 movclr.l %acc1, %d6 | %d5 = fetch -res2 in s0.31
171 add.l %d6, %d2 | vcr += -res2 173 add.l %d6, %d2 | vcr += -res2
172 subq.l #1, %d0 | count-- 174 subq.l #1, %d0 | count--
173 bgt 10b | loop | more samples? 175 bgt .cfmp_loop | more samples?
174 | 176 |
175 movem.l %d1-%d3, 16(%a0) | save vcl, vcr, vdiff 177 movem.l %d1-%d3, 4(%a0) | save vcl, vcr, vdiff
176 movem.l (%sp), %d2-%d6/%a2 | restore non-volatiles 178 movem.l (%sp), %d2-%d6/%a2 | restore non-volatiles
177 lea.l 24(%sp), %sp | . 179 lea.l 24(%sp), %sp | .
178 rts | 180 rts |
diff --git a/lib/rbcodec/dsp/dsp_core.c b/lib/rbcodec/dsp/dsp_core.c
index 871ccbfd23..b0e9c8a304 100644
--- a/lib/rbcodec/dsp/dsp_core.c
+++ b/lib/rbcodec/dsp/dsp_core.c
@@ -103,8 +103,21 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting,
103 intptr_t value) 103 intptr_t value)
104{ 104{
105 bool multi = setting < DSP_PROC_SETTING; 105 bool multi = setting < DSP_PROC_SETTING;
106 struct dsp_proc_slot *s = multi ? dsp->proc_slots : 106 struct dsp_proc_slot *s;
107 find_proc_slot(dsp, setting - DSP_PROC_SETTING); 107
108 if (multi)
109 {
110 /* Message to all enabled stages */
111 if (dsp_sample_io_configure(&dsp->io_data, setting, &value))
112 return value; /* To I/O only */
113
114 s = dsp->proc_slots;
115 }
116 else
117 {
118 /* Message to a particular stage */
119 s = find_proc_slot(dsp, setting - DSP_PROC_SETTING);
120 }
108 121
109 while (s != NULL) 122 while (s != NULL)
110 { 123 {
@@ -117,7 +130,7 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting,
117 s = s->next; 130 s = s->next;
118 } 131 }
119 132
120 return multi ? 1 : 0; 133 return 0;
121} 134}
122 135
123/* Add an item to the enabled list */ 136/* Add an item to the enabled list */
@@ -244,6 +257,12 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
244 proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0); 257 proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0);
245} 258}
246 259
260/* Is the stage specified by the id currently enabled? */
261bool dsp_proc_enabled(struct dsp_config *dsp, enum dsp_proc_ids id)
262{
263 return (dsp->proc_mask_enabled & BIT_N(id)) != 0;
264}
265
247/* Activate or deactivate a stage */ 266/* Activate or deactivate a stage */
248void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id, 267void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id,
249 bool activate) 268 bool activate)
@@ -454,7 +473,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src,
454intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, 473intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting,
455 intptr_t value) 474 intptr_t value)
456{ 475{
457 dsp_sample_io_configure(&dsp->io_data, setting, value);
458 return proc_broadcast(dsp, setting, value); 476 return proc_broadcast(dsp, setting, value);
459} 477}
460 478
@@ -497,7 +515,8 @@ void INIT_ATTR dsp_init(void)
497 count = slot_count[i]; 515 count = slot_count[i];
498 dsp->slot_free_mask = MASK_N(uint32_t, count, shift); 516 dsp->slot_free_mask = MASK_N(uint32_t, count, shift);
499 517
500 dsp_sample_io_configure(&dsp->io_data, DSP_INIT, i); 518 intptr_t value = i;
519 dsp_sample_io_configure(&dsp->io_data, DSP_INIT, &value);
501 520
502 /* Notify each db entry of global init for each DSP */ 521 /* Notify each db entry of global init for each DSP */
503 for (unsigned int j = 0; j < DSP_NUM_PROC_STAGES; j++) 522 for (unsigned int j = 0; j < DSP_NUM_PROC_STAGES; j++)
diff --git a/lib/rbcodec/dsp/dsp_core.h b/lib/rbcodec/dsp/dsp_core.h
index d3cfdd133c..0f63b62e00 100644
--- a/lib/rbcodec/dsp/dsp_core.h
+++ b/lib/rbcodec/dsp/dsp_core.h
@@ -39,14 +39,14 @@ enum dsp_settings
39 DSP_SET_STEREO_MODE, 39 DSP_SET_STEREO_MODE,
40 DSP_FLUSH, 40 DSP_FLUSH,
41 DSP_SET_PITCH, 41 DSP_SET_PITCH,
42 DSP_SET_OUT_FREQUENCY,
43 DSP_GET_OUT_FREQUENCY,
42 DSP_PROC_INIT, 44 DSP_PROC_INIT,
43 DSP_PROC_CLOSE, 45 DSP_PROC_CLOSE,
44 DSP_PROC_NEW_FORMAT, 46 DSP_PROC_NEW_FORMAT,
45 DSP_PROC_SETTING, /* stage-specific should be this + id */ 47 DSP_PROC_SETTING, /* stage-specific should be this + id */
46}; 48};
47 49
48#define NATIVE_FREQUENCY 44100 /* internal/output sample rate */
49
50enum dsp_stereo_modes 50enum dsp_stereo_modes
51{ 51{
52 STEREO_INTERLEAVED, 52 STEREO_INTERLEAVED,
diff --git a/lib/rbcodec/dsp/dsp_misc.c b/lib/rbcodec/dsp/dsp_misc.c
index cc74a790ea..ad6f5b5b31 100644
--- a/lib/rbcodec/dsp/dsp_misc.c
+++ b/lib/rbcodec/dsp/dsp_misc.c
@@ -134,6 +134,21 @@ int32_t dsp_get_pitch(void)
134} 134}
135#endif /* HAVE_PITCHCONTROL */ 135#endif /* HAVE_PITCHCONTROL */
136 136
137/* Set output samplerate for all DSPs */
138void dsp_set_all_output_frequency(unsigned int samplerate)
139{
140
141 struct dsp_config *dsp;
142 for (int i = 0; (dsp = dsp_get_config(i)); i++)
143 dsp_configure(dsp, DSP_SET_OUT_FREQUENCY, samplerate);
144}
145
146/* Return DSP's output samplerate */
147unsigned int dsp_get_output_frequency(struct dsp_config *dsp)
148{
149 return dsp_configure(dsp, DSP_GET_OUT_FREQUENCY, 0);
150}
151
137static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp, 152static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp,
138 enum dsp_ids dsp_id) 153 enum dsp_ids dsp_id)
139{ 154{
diff --git a/lib/rbcodec/dsp/dsp_misc.h b/lib/rbcodec/dsp/dsp_misc.h
index 2fed9400f2..af259bfa3e 100644
--- a/lib/rbcodec/dsp/dsp_misc.h
+++ b/lib/rbcodec/dsp/dsp_misc.h
@@ -59,4 +59,11 @@ void dsp_set_pitch(int32_t pitch);
59int32_t dsp_get_pitch(void); 59int32_t dsp_get_pitch(void);
60#endif /* HAVE_PITCHCONTROL */ 60#endif /* HAVE_PITCHCONTROL */
61 61
62/* Set output samplerate for all DSPs */
63void dsp_set_all_output_frequency(unsigned int samplerate);
64
65/* Return DSP's output samplerate */
66struct dsp_config;
67unsigned int dsp_get_output_frequency(struct dsp_config *dsp);
68
62#endif /* DSP_MISC_H */ 69#endif /* DSP_MISC_H */
diff --git a/lib/rbcodec/dsp/dsp_proc_database.h b/lib/rbcodec/dsp/dsp_proc_database.h
index c4c93ef2d9..534c165eef 100644
--- a/lib/rbcodec/dsp/dsp_proc_database.h
+++ b/lib/rbcodec/dsp/dsp_proc_database.h
@@ -40,7 +40,7 @@ DSP_PROC_DB_START
40#ifdef HAVE_PITCHCONTROL 40#ifdef HAVE_PITCHCONTROL
41 DSP_PROC_DB_ITEM(TIMESTRETCH) /* time-stretching */ 41 DSP_PROC_DB_ITEM(TIMESTRETCH) /* time-stretching */
42#endif 42#endif
43 DSP_PROC_DB_ITEM(RESAMPLE) /* resampler providing NATIVE_FREQUENCY */ 43 DSP_PROC_DB_ITEM(RESAMPLE) /* resampler providing output frequency */
44 DSP_PROC_DB_ITEM(CROSSFEED) /* stereo crossfeed */ 44 DSP_PROC_DB_ITEM(CROSSFEED) /* stereo crossfeed */
45 DSP_PROC_DB_ITEM(EQUALIZER) /* n-band equalizer */ 45 DSP_PROC_DB_ITEM(EQUALIZER) /* n-band equalizer */
46#ifdef HAVE_SW_TONE_CONTROLS 46#ifdef HAVE_SW_TONE_CONTROLS
diff --git a/lib/rbcodec/dsp/dsp_proc_entry.h b/lib/rbcodec/dsp/dsp_proc_entry.h
index 902385f08d..1bf59dd73a 100644
--- a/lib/rbcodec/dsp/dsp_proc_entry.h
+++ b/lib/rbcodec/dsp/dsp_proc_entry.h
@@ -132,6 +132,10 @@ typedef intptr_t (*dsp_proc_config_fn_type)(struct dsp_proc_entry *this,
132 * by processing code! */ 132 * by processing code! */
133void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, 133void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id,
134 bool enable); 134 bool enable);
135
136/* Is the specified stage enabled on the DSP? */
137bool dsp_proc_enabled(struct dsp_config *dsp, enum dsp_proc_ids id);
138
135/* Activate/deactivate processing stage, doesn't affect enabled status 139/* Activate/deactivate processing stage, doesn't affect enabled status
136 * thus will not enable anything - 140 * thus will not enable anything -
137 * may be called during processing to activate/deactivate for format 141 * may be called during processing to activate/deactivate for format
diff --git a/lib/rbcodec/dsp/dsp_sample_input.c b/lib/rbcodec/dsp/dsp_sample_input.c
index 561cb36d9e..537a659b73 100644
--- a/lib/rbcodec/dsp/dsp_sample_input.c
+++ b/lib/rbcodec/dsp/dsp_sample_input.c
@@ -286,14 +286,17 @@ static void INIT_ATTR dsp_sample_input_init(struct sample_io_data *this,
286static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this, 286static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this,
287 enum dsp_ids dsp_id) 287 enum dsp_ids dsp_id)
288{ 288{
289 this->output_sampr = DSP_OUT_DEFAULT_HZ;
289 dsp_sample_input_init(this, dsp_id); 290 dsp_sample_input_init(this, dsp_id);
290 dsp_sample_output_init(this); 291 dsp_sample_output_init(this);
291} 292}
292 293
293void dsp_sample_io_configure(struct sample_io_data *this, 294bool dsp_sample_io_configure(struct sample_io_data *this,
294 unsigned int setting, 295 unsigned int setting,
295 intptr_t value) 296 intptr_t *value_p)
296{ 297{
298 intptr_t value = *value_p;
299
297 switch (setting) 300 switch (setting)
298 { 301 {
299 case DSP_INIT: 302 case DSP_INIT:
@@ -306,15 +309,15 @@ void dsp_sample_io_configure(struct sample_io_data *this,
306 this->format.num_channels = 2; 309 this->format.num_channels = 2;
307 this->format.frac_bits = WORD_FRACBITS; 310 this->format.frac_bits = WORD_FRACBITS;
308 this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH; 311 this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH;
309 this->format.frequency = NATIVE_FREQUENCY; 312 this->format.frequency = this->output_sampr;
310 this->format.codec_frequency = NATIVE_FREQUENCY; 313 this->format.codec_frequency = this->output_sampr;
311 this->sample_depth = NATIVE_DEPTH; 314 this->sample_depth = NATIVE_DEPTH;
312 this->stereo_mode = STEREO_NONINTERLEAVED; 315 this->stereo_mode = STEREO_NONINTERLEAVED;
313 break; 316 break;
314 317
315 case DSP_SET_FREQUENCY: 318 case DSP_SET_FREQUENCY:
316 format_change_set(this); 319 format_change_set(this);
317 value = value > 0 ? value : NATIVE_FREQUENCY; 320 value = value > 0 ? (unsigned int)value : this->output_sampr;
318 this->format.frequency = value; 321 this->format.frequency = value;
319 this->format.codec_frequency = value; 322 this->format.codec_frequency = value;
320 break; 323 break;
@@ -345,5 +348,22 @@ void dsp_sample_io_configure(struct sample_io_data *this,
345 this->format.frequency = 348 this->format.frequency =
346 fp_mul(value, this->format.codec_frequency, 16); 349 fp_mul(value, this->format.codec_frequency, 16);
347 break; 350 break;
351
352 case DSP_SET_OUT_FREQUENCY:
353 value = value > 0 ? value : DSP_OUT_DEFAULT_HZ;
354 value = MIN(DSP_OUT_MAX_HZ, MAX(DSP_OUT_MIN_HZ, value));
355 *value_p = value;
356
357 if ((unsigned int)value == this->output_sampr)
358 return true; /* No change; don't broadcast */
359
360 this->output_sampr = value;
361 break;
362
363 case DSP_GET_OUT_FREQUENCY:
364 *value_p = this->output_sampr;
365 return true; /* Only I/O handles it */
348 } 366 }
367
368 return false;
349} 369}
diff --git a/lib/rbcodec/dsp/dsp_sample_io.h b/lib/rbcodec/dsp/dsp_sample_io.h
index 22b7a4a3f4..5117e04a3e 100644
--- a/lib/rbcodec/dsp/dsp_sample_io.h
+++ b/lib/rbcodec/dsp/dsp_sample_io.h
@@ -50,6 +50,7 @@ struct sample_io_data
50 struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */ 50 struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */
51 int32_t *sample_buf_p[2]; /* Internal format buffer pointers */ 51 int32_t *sample_buf_p[2]; /* Internal format buffer pointers */
52 sample_output_fn_type output_samples; /* Final output function */ 52 sample_output_fn_type output_samples; /* Final output function */
53 unsigned int output_sampr; /* Master output samplerate */
53 uint8_t format_dirty; /* Format change set, avoids superfluous 54 uint8_t format_dirty; /* Format change set, avoids superfluous
54 increments before carrying it out */ 55 increments before carrying it out */
55 uint8_t output_version; /* Format version of src buffer at output */ 56 uint8_t output_version; /* Format version of src buffer at output */
@@ -62,8 +63,8 @@ void dsp_sample_output_format_change(struct sample_io_data *this,
62 struct sample_format *format); 63 struct sample_format *format);
63 64
64/* Sample IO watches the format setting from the codec */ 65/* Sample IO watches the format setting from the codec */
65void dsp_sample_io_configure(struct sample_io_data *this, 66bool dsp_sample_io_configure(struct sample_io_data *this,
66 unsigned int setting, 67 unsigned int setting,
67 intptr_t value); 68 intptr_t *value_p);
68 69
69#endif /* DSP_SAMPLE_IO_H */ 70#endif /* DSP_SAMPLE_IO_H */
diff --git a/lib/rbcodec/dsp/eq.c b/lib/rbcodec/dsp/eq.c
index 94cb61deec..e4d7bf5e02 100644
--- a/lib/rbcodec/dsp/eq.c
+++ b/lib/rbcodec/dsp/eq.c
@@ -25,6 +25,7 @@
25#include "dsp_filter.h" 25#include "dsp_filter.h"
26#include "dsp_proc_entry.h" 26#include "dsp_proc_entry.h"
27#include "dsp_core.h" 27#include "dsp_core.h"
28#include "dsp_misc.h"
28#include "eq.h" 29#include "eq.h"
29#include "pga.h" 30#include "pga.h"
30#include "replaygain.h" 31#include "replaygain.h"
@@ -42,6 +43,9 @@
42#error Band count must be greater than or equal to 3 43#error Band count must be greater than or equal to 3
43#endif 44#endif
44 45
46/* Cached band settings */
47static struct eq_band_setting settings[EQ_NUM_BANDS];
48
45static struct eq_state 49static struct eq_state
46{ 50{
47 uint32_t enabled; /* Mask of enabled bands */ 51 uint32_t enabled; /* Mask of enabled bands */
@@ -49,16 +53,48 @@ static struct eq_state
49 struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */ 53 struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */
50} eq_data IBSS_ATTR; 54} eq_data IBSS_ATTR;
51 55
56#define FOR_EACH_ENB_BAND(b) \
57 for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++)
58
52/* Clear histories of all enabled bands */ 59/* Clear histories of all enabled bands */
53static void eq_flush(void) 60static void eq_flush(void)
54{ 61{
55 if (eq_data.enabled == 0) 62 if (eq_data.enabled == 0)
56 return; /* Not initialized yet/no bands on */ 63 return; /* Not initialized yet/no bands on */
57 64
58 for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) 65 FOR_EACH_ENB_BAND(b)
59 filter_flush(&eq_data.filters[*b]); 66 filter_flush(&eq_data.filters[*b]);
60} 67}
61 68
69static void update_band_filter(int band, unsigned int fout)
70{
71 /* Convert user settings to format required by coef generator
72 functions */
73 typeof (filter_pk_coefs) *coef_gen = filter_pk_coefs;
74
75 /* Only first and last bands are not peaking filters */
76 if (band == 0)
77 coef_gen = filter_ls_coefs;
78 else if (band == EQ_NUM_BANDS-1)
79 coef_gen = filter_hs_coefs;
80
81 const struct eq_band_setting *setting = &settings[band];
82 struct dsp_filter *filter = &eq_data.filters[band];
83
84 coef_gen(fp_div(setting->cutoff, fout, 32), setting->q ?: 1,
85 setting->gain, filter);
86}
87
88/* Resync all bands to a new DSP output frequency */
89static void update_samplerate(unsigned int fout)
90{
91 if (eq_data.enabled == 0)
92 return; /* Not initialized yet/no bands on */
93
94 FOR_EACH_ENB_BAND(b)
95 update_band_filter(*b, fout);
96}
97
62/** DSP interface **/ 98/** DSP interface **/
63 99
64/* Set the precut gain value */ 100/* Set the precut gain value */
@@ -73,11 +109,14 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting)
73 if (band < 0 || band >= EQ_NUM_BANDS) 109 if (band < 0 || band >= EQ_NUM_BANDS)
74 return; 110 return;
75 111
112 settings[band] = *setting; /* cache setting */
113
114 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
115
76 /* NOTE: The coef functions assume the EMAC unit is in fractional mode, 116 /* NOTE: The coef functions assume the EMAC unit is in fractional mode,
77 which it should be, since we're executed from the main thread. */ 117 which it should be, since we're executed from the main thread. */
78 118
79 uint32_t mask = eq_data.enabled; 119 uint32_t mask = eq_data.enabled;
80 struct dsp_filter *filter = &eq_data.filters[band];
81 120
82 /* Assume a band is disabled if the gain is zero */ 121 /* Assume a band is disabled if the gain is zero */
83 mask &= ~BIT_N(band); 122 mask &= ~BIT_N(band);
@@ -85,33 +124,19 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting)
85 if (setting->gain != 0) 124 if (setting->gain != 0)
86 { 125 {
87 mask |= BIT_N(band); 126 mask |= BIT_N(band);
88 127 update_band_filter(band, dsp_get_output_frequency(dsp));
89 /* Convert user settings to format required by coef generator
90 functions */
91 void (* coef_gen)(unsigned long cutoff, unsigned long Q, long db,
92 struct dsp_filter *f) = filter_pk_coefs;
93
94 /* Only first and last bands are not peaking filters */
95 if (band == 0)
96 coef_gen = filter_ls_coefs;
97 else if (band == EQ_NUM_BANDS-1)
98 coef_gen = filter_hs_coefs;
99
100 coef_gen(0xffffffff / NATIVE_FREQUENCY * setting->cutoff,
101 setting->q ?: 1, setting->gain, filter);
102 } 128 }
103 129
104 if (mask == eq_data.enabled) 130 if (mask == eq_data.enabled)
105 return; /* No change in band-enable state */ 131 return; /* No change in band-enable state */
106 132
107 if (mask & BIT_N(band)) 133 if (mask & BIT_N(band))
108 filter_flush(filter); /* Coming online */ 134 filter_flush(&eq_data.filters[band]); /* Coming online */
109 135
110 eq_data.enabled = mask; 136 eq_data.enabled = mask;
111 137
112 /* Only be active if there are bands to process - if EQ is off, then 138 /* Only be active if there are bands to process - if EQ is off, then
113 this call has no effect */ 139 this call has no effect */
114 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
115 dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0); 140 dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0);
116 141
117 /* Prepare list of enabled bands for efficient iteration */ 142 /* Prepare list of enabled bands for efficient iteration */
@@ -125,6 +150,11 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting)
125void dsp_eq_enable(bool enable) 150void dsp_eq_enable(bool enable)
126{ 151{
127 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); 152 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
153 bool enabled = dsp_proc_enabled(dsp, DSP_PROC_EQUALIZER);
154
155 if (enable == enabled)
156 return;
157
128 dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable); 158 dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable);
129 159
130 if (enable && eq_data.enabled != 0) 160 if (enable && eq_data.enabled != 0)
@@ -139,7 +169,7 @@ static void eq_process(struct dsp_proc_entry *this,
139 int count = buf->remcount; 169 int count = buf->remcount;
140 unsigned int channels = buf->format.num_channels; 170 unsigned int channels = buf->format.num_channels;
141 171
142 for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) 172 FOR_EACH_ENB_BAND(b)
143 filter_process(&eq_data.filters[*b], buf->p32, count, channels); 173 filter_process(&eq_data.filters[*b], buf->p32, count, channels);
144 174
145 (void)this; 175 (void)this;
@@ -154,10 +184,9 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
154 switch (setting) 184 switch (setting)
155 { 185 {
156 case DSP_PROC_INIT: 186 case DSP_PROC_INIT:
157 if (value != 0)
158 break; /* Already enabled */
159
160 this->process = eq_process; 187 this->process = eq_process;
188 /* Wouldn't have been getting frequency updates */
189 update_samplerate(dsp_get_output_frequency(dsp));
161 /* Fall-through */ 190 /* Fall-through */
162 case DSP_PROC_CLOSE: 191 case DSP_PROC_CLOSE:
163 pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT); 192 pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT);
@@ -166,6 +195,10 @@ static intptr_t eq_configure(struct dsp_proc_entry *this,
166 case DSP_FLUSH: 195 case DSP_FLUSH:
167 eq_flush(); 196 eq_flush();
168 break; 197 break;
198
199 case DSP_SET_OUT_FREQUENCY:
200 update_samplerate(value);
201 break;
169 } 202 }
170 203
171 return 0; 204 return 0;
diff --git a/lib/rbcodec/dsp/resample.c b/lib/rbcodec/dsp/resample.c
index 6e7e5b7b45..0a97bdf70c 100644
--- a/lib/rbcodec/dsp/resample.c
+++ b/lib/rbcodec/dsp/resample.c
@@ -25,6 +25,7 @@
25#include "fracmul.h" 25#include "fracmul.h"
26#include "fixedpoint.h" 26#include "fixedpoint.h"
27#include "dsp_proc_entry.h" 27#include "dsp_proc_entry.h"
28#include "dsp_misc.h"
28#include <string.h> 29#include <string.h>
29 30
30/** 31/**
@@ -50,9 +51,10 @@ static struct resample_data
50 int32_t history[2][3]; /* 08h: Last samples for interpolation (L+R) 51 int32_t history[2][3]; /* 08h: Last samples for interpolation (L+R)
51 0 = oldest, 2 = newest */ 52 0 = oldest, 2 = newest */
52 /* 20h */ 53 /* 20h */
53 int32_t frequency; /* Virtual samplerate */ 54 unsigned int frequency; /* Virtual input samplerate */
55 unsigned int frequency_out; /* Resampler output samplerate */
54 struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */ 56 struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */
55 int32_t *resample_out_p[2]; /* Actual output buffer pointers */ 57 int32_t *resample_out_p[2]; /* Actual output buffer pointers */
56} resample_data[DSP_COUNT] IBSS_ATTR; 58} resample_data[DSP_COUNT] IBSS_ATTR;
57 59
58/* Actual worker function. Implemented here or in target assembly code. */ 60/* Actual worker function. Implemented here or in target assembly code. */
@@ -73,14 +75,16 @@ static void resample_flush(struct dsp_proc_entry *this)
73} 75}
74 76
75static bool resample_new_delta(struct resample_data *data, 77static bool resample_new_delta(struct resample_data *data,
76 struct sample_format *format) 78 struct sample_format *format,
79 unsigned int fout)
77{ 80{
78 int32_t frequency = format->frequency; /* virtual samplerate */ 81 unsigned int frequency = format->frequency; /* virtual samplerate */
79 82
80 data->frequency = frequency; 83 data->frequency = frequency;
81 data->delta = fp_div(frequency, NATIVE_FREQUENCY, 16); 84 data->frequency_out = fout;
85 data->delta = fp_div(frequency, fout, 16);
82 86
83 if (frequency == NATIVE_FREQUENCY) 87 if (frequency == data->frequency_out)
84 { 88 {
85 /* NOTE: If fully glitch-free transistions from no resampling to 89 /* NOTE: If fully glitch-free transistions from no resampling to
86 resampling are desired, history should be maintained even when 90 resampling are desired, history should be maintained even when
@@ -232,20 +236,23 @@ static intptr_t resample_new_format(struct dsp_proc_entry *this,
232 236
233 DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format); 237 DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format);
234 238
235 int32_t frequency = data->frequency; 239 unsigned int frequency = data->frequency;
240 unsigned int fout = dsp_get_output_frequency(dsp);
236 bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE); 241 bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE);
237 242
238 if (format->frequency != frequency) 243 if ((unsigned int)format->frequency != frequency ||
244 data->frequency_out != fout)
239 { 245 {
240 DEBUGF(" DSP_PROC_RESAMPLE- new delta\n"); 246 DEBUGF(" DSP_PROC_RESAMPLE- new settings: %u %u\n",
241 active = resample_new_delta(data, format); 247 format->frequency, fout);
248 active = resample_new_delta(data, format, fout);
242 dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active); 249 dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active);
243 } 250 }
244 251
245 /* Everything after us is NATIVE_FREQUENCY */ 252 /* Everything after us is fout */
246 dst->format = *format; 253 dst->format = *format;
247 dst->format.frequency = NATIVE_FREQUENCY; 254 dst->format.frequency = fout;
248 dst->format.codec_frequency = NATIVE_FREQUENCY; 255 dst->format.codec_frequency = fout;
249 256
250 if (active) 257 if (active)
251 return PROC_NEW_FORMAT_OK; 258 return PROC_NEW_FORMAT_OK;
@@ -287,8 +294,10 @@ static void INIT_ATTR resample_dsp_init(struct dsp_config *dsp,
287static void INIT_ATTR resample_proc_init(struct dsp_proc_entry *this, 294static void INIT_ATTR resample_proc_init(struct dsp_proc_entry *this,
288 struct dsp_config *dsp) 295 struct dsp_config *dsp)
289{ 296{
297 struct resample_data *data = &resample_data[dsp_get_id(dsp)];
298 this->data = (intptr_t)data;
290 dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false); 299 dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false);
291 this->data = (intptr_t)&resample_data[dsp_get_id(dsp)]; 300 data->frequency_out = DSP_OUT_DEFAULT_HZ;
292 this->process = resample_process; 301 this->process = resample_process;
293} 302}
294 303
@@ -322,6 +331,10 @@ static intptr_t resample_configure(struct dsp_proc_entry *this,
322 case DSP_PROC_NEW_FORMAT: 331 case DSP_PROC_NEW_FORMAT:
323 retval = resample_new_format(this, dsp, (struct sample_format *)value); 332 retval = resample_new_format(this, dsp, (struct sample_format *)value);
324 break; 333 break;
334
335 case DSP_SET_OUT_FREQUENCY:
336 dsp_proc_want_format_update(dsp, DSP_PROC_RESAMPLE);
337 break;
325 } 338 }
326 339
327 return retval; 340 return retval;
diff --git a/lib/rbcodec/dsp/tone_controls.c b/lib/rbcodec/dsp/tone_controls.c
index e636b04b9a..4266af4d97 100644
--- a/lib/rbcodec/dsp/tone_controls.c
+++ b/lib/rbcodec/dsp/tone_controls.c
@@ -21,9 +21,11 @@
21 ****************************************************************************/ 21 ****************************************************************************/
22#include "rbcodecconfig.h" 22#include "rbcodecconfig.h"
23#include "platform.h" 23#include "platform.h"
24#include "fixedpoint.h"
24#include "dsp_proc_entry.h" 25#include "dsp_proc_entry.h"
25#include "dsp_filter.h" 26#include "dsp_filter.h"
26#include "tone_controls.h" 27#include "tone_controls.h"
28#include "dsp_misc.h"
27 29
28/* These apply to all DSP streams to remain as consistant as possible with 30/* These apply to all DSP streams to remain as consistant as possible with
29 * the behavior of hardware tone controls */ 31 * the behavior of hardware tone controls */
@@ -36,32 +38,39 @@ static const unsigned int tone_treble_cutoff = 3500;
36static int tone_bass = 0; 38static int tone_bass = 0;
37static int tone_treble = 0; 39static int tone_treble = 0;
38 40
41/* Current prescaler setting */
42static int tone_prescale = 0;
43
39/* Data for each DSP */ 44/* Data for each DSP */
40static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR; 45static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR;
41 46
47static void update_filter(int id, unsigned int fout)
48{
49 filter_bishelf_coefs(fp_div(tone_bass_cutoff, fout, 32),
50 fp_div(tone_treble_cutoff, fout, 32),
51 tone_bass, tone_treble, -tone_prescale,
52 &tone_filters[id]);
53}
54
42/* Update the filters' coefficients based upon the bass/treble settings */ 55/* Update the filters' coefficients based upon the bass/treble settings */
43void tone_set_prescale(int prescale) 56void tone_set_prescale(int prescale)
44{ 57{
45 int bass = tone_bass; 58 int bass = tone_bass;
46 int treble = tone_treble; 59 int treble = tone_treble;
47 60
48 struct dsp_filter tone_filter; /* Temp to hold new version */ 61 tone_prescale = prescale;
49 filter_bishelf_coefs(0xffffffff / NATIVE_FREQUENCY * tone_bass_cutoff,
50 0xffffffff / NATIVE_FREQUENCY * tone_treble_cutoff,
51 bass, treble, -prescale, &tone_filter);
52 62
53 struct dsp_config *dsp; 63 struct dsp_config *dsp;
54 for (int i = 0; (dsp = dsp_get_config(i)); i++) 64 for (int i = 0; (dsp = dsp_get_config(i)); i++)
55 { 65 {
56 struct dsp_filter *filter = &tone_filters[i]; 66 update_filter(i, dsp_get_output_frequency(dsp));
57 filter_copy(filter, &tone_filter);
58 67
59 bool enable = bass != 0 || treble != 0; 68 bool enable = bass != 0 || treble != 0;
60 dsp_proc_enable(dsp, DSP_PROC_TONE_CONTROLS, enable); 69 dsp_proc_enable(dsp, DSP_PROC_TONE_CONTROLS, enable);
61 70
62 if (!dsp_proc_active(dsp, DSP_PROC_TONE_CONTROLS)) 71 if (enable && !dsp_proc_active(dsp, DSP_PROC_TONE_CONTROLS))
63 { 72 {
64 filter_flush(filter); /* Going online */ 73 filter_flush(&tone_filters[i]); /* Going online */
65 dsp_proc_activate(dsp, DSP_PROC_TONE_CONTROLS, true); 74 dsp_proc_activate(dsp, DSP_PROC_TONE_CONTROLS, true);
66 } 75 }
67 } 76 }
@@ -109,6 +118,10 @@ static intptr_t tone_configure(struct dsp_proc_entry *this,
109 case DSP_FLUSH: 118 case DSP_FLUSH:
110 filter_flush((struct dsp_filter *)this->data); 119 filter_flush((struct dsp_filter *)this->data);
111 break; 120 break;
121
122 case DSP_SET_OUT_FREQUENCY:
123 update_filter(dsp_get_id(dsp), value);
124 break;
112 } 125 }
113 126
114 return 0; 127 return 0;
diff --git a/lib/rbcodec/rbcodecconfig-example.h b/lib/rbcodec/rbcodecconfig-example.h
index 7ecbc1e96f..e5da42feba 100644
--- a/lib/rbcodec/rbcodecconfig-example.h
+++ b/lib/rbcodec/rbcodecconfig-example.h
@@ -5,6 +5,10 @@
5#define HAVE_SW_TONE_CONTROLS 5#define HAVE_SW_TONE_CONTROLS
6#define HAVE_ALBUMART 6#define HAVE_ALBUMART
7#define NUM_CORES 1 7#define NUM_CORES 1
8/* All the same unless a configuration option is added to warble */
9#define DSP_OUT_MIN_HZ 44100
10#define DSP_OUT_DEFAULT_HZ 44100
11#define DSP_OUT_MAX_HZ 44100
8 12
9#ifndef __ASSEMBLER__ 13#ifndef __ASSEMBLER__
10 14
diff --git a/lib/rbcodec/test/warble.c b/lib/rbcodec/test/warble.c
index 735fa2511f..336438374c 100644
--- a/lib/rbcodec/test/warble.c
+++ b/lib/rbcodec/test/warble.c
@@ -145,7 +145,7 @@ static void write_wav_header(void)
145 if (use_dsp) { 145 if (use_dsp) {
146 channels = 2; 146 channels = 2;
147 sample_size = 16; 147 sample_size = 16;
148 freq = NATIVE_FREQUENCY; 148 freq = dsp_get_output_frequency(ci.dsp);
149 type = WAVE_FORMAT_PCM; 149 type = WAVE_FORMAT_PCM;
150 } else { 150 } else {
151 channels = format.channels; 151 channels = format.channels;
@@ -312,7 +312,7 @@ static void playback_start(void)
312{ 312{
313 playback_running = true; 313 playback_running = true;
314 SDL_AudioSpec spec = {0}; 314 SDL_AudioSpec spec = {0};
315 spec.freq = NATIVE_FREQUENCY; 315 spec.freq = dsp_get_output_frequency(ci.dsp);
316 spec.format = AUDIO_S16SYS; 316 spec.format = AUDIO_S16SYS;
317 spec.channels = 2; 317 spec.channels = 2;
318 spec.samples = 0x400; 318 spec.samples = 0x400;
@@ -776,6 +776,7 @@ static void decode_file(const char *input_fn)
776 ci.id3 = &id3; 776 ci.id3 = &id3;
777 if (use_dsp) { 777 if (use_dsp) {
778 ci.dsp = dsp_get_config(CODEC_IDX_AUDIO); 778 ci.dsp = dsp_get_config(CODEC_IDX_AUDIO);
779 dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, DSP_OUT_DEFAULT_HZ);
779 dsp_configure(ci.dsp, DSP_RESET, 0); 780 dsp_configure(ci.dsp, DSP_RESET, 0);
780 dsp_dither_enable(false); 781 dsp_dither_enable(false);
781 } 782 }