summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2013-05-23 13:58:51 -0400
committerMichael Sevakis <jethead71@rockbox.org>2013-07-06 04:22:04 +0200
commitd37bf24d9011addbfbd40942a4e9bbf26de7df00 (patch)
treedafb7eaeb494081668a4841d490fce2bfbb2438d /lib
parent00faabef5e902008172e08d3bcd77683cbafef51 (diff)
downloadrockbox-d37bf24d9011addbfbd40942a4e9bbf26de7df00.tar.gz
rockbox-d37bf24d9011addbfbd40942a4e9bbf26de7df00.zip
Enable setting of global output samplerate on certain targets.
Replaces the NATIVE_FREQUENCY constant with a configurable frequency. The user may select 48000Hz if the hardware supports it. The default is still 44100Hz and the minimum is 44100Hz. The setting is located in the playback settings, under "Frequency". "Frequency" was duplicated in english.lang for now to avoid having to fix every .lang file for the moment and throwing everything out of sync because of the new play_frequency feature in features.txt. The next cleanup should combine it with the one included for recording and generalize the ID label. If the hardware doesn't support 48000Hz, no setting will be available. On particular hardware where very high rates are practical and desireable, the upper bound can be extended by patching. The PCM mixer can be configured to play at the full hardware frequency range. The DSP core can configure to the hardware minimum up to the maximum playback setting (some buffers must be reserved according to the maximum rate). If only 44100Hz is supported or possible on a given target for playback, using the DSP and mixer at other samperates is possible if the hardware offers them. Change-Id: I6023cf0c0baa8bc6292b6919b4dd3618a6a25622 Reviewed-on: http://gerrit.rockbox.org/479 Reviewed-by: Michael Sevakis <jethead71@rockbox.org> Tested-by: Michael Sevakis <jethead71@rockbox.org>
Diffstat (limited to 'lib')
-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 }