diff options
Diffstat (limited to 'lib/rbcodec')
-rw-r--r-- | lib/rbcodec/dsp/crossfeed.c | 133 | ||||
-rw-r--r-- | lib/rbcodec/dsp/crossfeed.h | 9 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_arm.S | 44 | ||||
-rw-r--r-- | lib/rbcodec/dsp/dsp_cf.S | 47 |
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 */ |
34 | void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p); | 35 | void crossfeed_process(struct dsp_proc_entry *this, |
36 | struct dsp_buffer **buf_p); | ||
37 | void 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 | ||
75 | static int crossfeed_type = CROSSFEED_TYPE_NONE; | ||
76 | |||
56 | /* Discard the sample histories */ | 77 | /* Discard the sample histories */ |
57 | static void crossfeed_flush(struct dsp_proc_entry *this) | 78 | static 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 */ |
94 | void dsp_crossfeed_enable(bool enable) | 139 | void 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 | |||
238 | void 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 */ |
186 | static intptr_t crossfeed_configure(struct dsp_proc_entry *this, | 277 | static 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 | ||
24 | void dsp_crossfeed_enable(bool enable); | 24 | enum crossfeed_type |
25 | { | ||
26 | CROSSFEED_TYPE_NONE, | ||
27 | CROSSFEED_TYPE_MEIER, | ||
28 | CROSSFEED_TYPE_CUSTOM, | ||
29 | }; | ||
30 | |||
31 | void dsp_set_crossfeed_type(int type); | ||
25 | void dsp_set_crossfeed_direct_gain(int gain); | 32 | void dsp_set_crossfeed_direct_gain(int gain); |
26 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff); | 33 | void 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 | ||
257 | crossfeed_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 | ||
143 | crossfeed_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] | ||
158 | 10: | 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) |