diff options
Diffstat (limited to 'lib/rbcodec/dsp/channel_mode.c')
-rw-r--r-- | lib/rbcodec/dsp/channel_mode.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/lib/rbcodec/dsp/channel_mode.c b/lib/rbcodec/dsp/channel_mode.c new file mode 100644 index 0000000000..5b678887c2 --- /dev/null +++ b/lib/rbcodec/dsp/channel_mode.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 Thom Johansen | ||
11 | * Copyright (C) 2012 Michael Sevakis | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "config.h" | ||
23 | #include "system.h" | ||
24 | #include "dsp.h" | ||
25 | #include "settings.h" | ||
26 | #include "sound.h" | ||
27 | #include "fixedpoint.h" | ||
28 | #include "fracmul.h" | ||
29 | #include "dsp_proc_entry.h" | ||
30 | |||
31 | #if 0 | ||
32 | /* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for | ||
33 | * completeness. */ | ||
34 | void channel_mode_proc_stereo(struct dsp_proc_entry *this, | ||
35 | struct dsp_buffer **buf_p); | ||
36 | #endif | ||
37 | void channel_mode_proc_mono(struct dsp_proc_entry *this, | ||
38 | struct dsp_buffer **buf_p); | ||
39 | void channel_mode_proc_mono_left(struct dsp_proc_entry *this, | ||
40 | struct dsp_buffer **buf_p); | ||
41 | void channel_mode_proc_mono_right(struct dsp_proc_entry *this, | ||
42 | struct dsp_buffer **buf_p); | ||
43 | void channel_mode_proc_custom(struct dsp_proc_entry *this, | ||
44 | struct dsp_buffer **buf_p); | ||
45 | void channel_mode_proc_karaoke(struct dsp_proc_entry *this, | ||
46 | struct dsp_buffer **buf_p); | ||
47 | |||
48 | static struct channel_mode_data | ||
49 | { | ||
50 | long sw_gain; /* 00h: for mode: custom */ | ||
51 | long sw_cross; /* 04h: for mode: custom */ | ||
52 | struct dsp_config *dsp; | ||
53 | int mode; | ||
54 | const dsp_proc_fn_type fns[SOUND_CHAN_NUM_MODES]; | ||
55 | } channel_mode_data = | ||
56 | { | ||
57 | .sw_gain = 0, | ||
58 | .sw_cross = 0, | ||
59 | .mode = SOUND_CHAN_STEREO, | ||
60 | .fns = | ||
61 | { | ||
62 | [SOUND_CHAN_STEREO] = NULL, | ||
63 | [SOUND_CHAN_MONO] = channel_mode_proc_mono, | ||
64 | [SOUND_CHAN_CUSTOM] = channel_mode_proc_custom, | ||
65 | [SOUND_CHAN_MONO_LEFT] = channel_mode_proc_mono_left, | ||
66 | [SOUND_CHAN_MONO_RIGHT] = channel_mode_proc_mono_right, | ||
67 | [SOUND_CHAN_KARAOKE] = channel_mode_proc_karaoke, | ||
68 | }, | ||
69 | }; | ||
70 | |||
71 | static dsp_proc_fn_type get_process_fn(void) | ||
72 | { | ||
73 | return channel_mode_data.fns[channel_mode_data.mode]; | ||
74 | } | ||
75 | |||
76 | #if 0 | ||
77 | /* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for | ||
78 | * completeness. */ | ||
79 | void channel_mode_proc_stereo(struct dsp_proc_entry *this, | ||
80 | struct dsp_buffer **buf_p) | ||
81 | { | ||
82 | /* The channels are each just themselves */ | ||
83 | (void)this; (void)buf_p; | ||
84 | } | ||
85 | #endif | ||
86 | |||
87 | #if !defined(CPU_COLDFIRE) && !defined(CPU_ARM) | ||
88 | /* Unoptimized routines */ | ||
89 | void channel_mode_proc_mono(struct dsp_proc_entry *this, | ||
90 | struct dsp_buffer **buf_p) | ||
91 | { | ||
92 | struct dsp_buffer *buf = *buf_p; | ||
93 | int32_t *sl = buf->p32[0]; | ||
94 | int32_t *sr = buf->p32[1]; | ||
95 | int count = buf->remcount; | ||
96 | |||
97 | do | ||
98 | { | ||
99 | int32_t lr = *sl / 2 + *sr / 2; | ||
100 | *sl++ = lr; | ||
101 | *sr++ = lr; | ||
102 | } | ||
103 | while (--count > 0); | ||
104 | |||
105 | (void)this; | ||
106 | } | ||
107 | |||
108 | void channel_mode_proc_custom(struct dsp_proc_entry *this, | ||
109 | struct dsp_buffer **buf_p) | ||
110 | { | ||
111 | struct channel_mode_data *data = (void *)this->data; | ||
112 | struct dsp_buffer *buf = *buf_p; | ||
113 | |||
114 | int32_t *sl = buf->p32[0]; | ||
115 | int32_t *sr = buf->p32[1]; | ||
116 | int count = buf->remcount; | ||
117 | |||
118 | const int32_t gain = data->sw_gain; | ||
119 | const int32_t cross = data->sw_cross; | ||
120 | |||
121 | do | ||
122 | { | ||
123 | int32_t l = *sl; | ||
124 | int32_t r = *sr; | ||
125 | *sl++ = FRACMUL(l, gain) + FRACMUL(r, cross); | ||
126 | *sr++ = FRACMUL(r, gain) + FRACMUL(l, cross); | ||
127 | } | ||
128 | while (--count > 0); | ||
129 | } | ||
130 | |||
131 | void channel_mode_proc_karaoke(struct dsp_proc_entry *this, | ||
132 | struct dsp_buffer **buf_p) | ||
133 | { | ||
134 | struct dsp_buffer *buf = *buf_p; | ||
135 | int32_t *sl = buf->p32[0]; | ||
136 | int32_t *sr = buf->p32[1]; | ||
137 | int count = buf->remcount; | ||
138 | |||
139 | do | ||
140 | { | ||
141 | int32_t ch = *sl / 2 - *sr / 2; | ||
142 | *sl++ = ch; | ||
143 | *sr++ = -ch; | ||
144 | } | ||
145 | while (--count > 0); | ||
146 | |||
147 | (void)this; | ||
148 | } | ||
149 | #endif /* CPU */ | ||
150 | |||
151 | void channel_mode_proc_mono_left(struct dsp_proc_entry *this, | ||
152 | struct dsp_buffer **buf_p) | ||
153 | { | ||
154 | /* Just copy over the other channel */ | ||
155 | struct dsp_buffer *buf = *buf_p; | ||
156 | memcpy(buf->p32[1], buf->p32[0], buf->remcount * sizeof (int32_t)); | ||
157 | (void)this; | ||
158 | } | ||
159 | |||
160 | void channel_mode_proc_mono_right(struct dsp_proc_entry *this, | ||
161 | struct dsp_buffer **buf_p) | ||
162 | { | ||
163 | /* Just copy over the other channel */ | ||
164 | struct dsp_buffer *buf = *buf_p; | ||
165 | memcpy(buf->p32[0], buf->p32[1], buf->remcount * sizeof (int32_t)); | ||
166 | (void)this; | ||
167 | } | ||
168 | |||
169 | /* This is the initial function pointer when first enabled/changed in order | ||
170 | * to facilitate verification of the format compatibility at the proper time | ||
171 | * This gets called for changes even if stage is inactive. */ | ||
172 | static void channel_mode_process_new_format(struct dsp_proc_entry *this, | ||
173 | struct dsp_buffer **buf_p) | ||
174 | { | ||
175 | struct channel_mode_data *data = (void *)this->data; | ||
176 | struct dsp_buffer *buf = *buf_p; | ||
177 | |||
178 | DSP_PRINT_FORMAT(DSP_PROC_CHANNEL_MODE, DSP_PROC_CHANNEL_MODE, | ||
179 | buf->format); | ||
180 | |||
181 | bool active = buf->format.num_channels >= 2; | ||
182 | dsp_proc_activate(data->dsp, DSP_PROC_CHANNEL_MODE, active); | ||
183 | |||
184 | if (!active) | ||
185 | { | ||
186 | /* Can't do this. Sleep until next change. */ | ||
187 | DEBUGF(" DSP_PROC_CHANNEL_MODE- deactivated\n"); | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | /* Switch to the real function and call it once */ | ||
192 | this->process[0] = get_process_fn(); | ||
193 | dsp_proc_call(this, buf_p, (unsigned)buf->format.changed - 1); | ||
194 | } | ||
195 | |||
196 | void channel_mode_set_config(int value) | ||
197 | { | ||
198 | if (value < 0 || value >= SOUND_CHAN_NUM_MODES) | ||
199 | value = SOUND_CHAN_STEREO; /* Out of range */ | ||
200 | |||
201 | if (value == channel_mode_data.mode) | ||
202 | return; | ||
203 | |||
204 | channel_mode_data.mode = value; | ||
205 | dsp_proc_enable(dsp_get_config(CODEC_IDX_AUDIO), DSP_PROC_CHANNEL_MODE, | ||
206 | value != SOUND_CHAN_STEREO); | ||
207 | } | ||
208 | |||
209 | void channel_mode_custom_set_width(int value) | ||
210 | { | ||
211 | long width, straight, cross; | ||
212 | |||
213 | width = value * 0x7fffff / 100; | ||
214 | |||
215 | if (value <= 100) | ||
216 | { | ||
217 | straight = (0x7fffff + width) / 2; | ||
218 | cross = straight - width; | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | /* straight = (1 + width) / (2 * width) */ | ||
223 | straight = fp_div(0x7fffff + width, width, 22); | ||
224 | cross = straight - 0x7fffff; | ||
225 | } | ||
226 | |||
227 | channel_mode_data.sw_gain = straight << 8; | ||
228 | channel_mode_data.sw_cross = cross << 8; | ||
229 | } | ||
230 | |||
231 | /* DSP message hook */ | ||
232 | static intptr_t channel_mode_configure(struct dsp_proc_entry *this, | ||
233 | struct dsp_config *dsp, | ||
234 | unsigned int setting, | ||
235 | intptr_t value) | ||
236 | { | ||
237 | switch (setting) | ||
238 | { | ||
239 | case DSP_PROC_INIT: | ||
240 | if (value == 0) | ||
241 | { | ||
242 | /* New object */ | ||
243 | this->data = (intptr_t)&channel_mode_data; | ||
244 | this->process[1] = channel_mode_process_new_format; | ||
245 | ((struct channel_mode_data *)this->data)->dsp = dsp; | ||
246 | } | ||
247 | |||
248 | /* Force format change call each time */ | ||
249 | this->process[0] = channel_mode_process_new_format; | ||
250 | dsp_proc_activate(dsp, DSP_PROC_CHANNEL_MODE, true); | ||
251 | break; | ||
252 | |||
253 | case DSP_PROC_CLOSE: | ||
254 | ((struct channel_mode_data *)this->data)->dsp = NULL; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | return 1; | ||
259 | } | ||
260 | |||
261 | /* Database entry */ | ||
262 | DSP_PROC_DB_ENTRY( | ||
263 | CHANNEL_MODE, | ||
264 | channel_mode_configure); | ||