summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-06-26 19:41:29 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-06-26 19:41:29 +0000
commitd8cb703b1e86c9f910211a976d8bed0c7a99379a (patch)
tree6db3b698d83e639974bd6603225ff11891652113
parent316eb6538e2fc88efa93248deb761679071409f1 (diff)
downloadrockbox-d8cb703b1e86c9f910211a976d8bed0c7a99379a.tar.gz
rockbox-d8cb703b1e86c9f910211a976d8bed0c7a99379a.zip
Initial DSP implementation. DSP supports resampling audio stream from
codecs (currently works corrently only with mp3's, somebody should fix that). git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6877 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/codecs.c1
-rw-r--r--apps/codecs.h1
-rw-r--r--apps/codecs/a52.c15
-rw-r--r--apps/codecs/flac.c15
-rw-r--r--apps/codecs/mpa.c303
-rw-r--r--apps/codecs/vorbis.c30
-rw-r--r--apps/codecs/wav.c17
-rw-r--r--apps/codecs/wavpack.c16
-rw-r--r--apps/dsp.c397
-rw-r--r--apps/dsp.h48
-rw-r--r--apps/playback.c131
-rw-r--r--apps/playback.h17
-rw-r--r--firmware/export/pcm_playback.h8
-rw-r--r--firmware/pcm_playback.c133
15 files changed, 805 insertions, 328 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 738533105b..271c2ba48c 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -52,6 +52,7 @@ recorder/recording.c
52playback.c 52playback.c
53metadata.c 53metadata.c
54codecs.c 54codecs.c
55dsp.c
55#ifndef SIMULATOR 56#ifndef SIMULATOR
56pcm_recording.c 57pcm_recording.c
57#endif 58#endif
diff --git a/apps/codecs.c b/apps/codecs.c
index 053a622841..da4b1f8bff 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -88,6 +88,7 @@ struct codec_api ci = {
88 NULL, 88 NULL,
89 NULL, 89 NULL,
90 NULL, 90 NULL,
91 NULL,
91 92
92 splash, 93 splash,
93 94
diff --git a/apps/codecs.h b/apps/codecs.h
index e322d758e1..c373bdb8ba 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -143,6 +143,7 @@ struct codec_api {
143 /* Insert PCM data into audio buffer for playback. Playback will start 143 /* Insert PCM data into audio buffer for playback. Playback will start
144 automatically. */ 144 automatically. */
145 bool (*audiobuffer_insert)(char *data, size_t length); 145 bool (*audiobuffer_insert)(char *data, size_t length);
146 bool (*audiobuffer_insert_split)(void *ch1, void *ch2, size_t length);
146 /* Set song position in WPS (value in ms). */ 147 /* Set song position in WPS (value in ms). */
147 void (*set_elapsed)(unsigned int value); 148 void (*set_elapsed)(unsigned int value);
148 149
diff --git a/apps/codecs/a52.c b/apps/codecs/a52.c
index bc711965ec..663e7941ec 100644
--- a/apps/codecs/a52.c
+++ b/apps/codecs/a52.c
@@ -24,6 +24,7 @@
24#include <codecs/liba52/a52.h> 24#include <codecs/liba52/a52.h>
25 25
26#include "playback.h" 26#include "playback.h"
27#include "dsp.h"
27#include "lib/codeclib.h" 28#include "lib/codeclib.h"
28 29
29#define BUFFER_SIZE 4096 30#define BUFFER_SIZE 4096
@@ -173,12 +174,26 @@ enum codec_status codec_start(struct codec_api* api)
173 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); 174 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
174 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 175 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
175 176
177 ci->configure(DSP_DITHER, (bool *)false);
178 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
179 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
180
176 next_track: 181 next_track:
177 182
178 if (codec_init(api)) { 183 if (codec_init(api)) {
179 return CODEC_ERROR; 184 return CODEC_ERROR;
180 } 185 }
181 186
187 while (!rb->taginfo_ready)
188 rb->yield();
189
190 if (rb->id3->frequency != NATIVE_FREQUENCY) {
191 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
192 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
193 } else {
194 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
195 }
196
182 /* Intialise the A52 decoder and check for success */ 197 /* Intialise the A52 decoder and check for success */
183 state = a52_init (0); // Parameter is "accel" 198 state = a52_init (0); // Parameter is "accel"
184 199
diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c
index 07e5b8f566..d7ae037d26 100644
--- a/apps/codecs/flac.c
+++ b/apps/codecs/flac.c
@@ -22,6 +22,7 @@
22#include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h> 22#include <codecs/libFLAC/include/FLAC/seekable_stream_decoder.h>
23#include "playback.h" 23#include "playback.h"
24#include "lib/codeclib.h" 24#include "lib/codeclib.h"
25#include "dsp.h"
25 26
26#define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608 27#define FLAC_MAX_SUPPORTED_BLOCKSIZE 4608
27#define FLAC_MAX_SUPPORTED_CHANNELS 2 28#define FLAC_MAX_SUPPORTED_CHANNELS 2
@@ -180,12 +181,26 @@ enum codec_status codec_start(struct codec_api* api)
180 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 181 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
181 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 182 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
182 183
184 ci->configure(DSP_DITHER, (bool *)false);
185 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
186 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
187
183 next_track: 188 next_track:
184 189
185 if (codec_init(api)) { 190 if (codec_init(api)) {
186 return CODEC_ERROR; 191 return CODEC_ERROR;
187 } 192 }
188 193
194 while (!rb->taginfo_ready)
195 rb->yield();
196
197 if (rb->id3->frequency != NATIVE_FREQUENCY) {
198 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
199 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
200 } else {
201 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
202 }
203
189 /* Create a decoder instance */ 204 /* Create a decoder instance */
190 205
191 flacDecoder=FLAC__seekable_stream_decoder_new(); 206 flacDecoder=FLAC__seekable_stream_decoder_new();
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c
index 736eef1ffe..f052b9df88 100644
--- a/apps/codecs/mpa.c
+++ b/apps/codecs/mpa.c
@@ -22,6 +22,7 @@
22#include <codecs/libmad/mad.h> 22#include <codecs/libmad/mad.h>
23 23
24#include "playback.h" 24#include "playback.h"
25#include "dsp.h"
25#include "mp3data.h" 26#include "mp3data.h"
26#include "lib/codeclib.h" 27#include "lib/codeclib.h"
27 28
@@ -29,7 +30,6 @@ struct mad_stream Stream IDATA_ATTR;
29struct mad_frame Frame IDATA_ATTR; 30struct mad_frame Frame IDATA_ATTR;
30struct mad_synth Synth IDATA_ATTR; 31struct mad_synth Synth IDATA_ATTR;
31mad_timer_t Timer; 32mad_timer_t Timer;
32struct dither d0, d1;
33 33
34/* The following function is used inside libmad - let's hope it's never 34/* The following function is used inside libmad - let's hope it's never
35 called. 35 called.
@@ -38,122 +38,6 @@ struct dither d0, d1;
38void abort(void) { 38void abort(void) {
39} 39}
40 40
41/* The "dither" code to convert the 24-bit samples produced by libmad was
42 taken from the coolplayer project - coolplayer.sourceforge.net */
43
44struct dither {
45 mad_fixed_t error[3];
46 mad_fixed_t random;
47};
48
49# define SAMPLE_DEPTH 16
50# define scale(x, y) dither((x), (y))
51
52/*
53 * NAME: prng()
54 * DESCRIPTION: 32-bit pseudo-random number generator
55 */
56static __inline
57unsigned long prng(unsigned long state)
58{
59 return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
60}
61
62/*
63 * NAME: dither()
64 * DESCRIPTION: dither and scale sample
65 */
66inline int dither(mad_fixed_t sample, struct dither *dither)
67{
68 unsigned int scalebits;
69 mad_fixed_t output, mask, random;
70
71 enum {
72 MIN = -MAD_F_ONE,
73 MAX = MAD_F_ONE - 1
74 };
75
76 /* noise shape */
77 sample += dither->error[0] - dither->error[1] + dither->error[2];
78
79 dither->error[2] = dither->error[1];
80 dither->error[1] = dither->error[0]/2;
81
82 /* bias */
83 output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
84
85 scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
86 mask = (1L << scalebits) - 1;
87
88 /* dither */
89 random = prng(dither->random);
90 output += (random & mask) - (dither->random & mask);
91
92 //dither->random = random;
93
94 /* clip */
95 if (output > MAX) {
96 output = MAX;
97
98 if (sample > MAX)
99 sample = MAX;
100 } else if (output < MIN) {
101 output = MIN;
102
103 if (sample < MIN)
104 sample = MIN;
105 }
106
107 /* quantize */
108 output &= ~mask;
109
110 /* error feedback */
111 dither->error[0] = sample - output;
112
113 /* scale */
114 return output >> scalebits;
115}
116
117inline int detect_silence(mad_fixed_t sample)
118{
119 unsigned int scalebits;
120 mad_fixed_t output, mask;
121
122 enum {
123 MIN = -MAD_F_ONE,
124 MAX = MAD_F_ONE - 1
125 };
126
127 /* bias */
128 output = sample + (1L << (MAD_F_FRACBITS + 1 - SAMPLE_DEPTH - 1));
129
130 scalebits = MAD_F_FRACBITS + 1 - SAMPLE_DEPTH;
131 mask = (1L << scalebits) - 1;
132
133 /* clip */
134 if (output > MAX) {
135 output = MAX;
136
137 if (sample > MAX)
138 sample = MAX;
139 } else if (output < MIN) {
140 output = MIN;
141
142 if (sample < MIN)
143 sample = MIN;
144 }
145
146 /* quantize */
147 output &= ~mask;
148
149 /* scale */
150 output >>= scalebits + 4;
151
152 if (output == 0x00 || output == 0xff)
153 return 1;
154
155 return 0;
156}
157 41
158#define INPUT_CHUNK_SIZE 8192 42#define INPUT_CHUNK_SIZE 8192
159#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */ 43#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */
@@ -162,7 +46,6 @@ unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
162unsigned char *OutputPtr; 46unsigned char *OutputPtr;
163unsigned char *GuardPtr = NULL; 47unsigned char *GuardPtr = NULL;
164const unsigned char *OutputBufferEnd = OutputBuffer + OUTPUT_BUFFER_SIZE; 48const unsigned char *OutputBufferEnd = OutputBuffer + OUTPUT_BUFFER_SIZE;
165long resampled_data[2][5000]; /* enough to cope with 11khz upsampling */
166 49
167mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR; 50mad_fixed_t mad_frame_overlap[2][32][18] IDATA_ATTR;
168unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR; 51unsigned char mad_main_data[MAD_BUFFER_MDLEN] IDATA_ATTR;
@@ -174,73 +57,7 @@ extern char iramstart[];
174extern char iramend[]; 57extern char iramend[];
175#endif 58#endif
176 59
177#undef DEBUG_GAPLESS 60/*
178
179struct resampler {
180 long last_sample, phase, delta;
181};
182
183#if CONFIG_CPU==MCF5249 && !defined(SIMULATOR)
184
185#define INIT() asm volatile ("move.l #0xb0, %macsr") /* frac, round, clip */
186#define FRACMUL(x, y) \
187({ \
188 long t; \
189 asm volatile ("mac.l %[a], %[b], %%acc0\n\t" \
190 "movclr.l %%acc0, %[t]\n\t" \
191 : [t] "=r" (t) : [a] "r" (x), [b] "r" (y)); \
192 t; \
193})
194
195#else
196
197#define INIT()
198#define FRACMUL(x, y) (long)(((long long)(x)*(long long)(y)) << 1)
199#endif
200
201/* linear resampling, introduces one sample delay, because of our inability to
202 look into the future at the end of a frame */
203long downsample(long *in, long *out, int num, struct resampler *s)
204{
205 long i = 1, pos;
206 long last = s->last_sample;
207
208 INIT();
209 pos = s->phase >> 16;
210 /* check if we need last sample of previous frame for interpolation */
211 if (pos > 0)
212 last = in[pos - 1];
213 out[0] = last + FRACMUL((s->phase & 0xffff) << 15, in[pos] - last);
214 s->phase += s->delta;
215 while ((pos = s->phase >> 16) < num) {
216 out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
217 s->phase += s->delta;
218 }
219 /* wrap phase accumulator back to start of next frame */
220 s->phase -= num << 16;
221 s->last_sample = in[num - 1];
222 return i;
223}
224
225long upsample(long *in, long *out, int num, struct resampler *s)
226{
227 long i = 0, pos;
228
229 INIT();
230 while ((pos = s->phase >> 16) == 0) {
231 out[i++] = s->last_sample + FRACMUL((s->phase & 0xffff) << 15, in[pos] - s->last_sample);
232 s->phase += s->delta;
233 }
234 while ((pos = s->phase >> 16) < num) {
235 out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
236 s->phase += s->delta;
237 }
238 /* wrap phase accumulator back to start of next frame */
239 s->phase -= num << 16;
240 s->last_sample = in[num - 1];
241 return i;
242}
243
244long resample(long *in, long *out, int num, struct resampler *s) 61long resample(long *in, long *out, int num, struct resampler *s)
245{ 62{
246 if (s->delta >= (1 << 16)) 63 if (s->delta >= (1 << 16))
@@ -248,7 +65,7 @@ long resample(long *in, long *out, int num, struct resampler *s)
248 else 65 else
249 return upsample(in, out, num, s); 66 return upsample(in, out, num, s);
250} 67}
251 68*/
252/* this is the codec entry point */ 69/* this is the codec entry point */
253enum codec_status codec_start(struct codec_api* api) 70enum codec_status codec_start(struct codec_api* api)
254{ 71{
@@ -257,20 +74,12 @@ enum codec_status codec_start(struct codec_api* api)
257 int Status = 0; 74 int Status = 0;
258 size_t size; 75 size_t size;
259 int file_end; 76 int file_end;
260 unsigned short Sample;
261 char *InputBuffer; 77 char *InputBuffer;
262 unsigned int samplecount; 78 unsigned int samplecount;
263 unsigned int samplesdone; 79 unsigned int samplesdone;
264 bool first_frame; 80 bool first_frame;
265#ifdef DEBUG_GAPLESS
266 bool first = true;
267 int fd;
268#endif
269 int i;
270 int yieldcounter = 0;
271 int stop_skip, start_skip; 81 int stop_skip, start_skip;
272 struct resampler lr = { 0, 0, 0 }, rr = { 0, 0, 0 }; 82 // struct resampler lr = { 0, 0, 0 }, rr = { 0, 0, 0 };
273 long length;
274 /* Generic codec inititialisation */ 83 /* Generic codec inititialisation */
275 84
276 TEST_CODEC_API(api); 85 TEST_CODEC_API(api);
@@ -289,7 +98,13 @@ enum codec_status codec_start(struct codec_api* api)
289 98
290 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); 99 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
291 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); 100 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
292 101 ci->configure(DSP_SET_CLIP_MIN, (int *)-MAD_F_ONE);
102 ci->configure(DSP_SET_CLIP_MAX, (int *)(MAD_F_ONE - 1));
103 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(MAD_F_FRACBITS));
104 ci->configure(DSP_DITHER, (bool *)true);
105 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
106 ci->configure(CODEC_DSP_ENABLE, (bool *)true);
107
293 ci->memset(&Stream, 0, sizeof(struct mad_stream)); 108 ci->memset(&Stream, 0, sizeof(struct mad_stream));
294 ci->memset(&Frame, 0, sizeof(struct mad_frame)); 109 ci->memset(&Frame, 0, sizeof(struct mad_frame));
295 ci->memset(&Synth, 0, sizeof(struct mad_synth)); 110 ci->memset(&Synth, 0, sizeof(struct mad_synth));
@@ -309,14 +124,6 @@ enum codec_status codec_start(struct codec_api* api)
309 for gapless playback */ 124 for gapless playback */
310 next_track: 125 next_track:
311 126
312#ifdef DEBUG_GAPLESS
313 if (first)
314 fd = ci->open("/first.pcm", O_WRONLY | O_CREAT);
315 else
316 fd = ci->open("/second.pcm", O_WRONLY | O_CREAT);
317 first = false;
318#endif
319
320 info = ci->mp3data; 127 info = ci->mp3data;
321 first_frame = false; 128 first_frame = false;
322 file_end = 0; 129 file_end = 0;
@@ -325,6 +132,8 @@ enum codec_status codec_start(struct codec_api* api)
325 while (!*ci->taginfo_ready) 132 while (!*ci->taginfo_ready)
326 ci->yield(); 133 ci->yield();
327 134
135 ci->configure(DSP_SET_FREQUENCY, (int *)ci->id3->frequency);
136
328 ci->request_buffer(&size, ci->id3->first_frame_offset); 137 ci->request_buffer(&size, ci->id3->first_frame_offset);
329 ci->advance_buffer(size); 138 ci->advance_buffer(size);
330 139
@@ -350,13 +159,7 @@ enum codec_status codec_start(struct codec_api* api)
350 samplecount = ci->id3->length * (ci->id3->frequency / 100) / 10; 159 samplecount = ci->id3->length * (ci->id3->frequency / 100) / 10;
351 samplesdone = ci->id3->elapsed * (ci->id3->frequency / 100) / 10; 160 samplesdone = ci->id3->elapsed * (ci->id3->frequency / 100) / 10;
352 } 161 }
353 /* rb->snprintf(buf2, sizeof(buf2), "sc: %d", samplecount); 162
354 rb->splash(0, true, buf2);
355 rb->snprintf(buf2, sizeof(buf2), "length: %d", ci->id3->length);
356 rb->splash(HZ*5, true, buf2);
357 rb->snprintf(buf2, sizeof(buf2), "frequency: %d", ci->id3->frequency);
358 rb->splash(HZ*5, true, buf2); */
359 lr.delta = rr.delta = ci->id3->frequency*65536/44100;
360 /* This is the decoding loop. */ 163 /* This is the decoding loop. */
361 while (1) { 164 while (1) {
362 ci->yield(); 165 ci->yield();
@@ -387,9 +190,6 @@ enum codec_status codec_start(struct codec_api* api)
387 mad_stream_buffer(&Stream, InputBuffer, size); 190 mad_stream_buffer(&Stream, InputBuffer, size);
388 } 191 }
389 192
390 //if ((int)ci->curpos >= ci->id3->first_frame_offset)
391 //first_frame = true;
392
393 if(mad_frame_decode(&Frame,&Stream)) 193 if(mad_frame_decode(&Frame,&Stream))
394 { 194 {
395 if (Stream.error == MAD_FLAG_INCOMPLETE || Stream.error == MAD_ERROR_BUFLEN) { 195 if (Stream.error == MAD_FLAG_INCOMPLETE || Stream.error == MAD_ERROR_BUFLEN) {
@@ -428,78 +228,23 @@ enum codec_status codec_start(struct codec_api* api)
428 228
429 mad_synth_frame(&Synth,&Frame); 229 mad_synth_frame(&Synth,&Frame);
430 230
431 //if (!first_frame) {
432 //samplecount -= Synth.pcm.length;
433 //continue ;
434 //}
435
436 /* Convert MAD's numbers to an array of 16-bit LE signed integers */ 231 /* Convert MAD's numbers to an array of 16-bit LE signed integers */
437 /* We skip start_skip number of samples here, this should only happen for 232 /* We skip start_skip number of samples here, this should only happen for
438 very first frame in the stream. */ 233 very first frame in the stream. */
439 /* TODO: possible for start_skip to exceed one frames worth of samples? */ 234 /* TODO: possible for start_skip to exceed one frames worth of samples? */
440 length = resample((long *)&Synth.pcm.samples[0][start_skip], resampled_data[0], Synth.pcm.length, &lr); 235 //length = resample((long *)&Synth.pcm.samples[0][start_skip], resampled_data[0], Synth.pcm.length, &lr);
441 if (MAD_NCHANNELS(&Frame.header) == 2) 236 //if (MAD_NCHANNELS(&Frame.header) == 2)
442 resample((long *)&Synth.pcm.samples[1][start_skip], resampled_data[1], Synth.pcm.length, &rr); 237 // resample((long *)&Synth.pcm.samples[1][start_skip], resampled_data[1], Synth.pcm.length, &rr);
443 for (i = 0; i < length; i++) 238 ci->audiobuffer_insert_split(&Synth.pcm.samples[0][start_skip],
444 { 239 &Synth.pcm.samples[1][start_skip],
445 start_skip = 0; /* not very elegant, and might want to keep this value */ 240 (Synth.pcm.length - start_skip) * 4);
446 samplesdone++; 241 start_skip = 0; /* not very elegant, and might want to keep this value */
447 //if (ci->mp3data->padding > 0) { 242
448 // ci->mp3data->padding--; 243 samplesdone += Synth.pcm.length;
449 // continue ; 244 samplecount -= Synth.pcm.length;
450 //}
451 /*if (!first_frame) {
452 if (detect_silence(Synth.pcm.samples[0][i]))
453 continue ;
454 first_frame = true;
455 }*/
456
457 /* Left channel */
458 Sample = scale(resampled_data[0][i], &d0);
459 *(OutputPtr++) = Sample >> 8;
460 *(OutputPtr++) = Sample & 0xff;
461
462 /* Right channel. If the decoded stream is monophonic then
463 * the right output channel is the same as the left one.
464 */
465 if (MAD_NCHANNELS(&Frame.header) == 2)
466 Sample = scale(resampled_data[1][i], &d1);
467 *(OutputPtr++) = Sample >> 8;
468 *(OutputPtr++) = Sample & 0xff;
469
470 samplecount--;
471 if (samplecount == 0) {
472#ifdef DEBUG_GAPLESS
473 ci->write(fd, OutputBuffer, (int)OutputPtr - (int)OutputBuffer);
474#endif
475 while (!ci->audiobuffer_insert(OutputBuffer, (int)OutputPtr - (int)OutputBuffer))
476 ci->yield();
477 goto song_end;
478 }
479
480 if (yieldcounter++ == 200) {
481 ci->yield();
482 yieldcounter = 0;
483 }
484
485 /* Flush the buffer if it is full. */
486 if (OutputPtr == OutputBufferEnd)
487 {
488#ifdef DEBUG_GAPLESS
489 ci->write(fd, OutputBuffer, OUTPUT_BUFFER_SIZE);
490#endif
491 while (!ci->audiobuffer_insert(OutputBuffer, OUTPUT_BUFFER_SIZE))
492 ci->yield();
493 OutputPtr = OutputBuffer;
494 }
495 }
496 ci->set_elapsed(samplesdone / (ci->id3->frequency/1000)); 245 ci->set_elapsed(samplesdone / (ci->id3->frequency/1000));
497 } 246 }
498 247
499 song_end:
500#ifdef DEBUG_GAPLESS
501 ci->close(fd);
502#endif
503 Stream.error = 0; 248 Stream.error = 0;
504 249
505 if (ci->request_next_track()) 250 if (ci->request_next_track())
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c
index f2939aa68d..9afeb053e1 100644
--- a/apps/codecs/vorbis.c
+++ b/apps/codecs/vorbis.c
@@ -21,6 +21,7 @@
21 21
22#include "Tremor/ivorbisfile.h" 22#include "Tremor/ivorbisfile.h"
23#include "playback.h" 23#include "playback.h"
24#include "dsp.h"
24#include "lib/codeclib.h" 25#include "lib/codeclib.h"
25 26
26static struct codec_api* rb; 27static struct codec_api* rb;
@@ -92,10 +93,6 @@ enum codec_status codec_start(struct codec_api* api)
92 long n; 93 long n;
93 int current_section; 94 int current_section;
94 int eof; 95 int eof;
95#if BYTE_ORDER == BIG_ENDIAN
96 int i;
97 char x;
98#endif
99 96
100 TEST_CODEC_API(api); 97 TEST_CODEC_API(api);
101 98
@@ -110,15 +107,27 @@ enum codec_status codec_start(struct codec_api* api)
110 rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); 107 rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
111 rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64)); 108 rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64));
112 109
113 /* We need to flush reserver memory every track load. */ 110 rb->configure(DSP_DITHER, (bool *)false);
111 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
112 rb->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
113
114/* We need to flush reserver memory every track load. */
114 next_track: 115 next_track:
115 if (codec_init(rb)) { 116 if (codec_init(rb)) {
116 return CODEC_ERROR; 117 return CODEC_ERROR;
117 } 118 }
118 119
119 120 while (!rb->taginfo_ready)
121 rb->yield();
122
123 if (rb->id3->frequency != NATIVE_FREQUENCY) {
124 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
125 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
126 } else {
127 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
128 }
129
120 /* Create a decoder instance */ 130 /* Create a decoder instance */
121
122 callbacks.read_func=read_handler; 131 callbacks.read_func=read_handler;
123 callbacks.seek_func=seek_handler; 132 callbacks.seek_func=seek_handler;
124 callbacks.tell_func=tell_handler; 133 callbacks.tell_func=tell_handler;
@@ -148,17 +157,10 @@ enum codec_status codec_start(struct codec_api* api)
148 if (rb->stop_codec || rb->reload_codec) 157 if (rb->stop_codec || rb->reload_codec)
149 break ; 158 break ;
150 159
151 rb->yield();
152 while (!rb->audiobuffer_insert(pcmbuf, n)) 160 while (!rb->audiobuffer_insert(pcmbuf, n))
153 rb->yield(); 161 rb->yield();
154 162
155 rb->set_elapsed(ov_time_tell(&vf)); 163 rb->set_elapsed(ov_time_tell(&vf));
156
157#if BYTE_ORDER == BIG_ENDIAN
158 for (i=0;i<n;i+=2) {
159 x=pcmbuf[i]; pcmbuf[i]=pcmbuf[i+1]; pcmbuf[i+1]=x;
160 }
161#endif
162 } 164 }
163 } 165 }
164 166
diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c
index dfed97d64c..49bd12da1f 100644
--- a/apps/codecs/wav.c
+++ b/apps/codecs/wav.c
@@ -20,6 +20,7 @@
20#include "codec.h" 20#include "codec.h"
21#include "playback.h" 21#include "playback.h"
22#include "lib/codeclib.h" 22#include "lib/codeclib.h"
23#include "dsp.h"
23 24
24#define BYTESWAP(x) (((x>>8) & 0xff) | ((x<<8) & 0xff00)) 25#define BYTESWAP(x) (((x>>8) & 0xff) | ((x<<8) & 0xff00))
25 26
@@ -60,12 +61,26 @@ enum codec_status codec_start(struct codec_api* api)
60 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 61 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
61 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); 62 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256));
62 63
64 ci->configure(DSP_DITHER, (bool *)false);
65 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
66 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
67
63 next_track: 68 next_track:
64 69
65 if (codec_init(api)) { 70 if (codec_init(api)) {
66 return CODEC_ERROR; 71 return CODEC_ERROR;
67 } 72 }
68 73
74 while (!rb->taginfo_ready)
75 rb->yield();
76
77 if (rb->id3->frequency != NATIVE_FREQUENCY) {
78 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
79 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
80 } else {
81 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
82 }
83
69 /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */ 84 /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */
70 85
71 header=ci->request_buffer(&n,44); 86 header=ci->request_buffer(&n,44);
@@ -116,7 +131,7 @@ enum codec_status codec_start(struct codec_api* api)
116 131
117 /* Byte-swap data */ 132 /* Byte-swap data */
118 for (i=0;i<n/2;i++) { 133 for (i=0;i<n/2;i++) {
119 wavbuf[i]=BYTESWAP(wavbuf[i]); 134 wavbuf[i]=SWAB16(wavbuf[i]);
120 } 135 }
121 136
122 samplesdone+=nsamples; 137 samplesdone+=nsamples;
diff --git a/apps/codecs/wavpack.c b/apps/codecs/wavpack.c
index 2ea8f052df..275f5f11e4 100644
--- a/apps/codecs/wavpack.c
+++ b/apps/codecs/wavpack.c
@@ -22,6 +22,7 @@
22#include <codecs/libwavpack/wavpack.h> 22#include <codecs/libwavpack/wavpack.h>
23#include "playback.h" 23#include "playback.h"
24#include "lib/codeclib.h" 24#include "lib/codeclib.h"
25#include "dsp.h"
25 26
26static struct codec_api *rb; 27static struct codec_api *rb;
27static struct codec_api *ci; 28static struct codec_api *ci;
@@ -61,14 +62,27 @@ enum codec_status codec_start(struct codec_api* api)
61 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); 62 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10));
62 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); 63 ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512));
63 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128)); 64 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*128));
65
66 ci->configure(DSP_DITHER, (bool *)false);
67 ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED);
68 ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16));
64 69
65 next_track: 70 next_track:
66 71
67 if (codec_init(api)) 72 if (codec_init(api))
68 return CODEC_ERROR; 73 return CODEC_ERROR;
69 74
75 while (!rb->taginfo_ready)
76 ci->yield();
77
78 if (ci->id3->frequency != NATIVE_FREQUENCY) {
79 ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency));
80 ci->configure(CODEC_DSP_ENABLE, (bool *)true);
81 } else {
82 ci->configure(CODEC_DSP_ENABLE, (bool *)false);
83 }
84
70 /* Create a decoder instance */ 85 /* Create a decoder instance */
71
72 wpc = WavpackOpenFileInput (read_callback, error); 86 wpc = WavpackOpenFileInput (read_callback, error);
73 87
74 if (!wpc) 88 if (!wpc)
diff --git a/apps/dsp.c b/apps/dsp.c
new file mode 100644
index 0000000000..963e98da2e
--- /dev/null
+++ b/apps/dsp.c
@@ -0,0 +1,397 @@
1/***************************************************************************
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 ****************************************************************************/
19#include "kernel.h"
20#include "logf.h"
21
22#include "dsp.h"
23#include "playback.h"
24#include "system.h"
25
26/* The "dither" code to convert the 24-bit samples produced by libmad was
27 taken from the coolplayer project - coolplayer.sourceforge.net */
28struct s_dither {
29 int error[3];
30 int random;
31};
32
33static struct s_dither dither[2];
34struct dsp_configuration dsp_config;
35static int channel;
36static int fracbits;
37
38#define SAMPLE_DEPTH 16
39
40/*
41 * NAME: prng()
42 * DESCRIPTION: 32-bit pseudo-random number generator
43 */
44static __inline
45unsigned long prng(unsigned long state)
46{
47 return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
48}
49
50inline long dsp_noiseshape(long sample)
51{
52 sample += dither[channel].error[0] - dither[channel].error[1]
53 + dither[channel].error[2];
54 dither[channel].error[2] = dither[channel].error[1];
55 dither[channel].error[1] = dither[channel].error[0]/2;
56
57 return sample;
58}
59
60inline long dsp_bias(long sample)
61{
62 sample = sample + (1L << (fracbits - SAMPLE_DEPTH));
63
64 return sample;
65}
66
67inline long dsp_dither(long *mask)
68{
69 long random, output;
70
71 random = prng(dither[channel].random);
72 output = (random & *mask) - (dither[channel].random & *mask);
73 dither[channel].random = random;
74
75 return output;
76}
77
78inline void dsp_clip(long *sample, long *output)
79{
80 if (*output > dsp_config.clip_max) {
81 *output = dsp_config.clip_max;
82
83 if (*sample > dsp_config.clip_max)
84 *sample = dsp_config.clip_max;
85 } else if (*output < dsp_config.clip_min) {
86 *output = dsp_config.clip_min;
87
88 if (*sample < dsp_config.clip_min)
89 *sample = dsp_config.clip_min;
90 }
91}
92
93/*
94 * NAME: dither()
95 * DESCRIPTION: dither and scale sample
96 */
97inline int scale_dither_clip(long sample)
98{
99 unsigned int scalebits;
100 long output, mask;
101
102 /* noise shape */
103 sample = dsp_noiseshape(sample);
104
105 /* bias */
106 output = dsp_bias(sample);
107
108 scalebits = fracbits + 1 - SAMPLE_DEPTH;
109 mask = (1L << scalebits) - 1;
110
111 /* dither */
112 output += dsp_dither(&mask);
113
114 /* clip */
115 dsp_clip(&sample, &output);
116
117 /* quantize */
118 output &= ~mask;
119
120 /* error feedback */
121 dither->error[0] = sample - output;
122
123 /* scale */
124 return output >> scalebits;
125}
126
127inline int scale_clip(long sample)
128{
129 unsigned int scalebits;
130 long output, mask;
131
132 output = sample;
133 scalebits = fracbits + 1 - SAMPLE_DEPTH;
134 mask = (1L << scalebits) - 1;
135
136 dsp_clip(&sample, &output);
137 output &= ~mask;
138
139 return output >> scalebits;
140}
141
142void dsp_scale_dither_clip(short *dest, long *src, int samplecount)
143{
144 dest += channel;
145 while (samplecount-- > 0) {
146 *dest = scale_dither_clip(*src);
147 src++;
148 dest += 2;
149 }
150}
151
152void dsp_scale_clip(short *dest, long *src, int samplecount)
153{
154 dest += channel;
155 while (samplecount-- > 0) {
156 *dest = scale_clip(*src);
157 src++;
158 dest += 2;
159 }
160}
161
162struct resampler {
163 long last_sample, phase, delta;
164};
165
166static struct resampler resample[2];
167
168#if CONFIG_CPU==MCF5249 && !defined(SIMULATOR)
169
170#define INIT() asm volatile ("move.l #0xb0, %macsr") /* frac, round, clip */
171#define FRACMUL(x, y) \
172({ \
173 long t; \
174 asm volatile ("mac.l %[a], %[b], %%acc0\n\t" \
175 "movclr.l %%acc0, %[t]\n\t" \
176 : [t] "=r" (t) : [a] "r" (x), [b] "r" (y)); \
177 t; \
178})
179
180#else
181
182#define INIT()
183#define FRACMUL(x, y) (long)(((long long)(x)*(long long)(y)) << 1)
184#endif
185
186/* linear resampling, introduces one sample delay, because of our inability to
187 look into the future at the end of a frame */
188long downsample(long *out, long *in, int num, struct resampler *s)
189{
190 long i = 1, pos;
191 long last = s->last_sample;
192
193 INIT();
194 pos = s->phase >> 16;
195 /* check if we need last sample of previous frame for interpolation */
196 if (pos > 0)
197 last = in[pos - 1];
198 out[0] = last + FRACMUL((s->phase & 0xffff) << 15, in[pos] - last);
199 s->phase += s->delta;
200 while ((pos = s->phase >> 16) < num) {
201 out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
202 s->phase += s->delta;
203 }
204 /* wrap phase accumulator back to start of next frame */
205 s->phase -= num << 16;
206 s->last_sample = in[num - 1];
207 return i;
208}
209
210long upsample(long *out, long *in, int num, struct resampler *s)
211{
212 long i = 0, pos;
213
214 INIT();
215 while ((pos = s->phase >> 16) == 0) {
216 out[i++] = s->last_sample + FRACMUL((s->phase & 0xffff) << 15, in[pos] - s->last_sample);
217 s->phase += s->delta;
218 }
219 while ((pos = s->phase >> 16) < num) {
220 out[i++] = in[pos - 1] + FRACMUL((s->phase & 0xffff) << 15, in[pos] - in[pos - 1]);
221 s->phase += s->delta;
222 }
223 /* wrap phase accumulator back to start of next frame */
224 s->phase -= num << 16;
225 s->last_sample = in[num - 1];
226 return i;
227}
228
229#define MAX_CHUNK_SIZE 1024
230static char samplebuf[MAX_CHUNK_SIZE*4];
231/* enough to cope with 11khz upsampling */
232long resampled[MAX_CHUNK_SIZE * 4];
233
234int process(short *dest, long *src, int samplecount)
235{
236 long *p;
237 int length = samplecount;
238
239 p = resampled;
240
241 /* Resample as necessary */
242 if (dsp_config.frequency > NATIVE_FREQUENCY)
243 length = upsample(resampled, src, samplecount, &resample[channel]);
244 else if (dsp_config.frequency < NATIVE_FREQUENCY)
245 length = downsample(resampled, src, samplecount, &resample[channel]);
246 else
247 p = src;
248
249 /* Scale & dither */
250 if (dsp_config.dither_enabled) {
251 dsp_scale_dither_clip(dest, p, length);
252 } else {
253 dsp_scale_clip(dest, p, length);
254 }
255
256 return length;
257}
258
259void convert_stereo_mode(long *dest, long *src, int samplecount)
260{
261 int i;
262
263 samplecount /= 2;
264
265 for (i = 0; i < samplecount; i++) {
266 dest[i] = src[i*2 + 0];
267 dest[i+samplecount] = src[i*2 + 1];
268 }
269}
270
271/* Not yet functional. */
272void scale_up(long *dest, short *src, int samplecount)
273{
274 int i;
275
276 for (i = 0; i < samplecount; i++)
277 dest[i] = (long)(src[i] << 8);
278}
279
280void scale_up_convert_stereo_mode(long *dest, short *src, int samplecount)
281{
282 int i;
283
284 samplecount /= 2;
285
286 for (i = 0; i < samplecount; i++) {
287 dest[i] = (long)(src[i*2+0] << SAMPLE_DEPTH);
288 dest[i+samplecount] = (long)(src[i*2+1] << SAMPLE_DEPTH);
289 //dest[i] = (long)(((src[i*2 + 0] << 8)&0x7fff) | ((1L << 31) & src[i*2+0]<<15));
290 //dest[i+samplecount] = (long)(((src[i*2 + 1] << 8)&0x7fff) | ((1L << 31) & src[i*2+1]<<15));
291 }
292}
293
294int dsp_process(char *dest, char *src, int samplecount)
295{
296 int copy_n, rc;
297 char *p;
298 int processed_bytes = 0;
299
300 fracbits = dsp_config.sample_depth;
301
302 while (samplecount > 0) {
303 yield();
304 copy_n = MIN(MAX_CHUNK_SIZE / 4, samplecount);
305
306 p = src;
307 /* Scale up to 32-bit samples. */
308 if (dsp_config.sample_depth <= SAMPLE_DEPTH) {
309 if (dsp_config.stereo_mode == STEREO_INTERLEAVED)
310 scale_up_convert_stereo_mode((long *)samplebuf,
311 (short *)p, copy_n);
312 else
313 scale_up((long *)samplebuf, (short *)p, copy_n);
314 p = samplebuf;
315 fracbits = 31;
316 }
317
318 /* Convert to non-interleaved stereo. */
319 else if (dsp_config.stereo_mode == STEREO_INTERLEAVED) {
320 convert_stereo_mode((long *)samplebuf, (long *)p, copy_n);
321 p = samplebuf;
322 }
323
324 /* Apply DSP functions. */
325 if (dsp_config.stereo_mode == STEREO_INTERLEAVED) {
326 channel = 0;
327 rc = process((short *)dest, (long *)p, copy_n / 2) * 4;
328 p += copy_n * 2;
329 channel = 1;
330 process((short *)dest, (long *)p, copy_n / 2);
331 dest += rc;
332 } else {
333 rc = process((short *)dest, (long *)p, copy_n) * 2;
334 dest += rc * 2;
335 }
336
337 samplecount -= copy_n;
338 if (dsp_config.sample_depth <= SAMPLE_DEPTH)
339 src += copy_n * 2;
340 else
341 src += copy_n * 4;
342
343 processed_bytes += rc;
344 }
345
346 /* Set stereo channel */
347 channel = channel ? 0 : 1;
348
349 return processed_bytes;
350}
351
352bool dsp_configure(int setting, void *value)
353{
354 switch (setting) {
355 case DSP_SET_FREQUENCY:
356 dsp_config.frequency = (int)value;
357 resample[0].delta = resample[1].delta =
358 (unsigned long)value*65536/NATIVE_FREQUENCY;
359 break ;
360
361 case DSP_SET_CLIP_MIN:
362 dsp_config.clip_min = (long)value;
363 break ;
364
365 case DSP_SET_CLIP_MAX:
366 dsp_config.clip_max = (long)value;
367 break ;
368
369 case DSP_SET_SAMPLE_DEPTH:
370 dsp_config.sample_depth = (long)value;
371 break ;
372
373 case DSP_SET_STEREO_MODE:
374 dsp_config.stereo_mode = (long)value;
375 channel = 0;
376 break ;
377
378 case DSP_RESET:
379 dsp_config.dither_enabled = false;
380 dsp_config.clip_max = 0x7fffffff;
381 dsp_config.clip_min = 0x80000000;
382 dsp_config.frequency = NATIVE_FREQUENCY;
383 channel = 0;
384 break ;
385
386 case DSP_DITHER:
387 dsp_config.dither_enabled = (bool)value;
388 break ;
389
390 default:
391 return 0;
392 }
393
394 return 1;
395}
396
397
diff --git a/apps/dsp.h b/apps/dsp.h
new file mode 100644
index 0000000000..65cd837c1e
--- /dev/null
+++ b/apps/dsp.h
@@ -0,0 +1,48 @@
1/***************************************************************************
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 ****************************************************************************/
19
20#ifndef _DSP_H
21#define _DSP_H
22
23#include <stdlib.h>
24#include <ctype.h>
25#include <stdbool.h>
26
27#define NATIVE_FREQUENCY 44100
28#define STEREO_INTERLEAVED 0
29#define STEREO_NONINTERLEAVED 1
30/* Not supported yet. */
31#define STEREO_MONO 2
32
33struct dsp_configuration {
34 long frequency;
35 long clip_min, clip_max;
36 int sample_depth;
37 bool dither_enabled;
38 int stereo_mode;
39};
40
41extern struct dsp_configuration dsp_config;
42
43int dsp_process(char *dest, char *src, int samplecount);
44bool dsp_configure(int setting, void *value);
45
46#endif
47
48
diff --git a/apps/playback.c b/apps/playback.c
index 500f44e45b..996e825e13 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -49,6 +49,7 @@
49#include "playback.h" 49#include "playback.h"
50#include "pcm_playback.h" 50#include "pcm_playback.h"
51#include "buffer.h" 51#include "buffer.h"
52#include "dsp.h"
52#ifdef HAVE_LCD_BITMAP 53#ifdef HAVE_LCD_BITMAP
53#include "icons.h" 54#include "icons.h"
54#include "peakmeter.h" 55#include "peakmeter.h"
@@ -171,7 +172,7 @@ int mp3_get_file_pos(void);
171 172
172/* Simulator stubs. */ 173/* Simulator stubs. */
173#ifdef SIMULATOR 174#ifdef SIMULATOR
174bool audiobuffer_insert(char *buf, size_t length) 175bool pcm_insert_buffer(char *buf, size_t length)
175{ 176{
176 (void)buf; 177 (void)buf;
177 (void)length; 178 (void)length;
@@ -179,6 +180,20 @@ bool audiobuffer_insert(char *buf, size_t length)
179 return true; 180 return true;
180} 181}
181 182
183void pcm_flush_buffer(size_t length)
184{
185 (void)length;
186}
187
188
189void* pcm_request_buffer(size_t length, size_t *realsize)
190{
191 (void)length;
192 (void)realsize;
193
194 return NULL;
195}
196
182void audiobuffer_add_event(void (*event_handler)(void)) 197void audiobuffer_add_event(void (*event_handler)(void))
183{ 198{
184 (void)event_handler; 199 (void)event_handler;
@@ -229,6 +244,92 @@ int ata_sleep(void)
229} 244}
230#endif 245#endif
231 246
247bool codec_audiobuffer_insert_callback(char *buf, size_t length)
248{
249 char *dest;
250 size_t realsize;
251 int factor;
252 int next_channel = 0;
253 int processed_length;
254
255 /* If non-interleaved stereo mode. */
256 if (dsp_config.stereo_mode == STEREO_NONINTERLEAVED) {
257 next_channel = length / 2;
258 }
259
260 if (dsp_config.sample_depth > 16) {
261 length /= 2;
262 factor = 1;
263 } else {
264 factor = 0;
265 }
266
267 while (length > 0) {
268 /* Request a few extra bytes for resampling. */
269 /* FIXME: Required extra bytes SHOULD be calculated. */
270 while ((dest = pcm_request_buffer(length+16384, &realsize)) == NULL)
271 yield();
272
273 if (realsize < 16384) {
274 pcm_flush_buffer(0);
275 continue ;
276 }
277
278 realsize -= 16384;
279
280 if (next_channel) {
281 processed_length = dsp_process(dest, buf, realsize / 4) * 2;
282 dsp_process(dest, buf + next_channel, realsize / 4);
283 } else {
284 processed_length = dsp_process(dest, buf, realsize / 2);
285 }
286 pcm_flush_buffer(processed_length);
287 length -= realsize;
288 buf += realsize << factor;
289 }
290
291 return true;
292}
293
294bool codec_audiobuffer_insert_split_callback(void *ch1, void *ch2,
295 size_t length)
296{
297 char *dest;
298 size_t realsize;
299 int factor;
300 int processed_length;
301
302 /* non-interleaved stereo mode. */
303 if (dsp_config.sample_depth > 16) {
304 factor = 0;
305 } else {
306 length /= 2;
307 factor = 1;
308 }
309
310 while (length > 0) {
311 /* Request a few extra bytes for resampling. */
312 while ((dest = pcm_request_buffer(length+4096, &realsize)) == NULL)
313 yield();
314
315 if (realsize < 4096) {
316 pcm_flush_buffer(0);
317 continue ;
318 }
319
320 realsize -= 4096;
321
322 processed_length = dsp_process(dest, ch1, realsize / 4) * 2;
323 dsp_process(dest, ch2, realsize / 4);
324 pcm_flush_buffer(processed_length);
325 length -= realsize;
326 ch1 += realsize >> factor;
327 ch2 += realsize >> factor;
328 }
329
330 return true;
331}
332
232void* get_codec_memory_callback(size_t *size) 333void* get_codec_memory_callback(size_t *size)
233{ 334{
234 *size = MALLOC_BUFSIZE; 335 *size = MALLOC_BUFSIZE;
@@ -260,7 +361,7 @@ size_t codec_filebuf_callback(void *ptr, size_t size)
260 361
261 if (ci.stop_codec || !playing) 362 if (ci.stop_codec || !playing)
262 return 0; 363 return 0;
263 364
264 copy_n = MIN((off_t)size, (off_t)cur_ti->available + cur_ti->filerem); 365 copy_n = MIN((off_t)size, (off_t)cur_ti->available + cur_ti->filerem);
265 366
266 while (copy_n > cur_ti->available) { 367 while (copy_n > cur_ti->available) {
@@ -283,7 +384,7 @@ size_t codec_filebuf_callback(void *ptr, size_t size)
283 buf_ridx -= codecbuflen; 384 buf_ridx -= codecbuflen;
284 ci.curpos += copy_n; 385 ci.curpos += copy_n;
285 cur_ti->available -= copy_n; 386 cur_ti->available -= copy_n;
286 codecbufused -= copy_n; 387 codecbufused -= copy_n;
287 388
288 return copy_n; 389 return copy_n;
289} 390}
@@ -427,8 +528,18 @@ void codec_configure_callback(int setting, void *value)
427 conf_bufferlimit = (unsigned int)value; 528 conf_bufferlimit = (unsigned int)value;
428 break; 529 break;
429 530
531 case CODEC_DSP_ENABLE:
532 if ((bool)value)
533 ci.audiobuffer_insert = codec_audiobuffer_insert_callback;
534 else
535 ci.audiobuffer_insert = pcm_insert_buffer;
536 break ;
537
538#ifndef SIMULATOR
430 default: 539 default:
431 logf("Illegal key: %d", setting); 540 if (!dsp_configure(setting, value))
541 logf("Illegal key: %d", setting);
542#endif
432 } 543 }
433} 544}
434 545
@@ -647,6 +758,8 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
647 conf_bufferlimit = 0; 758 conf_bufferlimit = 0;
648 conf_watermark = AUDIO_DEFAULT_WATERMARK; 759 conf_watermark = AUDIO_DEFAULT_WATERMARK;
649 conf_filechunk = AUDIO_DEFAULT_FILECHUNK; 760 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
761 dsp_configure(DSP_RESET, 0);
762 ci.configure(CODEC_DSP_ENABLE, false);
650 } 763 }
651 764
652 tracks[track_widx].codecbuf = &codecbuf[buf_widx]; 765 tracks[track_widx].codecbuf = &codecbuf[buf_widx];
@@ -697,7 +810,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
697 copy_n = MIN(size - i, copy_n); 810 copy_n = MIN(size - i, copy_n);
698 copy_n = MIN((int)fill_bytesleft, copy_n); 811 copy_n = MIN((int)fill_bytesleft, copy_n);
699 rc = read(fd, &codecbuf[buf_widx], copy_n); 812 rc = read(fd, &codecbuf[buf_widx], copy_n);
700 if (rc < 0) { 813 if (rc <= 0) {
701 logf("File error!"); 814 logf("File error!");
702 close(fd); 815 close(fd);
703 return false; 816 return false;
@@ -1152,7 +1265,7 @@ struct mp3entry* audio_next_track(void)
1152 1265
1153bool audio_has_changed_track(void) 1266bool audio_has_changed_track(void)
1154{ 1267{
1155 if (track_changed && track_count > 0) { 1268 if (track_changed && track_count > 0 && playing) {
1156 if (!cur_ti->taginfo_ready) 1269 if (!cur_ti->taginfo_ready)
1157 return false; 1270 return false;
1158 track_changed = false; 1271 track_changed = false;
@@ -1384,6 +1497,7 @@ int mp3_get_file_pos(void)
1384void audio_set_buffer_margin(int seconds) 1497void audio_set_buffer_margin(int seconds)
1385{ 1498{
1386 (void)seconds; 1499 (void)seconds;
1500 logf("bufmargin: %d", seconds);
1387} 1501}
1388#endif 1502#endif
1389 1503
@@ -1395,7 +1509,7 @@ void mpeg_id3_options(bool _v1first)
1395void audio_init(void) 1509void audio_init(void)
1396{ 1510{
1397 logf("audio api init"); 1511 logf("audio api init");
1398 codecbuflen = audiobufend - audiobuf - PCMBUF_SIZE 1512 codecbuflen = audiobufend - audiobuf - PCMBUF_SIZE - PCMBUF_GUARD
1399 - MALLOC_BUFSIZE - GUARD_BUFSIZE; 1513 - MALLOC_BUFSIZE - GUARD_BUFSIZE;
1400 //codecbuflen = 2*512*1024; 1514 //codecbuflen = 2*512*1024;
1401 codecbufused = 0; 1515 codecbufused = 0;
@@ -1412,7 +1526,8 @@ void audio_init(void)
1412 1526
1413 /* Initialize codec api. */ 1527 /* Initialize codec api. */
1414 ci.read_filebuf = codec_filebuf_callback; 1528 ci.read_filebuf = codec_filebuf_callback;
1415 ci.audiobuffer_insert = audiobuffer_insert; 1529 ci.audiobuffer_insert = pcm_insert_buffer;
1530 ci.audiobuffer_insert_split = codec_audiobuffer_insert_split_callback;
1416 ci.get_codec_memory = get_codec_memory_callback; 1531 ci.get_codec_memory = get_codec_memory_callback;
1417 ci.request_buffer = codec_request_buffer_callback; 1532 ci.request_buffer = codec_request_buffer_callback;
1418 ci.advance_buffer = codec_advance_buffer_callback; 1533 ci.advance_buffer = codec_advance_buffer_callback;
diff --git a/apps/playback.h b/apps/playback.h
index 24fc8570e8..672ddae440 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -27,10 +27,19 @@
27#include "id3.h" 27#include "id3.h"
28#include "mp3data.h" 28#include "mp3data.h"
29 29
30/* File buffer configuration keys. */ 30enum {
31#define CODEC_SET_FILEBUF_WATERMARK 1 31 CODEC_SET_FILEBUF_WATERMARK = 1,
32#define CODEC_SET_FILEBUF_CHUNKSIZE 2 32 CODEC_SET_FILEBUF_CHUNKSIZE,
33#define CODEC_SET_FILEBUF_LIMIT 3 33 CODEC_SET_FILEBUF_LIMIT,
34 CODEC_DSP_ENABLE,
35 DSP_SET_FREQUENCY,
36 DSP_SET_CLIP_MIN,
37 DSP_SET_CLIP_MAX,
38 DSP_SET_SAMPLE_DEPTH,
39 DSP_SET_STEREO_MODE,
40 DSP_RESET,
41 DSP_DITHER
42};
34 43
35/* Not yet implemented. */ 44/* Not yet implemented. */
36#define CODEC_SET_AUDIOBUF_WATERMARK 4 45#define CODEC_SET_AUDIOBUF_WATERMARK 4
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h
index aa29601f70..3fe60670b3 100644
--- a/firmware/export/pcm_playback.h
+++ b/firmware/export/pcm_playback.h
@@ -19,6 +19,10 @@
19#ifndef PCM_PLAYBACK_H 19#ifndef PCM_PLAYBACK_H
20#define PCM_PLAYBACK_H 20#define PCM_PLAYBACK_H
21 21
22/* Guard buffer for crossfader when dsp is enabled. */
23#define PCMBUF_GUARD 32768
24
25/* PCM audio buffer. */
22#define PCMBUF_SIZE (1*1024*1024) 26#define PCMBUF_SIZE (1*1024*1024)
23 27
24void pcm_init(void); 28void pcm_init(void);
@@ -44,7 +48,9 @@ bool pcm_is_lowdata(void);
44bool pcm_crossfade_init(void); 48bool pcm_crossfade_init(void);
45void audiobuffer_add_event(void (*event_handler)(void)); 49void audiobuffer_add_event(void (*event_handler)(void));
46unsigned int audiobuffer_get_latency(void); 50unsigned int audiobuffer_get_latency(void);
47bool audiobuffer_insert(char *buf, size_t length); 51bool pcm_insert_buffer(char *buf, size_t length);
52void pcm_flush_buffer(size_t length);
53void* pcm_request_buffer(size_t length, size_t *realsize);
48bool pcm_is_crossfade_enabled(void); 54bool pcm_is_crossfade_enabled(void);
49void pcm_crossfade_enable(bool on_off); 55void pcm_crossfade_enable(bool on_off);
50 56
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 24fc5d4530..12ecfd14e2 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -67,6 +67,7 @@ static int crossfade_pos;
67static int crossfade_amount; 67static int crossfade_amount;
68static int crossfade_rem; 68static int crossfade_rem;
69 69
70static char *guardbuf;
70static void (*pcm_event_handler)(void); 71static void (*pcm_event_handler)(void);
71 72
72static unsigned char *next_start; 73static unsigned char *next_start;
@@ -258,7 +259,6 @@ void pcm_play_pause(bool play)
258 IIS2CONFIG = 0x800; 259 IIS2CONFIG = 0x800;
259 } 260 }
260 pcm_paused = !play; 261 pcm_paused = !play;
261 pcm_boost(false);
262} 262}
263 263
264bool pcm_is_playing(void) 264bool pcm_is_playing(void)
@@ -401,15 +401,8 @@ bool pcm_crossfade_init(void)
401 401
402} 402}
403 403
404static void crossfade_start(void) 404void pcm_flush_fillpos(void)
405{ 405{
406 if (!crossfade_init)
407 return ;
408
409 crossfade_init = 0;
410 if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6)
411 return ;
412
413 if (audiobuffer_fillpos) { 406 if (audiobuffer_fillpos) {
414 while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos], 407 while (!pcm_play_add_chunk(&audiobuffer[audiobuffer_pos],
415 audiobuffer_fillpos, pcm_event_handler)) { 408 audiobuffer_fillpos, pcm_event_handler)) {
@@ -419,13 +412,26 @@ static void crossfade_start(void)
419 audiobuffer_pos += audiobuffer_fillpos; 412 audiobuffer_pos += audiobuffer_fillpos;
420 if (audiobuffer_pos >= PCMBUF_SIZE) 413 if (audiobuffer_pos >= PCMBUF_SIZE)
421 audiobuffer_pos -= PCMBUF_SIZE; 414 audiobuffer_pos -= PCMBUF_SIZE;
415 audiobuffer_free -= audiobuffer_fillpos;
416 audiobuffer_fillpos = 0;
422 } 417 }
418}
419
420static void crossfade_start(void)
421{
422 if (!crossfade_init)
423 return ;
424
425 crossfade_init = 0;
426 if (PCMBUF_SIZE - audiobuffer_free < CHUNK_SIZE * 6)
427 return ;
428
429 pcm_flush_fillpos();
423 pcm_boost(true); 430 pcm_boost(true);
424 crossfade_active = true; 431 crossfade_active = true;
425 crossfade_pos = audiobuffer_pos; 432 crossfade_pos = audiobuffer_pos;
426 crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2; 433 crossfade_amount = (PCMBUF_SIZE - audiobuffer_free - (CHUNK_SIZE * 2))/2;
427 crossfade_rem = crossfade_amount; 434 crossfade_rem = crossfade_amount;
428 audiobuffer_fillpos = 0;
429 435
430 crossfade_pos -= crossfade_amount*2; 436 crossfade_pos -= crossfade_amount*2;
431 if (crossfade_pos < 0) 437 if (crossfade_pos < 0)
@@ -451,12 +457,11 @@ int crossfade(short *buf, const short *buf2, int length)
451 return size; 457 return size;
452} 458}
453 459
454bool audiobuffer_insert(char *buf, size_t length) 460inline static bool prepare_insert(size_t length)
455{ 461{
456 size_t copy_n = 0;
457
458 crossfade_start(); 462 crossfade_start();
459 if (audiobuffer_free < length + CHUNK_SIZE && !crossfade_active) { 463 if (audiobuffer_free < length + audiobuffer_fillpos
464 + CHUNK_SIZE && !crossfade_active) {
460 pcm_boost(false); 465 pcm_boost(false);
461 return false; 466 return false;
462 } 467 }
@@ -467,7 +472,94 @@ bool audiobuffer_insert(char *buf, size_t length)
467 if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*4) 472 if (audiobuffer_free < PCMBUF_SIZE - CHUNK_SIZE*4)
468 pcm_play_start(); 473 pcm_play_start();
469 } 474 }
475
476 return true;
477}
478
479void* pcm_request_buffer(size_t length, size_t *realsize)
480{
481 void *ptr = NULL;
482
483 if (!prepare_insert(length)) {
484 *realsize = 0;
485 return NULL;
486 }
487
488 if (crossfade_active) {
489 *realsize = MIN(length, PCMBUF_GUARD);
490 ptr = &guardbuf[0];
491 } else {
492 *realsize = MIN(length, PCMBUF_SIZE - audiobuffer_pos
493 - audiobuffer_fillpos);
494 if (*realsize < length) {
495 *realsize += MIN((long)(length - *realsize), PCMBUF_GUARD);
496 //logf("gbr:%d/%d", *realsize, length);
497 }
498 ptr = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
499 }
500
501 return ptr;
502}
503
504void pcm_flush_buffer(size_t length)
505{
506 int copy_n;
507 char *buf;
508
509 if (crossfade_active) {
510 buf = &guardbuf[0];
511 length = MIN(length, PCMBUF_GUARD);
512 while (length > 0 && crossfade_active) {
513 copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos);
514 copy_n = 2 * crossfade((short *)&audiobuffer[crossfade_pos],
515 (const short *)buf, copy_n/2);
516 buf += copy_n;
517 length -= copy_n;
518 crossfade_pos += copy_n;
519 if (crossfade_pos >= PCMBUF_SIZE)
520 crossfade_pos -= PCMBUF_SIZE;
521 }
522
523 if (length > 0) {
524 memcpy(&audiobuffer[audiobuffer_pos], buf, length);
525 audiobuffer_fillpos = length;
526 goto try_flush;
527 }
528 } else {
529 /* if (length == 0) {
530 pcm_flush_fillpos();
531 audiobuffer_pos = 0;
532 return ;
533 } */
534
535 audiobuffer_fillpos += length;
536
537 try_flush:
538 if (audiobuffer_fillpos < CHUNK_SIZE && PCMBUF_SIZE
539 - audiobuffer_pos - audiobuffer_fillpos > 0)
540 return ;
541
542 copy_n = MIN((long)(audiobuffer_fillpos - (PCMBUF_SIZE
543 - audiobuffer_pos)), PCMBUF_GUARD);
544 if (copy_n > 0) {
545 //logf("guard buf used:%d", copy_n);
546 audiobuffer_fillpos -= copy_n;
547 pcm_flush_fillpos();
548 memcpy(&audiobuffer[0], &guardbuf[0], copy_n);
549 audiobuffer_fillpos = copy_n;
550 goto try_flush;
551 }
552 pcm_flush_fillpos();
553 }
554}
470 555
556bool pcm_insert_buffer(char *buf, size_t length)
557{
558 size_t copy_n = 0;
559
560 if (!prepare_insert(length))
561 return false;
562
471 while (length > 0) { 563 while (length > 0) {
472 if (crossfade_active) { 564 if (crossfade_active) {
473 copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos); 565 copy_n = MIN(length, PCMBUF_SIZE - (unsigned int)crossfade_pos);
@@ -521,7 +613,8 @@ bool audiobuffer_insert(char *buf, size_t length)
521void pcm_play_init(void) 613void pcm_play_init(void)
522{ 614{
523 audiobuffer = &audiobuf[(audiobufend - audiobuf) - 615 audiobuffer = &audiobuf[(audiobufend - audiobuf) -
524 PCMBUF_SIZE]; 616 PCMBUF_SIZE - PCMBUF_GUARD];
617 guardbuf = &audiobuffer[PCMBUF_SIZE];
525 audiobuffer_free = PCMBUF_SIZE; 618 audiobuffer_free = PCMBUF_SIZE;
526 audiobuffer_pos = 0; 619 audiobuffer_pos = 0;
527 audiobuffer_fillpos = 0; 620 audiobuffer_fillpos = 0;
@@ -532,11 +625,6 @@ void pcm_play_init(void)
532 crossfade_active = false; 625 crossfade_active = false;
533 crossfade_init = false; 626 crossfade_init = false;
534 pcm_event_handler = NULL; 627 pcm_event_handler = NULL;
535 if (crossfade_enabled) {
536 pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback);
537 } else {
538 pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback);
539 }
540} 628}
541 629
542void pcm_crossfade_enable(bool on_off) 630void pcm_crossfade_enable(bool on_off)
@@ -555,6 +643,11 @@ void pcm_play_start(void)
555 int size; 643 int size;
556 char *start; 644 char *start;
557 645
646 if (crossfade_enabled) {
647 pcm_play_set_watermark(PCM_CF_WATERMARK, pcm_watermark_callback);
648 } else {
649 pcm_play_set_watermark(PCM_WATERMARK, pcm_watermark_callback);
650 }
558 crossfade_active = false; 651 crossfade_active = false;
559 if(!pcm_is_playing()) 652 if(!pcm_is_playing())
560 { 653 {