diff options
Diffstat (limited to 'lib/rbcodec/dsp/crossfeed.c')
-rw-r--r-- | lib/rbcodec/dsp/crossfeed.c | 133 |
1 files changed, 116 insertions, 17 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; |