blob: 8064a881a344a8ae2906b32e3d41556a84fa8692 [file] [log] [blame]
Miika Pekkarinend8cb7032005-06-26 19:41:29 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Miika Pekkarinen
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
Magnus Holmgren4a537872005-07-24 15:32:28 +000019#include <inttypes.h>
Miika Pekkarinen46136592005-06-27 21:12:09 +000020#include <string.h>
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000021#include "dsp.h"
Magnus Holmgren08761aa2005-07-16 12:25:28 +000022#include "kernel.h"
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000023#include "playback.h"
24#include "system.h"
Magnus Holmgren4a537872005-07-24 15:32:28 +000025#include "settings.h"
Magnus Holmgren5a8eac12005-08-11 18:56:20 +000026#include "replaygain.h"
Magnus Holmgren4a537872005-07-24 15:32:28 +000027#include "debug.h"
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000028
29/* The "dither" code to convert the 24-bit samples produced by libmad was
Magnus Holmgren08761aa2005-07-16 12:25:28 +000030 * taken from the coolplayer project - coolplayer.sourceforge.net
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000031 */
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000032
Magnus Holmgren5a8eac12005-08-11 18:56:20 +000033/* 16-bit samples are scaled based on these constants. The shift should be
Magnus Holmgren08761aa2005-07-16 12:25:28 +000034 * no more than 15.
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000035 */
Magnus Holmgren08761aa2005-07-16 12:25:28 +000036#define WORD_SHIFT 12
37#define WORD_FRACBITS 27
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000038
Magnus Holmgren08761aa2005-07-16 12:25:28 +000039#define NATIVE_DEPTH 16
40#define SAMPLE_BUF_SIZE 256
41#define RESAMPLE_BUF_SIZE (256 * 4) /* Enough for 11,025 Hz -> 44,100 Hz*/
Magnus Holmgren4a537872005-07-24 15:32:28 +000042#define DEFAULT_REPLAYGAIN 0x01000000
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000043
Christian Gmeiner6753fb52005-07-18 13:09:05 +000044#if defined(CPU_COLDFIRE) && !defined(SIMULATOR)
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000045
46#define INIT() asm volatile ("move.l #0xb0, %macsr") /* frac, round, clip */
Magnus Holmgren059a6c82005-07-30 13:47:16 +000047/* Multiply two S.31 fractional integers and return the sign bit and the
48 * 31 most significant bits of the result.
Magnus Holmgren08761aa2005-07-16 12:25:28 +000049 */
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000050#define FRACMUL(x, y) \
51({ \
52 long t; \
Magnus Holmgren4a537872005-07-24 15:32:28 +000053 asm volatile ("mac.l %[a], %[b], %%acc0\n\t" \
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000054 "movclr.l %%acc0, %[t]\n\t" \
55 : [t] "=r" (t) : [a] "r" (x), [b] "r" (y)); \
56 t; \
57})
Magnus Holmgren75ef3122005-08-18 19:25:39 +000058
59/* Multiply one S.31-bit and one S8.23 fractional integer and return the
Magnus Holmgren059a6c82005-07-30 13:47:16 +000060 * sign bit and the 31 most significant bits of the result.
Magnus Holmgren4a537872005-07-24 15:32:28 +000061 */
62#define FRACMUL_8(x, y) \
63({ \
64 long t; \
65 long u; \
66 asm volatile ("mac.l %[a], %[b], %%acc0\n\t" \
67 "move.l %%accext01, %[u]\n\t" \
68 "movclr.l %%acc0, %[t]\n\t" \
69 : [t] "=r" (t), [u] "=r" (u) : [a] "r" (x), [b] "r" (y)); \
Magnus Holmgren75ef3122005-08-18 19:25:39 +000070 (t << 8) | (u & 0xff); \
71})
72
73/* Multiply one S.31-bit and one S8.23 fractional integer and return the
74 * sign bit and the 31 most significant bits of the result. Load next value
75 * to multiply with into x from s (and increase s); x must contain the
76 * initial value.
77 */
78#define FRACMUL_8_LOOP(x, y, s) \
79({ \
80 long t; \
81 long u; \
82 asm volatile ("mac.l %[a], %[b], (%[c])+, %[a], %%acc0\n\t" \
83 "move.l %%accext01, %[u]\n\t" \
84 "movclr.l %%acc0, %[t]\n\t" \
85 : [a] "+r" (x), [c] "+a" (s), [t] "=r" (t), [u] "=r" (u) \
86 : [b] "r" (y)); \
87 (t << 8) | (u & 0xff); \
Magnus Holmgren4a537872005-07-24 15:32:28 +000088})
Miika Pekkarinend8cb7032005-06-26 19:41:29 +000089
90#else
91
92#define INIT()
Magnus Holmgren059a6c82005-07-30 13:47:16 +000093#define FRACMUL(x, y) (long) (((((long long) (x)) * ((long long) (y))) >> 31))
Magnus Holmgren75ef3122005-08-18 19:25:39 +000094#define FRACMUL_8(x, y) (long) (((((long long) (x)) * ((long long) (y))) >> 23))
95#define FRACMUL_8_LOOP(x, y, s) \
96({ \
97 long t = x; \
98 x = *(s)++; \
99 (long) (((((long long) (t)) * ((long long) (y))) >> 23)); \
100})
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000101
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000102#endif
103
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000104struct dsp_config
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000105{
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000106 long frequency;
107 long clip_min;
108 long clip_max;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000109 long track_gain;
110 long album_gain;
111 long track_peak;
112 long album_peak;
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000113 long replaygain; /* Note that this is in S8.23 format. */
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000114 int sample_depth;
115 int sample_bytes;
116 int stereo_mode;
117 int frac_bits;
118 bool dither_enabled;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000119 bool new_gain;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000120};
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000121
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000122struct resample_data
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000123{
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000124 long last_sample;
125 long phase;
126 long delta;
127};
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000128
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000129struct dither_data
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000130{
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000131 long error[3];
132 long random;
133};
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000134
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000135static struct dsp_config dsp_conf[2] IDATA_ATTR;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000136static struct dither_data dither_data[2] IDATA_ATTR;
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000137static struct resample_data resample_data[2][2] IDATA_ATTR;
138
139extern int current_codec;
140struct dsp_config *dsp;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000141
142/* The internal format is 32-bit samples, non-interleaved, stereo. This
143 * format is similar to the raw output from several codecs, so the amount
144 * of copying needed is minimized for that case.
145 */
146
147static long sample_buf[SAMPLE_BUF_SIZE] IDATA_ATTR;
148static long resample_buf[RESAMPLE_BUF_SIZE] IDATA_ATTR;
149
150
151/* Convert at most count samples to the internal format, if needed. Returns
152 * number of samples ready for further processing. Updates src to point
153 * past the samples "consumed" and dst is set to point to the samples to
154 * consume. Note that for mono, dst[0] equals dst[1], as there is no point
155 * in processing the same data twice.
156 */
157static int convert_to_internal(char* src[], int count, long* dst[])
158{
159 count = MIN(SAMPLE_BUF_SIZE / 2, count);
160
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000161 if ((dsp->sample_depth <= NATIVE_DEPTH)
162 || (dsp->stereo_mode == STEREO_INTERLEAVED))
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000163 {
164 dst[0] = &sample_buf[0];
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000165 dst[1] = (dsp->stereo_mode == STEREO_MONO)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000166 ? dst[0] : &sample_buf[SAMPLE_BUF_SIZE / 2];
167 }
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000168 else
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000169 {
170 dst[0] = (long*) src[0];
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000171 dst[1] = (long*) ((dsp->stereo_mode == STEREO_MONO) ? src[0] : src[1]);
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000172 }
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000173
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000174 if (dsp->sample_depth <= NATIVE_DEPTH)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000175 {
176 short* s0 = (short*) src[0];
177 long* d0 = dst[0];
178 long* d1 = dst[1];
179 int scale = WORD_SHIFT;
180 int i;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000181
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000182 if (dsp->stereo_mode == STEREO_INTERLEAVED)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000183 {
184 for (i = 0; i < count; i++)
185 {
186 *d0++ = *s0++ << scale;
187 *d1++ = *s0++ << scale;
Miika Pekkarinend54811f2005-07-02 16:52:30 +0000188 }
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000189 }
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000190 else if (dsp->stereo_mode == STEREO_NONINTERLEAVED)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000191 {
192 short* s1 = (short*) src[1];
193
194 for (i = 0; i < count; i++)
195 {
196 *d0++ = *s0++ << scale;
197 *d1++ = *s1++ << scale;
198 }
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000199 }
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000200 else
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000201 {
202 for (i = 0; i < count; i++)
203 {
204 *d0++ = *s0++ << scale;
205 }
206 }
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000207 }
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000208 else if (dsp->stereo_mode == STEREO_INTERLEAVED)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000209 {
210 long* s0 = (long*) src[0];
211 long* d0 = dst[0];
212 long* d1 = dst[1];
213 int i;
214
215 for (i = 0; i < count; i++)
216 {
217 *d0++ = *s0++;
218 *d1++ = *s0++;
219 }
220 }
221
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000222 if (dsp->stereo_mode == STEREO_NONINTERLEAVED)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000223 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000224 src[0] += count * dsp->sample_bytes;
225 src[1] += count * dsp->sample_bytes;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000226 }
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000227 else if (dsp->stereo_mode == STEREO_INTERLEAVED)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000228 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000229 src[0] += count * dsp->sample_bytes * 2;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000230 }
231 else
232 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000233 src[0] += count * dsp->sample_bytes;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000234 }
235
236 return count;
237}
238
239/* Linear resampling that introduces a one sample delay, because of our
240 * inability to look into the future at the end of a frame.
241 */
242
243static long downsample(long *dst, long *src, int count,
244 struct resample_data *r)
245{
246 long phase = r->phase;
247 long delta = r->delta;
248 long last_sample = r->last_sample;
249 int pos = phase >> 16;
250 int i = 1;
251
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000252 /* Do we need last sample of previous frame for interpolation? */
253 if (pos > 0)
254 {
255 last_sample = src[pos - 1];
256 }
257
258 *dst++ = last_sample + FRACMUL((phase & 0xffff) << 15,
259 src[pos] - last_sample);
260 phase += delta;
261
262 while ((pos = phase >> 16) < count)
263 {
264 *dst++ = src[pos - 1] + FRACMUL((phase & 0xffff) << 15,
265 src[pos] - src[pos - 1]);
266 phase += delta;
267 i++;
268 }
269
270 /* Wrap phase accumulator back to start of next frame. */
271 r->phase = phase - (count << 16);
272 r->delta = delta;
273 r->last_sample = src[count - 1];
274 return i;
275}
276
277static long upsample(long *dst, long *src, int count, struct resample_data *r)
278{
279 long phase = r->phase;
280 long delta = r->delta;
281 long last_sample = r->last_sample;
282 int i = 0;
283 int pos;
284
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000285 while ((pos = phase >> 16) == 0)
286 {
287 *dst++ = last_sample + FRACMUL((phase & 0xffff) << 15,
288 src[pos] - last_sample);
289 phase += delta;
290 i++;
291 }
292
293 while ((pos = phase >> 16) < count)
294 {
295 *dst++ = src[pos - 1] + FRACMUL((phase & 0xffff) << 15,
296 src[pos] - src[pos - 1]);
297 phase += delta;
298 i++;
299 }
300
301 /* Wrap phase accumulator back to start of next frame. */
302 r->phase = phase - (count << 16);
303 r->delta = delta;
304 r->last_sample = src[count - 1];
305 return i;
306}
307
308/* Resample count stereo samples. Updates the src array, if resampling is
309 * done, to refer to the resampled data. Returns number of stereo samples
310 * for further processing.
311 */
312static inline int resample(long* src[], int count)
313{
314 long new_count;
315
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000316 if (dsp->frequency != NATIVE_FREQUENCY)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000317 {
318 long* d0 = &resample_buf[0];
319 /* Only process the second channel if needed. */
320 long* d1 = (src[0] == src[1]) ? d0
321 : &resample_buf[RESAMPLE_BUF_SIZE / 2];
322
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000323 if (dsp->frequency < NATIVE_FREQUENCY)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000324 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000325 new_count = upsample(d0, src[0], count,
326 &resample_data[current_codec][0]);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000327
328 if (d0 != d1)
329 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000330 upsample(d1, src[1], count,
331 &resample_data[current_codec][1]);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000332 }
333 }
334 else
335 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000336 new_count = downsample(d0, src[0], count,
337 &resample_data[current_codec][0]);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000338
339 if (d0 != d1)
340 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000341 downsample(d1, src[1], count,
342 &resample_data[current_codec][1]);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000343 }
344 }
345
346 src[0] = d0;
347 src[1] = d1;
348 }
349 else
350 {
351 new_count = count;
352 }
353
354 return new_count;
355}
356
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000357static inline long clip_sample(long sample, long min, long max)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000358{
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000359 if (sample > max)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000360 {
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000361 sample = max;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000362 }
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000363 else if (sample < min)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000364 {
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000365 sample = min;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000366 }
367
368 return sample;
369}
370
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000371/* The "dither" code to convert the 24-bit samples produced by libmad was
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000372 * taken from the coolplayer project - coolplayer.sourceforge.net
373 */
374
375static long dither_sample(long sample, long bias, long mask,
376 struct dither_data* dither)
377{
378 long output;
379 long random;
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000380 long min;
381 long max;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000382
383 /* Noise shape and bias */
384
385 sample += dither->error[0] - dither->error[1] + dither->error[2];
386 dither->error[2] = dither->error[1];
387 dither->error[1] = dither->error[0] / 2;
388
389 output = sample + bias;
390
391 /* Dither */
392
393 random = dither->random * 0x0019660dL + 0x3c6ef35fL;
394 sample += (random & mask) - (dither->random & mask);
395 dither->random = random;
396
397 /* Clip and quantize */
398
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000399 min = dsp->clip_min;
400 max = dsp->clip_max;
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000401 sample = clip_sample(sample, min, max);
402 output = clip_sample(output, min, max) & ~mask;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000403
404 /* Error feedback */
405
406 dither->error[0] = sample - output;
407
408 return output;
409}
410
Magnus Holmgren4a537872005-07-24 15:32:28 +0000411/* Apply a constant gain to the samples (e.g., for ReplayGain). May update
412 * the src array if gain was applied.
413 * Note that this must be called before the resampler.
414 */
415static void apply_gain(long* src[], int count)
416{
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000417 if (dsp->replaygain)
Magnus Holmgren4a537872005-07-24 15:32:28 +0000418 {
419 long* s0 = src[0];
420 long* s1 = src[1];
421 long* d0 = &sample_buf[0];
422 long* d1 = (s0 == s1) ? d0 : &sample_buf[SAMPLE_BUF_SIZE / 2];
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000423 long gain = dsp->replaygain;
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000424 long s;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000425 long i;
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000426
Magnus Holmgren4a537872005-07-24 15:32:28 +0000427 src[0] = d0;
428 src[1] = d1;
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000429 s = *s0++;
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000430
Magnus Holmgren4a537872005-07-24 15:32:28 +0000431 for (i = 0; i < count; i++)
432 {
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000433 *d0++ = FRACMUL_8_LOOP(s, gain, s0);
Magnus Holmgren4a537872005-07-24 15:32:28 +0000434 }
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000435
Dave Bryantc5ebc8e2005-07-25 03:34:25 +0000436 if (src [0] != src [1])
Magnus Holmgren4a537872005-07-24 15:32:28 +0000437 {
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000438 s = *s1++;
439
Magnus Holmgren4a537872005-07-24 15:32:28 +0000440 for (i = 0; i < count; i++)
441 {
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000442 *d1++ = FRACMUL_8_LOOP(s, gain, s1);
Magnus Holmgren4a537872005-07-24 15:32:28 +0000443 }
444 }
445 }
446}
447
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000448static void write_samples(short* dst, long* src[], int count)
449{
450 long* s0 = src[0];
451 long* s1 = src[1];
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000452 int scale = dsp->frac_bits + 1 - NATIVE_DEPTH;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000453
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000454 if (dsp->dither_enabled)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000455 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000456 long bias = (1L << (dsp->frac_bits - NATIVE_DEPTH));
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000457 long mask = (1L << scale) - 1;
458
459 while (count-- > 0)
460 {
461 *dst++ = (short) (dither_sample(*s0++, bias, mask, &dither_data[0])
462 >> scale);
463 *dst++ = (short) (dither_sample(*s1++, bias, mask, &dither_data[1])
464 >> scale);
465 }
466 }
467 else
468 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000469 long min = dsp->clip_min;
470 long max = dsp->clip_max;
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000471
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000472 while (count-- > 0)
473 {
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000474 *dst++ = (short) (clip_sample(*s0++, min, max) >> scale);
475 *dst++ = (short) (clip_sample(*s1++, min, max) >> scale);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000476 }
477 }
478}
479
480/* Process and convert src audio to dst based on the DSP configuration,
481 * reading size bytes of audio data. dst is assumed to be large enough; use
482 * dst_get_dest_size() to get the required size. src is an array of
483 * pointers; for mono and interleaved stereo, it contains one pointer to the
484 * start of the audio data; for non-interleaved stereo, it contains two
485 * pointers, one for each audio channel. Returns number of bytes written to
486 * dest.
487 */
488long dsp_process(char* dst, char* src[], long size)
489{
490 long* tmp[2];
491 long written = 0;
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000492 long factor;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000493 int samples;
494
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000495 dsp = &dsp_conf[current_codec];
496
497 factor = (dsp->stereo_mode != STEREO_MONO) ? 2 : 1;
498 size /= dsp->sample_bytes * factor;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000499 INIT();
500 dsp_set_replaygain(false);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000501
502 while (size > 0)
503 {
504 samples = convert_to_internal(src, size, tmp);
505 size -= samples;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000506 apply_gain(tmp, samples);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000507 samples = resample(tmp, samples);
508 write_samples((short*) dst, tmp, samples);
509 written += samples;
510 dst += samples * sizeof(short) * 2;
511 yield();
512 }
513
514 return written * sizeof(short) * 2;
515}
516
517/* Given size bytes of input data, calculate the maximum number of bytes of
518 * output data that would be generated (the calculation is not entirely
519 * exact and rounds upwards to be on the safe side; during resampling,
520 * the number of samples generated depends on the current state of the
521 * resampler).
522 */
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000523/* dsp_input_size MUST be called afterwards */
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000524long dsp_output_size(long size)
525{
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000526 dsp = &dsp_conf[current_codec];
527
528 if (dsp->sample_depth > NATIVE_DEPTH)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000529 {
530 size /= 2;
531 }
532
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000533 if (dsp->frequency != NATIVE_FREQUENCY)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000534 {
535 size = (long) ((((unsigned long) size * NATIVE_FREQUENCY)
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000536 + (dsp->frequency - 1)) / dsp->frequency);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000537 }
538
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000539 /* round to the next multiple of 2 (these are shorts) */
540 size = (size + 1) & ~1;
541
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000542 if (dsp->stereo_mode == STEREO_MONO)
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000543 {
544 size *= 2;
545 }
546
547 /* now we have the size in bytes for two resampled channels,
548 * and the size in (short) must not exceed RESAMPLE_BUF_SIZE to
549 * avoid resample buffer overflow. One must call dsp_input_size()
550 * to get the correct input buffer size. */
551 if (size > RESAMPLE_BUF_SIZE*2)
552 size = RESAMPLE_BUF_SIZE*2;
553
554 return size;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000555}
556
557/* Given size bytes of output buffer, calculate number of bytes of input
558 * data that would be consumed in order to fill the output buffer.
559 */
560long dsp_input_size(long size)
561{
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000562 dsp = &dsp_conf[current_codec];
563
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000564 /* convert to number of output stereo samples. */
565 size /= 2;
566
567 /* Mono means we need half input samples to fill the output buffer */
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000568 if (dsp->stereo_mode == STEREO_MONO)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000569 size /= 2;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000570
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000571 /* size is now the number of resampled input samples. Convert to
572 original input samples. */
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000573 if (dsp->frequency != NATIVE_FREQUENCY)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000574 {
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000575 /* Use the real resampling delta =
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000576 * (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY, and
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000577 * round towards zero to avoid buffer overflows. */
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000578 size = ((unsigned long)size *
579 resample_data[current_codec][0].delta) >> 16;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000580 }
581
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000582 /* Convert back to bytes. */
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000583 if (dsp->sample_depth > NATIVE_DEPTH)
Linus Nielsen Feltzing591d2892005-08-10 23:17:55 +0000584 size *= 4;
585 else
586 size *= 2;
587
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000588 return size;
589}
590
591int dsp_stereo_mode(void)
592{
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000593 dsp = &dsp_conf[current_codec];
594
595 return dsp->stereo_mode;
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000596}
597
598bool dsp_configure(int setting, void *value)
599{
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000600 dsp = &dsp_conf[current_codec];
601
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000602 switch (setting)
603 {
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000604 case DSP_SET_FREQUENCY:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000605 memset(&resample_data[current_codec][0], 0,
606 sizeof(struct resample_data) * 2);
Linus Nielsen Feltzing315304a2005-08-10 22:56:24 +0000607 /* Fall through!!! */
608 case DSP_SWITCH_FREQUENCY:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000609 dsp->frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value;
610 resample_data[current_codec][0].delta =
611 resample_data[current_codec][1].delta =
612 (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000613 break;
614
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000615 case DSP_SET_CLIP_MIN:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000616 dsp->clip_min = (long) value;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000617 break;
618
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000619 case DSP_SET_CLIP_MAX:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000620 dsp->clip_max = (long) value;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000621 break;
622
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000623 case DSP_SET_SAMPLE_DEPTH:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000624 dsp->sample_depth = (long) value;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000625
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000626 if (dsp->sample_depth <= NATIVE_DEPTH)
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000627 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000628 dsp->frac_bits = WORD_FRACBITS;
629 dsp->sample_bytes = sizeof(short);
630 dsp->clip_max = ((1 << WORD_FRACBITS) - 1);
631 dsp->clip_min = -((1 << WORD_FRACBITS));
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000632 }
633 else
634 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000635 dsp->frac_bits = (long) value;
636 dsp->sample_bytes = sizeof(long);
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000637 }
638
639 break;
640
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000641 case DSP_SET_STEREO_MODE:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000642 dsp->stereo_mode = (long) value;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000643 break;
644
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000645 case DSP_RESET:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000646 dsp->dither_enabled = false;
647 dsp->stereo_mode = STEREO_NONINTERLEAVED;
648 dsp->clip_max = ((1 << WORD_FRACBITS) - 1);
649 dsp->clip_min = -((1 << WORD_FRACBITS));
650 dsp->track_gain = 0;
651 dsp->album_gain = 0;
652 dsp->track_peak = 0;
653 dsp->album_peak = 0;
654 dsp->frequency = NATIVE_FREQUENCY;
655 dsp->sample_depth = NATIVE_DEPTH;
656 dsp->frac_bits = WORD_FRACBITS;
657 dsp->new_gain = true;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000658 break;
659
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000660 case DSP_DITHER:
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000661 memset(dither_data, 0, sizeof(dither_data));
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000662 dsp->dither_enabled = (bool) value;
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000663 break;
664
Magnus Holmgren4a537872005-07-24 15:32:28 +0000665 case DSP_SET_TRACK_GAIN:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000666 dsp->track_gain = (long) value;
667 dsp->new_gain = true;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000668 break;
669
670 case DSP_SET_ALBUM_GAIN:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000671 dsp->album_gain = (long) value;
672 dsp->new_gain = true;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000673 break;
674
675 case DSP_SET_TRACK_PEAK:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000676 dsp->track_peak = (long) value;
677 dsp->new_gain = true;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000678 break;
679
680 case DSP_SET_ALBUM_PEAK:
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000681 dsp->album_peak = (long) value;
682 dsp->new_gain = true;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000683 break;
684
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000685 default:
686 return 0;
687 }
Magnus Holmgren08761aa2005-07-16 12:25:28 +0000688
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000689 return 1;
690}
Magnus Holmgren4a537872005-07-24 15:32:28 +0000691
692void dsp_set_replaygain(bool always)
693{
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000694 dsp = &dsp_conf[current_codec];
695
696 if (always || dsp->new_gain)
Magnus Holmgren4a537872005-07-24 15:32:28 +0000697 {
698 long gain = 0;
699
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000700 dsp->new_gain = false;
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000701
Magnus Holmgren4a537872005-07-24 15:32:28 +0000702 if (global_settings.replaygain || global_settings.replaygain_noclip)
703 {
704 long peak;
705
706 if (global_settings.replaygain)
707 {
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000708 gain = (global_settings.replaygain_track || !dsp->album_gain)
709 ? dsp->track_gain : dsp->album_gain;
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000710
711 if (global_settings.replaygain_preamp)
712 {
713 long preamp = get_replaygain_int(
714 global_settings.replaygain_preamp * 10);
715
716 gain = (long) ((((int64_t) gain * preamp)) >> 24);
717 }
Magnus Holmgren4a537872005-07-24 15:32:28 +0000718 }
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000719
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000720 peak = (global_settings.replaygain_track || !dsp->album_peak)
721 ? dsp->track_peak : dsp->album_peak;
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000722
Magnus Holmgren4a537872005-07-24 15:32:28 +0000723 if (gain == 0)
724 {
725 /* So that noclip can work even with no gain information. */
726 gain = DEFAULT_REPLAYGAIN;
727 }
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000728
Magnus Holmgren4a537872005-07-24 15:32:28 +0000729 if (global_settings.replaygain_noclip && (peak != 0)
730 && ((((int64_t) gain * peak) >> 24) >= DEFAULT_REPLAYGAIN))
731 {
732 gain = (((int64_t) DEFAULT_REPLAYGAIN << 24) / peak);
733 }
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000734
Magnus Holmgren4a537872005-07-24 15:32:28 +0000735 if (gain == DEFAULT_REPLAYGAIN)
736 {
737 /* Nothing to do, disable processing. */
738 gain = 0;
Magnus Holmgren5a8eac12005-08-11 18:56:20 +0000739
Magnus Holmgren4a537872005-07-24 15:32:28 +0000740 }
741 }
742
Magnus Holmgren75ef3122005-08-18 19:25:39 +0000743 /* Store in S8.23 format to simplify calculations. */
Miika Pekkarinen159c52d2005-08-20 11:13:19 +0000744 dsp->replaygain = gain >> 1;
Magnus Holmgren4a537872005-07-24 15:32:28 +0000745 }
746}