diff options
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/dsp/compressor.c | 18 | ||||
-rw-r--r-- | lib/rbcodec/dsp/crossfeed.c | 117 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_arm.S | 84 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_cf.S | 102 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_core.c | 29 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_core.h | 4 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_misc.c | 15 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_misc.h | 7 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_proc_database.h | 2 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_proc_entry.h | 4 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_sample_input.c | 30 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_sample_io.h | 5 | ||||
-rw-r--r-- | lib/rbcodec/dsp/eq.c | 77 | ||||
-rw-r--r-- | lib/rbcodec/dsp/resample.c | 41 | ||||
-rw-r--r-- | lib/rbcodec/dsp/tone_controls.c | 29 | ||||
-rw-r--r-- | lib/rbcodec/rbcodecconfig-example.h | 4 | ||||
-rw-r--r-- | lib/rbcodec/test/warble.c | 5 |
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 | ||
32 | static struct compressor_settings curr_set; /* Cached settings */ | 33 | static 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 */ |
43 | static bool compressor_update(const struct compressor_settings *settings) | 44 | static 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, | |||
300 | void dsp_set_compressor(const struct compressor_settings *settings) | 303 | void 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 */ |
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 | ||
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 | */ |
102 | 10: | 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)+ | . |
107 | 20: | 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 | |
122 | 30: | wrap buffer | ...fwd taken branches more costly | 120 | tpf.w | trap the buffer wrap |
123 | lea.l -104(%a6), %a0 | wrap it up | 121 | 1: | ...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] |
158 | 10: | 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? */ | ||
261 | bool 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 */ |
248 | void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id, | 267 | void 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, | |||
454 | intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, | 473 | intptr_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 | |||
50 | enum dsp_stereo_modes | 50 | enum 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 */ | ||
138 | void 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 */ | ||
147 | unsigned int dsp_get_output_frequency(struct dsp_config *dsp) | ||
148 | { | ||
149 | return dsp_configure(dsp, DSP_GET_OUT_FREQUENCY, 0); | ||
150 | } | ||
151 | |||
137 | static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp, | 152 | static 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); | |||
59 | int32_t dsp_get_pitch(void); | 59 | int32_t dsp_get_pitch(void); |
60 | #endif /* HAVE_PITCHCONTROL */ | 60 | #endif /* HAVE_PITCHCONTROL */ |
61 | 61 | ||
62 | /* Set output samplerate for all DSPs */ | ||
63 | void dsp_set_all_output_frequency(unsigned int samplerate); | ||
64 | |||
65 | /* Return DSP's output samplerate */ | ||
66 | struct dsp_config; | ||
67 | unsigned 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! */ |
133 | void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, | 133 | void 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? */ | ||
137 | bool 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, | |||
286 | static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this, | 286 | static 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 | ||
293 | void dsp_sample_io_configure(struct sample_io_data *this, | 294 | bool 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 */ |
65 | void dsp_sample_io_configure(struct sample_io_data *this, | 66 | bool 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 */ | ||
47 | static struct eq_band_setting settings[EQ_NUM_BANDS]; | ||
48 | |||
45 | static struct eq_state | 49 | static 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 */ |
53 | static void eq_flush(void) | 60 | static 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 | ||
69 | static 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 */ | ||
89 | static 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) | |||
125 | void dsp_eq_enable(bool enable) | 150 | void 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 | ||
75 | static bool resample_new_delta(struct resample_data *data, | 77 | static 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, | |||
287 | static void INIT_ATTR resample_proc_init(struct dsp_proc_entry *this, | 294 | static 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; | |||
36 | static int tone_bass = 0; | 38 | static int tone_bass = 0; |
37 | static int tone_treble = 0; | 39 | static int tone_treble = 0; |
38 | 40 | ||
41 | /* Current prescaler setting */ | ||
42 | static int tone_prescale = 0; | ||
43 | |||
39 | /* Data for each DSP */ | 44 | /* Data for each DSP */ |
40 | static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR; | 45 | static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR; |
41 | 46 | ||
47 | static 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 */ |
43 | void tone_set_prescale(int prescale) | 56 | void 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 | } |