summaryrefslogtreecommitdiff
path: root/lib/rbcodec/dsp/crossfeed.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/dsp/crossfeed.c')
-rw-r--r--lib/rbcodec/dsp/crossfeed.c133
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 */
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;