summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp
diff options
context:
space:
mode:
authorBertrik Sikken <bertrik@sikken.nl>2012-05-01 03:58:27 -0400
committerThomas Martitz <kugel@rockbox.org>2012-05-28 11:34:15 +0200
commitafc96087f8a6282cf732d142a4db7a3d604d39d8 (patch)
treeccdf78007bb087ab658edaa951f245ad4141bae2 /lib/rbcodec/dsp
parent08f5224b1bf1293ab1d59fdfbf9045561733c38d (diff)
downloadrockbox-afc96087f8a6282cf732d142a4db7a3d604d39d8.tar.gz
rockbox-afc96087f8a6282cf732d142a4db7a3d604d39d8.zip
New crossfeed algorithm for Rockbox: "Meier" crossfeed
Emulates the basic "Meier" crossfeed (2 capacitors, 3 resistors) as discussed in http://www.meier-audio.homepage.t-online.de/passivefilter.htm This crossfeed blends a bit of low-pass filtered L signal into the R signal (and vice versa) while adding about 300 us delay to the crossfed-signal. A difference with the crossfeed already present in rockbox, is that this algorithm keeps the total spectrum flat (the one currently in rockbox accentuates low-frequency signals, making it sound a bit muffled). This implementation is quite lightweight, just 3 multiplies per left-right pair of samples. Has a default C implementation and optimized assembly versions for ARM and Coldfire. The crossfeed effect is quite subtle and is noticeable mostly one albums that have very strong left-right separation (e.g. one instrument only on the left, another only on the right). In the user interface, the new crossfeed option appears as "Meier" and is not configureable. The existing crossfeed is renamed to "Custom" as it allows itself to be customised. There is no entry for the user manual yet. Change-Id: Iaa100616fe0fcd7e16f08cdb9a7f41501973eee1
Diffstat (limited to 'lib/rbcodec/dsp')
-rw-r--r--lib/rbcodec/dsp/crossfeed.c133
-rw-r--r--lib/rbcodec/dsp/crossfeed.h9
-rw-r--r--lib/rbcodec/dsp/dsp_arm.S44
-rw-r--r--lib/rbcodec/dsp/dsp_cf.S47
4 files changed, 214 insertions, 19 deletions
diff --git a/lib/rbcodec/dsp/crossfeed.c b/lib/rbcodec/dsp/crossfeed.c
index 344addadd7..3fb51a7594 100644
--- a/lib/rbcodec/dsp/crossfeed.c
+++ b/lib/rbcodec/dsp/crossfeed.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 Thom Johansen 10 * Copyright (C) 2006 Thom Johansen
11 * Copyright (C) 2010 Bertrik Sikken
11 * Copyright (C) 2012 Michael Sevakis 12 * Copyright (C) 2012 Michael Sevakis
12 * 13 *
13 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
@@ -31,7 +32,11 @@
31#include <string.h> 32#include <string.h>
32 33
33/* Implemented here or in target assembly code */ 34/* Implemented here or in target assembly code */
34void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p); 35void crossfeed_process(struct dsp_proc_entry *this,
36 struct dsp_buffer **buf_p);
37void crossfeed_meier_process(struct dsp_proc_entry *this,
38 struct dsp_buffer **buf_p);
39
35 40
36/** 41/**
37 * Applies crossfeed to the stereo signal. 42 * Applies crossfeed to the stereo signal.
@@ -46,20 +51,44 @@ static struct crossfeed_state
46{ 51{
47 int32_t gain; /* 00h: Direct path gain */ 52 int32_t gain; /* 00h: Direct path gain */
48 int32_t coefs[3]; /* 04h: Coefficients for the shelving filter */ 53 int32_t coefs[3]; /* 04h: Coefficients for the shelving filter */
49 int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */ 54 union
50 int32_t delay[13*2]; /* 20h: Delay line buffer (L + R interleaved) */ 55 {
56 struct /* 10h: Data for meier crossfeed */
57 {
58 int32_t vcl;
59 int32_t vcr;
60 int32_t vdiff;
61 int32_t coef1;
62 int32_t coef2;
63 };
64 struct /* 10h: Data for custom crossfeed */
65 {
66 int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */
67 int32_t delay[13*2];/* 20h: Delay line buffer (L + R interleaved) */
68 };
69 };
51 int32_t *index; /* 88h: Current pointer into the delay line */ 70 int32_t *index; /* 88h: Current pointer into the delay line */
52 struct dsp_config *dsp; /* 8ch: Current DSP */ 71 struct dsp_config *dsp; /* 8ch: Current DSP */
53 /* 90h */ 72 /* 90h */
54} crossfeed_state IBSS_ATTR; 73} crossfeed_state IBSS_ATTR;
55 74
75static int crossfeed_type = CROSSFEED_TYPE_NONE;
76
56/* Discard the sample histories */ 77/* Discard the sample histories */
57static void crossfeed_flush(struct dsp_proc_entry *this) 78static void crossfeed_flush(struct dsp_proc_entry *this)
58{ 79{
59 struct crossfeed_state *state = (void *)this->data; 80 struct crossfeed_state *state = (void *)this->data;
60 memset(state->history, 0, sizeof (state->history)); 81
61 memset(state->delay, 0, sizeof (state->delay)); 82 if (crossfeed_type == CROSSFEED_TYPE_CUSTOM)
62 state->index = state->delay; 83 {
84 memset(state->history, 0,
85 sizeof (state->history) + sizeof (state->delay));
86 state->index = state->delay;
87 }
88 else
89 {
90 state->vcl = state->vcr = state->vdiff = 0;
91 }
63} 92}
64 93
65 94
@@ -74,30 +103,48 @@ static void crossfeed_process_new_format(struct dsp_proc_entry *this,
74 103
75 DSP_PRINT_FORMAT(DSP_PROC_CROSSFEED, DSP_PROC_CROSSFEED, buf->format); 104 DSP_PRINT_FORMAT(DSP_PROC_CROSSFEED, DSP_PROC_CROSSFEED, buf->format);
76 105
106 bool was_active = dsp_proc_active(state->dsp, DSP_PROC_CROSSFEED);
77 bool active = buf->format.num_channels >= 2; 107 bool active = buf->format.num_channels >= 2;
78 dsp_proc_activate(state->dsp, DSP_PROC_CROSSFEED, active); 108 dsp_proc_activate(state->dsp, DSP_PROC_CROSSFEED, active);
79 109
80 if (!active) 110 if (!active)
81 { 111 {
82 /* Can't do this. Sleep until next change */ 112 /* Can't do this. Sleep until next change */
83 crossfeed_flush(this);
84 DEBUGF(" DSP_PROC_CROSSFEED- deactivated\n"); 113 DEBUGF(" DSP_PROC_CROSSFEED- deactivated\n");
85 return; 114 return;
86 } 115 }
87 116
88 /* Switch to the real function and call it once */ 117 dsp_proc_fn_type fn = crossfeed_process;
89 this->process[0] = crossfeed_process; 118
119 if (crossfeed_type != CROSSFEED_TYPE_CUSTOM)
120 {
121 /* 1 / (F.Rforward.C) */
122 state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128;
123 /* 1 / (F.Rcross.C) */
124 state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000;
125 fn = crossfeed_meier_process;
126 }
127
128 if (!was_active || this->process[0] != fn)
129 {
130 crossfeed_flush(this); /* Going online or actual type change */
131 this->process[0] = fn; /* Set real function */
132 }
133
134 /* Call it once */
90 dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1); 135 dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1);
91} 136}
92 137
93/* Enable or disable the crossfeed */ 138/* Set the type of crossfeed to use */
94void dsp_crossfeed_enable(bool enable) 139void dsp_set_crossfeed_type(int type)
95{ 140{
96 if (enable != !crossfeed_state.dsp) 141 if (type == crossfeed_type)
97 return; 142 return; /* No change */
143
144 crossfeed_type = type;
98 145
99 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); 146 struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO);
100 dsp_proc_enable(dsp, DSP_PROC_CROSSFEED, enable); 147 dsp_proc_enable(dsp, DSP_PROC_CROSSFEED, type != CROSSFEED_TYPE_NONE);
101} 148}
102 149
103/* Set the gain of the dry mix */ 150/* Set the gain of the dry mix */
@@ -182,6 +229,50 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p)
182} 229}
183#endif /* CPU */ 230#endif /* CPU */
184 231
232#if !defined(CPU_COLDFIRE) && !defined(CPU_ARM)
233/**
234 * Implementation of the "simple" passive crossfeed circuit by Jan Meier.
235 * See also: http://www.meier-audio.homepage.t-online.de/passivefilter.htm
236 */
237
238void crossfeed_meier_process(struct dsp_proc_entry *this,
239 struct dsp_buffer **buf_p)
240{
241 struct dsp_buffer *buf = *buf_p;
242
243 /* Get filter state */
244 struct crossfeed_state *state = (struct crossfeed_state *)this->data;
245 int32_t vcl = state->vcl;
246 int32_t vcr = state->vcr;
247 int32_t vdiff = state->vdiff;
248 int32_t coef1 = state->coef1;
249 int32_t coef2 = state->coef2;
250
251 int count = buf->remcount;
252
253 for (int i = 0; i < count; i++)
254 {
255 /* Calculate new output */
256 int32_t lout = buf->p32[0][i] + vcl;
257 int32_t rout = buf->p32[1][i] + vcr;
258 buf->p32[0][i] = lout;
259 buf->p32[1][i] = rout;
260
261 /* Update filter state */
262 int32_t common = FRACMUL(vdiff, coef2);
263 vcl -= FRACMUL(vcl, coef1) + common;
264 vcr -= FRACMUL(vcr, coef1) - common;
265
266 vdiff = lout - rout;
267 }
268
269 /* Store filter state */
270 state->vcl = vcl;
271 state->vcr = vcr;
272 state->vdiff = vdiff;
273}
274#endif /* CPU */
275
185/* DSP message hook */ 276/* DSP message hook */
186static intptr_t crossfeed_configure(struct dsp_proc_entry *this, 277static intptr_t crossfeed_configure(struct dsp_proc_entry *this,
187 struct dsp_config *dsp, 278 struct dsp_config *dsp,
@@ -191,11 +282,19 @@ static intptr_t crossfeed_configure(struct dsp_proc_entry *this,
191 switch (setting) 282 switch (setting)
192 { 283 {
193 case DSP_PROC_INIT: 284 case DSP_PROC_INIT:
194 this->data = (intptr_t)&crossfeed_state; 285 if (value == 0)
286 {
287 /* New object */
288 this->data = (intptr_t)&crossfeed_state;
289 this->process[1] = crossfeed_process_new_format;
290 ((struct crossfeed_state *)this->data)->dsp = dsp;
291 }
292
293 /* Force format change call each time */
195 this->process[0] = crossfeed_process_new_format; 294 this->process[0] = crossfeed_process_new_format;
196 this->process[1] = crossfeed_process_new_format;
197 ((struct crossfeed_state *)this->data)->dsp = dsp;
198 dsp_proc_activate(dsp, DSP_PROC_CROSSFEED, true); 295 dsp_proc_activate(dsp, DSP_PROC_CROSSFEED, true);
296 break;
297
199 case DSP_FLUSH: 298 case DSP_FLUSH:
200 crossfeed_flush(this); 299 crossfeed_flush(this);
201 break; 300 break;
diff --git a/lib/rbcodec/dsp/crossfeed.h b/lib/rbcodec/dsp/crossfeed.h
index 63261bde9f..2c4d47dba5 100644
--- a/lib/rbcodec/dsp/crossfeed.h
+++ b/lib/rbcodec/dsp/crossfeed.h
@@ -21,7 +21,14 @@
21#ifndef CROSSFEED_H 21#ifndef CROSSFEED_H
22#define CROSSFEED_H 22#define CROSSFEED_H
23 23
24void dsp_crossfeed_enable(bool enable); 24enum crossfeed_type
25{
26 CROSSFEED_TYPE_NONE,
27 CROSSFEED_TYPE_MEIER,
28 CROSSFEED_TYPE_CUSTOM,
29};
30
31void dsp_set_crossfeed_type(int type);
25void dsp_set_crossfeed_direct_gain(int gain); 32void dsp_set_crossfeed_direct_gain(int gain);
26void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff); 33void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff);
27 34
diff --git a/lib/rbcodec/dsp/dsp_arm.S b/lib/rbcodec/dsp/dsp_arm.S
index 1674d6617a..4fdaf8d5a8 100644
--- a/lib/rbcodec/dsp/dsp_arm.S
+++ b/lib/rbcodec/dsp/dsp_arm.S
@@ -8,6 +8,8 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006-2007 Thom Johansen 10 * Copyright (C) 2006-2007 Thom Johansen
11 * Copyright (C) 2010 Bertrik Sikken
12 * Copyright (C) 2012 Michael Sevakis
11 * 13 *
12 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -247,6 +249,48 @@ crossfeed_process:
247 .size crossfeed_process, .-crossfeed_process 249 .size crossfeed_process, .-crossfeed_process
248 250
249/**************************************************************************** 251/****************************************************************************
252 * void crossfeed_meier_process(struct dsp_proc_entry *this,
253 * struct dsp_buffer **buf_p)
254 */
255 .section .text
256 .global crossfeed_meier_process
257crossfeed_meier_process:
258 @ input: r0 = this, r1 = buf_p
259 ldr r1, [r1] @ r1 = buf = *buf_p;
260 ldr r0, [r0] @ r0 = this->data = &crossfeed_state
261 stmfd sp!, { r4-r10, lr } @ stack non-volatile context
262 ldmia r1, { r1-r3 } @ r1 = buf->remcout, r2=p32[0], r3=p32[1]
263 add r0, r0, #16 @ r0 = &state->vcl
264 ldmia r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff
265 @ r7 = coef1, r8 = coef2
266.cfm_loop:
267 ldr r12, [r2] @ r12 = lout
268 ldr r14, [r3] @ r14 = rout
269 smull r9, r10, r8, r6 @ r9, r10 = common = coef2*vdiff
270 add r12, r12, r4 @ lout += vcl
271 add r14, r14, r5 @ rout += vcr
272 sub r6, r12, r14 @ r6 = vdiff = lout - rout
273 str r12, [r2], #4 @ store left channel
274 str r14, [r3], #4 @ store right channel
275 rsbs r12, r9, #0 @ r12 = -common (lo)
276 rsc r14, r10, #0 @ r14 = -common (hi)
277 smlal r9, r10, r7, r4 @ r9, r10 = res1 = coef1*vcl + common
278 smlal r12, r14, r7, r5 @ r12, r14 = res2 = coef1*vcr - common
279 subs r1, r1, #1 @ count--
280 mov r9, r9, lsr #31 @ r9 = convert res1 to s0.31
281 orr r9, r9, r10, asl #1 @ .
282 mov r12, r12, lsr #31 @ r12 = convert res2 to s0.31
283 orr r12, r12, r14, asl #1 @ .
284 sub r4, r4, r9 @ r4 = vcl -= res1
285 sub r5, r5, r12 @ r5 = vcr -= res2
286 bgt .cfm_loop @ more samples?
287
288 stmia r0, { r4-r6 } @ save vcl, vcr, vdiff
289 ldmpc regs=r4-r10 @ restore non-volatile context, return
290 .size crossfeed_meier_process, .-crossfeed_meier_process
291
292
293/****************************************************************************
250 * int lin_resample_resample(struct resample_data *data, 294 * int lin_resample_resample(struct resample_data *data,
251 * struct dsp_buffer *src, 295 * struct dsp_buffer *src,
252 * struct dsp_buffer *dst) 296 * struct dsp_buffer *dst)
diff --git a/lib/rbcodec/dsp/dsp_cf.S b/lib/rbcodec/dsp/dsp_cf.S
index c710df5177..7d193e0957 100644
--- a/lib/rbcodec/dsp/dsp_cf.S
+++ b/lib/rbcodec/dsp/dsp_cf.S
@@ -8,7 +8,8 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2006 Thom Johansen 10 * Copyright (C) 2006 Thom Johansen
11 * Portions Copyright (C) 2007 Michael Sevakis 11 * Copyright (C) 2007, 2012 Michael Sevakis
12 * Copyright (C) 2010 Bertrik Sikken
12 * 13 *
13 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -134,6 +135,50 @@ crossfeed_process:
134 .size crossfeed_process,.-crossfeed_process 135 .size crossfeed_process,.-crossfeed_process
135 136
136/**************************************************************************** 137/****************************************************************************
138 * void crossfeed_meier_process(struct dsp_proc_entry *this,
139 * struct dsp_buffer **buf_p)
140 */
141 .section .text
142 .global crossfeed_meier_process
143crossfeed_meier_process:
144 | input: 4(sp) = this, 8(sp) = buf_p
145 movem.l 4(%sp), %a0-%a1 | %a0 = this, %a1 = buf_p
146 lea.l -24(%sp), %sp | save non-volatiles
147 movem.l %d2-%d6/%a2, (%sp) | .
148 move.l (%a0), %a0 | %a0 = &this->data = &crossfeed_state
149 move.l (%a1), %a1 | %a1 = buf = *buf_p
150 movem.l 16(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff,
151 | %d4 = coef1, %d5 = coef2
152 movem.l (%a1), %d0/%a1-%a2 | %d0 = count = buf->remcount
153 | %a1 = p32[0], %a2 = p32[1]
154 | Register usage in loop:
155 | %d0 = count, %d1 = vcl, %d2 = vcr, %d3 = vdiff/lout,
156 | %d4 = coef1, %d5 = coef2, %d6 = rout/scratch
157 | %a1 = p32[0], %a2 = p32[1]
15810: | loop
159 mac.l %d5, %d3, %acc0 | %acc0 = common = coef2*vdiff
160 move.l %acc0, %acc1 | copy common
161 mac.l %d4, %d1, (%a1), %d3, %acc0 | %acc0 += coef1*vcl, %d3 = lout
162 msac.l %d4, %d2, (%a2), %d6, %acc1 | %acc1 -= coef1*vcr, %d6 = rout
163 add.l %d1, %d3 | lout += vcl
164 add.l %d2, %d6 | rout += vcr
165 move.l %d3, (%a1)+ | store left channel, pos inc
166 move.l %d6, (%a2)+ | store right channel, pos inc
167 sub.l %d6, %d3 | vdiff = lout - rout
168 movclr.l %acc0, %d6 | %d4 = fetch res1 in s0.31
169 sub.l %d6, %d1 | vcl -= res1
170 movclr.l %acc1, %d6 | %d5 = fetch -res2 in s0.31
171 add.l %d6, %d2 | vcr += -res2
172 subq.l #1, %d0 | count--
173 bgt 10b | loop | more samples?
174 |
175 movem.l %d1-%d3, 16(%a0) | save vcl, vcr, vdiff
176 movem.l (%sp), %d2-%d6/%a2 | restore non-volatiles
177 lea.l 24(%sp), %sp | .
178 rts |
179 .size crossfeed_meier_process, .-crossfeed_meier_process
180
181/****************************************************************************
137 * int lin_resample_resample(struct resample_data *data, 182 * int lin_resample_resample(struct resample_data *data,
138 * struct dsp_buffer *src, 183 * struct dsp_buffer *src,
139 * struct dsp_buffer *dst) 184 * struct dsp_buffer *dst)