summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
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 @@
#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);
}