summaryrefslogtreecommitdiffstats
path: root/lib/rbcodec
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/rbcodec
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/rbcodec')
-rw-r--r--lib/rbcodec/dsp/compressor.c18
-rw-r--r--lib/rbcodec/dsp/crossfeed.c117
-rw-r--r--lib/rbcodec/dsp/dsp_arm.S84
-rw-r--r--lib/rbcodec/dsp/dsp_cf.S102
-rw-r--r--lib/rbcodec/dsp/dsp_core.c29
-rw-r--r--lib/rbcodec/dsp/dsp_core.h4
-rw-r--r--lib/rbcodec/dsp/dsp_misc.c15
-rw-r--r--lib/rbcodec/dsp/dsp_misc.h7
-rw-r--r--lib/rbcodec/dsp/dsp_proc_database.h2
-rw-r--r--lib/rbcodec/dsp/dsp_proc_entry.h4
-rw-r--r--lib/rbcodec/dsp/dsp_sample_input.c30
-rw-r--r--lib/rbcodec/dsp/dsp_sample_io.h5
-rw-r--r--lib/rbcodec/dsp/eq.c77
-rw-r--r--lib/rbcodec/dsp/resample.c41
-rw-r--r--lib/rbcodec/dsp/tone_controls.c29
-rw-r--r--lib/rbcodec/rbcodecconfig-example.h4
-rw-r--r--lib/rbcodec/test/warble.c5
17 files changed, 377 insertions, 196 deletions
diff --git a/lib/rbcodec/dsp/compressor.c b/lib/rbcodec/dsp/compressor.c
index fc73f761a7..a222caed7f 100644
--- a/lib/rbcodec/dsp/compressor.c
+++ b/lib/rbcodec/dsp/compressor.c
@@ -28,6 +28,7 @@
#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);
}