diff options
Diffstat (limited to 'lib')
-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 @@ #include "logf.h" #include "dsp_proc_entry.h" #include "compressor.h" +#include "dsp_misc.h" static struct compressor_settings curr_set; /* Cached settings */ @@ -40,7 +41,8 @@ static int32_t release_gain IBSS_ATTR; /* S7.24 format */ /** COMPRESSOR UPDATE * Called via the menu system to configure the compressor process */ -static bool compressor_update(const struct compressor_settings *settings) +static bool compressor_update(struct dsp_config *dsp, + const struct compressor_settings *settings) { /* make settings values useful */ int threshold = settings->threshold; @@ -48,9 +50,10 @@ static bool compressor_update(const struct compressor_settings *settings) static const int comp_ratios[] = { 2, 4, 6, 10, 0 }; int ratio = comp_ratios[settings->ratio]; bool soft_knee = settings->knee == 1; - int release = settings->release_time * NATIVE_FREQUENCY / 1000; + int release = settings->release_time * + dsp_get_output_frequency(dsp) / 1000; - bool changed = false; + bool changed = settings == &curr_set; /* If frequency change */ bool active = threshold < 0; if (memcmp(settings, &curr_set, sizeof (curr_set))) @@ -300,8 +303,8 @@ static inline int32_t get_compression_gain(struct sample_format *format, void dsp_set_compressor(const struct compressor_settings *settings) { /* enable/disable the compressor depending upon settings */ - bool enable = compressor_update(settings); struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); + bool enable = compressor_update(dsp, settings); dsp_proc_enable(dsp, DSP_PROC_COMPRESSOR, enable); dsp_proc_activate(dsp, DSP_PROC_COMPRESSOR, true); } @@ -386,15 +389,20 @@ static intptr_t compressor_configure(struct dsp_proc_entry *this, break; /* Already enabled */ this->process = compressor_process; + /* Won't have been getting frequency updates */ + compressor_update(dsp, &curr_set); /* Fall-through */ case DSP_RESET: case DSP_FLUSH: release_gain = UNITY; break; + + case DSP_SET_OUT_FREQUENCY: + compressor_update(dsp, &curr_set); + break; } return 0; - (void)dsp; } /* 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 @@ #include "fixedpoint.h" #include "fracmul.h" #include "replaygain.h" +#include "dsp_misc.h" #include "dsp_proc_entry.h" #include "dsp_filter.h" #include "crossfeed.h" @@ -44,32 +45,40 @@ void crossfeed_meier_process(struct dsp_proc_entry *this, * to listen to on headphones with no crossfeed. */ +#define DELAY_LEN(fs) ((300*(fs) / 1000000)*2) /* ~300 uS */ + /* Crossfeed */ static struct crossfeed_state { - int32_t gain; /* 00h: Direct path gain */ - int32_t coefs[3]; /* 04h: Coefficients for the shelving filter */ union { - struct /* 10h: Data for meier crossfeed */ + struct /* Data for meier crossfeed */ { - int32_t vcl; - int32_t vcr; - int32_t vdiff; - int32_t coef1; - int32_t coef2; + int32_t reserved; /* 00h: Reserved: overlaps gain */ + int32_t vcl; /* 04h: Left filter output */ + int32_t vcr; /* 08h: Right filter output */ + int32_t vdiff; /* 0ch: L-R difference signal */ + int32_t coef1; /* 10h: Left/right filter coef */ + int32_t coef2; /* 14h: Crossfeed filter coef */ }; - struct /* 10h: Data for custom crossfeed */ + struct /* Data for custom crossfeed */ { + int32_t gain; /* 00h: Direct path gain */ + int32_t coefs[3]; /* 04h: Filter coefficients: b0, b1, a1 */ int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */ - int32_t delay[13*2];/* 20h: Delay line buffer (L + R interleaved) */ + int32_t *index; /* 20h: Current pointer into the delay line */ + int32_t *index_max; /* 24h: Current max pointer of delay line */ + /* 28h: Delay line buffer (L + R interleaved) */ + int32_t delay[DELAY_LEN(DSP_OUT_MAX_HZ)]; /* Target-dependent size */ }; }; - int32_t *index; /* 88h: Current pointer into the delay line */ - /* 8ch */ } crossfeed_state IBSS_ATTR; static int crossfeed_type = CROSSFEED_TYPE_NONE; +/* Cached custom settings */ +static long crossfeed_lf_gain; +static long crossfeed_hf_gain; +static long crossfeed_cutoff; /* Discard the sample histories */ static void crossfeed_flush(struct dsp_proc_entry *this) @@ -82,12 +91,49 @@ static void crossfeed_flush(struct dsp_proc_entry *this) } else { - memset(state->history, 0, - sizeof (state->history) + sizeof (state->delay)); + memset(state->history, 0, sizeof (state->history)); + memset(state->delay, 0, sizeof (state->delay)); state->index = state->delay; } } +static void crossfeed_meier_update_filter(struct crossfeed_state *state, + unsigned int fout) +{ + /* 1 / (F.Rforward.C) */ + state->coef1 = fp_div(2128, fout, 31); + /* 1 / (F.Rcross.C) */ + state->coef2 = fp_div(1000, fout, 31); +} + +static void crossfeed_custom_update_filter(struct crossfeed_state *state, + unsigned int fout) +{ + long lf_gain = crossfeed_lf_gain; + long hf_gain = crossfeed_hf_gain; + long cutoff = crossfeed_cutoff; + int32_t *c = state->coefs; + + long scaler = get_replaygain_int(lf_gain * 10) << 7; + + cutoff = fp_div(cutoff, fout, 32); + hf_gain -= lf_gain; + /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB + * point instead of shelf midpoint. This is for compatibility with the old + * crossfeed shelf filter and should be removed if crossfeed settings are + * ever made incompatible for any other good reason. + */ + cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24); + + filter_shelf_coefs(cutoff, hf_gain, false, c); + /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains + * over 1 and can do this safely + */ + c[0] = FRACMUL_SHL(c[0], scaler, 4); + c[1] = FRACMUL_SHL(c[1], scaler, 4); + c[2] <<= 4; +} + /** DSP interface **/ @@ -114,24 +160,13 @@ void dsp_set_crossfeed_direct_gain(int gain) /* Both gains should be below 0 dB */ void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) { - int32_t *c = crossfeed_state.coefs; - long scaler = get_replaygain_int(lf_gain * 10) << 7; + crossfeed_lf_gain = lf_gain; + crossfeed_hf_gain = hf_gain; + crossfeed_cutoff = cutoff; - cutoff = 0xffffffff / NATIVE_FREQUENCY * cutoff; - hf_gain -= lf_gain; - /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB - * point instead of shelf midpoint. This is for compatibility with the old - * crossfeed shelf filter and should be removed if crossfeed settings are - * ever made incompatible for any other good reason. - */ - cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24); - filter_shelf_coefs(cutoff, hf_gain, false, c); - /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains - * over 1 and can do this safely - */ - c[0] = FRACMUL_SHL(c[0], scaler, 4); - c[1] = FRACMUL_SHL(c[1], scaler, 4); - c[2] <<= 4; + struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); + crossfeed_custom_update_filter(&crossfeed_state, + dsp_get_output_frequency(dsp)); } #if !defined(CPU_COLDFIRE) && !defined(CPU_ARM) @@ -147,6 +182,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p) int32_t *coefs = &state->coefs[0]; int32_t gain = state->gain; int32_t *di = state->index; + int32_t *di_max = state->index_max; int count = buf->remcount; @@ -176,7 +212,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p) buf->p32[1][i] = FRACMUL(right, gain) + hist_l[1]; /* Wrap delay line index if bigger than delay line size */ - if (di >= delay + 13*2) + if (di >= di_max) di = delay; } @@ -234,17 +270,21 @@ static void update_process_fn(struct dsp_proc_entry *this, struct dsp_config *dsp) { struct crossfeed_state *state = (struct crossfeed_state *)this->data; - dsp_proc_fn_type fn = crossfeed_process; + dsp_proc_fn_type fn; + + unsigned int fout = dsp_get_output_frequency(dsp); if (crossfeed_type != CROSSFEED_TYPE_CUSTOM) { - /* Set up for Meier */ - /* 1 / (F.Rforward.C) */ - state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128; - /* 1 / (F.Rcross.C) */ - state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000; + crossfeed_meier_update_filter(state, fout); fn = crossfeed_meier_process; } + else + { + state->index_max = state->delay + DELAY_LEN(fout); + crossfeed_custom_update_filter(state, fout); + fn = crossfeed_process; + } if (this->process != fn) { @@ -292,6 +332,7 @@ static intptr_t crossfeed_configure(struct dsp_proc_entry *this, if (value == 0) this->data = (intptr_t)&crossfeed_state; + case DSP_SET_OUT_FREQUENCY: update_process_fn(this, dsp); break; 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: @ to keep the count on the stack :/ ldr r1, [r1] @ r1 = buf = *buf_p; stmfd sp!, { r4-r11, lr } @ stack modified regs - ldr r12, [r1] @ r12 = buf->remcount - ldr r14, [r0] @ r14 = this->data = &crossfeed_state - ldmib r1, { r2-r3 } @ r2 = buf->p32[0], r3 = buf->p32[1] - ldmia r14!, { r4-r11 } @ load direct gain and filter data - add r0, r14, #13*2*4 @ calculate end of delay - stmfd sp!, { r0, r12 } @ stack end of delay adr, count and state - ldr r0, [r0] @ fetch current delay line address - - /* Register usage in loop: - * r0 = &delay[index][0], r1 = accumulator high, r2 = buf->p32[0], + ldr r0, [r0] @ r0 = this->data = &crossfeed_state + ldmia r1, { r1-r3 } @ r1 = buf->remcount, r2 = buf->p32[0], + @ r3 = buf->p32[1] + ldmia r0, { r4-r12, r14 } @ r4 = gain, r5-r7 = coeffs, + @ r8-r11 = history, r12 = index, + @ r14 = index_max + add r0, r0, #0x28 @ r0 = state->delay + stmfd sp!, { r0-r1, r14 } @ stack state->delay, count, index_max + + /* Register usage in loop: + * r0 = acc low/count, r1 = acc high, r2 = buf->p32[0], * r3 = buf->p32[1], r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs), - * r8-r11 = filter history, r12 = temp, r14 = accumulator low + * r8 = dr[n-1], r9 = y_r[n-1], r10 = dl[n-1], r11 = y_l[n-1], + * r12 = index, r14 = scratch/index_max */ .cfloop: - smull r14, r1, r6, r8 @ acc = b1*dr[n - 1] - smlal r14, r1, r7, r9 @ acc += a1*y_l[n - 1] - ldr r8, [r0, #4] @ r8 = dr[n] - smlal r14, r1, r5, r8 @ acc += b0*dr[n] - mov r9, r1, lsl #1 @ fix format for filter history - ldr r12, [r2] @ load left input - smlal r14, r1, r4, r12 @ acc += gain*x_l[n] - mov r1, r1, lsl #1 @ fix format + smull r0, r1, r6, r8 @ acc = b1*dr[n - 1] + ldr r8, [r12, #4] @ r8 = dr[n] + smlal r0, r1, r7, r9 @ acc += a1*y_r[n - 1] + smlal r0, r1, r5, r8 @ acc += b0*dr[n] + ldr r14, [r2] @ load left input: x_l[n] + mov r9, r1, asl #1 @ fix format for filter history + smlal r0, r1, r4, r14 @ acc += gain*x_l[n] + mov r1, r1, asl #1 @ fix format str r1, [r2], #4 @ save result - - smull r14, r1, r6, r10 @ acc = b1*dl[n - 1] - smlal r14, r1, r7, r11 @ acc += a1*y_r[n - 1] - ldr r10, [r0] @ r10 = dl[n] - str r12, [r0], #4 @ save left input to delay line - smlal r14, r1, r5, r10 @ acc += b0*dl[n] - mov r11, r1, lsl #1 @ fix format for filter history - ldr r12, [r3] @ load right input - smlal r14, r1, r4, r12 @ acc += gain*x_r[n] - str r12, [r0], #4 @ save right input to delay line - mov r1, r1, lsl #1 @ fix format - ldmia sp, { r12, r14 } @ fetch delay line end addr and count from stack + smull r0, r1, r6, r10 @ acc = b1*dl[n - 1] + ldr r10, [r12] @ r10 = dl[n] + smlal r0, r1, r7, r11 @ acc += a1*y_l[n - 1] + smlal r0, r1, r5, r10 @ acc += b0*dl[n] + str r14, [r12], #4 @ save left input to delay line + ldr r14, [r3] @ load right input: x_r[n] + mov r11, r1, asl #1 @ fix format for filter history + smlal r0, r1, r4, r14 @ acc += gain*x_r[n] + str r14, [r12], #4 @ save right input to delay line + ldmib sp, { r0, r14 } @ fetch count and delay end + mov r1, r1, asl #1 @ fix format str r1, [r3], #4 @ save result - cmp r0, r12 @ need to wrap to start of delay? - subhs r0, r12, #13*2*4 @ wrap back delay line ptr to start + cmp r12, r14 @ need to wrap to start of delay? + ldrhs r12, [sp] @ wrap delay index - subs r14, r14, #1 @ are we finished? - strgt r14, [sp, #4] @ nope, save count back to stack + subs r0, r0, #1 @ are we finished? + strgt r0, [sp, #4] @ save count to stack bgt .cfloop @ save data back to struct - str r0, [r12] @ save delay line index - sub r12, r12, #13*2*4 + 4*4 @ r12 = data->history - stmia r12, { r8-r11 } @ save filter history - add sp, sp, #8 @ remove temp variables from stack + ldr r0, [sp] @ fetch state->delay + sub r0, r0, #0x18 @ save filter history and delay index + stmia r0, { r8-r12 } @ + add sp, sp, #12 @ remove temp variables from stack ldmpc regs=r4-r11 .size crossfeed_process, .-crossfeed_process @@ -260,8 +261,7 @@ crossfeed_meier_process: ldr r0, [r0] @ r0 = this->data = &crossfeed_state stmfd sp!, { r4-r10, lr } @ stack non-volatile context ldmia r1, { r1-r3 } @ r1 = buf->remcout, r2=p32[0], r3=p32[1] - add r0, r0, #16 @ r0 = &state->vcl - ldmia r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff + ldmib r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff @ r7 = coef1, r8 = coef2 .cfm_loop: ldr r12, [r2] @ r12 = lout @@ -285,7 +285,7 @@ crossfeed_meier_process: sub r5, r5, r12 @ r5 = vcr -= res2 bgt .cfm_loop @ more samples? - stmia r0, { r4-r6 } @ save vcl, vcr, vdiff + stmib r0, { r4-r6 } @ save vcl, vcr, vdiff ldmpc regs=r4-r10 @ restore non-volatile context, return .size crossfeed_meier_process, .-crossfeed_meier_process 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: movem.l %d2-%d7/%a2-%a6, (%sp) | save all regs movem.l 48(%sp), %a1/%a4 | %a1 = this, %a4 = buf_p move.l (%a4), %a4 | %a4 = buf = *buf_p - movem.l (%a4), %d7/%a4-%a5 | %d7 = buf->remcount, %a4 = buf->p32[0], + movem.l (%a4), %d0/%a4-%a5 | %d0 = buf->remcount, %a4 = buf->p32[0], | %a5 = buf->p32[1] - move.l (%a1), %a1 | %a1 = &crossfeed_state - move.l (%a1)+, %d6 | %d6 = direct gain - movem.l 12(%a1), %d0-%d3 | fetch filter history samples - lea.l 132(%a1), %a6 | %a6 = delay line wrap limit - move.l (%a6), %a0 | fetch delay line address - movem.l (%a1), %a1-%a3 | load filter coefs - bra.b 20f | loop start | go to loop start point + move.l (%a1), %a6 | %d7 = state = &crossfeed_state + movem.l (%a6), %d1-%d6/%a0-%a3 | %d1 = gain, %d2-%d4 = coefs, + | %d5..%d6 = history[0..1], + | %a0..%a1 = history[2..3], + | %a2 = index, %a3 = index_max + lea.l 0x28(%a6), %a6 | %a6 = state->delay + move.l %a6, -(%sp) | push state->delay + bra.b .cfp_loop_start /* Register usage in loop: - * %a0 = delay_p, %a1..%a3 = b0, b1, a1 (filter coefs), - * %a4 = buf[0], %a5 = buf[1], - * %a6 = delay line pointer wrap limit, - * %d0..%d3 = history - * %d4..%d5 = temp. - * %d6 = direct gain, - * %d7 = count + * %d0 = count, %d1 = direct gain, %d2..%d4 = b0, b1, a1 (filter coefs), + * %d5..%d6 = history[0..1], %d7 = scratch + * %a0..%a1 = history[2..3], %a2 = index, %a3 = index_max, + * %a4 = buf[0], %a5 = buf[1], %a6 = scratch */ -10: | loop | - movclr.l %acc0, %d4 | write outputs - move.l %d4, (%a4)+ | . - movclr.l %acc1, %d5 | . - move.l %d5, (%a5)+ | . -20: | loop start | - mac.l %a2, %d0, (%a0)+, %d0, %acc0 | %acc0 = b1*dl[n - 1], %d0 = dl[n] - mac.l %a1, %d0 , %acc0 | %acc0 += b0*dl[n] - mac.l %a3, %d1, (%a5), %d5, %acc0 | %acc0 += a1*y_r[n - 1], load R - mac.l %a2, %d2, (%a0)+, %d2, %acc1 | %acc1 = b1*dr[n - 1], %d2 = dr[n] - mac.l %a1, %d2 , %acc1 | %acc1 += b0*dr[n] - mac.l %a3, %d3, (%a4), %d4, %acc1 | %acc1 += a1*y_l[n - 1], load L - movem.l %d4-%d5, -8(%a0) | save left & right inputs to delay line - move.l %acc0, %d3 | get filtered delayed left sample (y_l[n]) - move.l %acc1, %d1 | get filtered delayed right sample (y_r[n]) - mac.l %d6, %d4, %acc0 | %acc0 += gain*x_l[n] - mac.l %d6, %d5, %acc1 | %acc1 += gain*x_r[n] - cmp.l %a6, %a0 | wrap %a0 if passed end - bhs.b 30f | wrap buffer | - tpf.l | trap the buffer wrap -30: | wrap buffer | ...fwd taken branches more costly - lea.l -104(%a6), %a0 | wrap it up - subq.l #1, %d7 | --count > 0 ? - bgt.b 10b | loop | yes? do more - movclr.l %acc0, %d4 | write last outputs - move.l %d4, (%a4) | . - movclr.l %acc1, %d5 | . - move.l %d5, (%a5) | . - movem.l %d0-%d3, -120(%a6) | ...history - move.l %a0, (%a6) | ...delay_p +.cfp_loop: + movclr.l %acc0, %d7 | write outputs + move.l %d7, (%a4)+ | . + movclr.l %acc1, %a6 | . + move.l %a6, (%a5)+ | . +.cfp_loop_start: + mac.l %d3, %d5, (%a2)+, %d5, %acc1 | %acc1 = b1*dl[n - 1], %d5 = dl[n] + mac.l %d2, %d5 , %acc1 | %acc1 += b0*dl[n] + mac.l %d4, %d6, (%a4), %d7, %acc1 | %acc1 += a1*y_l[n - 1], %d7 = x_l[n] + mac.l %d3, %a0, (%a2)+, %a0, %acc0 | %acc0 = b1*dr[n - 1], %a0 = dr[n] + mac.l %a2, %a0 , %acc0 | %acc0 += b0*dr[n] + mac.l %d4, %a1, (%a5), %a6, %acc0 | %acc0 += a1*y_r[n - 1], %a6 = x_r[n] + movem.l %d7/%a6, -8(%a2) | save x_l[n] and x_r[n] to delay line + move.l %acc1, %d6 | get filtered delayed left sample (y_l[n]) + move.l %acc0, %a1 | get filtered delayed right sample (y_r[n]) + mac.l %d1, %d7, %acc0 | %acc0 = gain*x_l[n] + y_r[n] + mac.l %d1, %a6, %acc1 | %acc1 = gain*x_r[n] + y_l[n] + + cmp.l %a3, %a2 | wrap index if past end + bhs.b 1f | + tpf.w | trap the buffer wrap +1: | ...fwd taken branches more costly + move.l (%sp), %a2 | 2b | wrap it up + + subq.l #1, %d0 | --count > 0 ? + bgt.b .cfp_loop | yes? do more + + movclr.l %acc0, %d7 | write last outputs + move.l %d7, (%a4) | . + movclr.l %acc1, %a6 | . + move.l %a6, (%a5) | . + + move.l (%sp)+, %a6 | pop state->delay + movem.l %d5-%d6/%a0-%a2, -0x18(%a6) | save history, index movem.l (%sp), %d2-%d7/%a2-%a6 | restore all regs lea.l 44(%sp), %sp | rts | - .size crossfeed_process,.-crossfeed_process + .size crossfeed_process, .-crossfeed_process /**************************************************************************** * void crossfeed_meier_process(struct dsp_proc_entry *this, @@ -147,7 +149,7 @@ crossfeed_meier_process: movem.l %d2-%d6/%a2, (%sp) | . move.l (%a0), %a0 | %a0 = &this->data = &crossfeed_state move.l (%a1), %a1 | %a1 = buf = *buf_p - movem.l 16(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff, + movem.l 4(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff, | %d4 = coef1, %d5 = coef2 movem.l (%a1), %d0/%a1-%a2 | %d0 = count = buf->remcount | %a1 = p32[0], %a2 = p32[1] @@ -155,7 +157,7 @@ crossfeed_meier_process: | %d0 = count, %d1 = vcl, %d2 = vcr, %d3 = vdiff/lout, | %d4 = coef1, %d5 = coef2, %d6 = rout/scratch | %a1 = p32[0], %a2 = p32[1] -10: | loop +.cfmp_loop: mac.l %d5, %d3, %acc0 | %acc0 = common = coef2*vdiff move.l %acc0, %acc1 | copy common mac.l %d4, %d1, (%a1), %d3, %acc0 | %acc0 += coef1*vcl, %d3 = lout @@ -170,9 +172,9 @@ crossfeed_meier_process: movclr.l %acc1, %d6 | %d5 = fetch -res2 in s0.31 add.l %d6, %d2 | vcr += -res2 subq.l #1, %d0 | count-- - bgt 10b | loop | more samples? + bgt .cfmp_loop | more samples? | - movem.l %d1-%d3, 16(%a0) | save vcl, vcr, vdiff + movem.l %d1-%d3, 4(%a0) | save vcl, vcr, vdiff movem.l (%sp), %d2-%d6/%a2 | restore non-volatiles lea.l 24(%sp), %sp | . 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, intptr_t value) { bool multi = setting < DSP_PROC_SETTING; - struct dsp_proc_slot *s = multi ? dsp->proc_slots : - find_proc_slot(dsp, setting - DSP_PROC_SETTING); + struct dsp_proc_slot *s; + + if (multi) + { + /* Message to all enabled stages */ + if (dsp_sample_io_configure(&dsp->io_data, setting, &value)) + return value; /* To I/O only */ + + s = dsp->proc_slots; + } + else + { + /* Message to a particular stage */ + s = find_proc_slot(dsp, setting - DSP_PROC_SETTING); + } while (s != NULL) { @@ -117,7 +130,7 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting, s = s->next; } - return multi ? 1 : 0; + return 0; } /* Add an item to the enabled list */ @@ -244,6 +257,12 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0); } +/* Is the stage specified by the id currently enabled? */ +bool dsp_proc_enabled(struct dsp_config *dsp, enum dsp_proc_ids id) +{ + return (dsp->proc_mask_enabled & BIT_N(id)) != 0; +} + /* Activate or deactivate a stage */ void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id, bool activate) @@ -454,7 +473,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, intptr_t value) { - dsp_sample_io_configure(&dsp->io_data, setting, value); return proc_broadcast(dsp, setting, value); } @@ -497,7 +515,8 @@ void INIT_ATTR dsp_init(void) count = slot_count[i]; dsp->slot_free_mask = MASK_N(uint32_t, count, shift); - dsp_sample_io_configure(&dsp->io_data, DSP_INIT, i); + intptr_t value = i; + dsp_sample_io_configure(&dsp->io_data, DSP_INIT, &value); /* Notify each db entry of global init for each DSP */ 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 DSP_SET_STEREO_MODE, DSP_FLUSH, DSP_SET_PITCH, + DSP_SET_OUT_FREQUENCY, + DSP_GET_OUT_FREQUENCY, DSP_PROC_INIT, DSP_PROC_CLOSE, DSP_PROC_NEW_FORMAT, DSP_PROC_SETTING, /* stage-specific should be this + id */ }; -#define NATIVE_FREQUENCY 44100 /* internal/output sample rate */ - enum dsp_stereo_modes { 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) } #endif /* HAVE_PITCHCONTROL */ +/* Set output samplerate for all DSPs */ +void dsp_set_all_output_frequency(unsigned int samplerate) +{ + + struct dsp_config *dsp; + for (int i = 0; (dsp = dsp_get_config(i)); i++) + dsp_configure(dsp, DSP_SET_OUT_FREQUENCY, samplerate); +} + +/* Return DSP's output samplerate */ +unsigned int dsp_get_output_frequency(struct dsp_config *dsp) +{ + return dsp_configure(dsp, DSP_GET_OUT_FREQUENCY, 0); +} + static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp, enum dsp_ids dsp_id) { 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); int32_t dsp_get_pitch(void); #endif /* HAVE_PITCHCONTROL */ +/* Set output samplerate for all DSPs */ +void dsp_set_all_output_frequency(unsigned int samplerate); + +/* Return DSP's output samplerate */ +struct dsp_config; +unsigned int dsp_get_output_frequency(struct dsp_config *dsp); + #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 #ifdef HAVE_PITCHCONTROL DSP_PROC_DB_ITEM(TIMESTRETCH) /* time-stretching */ #endif - DSP_PROC_DB_ITEM(RESAMPLE) /* resampler providing NATIVE_FREQUENCY */ + DSP_PROC_DB_ITEM(RESAMPLE) /* resampler providing output frequency */ DSP_PROC_DB_ITEM(CROSSFEED) /* stereo crossfeed */ DSP_PROC_DB_ITEM(EQUALIZER) /* n-band equalizer */ #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, * by processing code! */ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, bool enable); + +/* Is the specified stage enabled on the DSP? */ +bool dsp_proc_enabled(struct dsp_config *dsp, enum dsp_proc_ids id); + /* Activate/deactivate processing stage, doesn't affect enabled status * thus will not enable anything - * 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, static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this, enum dsp_ids dsp_id) { + this->output_sampr = DSP_OUT_DEFAULT_HZ; dsp_sample_input_init(this, dsp_id); dsp_sample_output_init(this); } -void dsp_sample_io_configure(struct sample_io_data *this, +bool dsp_sample_io_configure(struct sample_io_data *this, unsigned int setting, - intptr_t value) + intptr_t *value_p) { + intptr_t value = *value_p; + switch (setting) { case DSP_INIT: @@ -306,15 +309,15 @@ void dsp_sample_io_configure(struct sample_io_data *this, this->format.num_channels = 2; this->format.frac_bits = WORD_FRACBITS; this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH; - this->format.frequency = NATIVE_FREQUENCY; - this->format.codec_frequency = NATIVE_FREQUENCY; + this->format.frequency = this->output_sampr; + this->format.codec_frequency = this->output_sampr; this->sample_depth = NATIVE_DEPTH; this->stereo_mode = STEREO_NONINTERLEAVED; break; case DSP_SET_FREQUENCY: format_change_set(this); - value = value > 0 ? value : NATIVE_FREQUENCY; + value = value > 0 ? (unsigned int)value : this->output_sampr; this->format.frequency = value; this->format.codec_frequency = value; break; @@ -345,5 +348,22 @@ void dsp_sample_io_configure(struct sample_io_data *this, this->format.frequency = fp_mul(value, this->format.codec_frequency, 16); break; + + case DSP_SET_OUT_FREQUENCY: + value = value > 0 ? value : DSP_OUT_DEFAULT_HZ; + value = MIN(DSP_OUT_MAX_HZ, MAX(DSP_OUT_MIN_HZ, value)); + *value_p = value; + + if ((unsigned int)value == this->output_sampr) + return true; /* No change; don't broadcast */ + + this->output_sampr = value; + break; + + case DSP_GET_OUT_FREQUENCY: + *value_p = this->output_sampr; + return true; /* Only I/O handles it */ } + + return false; } 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 struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */ int32_t *sample_buf_p[2]; /* Internal format buffer pointers */ sample_output_fn_type output_samples; /* Final output function */ + unsigned int output_sampr; /* Master output samplerate */ uint8_t format_dirty; /* Format change set, avoids superfluous increments before carrying it out */ 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, struct sample_format *format); /* Sample IO watches the format setting from the codec */ -void dsp_sample_io_configure(struct sample_io_data *this, +bool dsp_sample_io_configure(struct sample_io_data *this, unsigned int setting, - intptr_t value); + intptr_t *value_p); #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 @@ #include "dsp_filter.h" #include "dsp_proc_entry.h" #include "dsp_core.h" +#include "dsp_misc.h" #include "eq.h" #include "pga.h" #include "replaygain.h" @@ -42,6 +43,9 @@ #error Band count must be greater than or equal to 3 #endif +/* Cached band settings */ +static struct eq_band_setting settings[EQ_NUM_BANDS]; + static struct eq_state { uint32_t enabled; /* Mask of enabled bands */ @@ -49,16 +53,48 @@ static struct eq_state struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */ } eq_data IBSS_ATTR; +#define FOR_EACH_ENB_BAND(b) \ + for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) + /* Clear histories of all enabled bands */ static void eq_flush(void) { if (eq_data.enabled == 0) return; /* Not initialized yet/no bands on */ - for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) + FOR_EACH_ENB_BAND(b) filter_flush(&eq_data.filters[*b]); } +static void update_band_filter(int band, unsigned int fout) +{ + /* Convert user settings to format required by coef generator + functions */ + typeof (filter_pk_coefs) *coef_gen = filter_pk_coefs; + + /* Only first and last bands are not peaking filters */ + if (band == 0) + coef_gen = filter_ls_coefs; + else if (band == EQ_NUM_BANDS-1) + coef_gen = filter_hs_coefs; + + const struct eq_band_setting *setting = &settings[band]; + struct dsp_filter *filter = &eq_data.filters[band]; + + coef_gen(fp_div(setting->cutoff, fout, 32), setting->q ?: 1, + setting->gain, filter); +} + +/* Resync all bands to a new DSP output frequency */ +static void update_samplerate(unsigned int fout) +{ + if (eq_data.enabled == 0) + return; /* Not initialized yet/no bands on */ + + FOR_EACH_ENB_BAND(b) + update_band_filter(*b, fout); +} + /** DSP interface **/ /* Set the precut gain value */ @@ -73,11 +109,14 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting) if (band < 0 || band >= EQ_NUM_BANDS) return; + settings[band] = *setting; /* cache setting */ + + struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); + /* NOTE: The coef functions assume the EMAC unit is in fractional mode, which it should be, since we're executed from the main thread. */ uint32_t mask = eq_data.enabled; - struct dsp_filter *filter = &eq_data.filters[band]; /* Assume a band is disabled if the gain is zero */ mask &= ~BIT_N(band); @@ -85,33 +124,19 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting) if (setting->gain != 0) { mask |= BIT_N(band); - - /* Convert user settings to format required by coef generator - functions */ - void (* coef_gen)(unsigned long cutoff, unsigned long Q, long db, - struct dsp_filter *f) = filter_pk_coefs; - - /* Only first and last bands are not peaking filters */ - if (band == 0) - coef_gen = filter_ls_coefs; - else if (band == EQ_NUM_BANDS-1) - coef_gen = filter_hs_coefs; - - coef_gen(0xffffffff / NATIVE_FREQUENCY * setting->cutoff, - setting->q ?: 1, setting->gain, filter); + update_band_filter(band, dsp_get_output_frequency(dsp)); } if (mask == eq_data.enabled) return; /* No change in band-enable state */ if (mask & BIT_N(band)) - filter_flush(filter); /* Coming online */ + filter_flush(&eq_data.filters[band]); /* Coming online */ eq_data.enabled = mask; /* Only be active if there are bands to process - if EQ is off, then this call has no effect */ - struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0); /* 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) void dsp_eq_enable(bool enable) { struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); + bool enabled = dsp_proc_enabled(dsp, DSP_PROC_EQUALIZER); + + if (enable == enabled) + return; + dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable); if (enable && eq_data.enabled != 0) @@ -139,7 +169,7 @@ static void eq_process(struct dsp_proc_entry *this, int count = buf->remcount; unsigned int channels = buf->format.num_channels; - for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) + FOR_EACH_ENB_BAND(b) filter_process(&eq_data.filters[*b], buf->p32, count, channels); (void)this; @@ -154,10 +184,9 @@ static intptr_t eq_configure(struct dsp_proc_entry *this, switch (setting) { case DSP_PROC_INIT: - if (value != 0) - break; /* Already enabled */ - this->process = eq_process; + /* Wouldn't have been getting frequency updates */ + update_samplerate(dsp_get_output_frequency(dsp)); /* Fall-through */ case DSP_PROC_CLOSE: pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT); @@ -166,6 +195,10 @@ static intptr_t eq_configure(struct dsp_proc_entry *this, case DSP_FLUSH: eq_flush(); break; + + case DSP_SET_OUT_FREQUENCY: + update_samplerate(value); + break; } 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 @@ #include "fracmul.h" #include "fixedpoint.h" #include "dsp_proc_entry.h" +#include "dsp_misc.h" #include <string.h> /** @@ -50,9 +51,10 @@ static struct resample_data int32_t history[2][3]; /* 08h: Last samples for interpolation (L+R) 0 = oldest, 2 = newest */ /* 20h */ - int32_t frequency; /* Virtual samplerate */ + unsigned int frequency; /* Virtual input samplerate */ + unsigned int frequency_out; /* Resampler output samplerate */ struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */ - int32_t *resample_out_p[2]; /* Actual output buffer pointers */ + int32_t *resample_out_p[2]; /* Actual output buffer pointers */ } resample_data[DSP_COUNT] IBSS_ATTR; /* Actual worker function. Implemented here or in target assembly code. */ @@ -73,14 +75,16 @@ static void resample_flush(struct dsp_proc_entry *this) } static bool resample_new_delta(struct resample_data *data, - struct sample_format *format) + struct sample_format *format, + unsigned int fout) { - int32_t frequency = format->frequency; /* virtual samplerate */ + unsigned int frequency = format->frequency; /* virtual samplerate */ data->frequency = frequency; - data->delta = fp_div(frequency, NATIVE_FREQUENCY, 16); + data->frequency_out = fout; + data->delta = fp_div(frequency, fout, 16); - if (frequency == NATIVE_FREQUENCY) + if (frequency == data->frequency_out) { /* NOTE: If fully glitch-free transistions from no resampling to resampling are desired, history should be maintained even when @@ -232,20 +236,23 @@ static intptr_t resample_new_format(struct dsp_proc_entry *this, DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format); - int32_t frequency = data->frequency; + unsigned int frequency = data->frequency; + unsigned int fout = dsp_get_output_frequency(dsp); bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE); - if (format->frequency != frequency) + if ((unsigned int)format->frequency != frequency || + data->frequency_out != fout) { - DEBUGF(" DSP_PROC_RESAMPLE- new delta\n"); - active = resample_new_delta(data, format); + DEBUGF(" DSP_PROC_RESAMPLE- new settings: %u %u\n", + format->frequency, fout); + active = resample_new_delta(data, format, fout); dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active); } - /* Everything after us is NATIVE_FREQUENCY */ + /* Everything after us is fout */ dst->format = *format; - dst->format.frequency = NATIVE_FREQUENCY; - dst->format.codec_frequency = NATIVE_FREQUENCY; + dst->format.frequency = fout; + dst->format.codec_frequency = fout; if (active) return PROC_NEW_FORMAT_OK; @@ -287,8 +294,10 @@ static void INIT_ATTR resample_dsp_init(struct dsp_config *dsp, static void INIT_ATTR resample_proc_init(struct dsp_proc_entry *this, struct dsp_config *dsp) { + struct resample_data *data = &resample_data[dsp_get_id(dsp)]; + this->data = (intptr_t)data; dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false); - this->data = (intptr_t)&resample_data[dsp_get_id(dsp)]; + data->frequency_out = DSP_OUT_DEFAULT_HZ; this->process = resample_process; } @@ -322,6 +331,10 @@ static intptr_t resample_configure(struct dsp_proc_entry *this, case DSP_PROC_NEW_FORMAT: retval = resample_new_format(this, dsp, (struct sample_format *)value); break; + + case DSP_SET_OUT_FREQUENCY: + dsp_proc_want_format_update(dsp, DSP_PROC_RESAMPLE); + break; } 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 @@ ****************************************************************************/ #include "rbcodecconfig.h" #include "platform.h" +#include "fixedpoint.h" #include "dsp_proc_entry.h" #include "dsp_filter.h" #include "tone_controls.h" +#include "dsp_misc.h" /* These apply to all DSP streams to remain as consistant as possible with * the behavior of hardware tone controls */ @@ -36,32 +38,39 @@ static const unsigned int tone_treble_cutoff = 3500; static int tone_bass = 0; static int tone_treble = 0; +/* Current prescaler setting */ +static int tone_prescale = 0; + /* Data for each DSP */ static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR; +static void update_filter(int id, unsigned int fout) +{ + filter_bishelf_coefs(fp_div(tone_bass_cutoff, fout, 32), + fp_div(tone_treble_cutoff, fout, 32), + tone_bass, tone_treble, -tone_prescale, + &tone_filters[id]); +} + /* Update the filters' coefficients based upon the bass/treble settings */ void tone_set_prescale(int prescale) { int bass = tone_bass; int treble = tone_treble; - struct dsp_filter tone_filter; /* Temp to hold new version */ - filter_bishelf_coefs(0xffffffff / NATIVE_FREQUENCY * tone_bass_cutoff, - 0xffffffff / NATIVE_FREQUENCY * tone_treble_cutoff, - bass, treble, -prescale, &tone_filter); + tone_prescale = prescale; struct dsp_config *dsp; for (int i = 0; (dsp = dsp_get_config(i)); i++) { - struct dsp_filter *filter = &tone_filters[i]; - filter_copy(filter, &tone_filter); + update_filter(i, dsp_get_output_frequency(dsp)); bool enable = bass != 0 || treble != 0; dsp_proc_enable(dsp, DSP_PROC_TONE_CONTROLS, enable); - if (!dsp_proc_active(dsp, DSP_PROC_TONE_CONTROLS)) + if (enable && !dsp_proc_active(dsp, DSP_PROC_TONE_CONTROLS)) { - filter_flush(filter); /* Going online */ + filter_flush(&tone_filters[i]); /* Going online */ dsp_proc_activate(dsp, DSP_PROC_TONE_CONTROLS, true); } } @@ -109,6 +118,10 @@ static intptr_t tone_configure(struct dsp_proc_entry *this, case DSP_FLUSH: filter_flush((struct dsp_filter *)this->data); break; + + case DSP_SET_OUT_FREQUENCY: + update_filter(dsp_get_id(dsp), value); + break; } 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 @@ #define HAVE_SW_TONE_CONTROLS #define HAVE_ALBUMART #define NUM_CORES 1 +/* All the same unless a configuration option is added to warble */ +#define DSP_OUT_MIN_HZ 44100 +#define DSP_OUT_DEFAULT_HZ 44100 +#define DSP_OUT_MAX_HZ 44100 #ifndef __ASSEMBLER__ 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) if (use_dsp) { channels = 2; sample_size = 16; - freq = NATIVE_FREQUENCY; + freq = dsp_get_output_frequency(ci.dsp); type = WAVE_FORMAT_PCM; } else { channels = format.channels; @@ -312,7 +312,7 @@ static void playback_start(void) { playback_running = true; SDL_AudioSpec spec = {0}; - spec.freq = NATIVE_FREQUENCY; + spec.freq = dsp_get_output_frequency(ci.dsp); spec.format = AUDIO_S16SYS; spec.channels = 2; spec.samples = 0x400; @@ -776,6 +776,7 @@ static void decode_file(const char *input_fn) ci.id3 = &id3; if (use_dsp) { ci.dsp = dsp_get_config(CODEC_IDX_AUDIO); + dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, DSP_OUT_DEFAULT_HZ); dsp_configure(ci.dsp, DSP_RESET, 0); dsp_dither_enable(false); } |