summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-08-20 11:13:19 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-08-20 11:13:19 +0000
commit159c52dd36e5c008612458192904f57ea6dfdfad (patch)
tree4b6f7d8329069e90d72284ef73ba542d75705b55
parent329caa8ade0b78a3235e9d28983cb1c506e573a0 (diff)
downloadrockbox-159c52dd36e5c008612458192904f57ea6dfdfad.tar.gz
rockbox-159c52dd36e5c008612458192904f57ea6dfdfad.zip
Initial voice ui support for software codec platforms. Added also a
beep when changing tracks. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7360 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES2
-rw-r--r--apps/codecs.c13
-rw-r--r--apps/codecs.h5
-rw-r--r--apps/codecs/wav.c13
-rw-r--r--apps/debug_menu.c10
-rw-r--r--apps/dsp.c195
-rw-r--r--apps/main.c3
-rw-r--r--apps/pcmbuf.c104
-rw-r--r--apps/pcmbuf.h7
-rw-r--r--apps/playback.c507
-rw-r--r--apps/playback.h1
-rw-r--r--apps/playlist.c7
-rw-r--r--apps/talk.c111
-rw-r--r--apps/talk.h1
-rw-r--r--firmware/mp3_playback.c16
-rw-r--r--firmware/sound.c7
-rw-r--r--uisimulator/common/stubs.c2
17 files changed, 774 insertions, 230 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index c1f3dfc88e..e8fd2d2ddb 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -22,7 +22,7 @@ settings_menu.c
22sleeptimer.c 22sleeptimer.c
23sound_menu.c 23sound_menu.c
24status.c 24status.c
25#ifndef SIMULATOR 25#if !defined(SIMULATOR) || CONFIG_HWCODEC == MASNONE
26talk.c 26talk.c
27#endif 27#endif
28tree.c 28tree.c
diff --git a/apps/codecs.c b/apps/codecs.c
index b1d30868bc..004d4681f7 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -54,7 +54,7 @@
54 54
55#ifdef SIMULATOR 55#ifdef SIMULATOR
56#if CONFIG_HWCODEC == MASNONE 56#if CONFIG_HWCODEC == MASNONE
57static unsigned char codecbuf[CODEC_SIZE]; 57unsigned char codecbuf[CODEC_SIZE];
58#endif 58#endif
59void *sim_codec_load_ram(char* codecptr, int size, 59void *sim_codec_load_ram(char* codecptr, int size,
60 void* ptr2, int bufwrap, int *pd); 60 void* ptr2, int bufwrap, int *pd);
@@ -68,6 +68,8 @@ extern void* plugin_get_audio_buffer(int *buffer_size);
68 68
69static int codec_test(int api_version, int model, int memsize); 69static int codec_test(int api_version, int model, int memsize);
70 70
71struct codec_api ci_voice;
72
71struct codec_api ci = { 73struct codec_api ci = {
72 CODEC_API_VERSION, 74 CODEC_API_VERSION,
73 codec_test, 75 codec_test,
@@ -247,7 +249,8 @@ struct codec_api ci = {
247 NULL, 249 NULL,
248}; 250};
249 251
250int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap) 252int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap,
253 struct codec_api *api)
251{ 254{
252 enum codec_status (*codec_start)(const struct codec_api* api); 255 enum codec_status (*codec_start)(const struct codec_api* api);
253 int status; 256 int status;
@@ -277,7 +280,7 @@ int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap)
277#endif /* SIMULATOR */ 280#endif /* SIMULATOR */
278 281
279 invalidate_icache(); 282 invalidate_icache();
280 status = codec_start(&ci); 283 status = codec_start(api);
281#ifdef SIMULATOR 284#ifdef SIMULATOR
282 sim_codec_close(pd); 285 sim_codec_close(pd);
283#endif 286#endif
@@ -285,7 +288,7 @@ int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap)
285 return status; 288 return status;
286} 289}
287 290
288int codec_load_file(const char *plugin) 291int codec_load_file(const char *plugin, struct codec_api *api)
289{ 292{
290 char msgbuf[80]; 293 char msgbuf[80];
291 int fd; 294 int fd;
@@ -309,7 +312,7 @@ int codec_load_file(const char *plugin)
309 return CODEC_ERROR; 312 return CODEC_ERROR;
310 } 313 }
311 314
312 return codec_load_ram(codecbuf, (size_t)rc, NULL, 0); 315 return codec_load_ram(codecbuf, (size_t)rc, NULL, 0, api);
313} 316}
314 317
315static int codec_test(int api_version, int model, int memsize) 318static int codec_test(int api_version, int model, int memsize)
diff --git a/apps/codecs.h b/apps/codecs.h
index b2cf9e5a1e..3b8e1d8394 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -331,8 +331,9 @@ struct codec_api {
331 331
332/* defined by the codec loader (codec.c) */ 332/* defined by the codec loader (codec.c) */
333#if CONFIG_HWCODEC == MASNONE 333#if CONFIG_HWCODEC == MASNONE
334int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap); 334int codec_load_ram(char* codecptr, int size, void* ptr2, int bufwrap,
335int codec_load_file(const char* codec); 335 struct codec_api *api);
336int codec_load_file(const char* codec, struct codec_api *api);
336#endif 337#endif
337 338
338/* defined by the codec */ 339/* defined by the codec */
diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c
index 527d33d286..d2ae7bd6c3 100644
--- a/apps/codecs/wav.c
+++ b/apps/codecs/wav.c
@@ -71,15 +71,12 @@ enum codec_status codec_start(struct codec_api* api)
71 return CODEC_ERROR; 71 return CODEC_ERROR;
72 } 72 }
73 73
74 while (!rb->taginfo_ready) 74 while (!*rb->taginfo_ready)
75 rb->yield(); 75 rb->yield();
76 76
77 if (rb->id3->frequency != NATIVE_FREQUENCY) { 77 /* Always enable DSP to support voice ui. */
78 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency)); 78 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
79 rb->configure(CODEC_DSP_ENABLE, (bool *)true); 79 rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency));
80 } else {
81 rb->configure(CODEC_DSP_ENABLE, (bool *)false);
82 }
83 80
84 /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */ 81 /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */
85 82
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 86e02a1e84..b4cd05699c 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -208,8 +208,8 @@ bool dbg_audio_thread(void)
208} 208}
209#else 209#else
210extern size_t audiobuffer_free; 210extern size_t audiobuffer_free;
211extern int codecbuflen; 211extern int filebuflen;
212extern int codecbufused; 212extern int filebufused;
213extern int track_count; 213extern int track_count;
214 214
215static int ticks, boost_ticks; 215static int ticks, boost_ticks;
@@ -260,12 +260,12 @@ bool dbg_audio_thread(void)
260 bufsize-audiobuffer_free, HORIZONTAL); 260 bufsize-audiobuffer_free, HORIZONTAL);
261 line++; 261 line++;
262 262
263 snprintf(buf, sizeof(buf), "codec: %d/%d", codecbufused, codecbuflen); 263 snprintf(buf, sizeof(buf), "codec: %d/%d", filebufused, filebuflen);
264 lcd_puts(0, line++, buf); 264 lcd_puts(0, line++, buf);
265 265
266 /* Playable space left */ 266 /* Playable space left */
267 scrollbar(0, line*8, LCD_WIDTH, 6, codecbuflen, 0, 267 scrollbar(0, line*8, LCD_WIDTH, 6, filebuflen, 0,
268 codecbufused, HORIZONTAL); 268 filebufused, HORIZONTAL);
269 line++; 269 line++;
270 270
271 snprintf(buf, sizeof(buf), "track count: %d", track_count); 271 snprintf(buf, sizeof(buf), "track count: %d", track_count);
diff --git a/apps/dsp.c b/apps/dsp.c
index 2ba7fb99f6..8064a881a3 100644
--- a/apps/dsp.c
+++ b/apps/dsp.c
@@ -132,9 +132,12 @@ struct dither_data
132 long random; 132 long random;
133}; 133};
134 134
135static struct dsp_config dsp IDATA_ATTR; 135static struct dsp_config dsp_conf[2] IDATA_ATTR;
136static struct dither_data dither_data[2] IDATA_ATTR; 136static struct dither_data dither_data[2] IDATA_ATTR;
137static struct resample_data resample_data[2] IDATA_ATTR; 137static struct resample_data resample_data[2][2] IDATA_ATTR;
138
139extern int current_codec;
140struct dsp_config *dsp;
138 141
139/* The internal format is 32-bit samples, non-interleaved, stereo. This 142/* The internal format is 32-bit samples, non-interleaved, stereo. This
140 * format is similar to the raw output from several codecs, so the amount 143 * format is similar to the raw output from several codecs, so the amount
@@ -155,20 +158,20 @@ static int convert_to_internal(char* src[], int count, long* dst[])
155{ 158{
156 count = MIN(SAMPLE_BUF_SIZE / 2, count); 159 count = MIN(SAMPLE_BUF_SIZE / 2, count);
157 160
158 if ((dsp.sample_depth <= NATIVE_DEPTH) 161 if ((dsp->sample_depth <= NATIVE_DEPTH)
159 || (dsp.stereo_mode == STEREO_INTERLEAVED)) 162 || (dsp->stereo_mode == STEREO_INTERLEAVED))
160 { 163 {
161 dst[0] = &sample_buf[0]; 164 dst[0] = &sample_buf[0];
162 dst[1] = (dsp.stereo_mode == STEREO_MONO) 165 dst[1] = (dsp->stereo_mode == STEREO_MONO)
163 ? dst[0] : &sample_buf[SAMPLE_BUF_SIZE / 2]; 166 ? dst[0] : &sample_buf[SAMPLE_BUF_SIZE / 2];
164 } 167 }
165 else 168 else
166 { 169 {
167 dst[0] = (long*) src[0]; 170 dst[0] = (long*) src[0];
168 dst[1] = (long*) ((dsp.stereo_mode == STEREO_MONO) ? src[0] : src[1]); 171 dst[1] = (long*) ((dsp->stereo_mode == STEREO_MONO) ? src[0] : src[1]);
169 } 172 }
170 173
171 if (dsp.sample_depth <= NATIVE_DEPTH) 174 if (dsp->sample_depth <= NATIVE_DEPTH)
172 { 175 {
173 short* s0 = (short*) src[0]; 176 short* s0 = (short*) src[0];
174 long* d0 = dst[0]; 177 long* d0 = dst[0];
@@ -176,7 +179,7 @@ static int convert_to_internal(char* src[], int count, long* dst[])
176 int scale = WORD_SHIFT; 179 int scale = WORD_SHIFT;
177 int i; 180 int i;
178 181
179 if (dsp.stereo_mode == STEREO_INTERLEAVED) 182 if (dsp->stereo_mode == STEREO_INTERLEAVED)
180 { 183 {
181 for (i = 0; i < count; i++) 184 for (i = 0; i < count; i++)
182 { 185 {
@@ -184,7 +187,7 @@ static int convert_to_internal(char* src[], int count, long* dst[])
184 *d1++ = *s0++ << scale; 187 *d1++ = *s0++ << scale;
185 } 188 }
186 } 189 }
187 else if (dsp.stereo_mode == STEREO_NONINTERLEAVED) 190 else if (dsp->stereo_mode == STEREO_NONINTERLEAVED)
188 { 191 {
189 short* s1 = (short*) src[1]; 192 short* s1 = (short*) src[1];
190 193
@@ -202,7 +205,7 @@ static int convert_to_internal(char* src[], int count, long* dst[])
202 } 205 }
203 } 206 }
204 } 207 }
205 else if (dsp.stereo_mode == STEREO_INTERLEAVED) 208 else if (dsp->stereo_mode == STEREO_INTERLEAVED)
206 { 209 {
207 long* s0 = (long*) src[0]; 210 long* s0 = (long*) src[0];
208 long* d0 = dst[0]; 211 long* d0 = dst[0];
@@ -216,18 +219,18 @@ static int convert_to_internal(char* src[], int count, long* dst[])
216 } 219 }
217 } 220 }
218 221
219 if (dsp.stereo_mode == STEREO_NONINTERLEAVED) 222 if (dsp->stereo_mode == STEREO_NONINTERLEAVED)
220 { 223 {
221 src[0] += count * dsp.sample_bytes; 224 src[0] += count * dsp->sample_bytes;
222 src[1] += count * dsp.sample_bytes; 225 src[1] += count * dsp->sample_bytes;
223 } 226 }
224 else if (dsp.stereo_mode == STEREO_INTERLEAVED) 227 else if (dsp->stereo_mode == STEREO_INTERLEAVED)
225 { 228 {
226 src[0] += count * dsp.sample_bytes * 2; 229 src[0] += count * dsp->sample_bytes * 2;
227 } 230 }
228 else 231 else
229 { 232 {
230 src[0] += count * dsp.sample_bytes; 233 src[0] += count * dsp->sample_bytes;
231 } 234 }
232 235
233 return count; 236 return count;
@@ -310,29 +313,33 @@ static inline int resample(long* src[], int count)
310{ 313{
311 long new_count; 314 long new_count;
312 315
313 if (dsp.frequency != NATIVE_FREQUENCY) 316 if (dsp->frequency != NATIVE_FREQUENCY)
314 { 317 {
315 long* d0 = &resample_buf[0]; 318 long* d0 = &resample_buf[0];
316 /* Only process the second channel if needed. */ 319 /* Only process the second channel if needed. */
317 long* d1 = (src[0] == src[1]) ? d0 320 long* d1 = (src[0] == src[1]) ? d0
318 : &resample_buf[RESAMPLE_BUF_SIZE / 2]; 321 : &resample_buf[RESAMPLE_BUF_SIZE / 2];
319 322
320 if (dsp.frequency < NATIVE_FREQUENCY) 323 if (dsp->frequency < NATIVE_FREQUENCY)
321 { 324 {
322 new_count = upsample(d0, src[0], count, &resample_data[0]); 325 new_count = upsample(d0, src[0], count,
326 &resample_data[current_codec][0]);
323 327
324 if (d0 != d1) 328 if (d0 != d1)
325 { 329 {
326 upsample(d1, src[1], count, &resample_data[1]); 330 upsample(d1, src[1], count,
331 &resample_data[current_codec][1]);
327 } 332 }
328 } 333 }
329 else 334 else
330 { 335 {
331 new_count = downsample(d0, src[0], count, &resample_data[0]); 336 new_count = downsample(d0, src[0], count,
337 &resample_data[current_codec][0]);
332 338
333 if (d0 != d1) 339 if (d0 != d1)
334 { 340 {
335 downsample(d1, src[1], count, &resample_data[1]); 341 downsample(d1, src[1], count,
342 &resample_data[current_codec][1]);
336 } 343 }
337 } 344 }
338 345
@@ -389,8 +396,8 @@ static long dither_sample(long sample, long bias, long mask,
389 396
390 /* Clip and quantize */ 397 /* Clip and quantize */
391 398
392 min = dsp.clip_min; 399 min = dsp->clip_min;
393 max = dsp.clip_max; 400 max = dsp->clip_max;
394 sample = clip_sample(sample, min, max); 401 sample = clip_sample(sample, min, max);
395 output = clip_sample(output, min, max) & ~mask; 402 output = clip_sample(output, min, max) & ~mask;
396 403
@@ -407,13 +414,13 @@ static long dither_sample(long sample, long bias, long mask,
407 */ 414 */
408static void apply_gain(long* src[], int count) 415static void apply_gain(long* src[], int count)
409{ 416{
410 if (dsp.replaygain) 417 if (dsp->replaygain)
411 { 418 {
412 long* s0 = src[0]; 419 long* s0 = src[0];
413 long* s1 = src[1]; 420 long* s1 = src[1];
414 long* d0 = &sample_buf[0]; 421 long* d0 = &sample_buf[0];
415 long* d1 = (s0 == s1) ? d0 : &sample_buf[SAMPLE_BUF_SIZE / 2]; 422 long* d1 = (s0 == s1) ? d0 : &sample_buf[SAMPLE_BUF_SIZE / 2];
416 long gain = dsp.replaygain; 423 long gain = dsp->replaygain;
417 long s; 424 long s;
418 long i; 425 long i;
419 426
@@ -442,11 +449,11 @@ static void write_samples(short* dst, long* src[], int count)
442{ 449{
443 long* s0 = src[0]; 450 long* s0 = src[0];
444 long* s1 = src[1]; 451 long* s1 = src[1];
445 int scale = dsp.frac_bits + 1 - NATIVE_DEPTH; 452 int scale = dsp->frac_bits + 1 - NATIVE_DEPTH;
446 453
447 if (dsp.dither_enabled) 454 if (dsp->dither_enabled)
448 { 455 {
449 long bias = (1L << (dsp.frac_bits - NATIVE_DEPTH)); 456 long bias = (1L << (dsp->frac_bits - NATIVE_DEPTH));
450 long mask = (1L << scale) - 1; 457 long mask = (1L << scale) - 1;
451 458
452 while (count-- > 0) 459 while (count-- > 0)
@@ -459,8 +466,8 @@ static void write_samples(short* dst, long* src[], int count)
459 } 466 }
460 else 467 else
461 { 468 {
462 long min = dsp.clip_min; 469 long min = dsp->clip_min;
463 long max = dsp.clip_max; 470 long max = dsp->clip_max;
464 471
465 while (count-- > 0) 472 while (count-- > 0)
466 { 473 {
@@ -482,10 +489,13 @@ long dsp_process(char* dst, char* src[], long size)
482{ 489{
483 long* tmp[2]; 490 long* tmp[2];
484 long written = 0; 491 long written = 0;
485 long factor = (dsp.stereo_mode != STEREO_MONO) ? 2 : 1; 492 long factor;
486 int samples; 493 int samples;
487 494
488 size /= dsp.sample_bytes * factor; 495 dsp = &dsp_conf[current_codec];
496
497 factor = (dsp->stereo_mode != STEREO_MONO) ? 2 : 1;
498 size /= dsp->sample_bytes * factor;
489 INIT(); 499 INIT();
490 dsp_set_replaygain(false); 500 dsp_set_replaygain(false);
491 501
@@ -513,21 +523,23 @@ long dsp_process(char* dst, char* src[], long size)
513/* dsp_input_size MUST be called afterwards */ 523/* dsp_input_size MUST be called afterwards */
514long dsp_output_size(long size) 524long dsp_output_size(long size)
515{ 525{
516 if (dsp.sample_depth > NATIVE_DEPTH) 526 dsp = &dsp_conf[current_codec];
527
528 if (dsp->sample_depth > NATIVE_DEPTH)
517 { 529 {
518 size /= 2; 530 size /= 2;
519 } 531 }
520 532
521 if (dsp.frequency != NATIVE_FREQUENCY) 533 if (dsp->frequency != NATIVE_FREQUENCY)
522 { 534 {
523 size = (long) ((((unsigned long) size * NATIVE_FREQUENCY) 535 size = (long) ((((unsigned long) size * NATIVE_FREQUENCY)
524 + (dsp.frequency - 1)) / dsp.frequency); 536 + (dsp->frequency - 1)) / dsp->frequency);
525 } 537 }
526 538
527 /* round to the next multiple of 2 (these are shorts) */ 539 /* round to the next multiple of 2 (these are shorts) */
528 size = (size + 1) & ~1; 540 size = (size + 1) & ~1;
529 541
530 if (dsp.stereo_mode == STEREO_MONO) 542 if (dsp->stereo_mode == STEREO_MONO)
531 { 543 {
532 size *= 2; 544 size *= 2;
533 } 545 }
@@ -547,25 +559,28 @@ long dsp_output_size(long size)
547 */ 559 */
548long dsp_input_size(long size) 560long dsp_input_size(long size)
549{ 561{
562 dsp = &dsp_conf[current_codec];
563
550 /* convert to number of output stereo samples. */ 564 /* convert to number of output stereo samples. */
551 size /= 2; 565 size /= 2;
552 566
553 /* Mono means we need half input samples to fill the output buffer */ 567 /* Mono means we need half input samples to fill the output buffer */
554 if (dsp.stereo_mode == STEREO_MONO) 568 if (dsp->stereo_mode == STEREO_MONO)
555 size /= 2; 569 size /= 2;
556 570
557 /* size is now the number of resampled input samples. Convert to 571 /* size is now the number of resampled input samples. Convert to
558 original input samples. */ 572 original input samples. */
559 if (dsp.frequency != NATIVE_FREQUENCY) 573 if (dsp->frequency != NATIVE_FREQUENCY)
560 { 574 {
561 /* Use the real resampling delta = 575 /* Use the real resampling delta =
562 * (unsigned long) dsp.frequency * 65536 / NATIVE_FREQUENCY, and 576 * (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY, and
563 * round towards zero to avoid buffer overflows. */ 577 * round towards zero to avoid buffer overflows. */
564 size = ((unsigned long)size * resample_data[0].delta) >> 16; 578 size = ((unsigned long)size *
579 resample_data[current_codec][0].delta) >> 16;
565 } 580 }
566 581
567 /* Convert back to bytes. */ 582 /* Convert back to bytes. */
568 if (dsp.sample_depth > NATIVE_DEPTH) 583 if (dsp->sample_depth > NATIVE_DEPTH)
569 size *= 4; 584 size *= 4;
570 else 585 else
571 size *= 2; 586 size *= 2;
@@ -575,90 +590,96 @@ long dsp_input_size(long size)
575 590
576int dsp_stereo_mode(void) 591int dsp_stereo_mode(void)
577{ 592{
578 return dsp.stereo_mode; 593 dsp = &dsp_conf[current_codec];
594
595 return dsp->stereo_mode;
579} 596}
580 597
581bool dsp_configure(int setting, void *value) 598bool dsp_configure(int setting, void *value)
582{ 599{
600 dsp = &dsp_conf[current_codec];
601
583 switch (setting) 602 switch (setting)
584 { 603 {
585 case DSP_SET_FREQUENCY: 604 case DSP_SET_FREQUENCY:
586 memset(resample_data, 0, sizeof(resample_data)); 605 memset(&resample_data[current_codec][0], 0,
606 sizeof(struct resample_data) * 2);
587 /* Fall through!!! */ 607 /* Fall through!!! */
588 case DSP_SWITCH_FREQUENCY: 608 case DSP_SWITCH_FREQUENCY:
589 dsp.frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value; 609 dsp->frequency = ((int) value == 0) ? NATIVE_FREQUENCY : (int) value;
590 resample_data[0].delta = resample_data[1].delta = 610 resample_data[current_codec][0].delta =
591 (unsigned long) dsp.frequency * 65536 / NATIVE_FREQUENCY; 611 resample_data[current_codec][1].delta =
612 (unsigned long) dsp->frequency * 65536 / NATIVE_FREQUENCY;
592 break; 613 break;
593 614
594 case DSP_SET_CLIP_MIN: 615 case DSP_SET_CLIP_MIN:
595 dsp.clip_min = (long) value; 616 dsp->clip_min = (long) value;
596 break; 617 break;
597 618
598 case DSP_SET_CLIP_MAX: 619 case DSP_SET_CLIP_MAX:
599 dsp.clip_max = (long) value; 620 dsp->clip_max = (long) value;
600 break; 621 break;
601 622
602 case DSP_SET_SAMPLE_DEPTH: 623 case DSP_SET_SAMPLE_DEPTH:
603 dsp.sample_depth = (long) value; 624 dsp->sample_depth = (long) value;
604 625
605 if (dsp.sample_depth <= NATIVE_DEPTH) 626 if (dsp->sample_depth <= NATIVE_DEPTH)
606 { 627 {
607 dsp.frac_bits = WORD_FRACBITS; 628 dsp->frac_bits = WORD_FRACBITS;
608 dsp.sample_bytes = sizeof(short); 629 dsp->sample_bytes = sizeof(short);
609 dsp.clip_max = ((1 << WORD_FRACBITS) - 1); 630 dsp->clip_max = ((1 << WORD_FRACBITS) - 1);
610 dsp.clip_min = -((1 << WORD_FRACBITS)); 631 dsp->clip_min = -((1 << WORD_FRACBITS));
611 } 632 }
612 else 633 else
613 { 634 {
614 dsp.frac_bits = (long) value; 635 dsp->frac_bits = (long) value;
615 dsp.sample_bytes = sizeof(long); 636 dsp->sample_bytes = sizeof(long);
616 } 637 }
617 638
618 break; 639 break;
619 640
620 case DSP_SET_STEREO_MODE: 641 case DSP_SET_STEREO_MODE:
621 dsp.stereo_mode = (long) value; 642 dsp->stereo_mode = (long) value;
622 break; 643 break;
623 644
624 case DSP_RESET: 645 case DSP_RESET:
625 dsp.dither_enabled = false; 646 dsp->dither_enabled = false;
626 dsp.stereo_mode = STEREO_NONINTERLEAVED; 647 dsp->stereo_mode = STEREO_NONINTERLEAVED;
627 dsp.clip_max = ((1 << WORD_FRACBITS) - 1); 648 dsp->clip_max = ((1 << WORD_FRACBITS) - 1);
628 dsp.clip_min = -((1 << WORD_FRACBITS)); 649 dsp->clip_min = -((1 << WORD_FRACBITS));
629 dsp.track_gain = 0; 650 dsp->track_gain = 0;
630 dsp.album_gain = 0; 651 dsp->album_gain = 0;
631 dsp.track_peak = 0; 652 dsp->track_peak = 0;
632 dsp.album_peak = 0; 653 dsp->album_peak = 0;
633 dsp.frequency = NATIVE_FREQUENCY; 654 dsp->frequency = NATIVE_FREQUENCY;
634 dsp.sample_depth = NATIVE_DEPTH; 655 dsp->sample_depth = NATIVE_DEPTH;
635 dsp.frac_bits = WORD_FRACBITS; 656 dsp->frac_bits = WORD_FRACBITS;
636 dsp.new_gain = true; 657 dsp->new_gain = true;
637 break; 658 break;
638 659
639 case DSP_DITHER: 660 case DSP_DITHER:
640 memset(dither_data, 0, sizeof(dither_data)); 661 memset(dither_data, 0, sizeof(dither_data));
641 dsp.dither_enabled = (bool) value; 662 dsp->dither_enabled = (bool) value;
642 break; 663 break;
643 664
644 case DSP_SET_TRACK_GAIN: 665 case DSP_SET_TRACK_GAIN:
645 dsp.track_gain = (long) value; 666 dsp->track_gain = (long) value;
646 dsp.new_gain = true; 667 dsp->new_gain = true;
647 break; 668 break;
648 669
649 case DSP_SET_ALBUM_GAIN: 670 case DSP_SET_ALBUM_GAIN:
650 dsp.album_gain = (long) value; 671 dsp->album_gain = (long) value;
651 dsp.new_gain = true; 672 dsp->new_gain = true;
652 break; 673 break;
653 674
654 case DSP_SET_TRACK_PEAK: 675 case DSP_SET_TRACK_PEAK:
655 dsp.track_peak = (long) value; 676 dsp->track_peak = (long) value;
656 dsp.new_gain = true; 677 dsp->new_gain = true;
657 break; 678 break;
658 679
659 case DSP_SET_ALBUM_PEAK: 680 case DSP_SET_ALBUM_PEAK:
660 dsp.album_peak = (long) value; 681 dsp->album_peak = (long) value;
661 dsp.new_gain = true; 682 dsp->new_gain = true;
662 break; 683 break;
663 684
664 default: 685 default:
@@ -670,11 +691,13 @@ bool dsp_configure(int setting, void *value)
670 691
671void dsp_set_replaygain(bool always) 692void dsp_set_replaygain(bool always)
672{ 693{
673 if (always || dsp.new_gain) 694 dsp = &dsp_conf[current_codec];
695
696 if (always || dsp->new_gain)
674 { 697 {
675 long gain = 0; 698 long gain = 0;
676 699
677 dsp.new_gain = false; 700 dsp->new_gain = false;
678 701
679 if (global_settings.replaygain || global_settings.replaygain_noclip) 702 if (global_settings.replaygain || global_settings.replaygain_noclip)
680 { 703 {
@@ -682,8 +705,8 @@ void dsp_set_replaygain(bool always)
682 705
683 if (global_settings.replaygain) 706 if (global_settings.replaygain)
684 { 707 {
685 gain = (global_settings.replaygain_track || !dsp.album_gain) 708 gain = (global_settings.replaygain_track || !dsp->album_gain)
686 ? dsp.track_gain : dsp.album_gain; 709 ? dsp->track_gain : dsp->album_gain;
687 710
688 if (global_settings.replaygain_preamp) 711 if (global_settings.replaygain_preamp)
689 { 712 {
@@ -694,8 +717,8 @@ void dsp_set_replaygain(bool always)
694 } 717 }
695 } 718 }
696 719
697 peak = (global_settings.replaygain_track || !dsp.album_peak) 720 peak = (global_settings.replaygain_track || !dsp->album_peak)
698 ? dsp.track_peak : dsp.album_peak; 721 ? dsp->track_peak : dsp->album_peak;
699 722
700 if (gain == 0) 723 if (gain == 0)
701 { 724 {
@@ -718,6 +741,6 @@ void dsp_set_replaygain(bool always)
718 } 741 }
719 742
720 /* Store in S8.23 format to simplify calculations. */ 743 /* Store in S8.23 format to simplify calculations. */
721 dsp.replaygain = gain >> 1; 744 dsp->replaygain = gain >> 1;
722 } 745 }
723} 746}
diff --git a/apps/main.c b/apps/main.c
index 90be703c6b..55897de5f5 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -129,6 +129,9 @@ void init(void)
129 global_settings.mdb_enable, 129 global_settings.mdb_enable,
130 global_settings.superbass); 130 global_settings.superbass);
131 button_clear_queue(); /* Empty the keyboard buffer */ 131 button_clear_queue(); /* Empty the keyboard buffer */
132#if CONFIG_HWCODEC == MASNONE
133 talk_init();
134#endif
132} 135}
133 136
134#else 137#else
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index 691f8d5a19..5f78901a56 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -34,6 +34,7 @@
34#include "buffer.h" 34#include "buffer.h"
35#include "settings.h" 35#include "settings.h"
36#include "audio.h" 36#include "audio.h"
37#include "dsp.h"
37 38
38#define CHUNK_SIZE PCMBUF_GUARD 39#define CHUNK_SIZE PCMBUF_GUARD
39/* Must be a power of 2 */ 40/* Must be a power of 2 */
@@ -86,9 +87,11 @@ struct pcmbufdesc
86volatile int pcmbuf_read_index; 87volatile int pcmbuf_read_index;
87volatile int pcmbuf_write_index; 88volatile int pcmbuf_write_index;
88int pcmbuf_unplayed_bytes; 89int pcmbuf_unplayed_bytes;
90int pcmbuf_mix_used_bytes;
89int pcmbuf_watermark; 91int pcmbuf_watermark;
90void (*pcmbuf_watermark_event)(int bytes_left); 92void (*pcmbuf_watermark_event)(int bytes_left);
91static int last_chunksize; 93static int last_chunksize;
94static long mixpos = 0;
92 95
93static void pcmbuf_boost(bool state) 96static void pcmbuf_boost(bool state)
94{ 97{
@@ -173,6 +176,7 @@ bool pcmbuf_add_chunk(void *addr, int size, void (*callback)(void))
173 pcmbuffers[pcmbuf_write_index].callback = callback; 176 pcmbuffers[pcmbuf_write_index].callback = callback;
174 pcmbuf_write_index = (pcmbuf_write_index+1) & NUM_PCM_BUFFERS_MASK; 177 pcmbuf_write_index = (pcmbuf_write_index+1) & NUM_PCM_BUFFERS_MASK;
175 pcmbuf_unplayed_bytes += size; 178 pcmbuf_unplayed_bytes += size;
179 pcmbuf_mix_used_bytes = MAX(0, pcmbuf_mix_used_bytes - size);
176 return true; 180 return true;
177 } 181 }
178 else 182 else
@@ -254,6 +258,7 @@ void pcmbuf_play_stop(void)
254 pcm_play_stop(); 258 pcm_play_stop();
255 last_chunksize = 0; 259 last_chunksize = 0;
256 pcmbuf_unplayed_bytes = 0; 260 pcmbuf_unplayed_bytes = 0;
261 pcmbuf_mix_used_bytes = 0;
257 pcmbuf_read_index = 0; 262 pcmbuf_read_index = 0;
258 pcmbuf_write_index = 0; 263 pcmbuf_write_index = 0;
259 audiobuffer_pos = 0; 264 audiobuffer_pos = 0;
@@ -297,6 +302,13 @@ void pcmbuf_flush_audio(void)
297 crossfade_init = true; 302 crossfade_init = true;
298} 303}
299 304
305/* Force playback. */
306void pcmbuf_play_start(void)
307{
308 if (!pcm_is_playing() && pcmbuf_unplayed_bytes)
309 pcm_play_data(pcmbuf_callback);
310}
311
300void pcmbuf_flush_fillpos(void) 312void pcmbuf_flush_fillpos(void)
301{ 313{
302 int copy_n; 314 int copy_n;
@@ -562,6 +574,98 @@ bool pcmbuf_insert_buffer(char *buf, long length)
562 return true; 574 return true;
563} 575}
564 576
577/* Generates a constant square wave sound with a given frequency
578 in Hertz for a duration in milliseconds. */
579void pcmbuf_beep(int frequency, int duration, int amplitude)
580{
581 int state = 0, count = 0;
582 int interval = NATIVE_FREQUENCY / frequency;
583 int pos;
584 short *buf = (short *)audiobuffer;
585 int bufsize = pcmbuf_size / 2;
586
587 /* FIXME: Should start playback. */
588 //if (pcmbuf_unplayed_bytes * 1000 < 4 * NATIVE_FREQUENCY * duration)
589 // return ;
590
591 pos = (audiobuffer_pos - pcmbuf_unplayed_bytes) / 2;
592 if (pos < 0)
593 pos += bufsize;
594
595 duration = NATIVE_FREQUENCY / 1000 * duration;
596 while (duration-- > 0)
597 {
598 if (state) {
599 buf[pos] = MIN(MAX(buf[pos] + amplitude, -32768), 32767);
600 if (++pos >= bufsize)
601 pos = 0;
602 buf[pos] = MIN(MAX(buf[pos] + amplitude, -32768), 32767);
603 } else {
604 buf[pos] = MIN(MAX(buf[pos] - amplitude, -32768), 32767);
605 if (++pos >= bufsize)
606 pos = 0;
607 buf[pos] = MIN(MAX(buf[pos] - amplitude, -32768), 32767);
608 }
609
610 if (++count >= interval)
611 {
612 count = 0;
613 if (state)
614 state = 0;
615 else
616 state = 1;
617 }
618 pos++;
619 if (pos >= bufsize)
620 pos = 0;
621 }
622}
623
624/* Returns pcm buffer usage in percents (0 to 100). */
625int pcmbuf_usage(void)
626{
627 return pcmbuf_unplayed_bytes * 100 / pcmbuf_size;
628}
629
630int pcmbuf_mix_usage(void)
631{
632 return pcmbuf_mix_used_bytes * 100 / pcmbuf_unplayed_bytes;
633}
634
635void pcmbuf_reset_mixpos(void)
636{
637 int bufsize = pcmbuf_size / 2;
638
639 pcmbuf_mix_used_bytes = 0;
640 mixpos = (audiobuffer_pos - pcmbuf_unplayed_bytes) / 2;
641 if (mixpos < 0)
642 mixpos += bufsize;
643 if (mixpos >= bufsize)
644 mixpos -= bufsize;
645}
646
647void pcmbuf_mix(char *buf, long length)
648{
649 short *ibuf = (short *)buf;
650 short *obuf = (short *)audiobuffer;
651 int bufsize = pcmbuf_size / 2;
652
653 if (pcmbuf_mix_used_bytes == 0)
654 pcmbuf_reset_mixpos();
655
656 pcmbuf_mix_used_bytes += length;
657 length /= 2;
658
659 while (length-- > 0) {
660 obuf[mixpos] = MIN(MAX(obuf[mixpos] + *ibuf*4, -32768), 32767);
661
662 ibuf++;
663 mixpos++;
664 if (mixpos >= bufsize)
665 mixpos = 0;
666 }
667}
668
565void pcmbuf_crossfade_enable(bool on_off) 669void pcmbuf_crossfade_enable(bool on_off)
566{ 670{
567 crossfade_enabled = on_off; 671 crossfade_enabled = on_off;
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 6381dbc27e..f2533defe6 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -36,6 +36,7 @@ void pcmbuf_set_watermark(int numbytes, void (*callback)(int bytes_left));
36void pcmbuf_set_boost_mode(bool state); 36void pcmbuf_set_boost_mode(bool state);
37bool pcmbuf_is_lowdata(void); 37bool pcmbuf_is_lowdata(void);
38void pcmbuf_flush_audio(void); 38void pcmbuf_flush_audio(void);
39void pcmbuf_play_start(void);
39bool pcmbuf_crossfade_init(int type); 40bool pcmbuf_crossfade_init(int type);
40void pcmbuf_add_event(void (*event_handler)(void)); 41void pcmbuf_add_event(void (*event_handler)(void));
41unsigned int pcmbuf_get_latency(void); 42unsigned int pcmbuf_get_latency(void);
@@ -45,4 +46,10 @@ void* pcmbuf_request_buffer(long length, long *realsize);
45bool pcmbuf_is_crossfade_enabled(void); 46bool pcmbuf_is_crossfade_enabled(void);
46void pcmbuf_crossfade_enable(bool on_off); 47void pcmbuf_crossfade_enable(bool on_off);
47 48
49int pcmbuf_usage(void);
50int pcmbuf_mix_usage(void);
51void pcmbuf_beep(int frequency, int duration, int amplitude);
52void pcmbuf_reset_mixpos(void);
53void pcmbuf_mix(char *buf, long length);
54
48#endif 55#endif
diff --git a/apps/playback.c b/apps/playback.c
index e12b01ee55..8829757949 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -60,18 +60,20 @@
60#include "misc.h" 60#include "misc.h"
61#include "sound.h" 61#include "sound.h"
62#include "metadata.h" 62#include "metadata.h"
63#include "talk.h"
63 64
64static volatile bool codec_loaded; 65static volatile bool audio_codec_loaded;
66static volatile bool voice_codec_loaded;
65static volatile bool playing; 67static volatile bool playing;
66static volatile bool paused; 68static volatile bool paused;
67 69
68#define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec"; 70#define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec"
69#define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec"; 71#define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec"
70#define CODEC_FLAC "/.rockbox/codecs/flac.codec"; 72#define CODEC_FLAC "/.rockbox/codecs/flac.codec"
71#define CODEC_WAV "/.rockbox/codecs/wav.codec"; 73#define CODEC_WAV "/.rockbox/codecs/wav.codec"
72#define CODEC_A52 "/.rockbox/codecs/a52.codec"; 74#define CODEC_A52 "/.rockbox/codecs/a52.codec"
73#define CODEC_MPC "/.rockbox/codecs/mpc.codec"; 75#define CODEC_MPC "/.rockbox/codecs/mpc.codec"
74#define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec"; 76#define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec"
75 77
76#define AUDIO_FILL_CYCLE (1024*256) 78#define AUDIO_FILL_CYCLE (1024*256)
77#define AUDIO_DEFAULT_WATERMARK (1024*512) 79#define AUDIO_DEFAULT_WATERMARK (1024*512)
@@ -96,6 +98,10 @@ static volatile bool paused;
96#define MALLOC_BUFSIZE (512*1024) 98#define MALLOC_BUFSIZE (512*1024)
97#define GUARD_BUFSIZE (8*1024) 99#define GUARD_BUFSIZE (8*1024)
98 100
101/* As defined in plugin.lds */
102#define CODEC_IRAM_ORIGIN 0x10010000
103#define CODEC_IRAM_SIZE 0x8000
104
99extern bool audio_is_initialized; 105extern bool audio_is_initialized;
100 106
101/* Buffer control thread. */ 107/* Buffer control thread. */
@@ -108,19 +114,39 @@ static struct event_queue codec_queue;
108static long codec_stack[(DEFAULT_STACK_SIZE + 0x2500)/sizeof(long)] IDATA_ATTR; 114static long codec_stack[(DEFAULT_STACK_SIZE + 0x2500)/sizeof(long)] IDATA_ATTR;
109static const char codec_thread_name[] = "codec"; 115static const char codec_thread_name[] = "codec";
110 116
117/* Voice codec thread. */
118static struct event_queue voice_codec_queue;
119/* Not enough IRAM for this. */
120static long voice_codec_stack[(DEFAULT_STACK_SIZE + 0x2500)/sizeof(long)];
121static const char voice_codec_thread_name[] = "voice codec";
122
111static struct mutex mutex_bufferfill; 123static struct mutex mutex_bufferfill;
124static struct mutex mutex_codecthread;
125
126static struct mp3entry id3_voice;
127
128#define CODEC_IDX_AUDIO 0
129#define CODEC_IDX_VOICE 1
130
131static char *voicebuf;
132static int voice_remaining;
133static bool voice_is_playing;
134static void (*voice_getmore)(unsigned char** start, int* size);
112 135
113/* Is file buffer currently being refilled? */ 136/* Is file buffer currently being refilled? */
114static volatile bool filling; 137static volatile bool filling;
115 138
139volatile int current_codec;
140extern unsigned char codecbuf[];
141
116/* Ring buffer where tracks and codecs are loaded. */ 142/* Ring buffer where tracks and codecs are loaded. */
117static char *codecbuf; 143static char *filebuf;
118 144
119/* Total size of the ring buffer. */ 145/* Total size of the ring buffer. */
120int codecbuflen; 146int filebuflen;
121 147
122/* Bytes available in the buffer. */ 148/* Bytes available in the buffer. */
123int codecbufused; 149int filebufused;
124 150
125/* Ring buffer read and write indexes. */ 151/* Ring buffer read and write indexes. */
126static volatile int buf_ridx; 152static volatile int buf_ridx;
@@ -153,6 +179,7 @@ static struct track_info *cur_ti;
153 179
154/* Codec API including function callbacks. */ 180/* Codec API including function callbacks. */
155extern struct codec_api ci; 181extern struct codec_api ci;
182extern struct codec_api ci_voice;
156 183
157/* When we change a song and buffer is not in filling state, this 184/* When we change a song and buffer is not in filling state, this
158 variable keeps information about whether to go a next/previous track. */ 185 variable keeps information about whether to go a next/previous track. */
@@ -174,6 +201,59 @@ static bool v1first = false;
174static void mp3_set_elapsed(struct mp3entry* id3); 201static void mp3_set_elapsed(struct mp3entry* id3);
175int mp3_get_file_pos(void); 202int mp3_get_file_pos(void);
176 203
204static void do_swap(int idx_old, int idx_new)
205{
206#ifndef SIMULATOR
207 unsigned char *iram_p = (unsigned char *)(CODEC_IRAM_ORIGIN);
208 unsigned char *iram_buf[2];
209#endif
210 unsigned char *dram_buf[2];
211
212
213#ifndef SIMULATOR
214 iram_buf[0] = &filebuf[filebuflen];
215 iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE];
216 memcpy(iram_buf[idx_old], iram_p, CODEC_IRAM_SIZE);
217 memcpy(iram_p, iram_buf[idx_new], CODEC_IRAM_SIZE);
218#endif
219
220 dram_buf[0] = &filebuf[filebuflen+CODEC_IRAM_SIZE*2];
221 dram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
222 memcpy(dram_buf[idx_old], codecbuf, CODEC_SIZE);
223 memcpy(codecbuf, dram_buf[idx_new], CODEC_SIZE);
224}
225
226static void swap_codec(void)
227{
228 int last_codec;
229
230 logf("swapping codec:%d", current_codec);
231
232 /* We should swap codecs' IRAM contents and code space. */
233 do_swap(current_codec, !current_codec);
234
235 last_codec = current_codec;
236 current_codec = !current_codec;
237
238 /* Release the semaphore and force a task switch. */
239 mutex_unlock(&mutex_codecthread);
240 sleep(1);
241
242 /* Waiting until we are ready to run again. */
243 mutex_lock(&mutex_codecthread);
244
245 /* Check if codec swap did not happen. */
246 if (current_codec != last_codec)
247 {
248 logf("no codec switch happened!");
249 do_swap(current_codec, !current_codec);
250 current_codec = !current_codec;
251 }
252
253 invalidate_icache();
254 logf("codec resuming:%d", current_codec);
255}
256
177bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2, 257bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
178 long length) 258 long length)
179{ 259{
@@ -209,12 +289,41 @@ bool codec_pcmbuf_insert_split_callback(void *ch1, void *ch2,
209 pcmbuf_flush_buffer(0); 289 pcmbuf_flush_buffer(0);
210 DEBUGF("Warning: dsp_input_size(%ld=dsp_output_size(%ld))=%ld <= 0\n", 290 DEBUGF("Warning: dsp_input_size(%ld=dsp_output_size(%ld))=%ld <= 0\n",
211 output_size, length, input_size); 291 output_size, length, input_size);
212 /* should we really continue, or should we break? */ 292 /* should we really continue, or should we break?
293 * We should probably continue because calling pcmbuf_flush_buffer(0)
294 * will wrap the buffer if it was fully filled and so next call to
295 * pcmbuf_request_buffer should give the requested output_size. */
213 continue; 296 continue;
214 } 297 }
215 298
216 output_size = dsp_process(dest, src, input_size); 299 output_size = dsp_process(dest, src, input_size);
217 pcmbuf_flush_buffer(output_size); 300
301 /* Hotswap between audio and voice codecs as necessary. */
302 switch (current_codec)
303 {
304 case CODEC_IDX_AUDIO:
305 pcmbuf_flush_buffer(output_size);
306 if (voice_is_playing && pcmbuf_usage() > 30
307 && pcmbuf_mix_usage() < 20)
308 {
309 cpu_boost(true);
310 swap_codec();
311 cpu_boost(false);
312 }
313 break ;
314
315 case CODEC_IDX_VOICE:
316 if (audio_codec_loaded) {
317 pcmbuf_mix(dest, output_size);
318 if ((pcmbuf_usage() < 10)
319 || pcmbuf_mix_usage() > 70)
320 swap_codec();
321 } else {
322 pcmbuf_flush_buffer(output_size);
323 }
324 break ;
325 }
326
218 length -= input_size; 327 length -= input_size;
219 } 328 }
220 329
@@ -241,6 +350,9 @@ bool codec_pcmbuf_insert_callback(char *buf, long length)
241void* get_codec_memory_callback(long *size) 350void* get_codec_memory_callback(long *size)
242{ 351{
243 *size = MALLOC_BUFSIZE; 352 *size = MALLOC_BUFSIZE;
353 if (voice_codec_loaded)
354 return &audiobuf[talk_get_bufsize()];
355
244 return &audiobuf[0]; 356 return &audiobuf[0];
245} 357}
246 358
@@ -248,7 +360,7 @@ void codec_set_elapsed_callback(unsigned int value)
248{ 360{
249 unsigned int latency; 361 unsigned int latency;
250 362
251 if (ci.stop_codec) 363 if (ci.stop_codec || current_codec == CODEC_IDX_VOICE)
252 return ; 364 return ;
253 365
254 latency = pcmbuf_get_latency(); 366 latency = pcmbuf_get_latency();
@@ -265,7 +377,7 @@ void codec_set_offset_callback(unsigned int value)
265{ 377{
266 unsigned int latency; 378 unsigned int latency;
267 379
268 if (ci.stop_codec) 380 if (ci.stop_codec || current_codec == CODEC_IDX_VOICE)
269 return ; 381 return ;
270 382
271 latency = pcmbuf_get_latency() * cur_ti->id3.bitrate / 8; 383 latency = pcmbuf_get_latency() * cur_ti->id3.bitrate / 8;
@@ -283,7 +395,7 @@ long codec_filebuf_callback(void *ptr, long size)
283 int copy_n; 395 int copy_n;
284 int part_n; 396 int part_n;
285 397
286 if (ci.stop_codec || !playing) 398 if (ci.stop_codec || !playing || current_codec == CODEC_IDX_VOICE)
287 return 0; 399 return 0;
288 400
289 copy_n = MIN((off_t)size, (off_t)cur_ti->available + cur_ti->filerem); 401 copy_n = MIN((off_t)size, (off_t)cur_ti->available + cur_ti->filerem);
@@ -297,26 +409,78 @@ long codec_filebuf_callback(void *ptr, long size)
297 if (copy_n == 0) 409 if (copy_n == 0)
298 return 0; 410 return 0;
299 411
300 part_n = MIN(copy_n, codecbuflen - buf_ridx); 412 part_n = MIN(copy_n, filebuflen - buf_ridx);
301 memcpy(buf, &codecbuf[buf_ridx], part_n); 413 memcpy(buf, &filebuf[buf_ridx], part_n);
302 if (part_n < copy_n) { 414 if (part_n < copy_n) {
303 memcpy(&buf[part_n], &codecbuf[0], copy_n - part_n); 415 memcpy(&buf[part_n], &filebuf[0], copy_n - part_n);
304 } 416 }
305 417
306 buf_ridx += copy_n; 418 buf_ridx += copy_n;
307 if (buf_ridx >= codecbuflen) 419 if (buf_ridx >= filebuflen)
308 buf_ridx -= codecbuflen; 420 buf_ridx -= filebuflen;
309 ci.curpos += copy_n; 421 ci.curpos += copy_n;
310 cur_ti->available -= copy_n; 422 cur_ti->available -= copy_n;
311 codecbufused -= copy_n; 423 filebufused -= copy_n;
312 424
313 return copy_n; 425 return copy_n;
314} 426}
315 427
428void* voice_request_data(long *realsize, long reqsize)
429{
430 while (queue_empty(&voice_codec_queue) && (voice_remaining == 0
431 || voicebuf == NULL) && !ci_voice.stop_codec)
432 {
433 yield();
434 if (audio_codec_loaded && (pcmbuf_usage() < 30
435 || !voice_is_playing || voicebuf == NULL))
436 {
437 swap_codec();
438 }
439 if (!voice_is_playing)
440 sleep(HZ/16);
441
442 if (voice_remaining)
443 {
444 voice_is_playing = true;
445 break ;
446 }
447
448 if (voice_getmore != NULL)
449 {
450 voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
451
452 if (!voice_remaining)
453 {
454 voice_is_playing = false;
455 /* Force pcm playback. */
456 pcmbuf_play_start();
457 }
458 }
459 }
460
461 if (reqsize < 0)
462 reqsize = 0;
463
464 voice_is_playing = true;
465 *realsize = voice_remaining;
466 if (*realsize > reqsize)
467 *realsize = reqsize;
468
469 if (*realsize == 0)
470 return NULL;
471
472 return voicebuf;
473}
474
316void* codec_request_buffer_callback(long *realsize, long reqsize) 475void* codec_request_buffer_callback(long *realsize, long reqsize)
317{ 476{
318 long part_n; 477 long part_n;
319 478
479 /* Voice codec. */
480 if (current_codec == CODEC_IDX_VOICE) {
481 return voice_request_data(realsize, reqsize);
482 }
483
320 if (ci.stop_codec || !playing) { 484 if (ci.stop_codec || !playing) {
321 *realsize = 0; 485 *realsize = 0;
322 return NULL; 486 return NULL;
@@ -335,22 +499,22 @@ void* codec_request_buffer_callback(long *realsize, long reqsize)
335 } 499 }
336 } 500 }
337 501
338 part_n = MIN((int)*realsize, codecbuflen - buf_ridx); 502 part_n = MIN((int)*realsize, filebuflen - buf_ridx);
339 if (part_n < *realsize) { 503 if (part_n < *realsize) {
340 part_n += GUARD_BUFSIZE; 504 part_n += GUARD_BUFSIZE;
341 if (part_n < *realsize) 505 if (part_n < *realsize)
342 *realsize = part_n; 506 *realsize = part_n;
343 memcpy(&codecbuf[codecbuflen], &codecbuf[0], *realsize - 507 memcpy(&filebuf[filebuflen], &filebuf[0], *realsize -
344 (codecbuflen - buf_ridx)); 508 (filebuflen - buf_ridx));
345 } 509 }
346 510
347 return (char *)&codecbuf[buf_ridx]; 511 return (char *)&filebuf[buf_ridx];
348} 512}
349 513
350static bool rebuffer_and_seek(int newpos) 514static bool rebuffer_and_seek(int newpos)
351{ 515{
352 int fd; 516 int fd;
353 517
354 logf("Re-buffering song"); 518 logf("Re-buffering song");
355 mutex_lock(&mutex_bufferfill); 519 mutex_lock(&mutex_bufferfill);
356 520
@@ -367,7 +531,7 @@ static bool rebuffer_and_seek(int newpos)
367 531
368 /* Clear codec buffer. */ 532 /* Clear codec buffer. */
369 audio_invalidate_tracks(); 533 audio_invalidate_tracks();
370 codecbufused = 0; 534 filebufused = 0;
371 buf_ridx = buf_widx = 0; 535 buf_ridx = buf_widx = 0;
372 cur_ti->filerem = cur_ti->filesize - newpos; 536 cur_ti->filerem = cur_ti->filesize - newpos;
373 cur_ti->filepos = newpos; 537 cur_ti->filepos = newpos;
@@ -390,6 +554,15 @@ static bool rebuffer_and_seek(int newpos)
390 554
391void codec_advance_buffer_callback(long amount) 555void codec_advance_buffer_callback(long amount)
392{ 556{
557 if (current_codec == CODEC_IDX_VOICE) {
558 //logf("voice ad.buf:%d", amount);
559 amount = MAX(0, MIN(amount, voice_remaining));
560 voicebuf += amount;
561 voice_remaining -= amount;
562
563 return ;
564 }
565
393 if (amount > cur_ti->available + cur_ti->filerem) 566 if (amount > cur_ti->available + cur_ti->filerem)
394 amount = cur_ti->available + cur_ti->filerem; 567 amount = cur_ti->available + cur_ti->filerem;
395 568
@@ -400,10 +573,10 @@ void codec_advance_buffer_callback(long amount)
400 } 573 }
401 574
402 buf_ridx += amount; 575 buf_ridx += amount;
403 if (buf_ridx >= codecbuflen) 576 if (buf_ridx >= filebuflen)
404 buf_ridx -= codecbuflen; 577 buf_ridx -= filebuflen;
405 cur_ti->available -= amount; 578 cur_ti->available -= amount;
406 codecbufused -= amount; 579 filebufused -= amount;
407 ci.curpos += amount; 580 ci.curpos += amount;
408 codec_set_offset_callback(ci.curpos); 581 codec_set_offset_callback(ci.curpos);
409} 582}
@@ -411,15 +584,18 @@ void codec_advance_buffer_callback(long amount)
411void codec_advance_buffer_loc_callback(void *ptr) 584void codec_advance_buffer_loc_callback(void *ptr)
412{ 585{
413 long amount; 586 long amount;
414 587
415 amount = (int)ptr - (int)&codecbuf[buf_ridx]; 588 if (current_codec == CODEC_IDX_VOICE)
589 amount = (int)ptr - (int)voicebuf;
590 else
591 amount = (int)ptr - (int)&filebuf[buf_ridx];
416 codec_advance_buffer_callback(amount); 592 codec_advance_buffer_callback(amount);
417} 593}
418 594
419off_t codec_mp3_get_filepos_callback(int newtime) 595off_t codec_mp3_get_filepos_callback(int newtime)
420{ 596{
421 off_t newpos; 597 off_t newpos;
422 598
423 cur_ti->id3.elapsed = newtime; 599 cur_ti->id3.elapsed = newtime;
424 newpos = mp3_get_file_pos(); 600 newpos = mp3_get_file_pos();
425 601
@@ -429,7 +605,10 @@ off_t codec_mp3_get_filepos_callback(int newtime)
429bool codec_seek_buffer_callback(off_t newpos) 605bool codec_seek_buffer_callback(off_t newpos)
430{ 606{
431 int difference; 607 int difference;
432 608
609 if (current_codec == CODEC_IDX_VOICE)
610 return false;
611
433 if (newpos < 0) 612 if (newpos < 0)
434 newpos = 0; 613 newpos = 0;
435 614
@@ -457,11 +636,11 @@ bool codec_seek_buffer_callback(off_t newpos)
457 636
458 /* Seeking inside buffer space. */ 637 /* Seeking inside buffer space. */
459 logf("seek: -%d", difference); 638 logf("seek: -%d", difference);
460 codecbufused += difference; 639 filebufused += difference;
461 cur_ti->available += difference; 640 cur_ti->available += difference;
462 buf_ridx -= difference; 641 buf_ridx -= difference;
463 if (buf_ridx < 0) 642 if (buf_ridx < 0)
464 buf_ridx = codecbuflen + buf_ridx; 643 buf_ridx = filebuflen + buf_ridx;
465 ci.curpos -= difference; 644 ci.curpos -= difference;
466 if (!pcmbuf_is_crossfade_active()) 645 if (!pcmbuf_is_crossfade_active())
467 pcmbuf_play_stop(); 646 pcmbuf_play_stop();
@@ -473,8 +652,11 @@ static void set_filebuf_watermark(int seconds)
473{ 652{
474 long bytes; 653 long bytes;
475 654
655 if (current_codec == CODEC_IDX_VOICE)
656 return ;
657
476 bytes = MAX((int)cur_ti->id3.bitrate * seconds * (1000/8), conf_watermark); 658 bytes = MAX((int)cur_ti->id3.bitrate * seconds * (1000/8), conf_watermark);
477 bytes = MIN(bytes, codecbuflen / 2); 659 bytes = MIN(bytes, filebuflen / 2);
478 conf_watermark = bytes; 660 conf_watermark = bytes;
479} 661}
480 662
@@ -540,7 +722,7 @@ void yield_codecs(void)
540 sleep(5); 722 sleep(5);
541 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata()) 723 while ((pcmbuf_is_crossfade_active() || pcmbuf_is_lowdata())
542 && !ci.stop_codec && playing && queue_empty(&audio_queue) 724 && !ci.stop_codec && playing && queue_empty(&audio_queue)
543 && codecbufused > (128*1024)) 725 && filebufused > (128*1024))
544 yield(); 726 yield();
545} 727}
546 728
@@ -552,18 +734,18 @@ void strip_id3v1_tag(void)
552 int tagptr; 734 int tagptr;
553 bool found = true; 735 bool found = true;
554 736
555 if (codecbufused >= 128) 737 if (filebufused >= 128)
556 { 738 {
557 tagptr = buf_widx - 128; 739 tagptr = buf_widx - 128;
558 if (tagptr < 0) 740 if (tagptr < 0)
559 tagptr += codecbuflen; 741 tagptr += filebuflen;
560 742
561 for(i = 0;i < 3;i++) 743 for(i = 0;i < 3;i++)
562 { 744 {
563 if(tagptr >= codecbuflen) 745 if(tagptr >= filebuflen)
564 tagptr -= codecbuflen; 746 tagptr -= filebuflen;
565 747
566 if(codecbuf[tagptr] != tag[i]) 748 if(filebuf[tagptr] != tag[i])
567 { 749 {
568 found = false; 750 found = false;
569 break; 751 break;
@@ -578,7 +760,7 @@ void strip_id3v1_tag(void)
578 logf("Skipping ID3v1 tag\n"); 760 logf("Skipping ID3v1 tag\n");
579 buf_widx -= 128; 761 buf_widx -= 128;
580 tracks[track_widx].available -= 128; 762 tracks[track_widx].available -= 128;
581 codecbufused -= 128; 763 filebufused -= 128;
582 } 764 }
583 } 765 }
584} 766}
@@ -603,9 +785,9 @@ void audio_fill_file_buffer(void)
603 785
604 if (fill_bytesleft == 0) 786 if (fill_bytesleft == 0)
605 break ; 787 break ;
606 rc = MIN(conf_filechunk, codecbuflen - buf_widx); 788 rc = MIN(conf_filechunk, filebuflen - buf_widx);
607 rc = MIN(rc, fill_bytesleft); 789 rc = MIN(rc, fill_bytesleft);
608 rc = read(current_fd, &codecbuf[buf_widx], rc); 790 rc = read(current_fd, &filebuf[buf_widx], rc);
609 if (rc <= 0) { 791 if (rc <= 0) {
610 tracks[track_widx].filerem = 0; 792 tracks[track_widx].filerem = 0;
611 strip_id3v1_tag(); 793 strip_id3v1_tag();
@@ -613,13 +795,13 @@ void audio_fill_file_buffer(void)
613 } 795 }
614 796
615 buf_widx += rc; 797 buf_widx += rc;
616 if (buf_widx >= codecbuflen) 798 if (buf_widx >= filebuflen)
617 buf_widx -= codecbuflen; 799 buf_widx -= filebuflen;
618 i += rc; 800 i += rc;
619 tracks[track_widx].available += rc; 801 tracks[track_widx].available += rc;
620 tracks[track_widx].filerem -= rc; 802 tracks[track_widx].filerem -= rc;
621 tracks[track_widx].filepos += rc; 803 tracks[track_widx].filepos += rc;
622 codecbufused += rc; 804 filebufused += rc;
623 fill_bytesleft -= rc; 805 fill_bytesleft -= rc;
624 } 806 }
625 807
@@ -725,15 +907,15 @@ bool loadcodec(const char *trackname, bool start_play)
725 while (i < size) { 907 while (i < size) {
726 yield_codecs(); 908 yield_codecs();
727 909
728 copy_n = MIN(conf_filechunk, codecbuflen - buf_widx); 910 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
729 rc = read(fd, &codecbuf[buf_widx], copy_n); 911 rc = read(fd, &filebuf[buf_widx], copy_n);
730 if (rc < 0) 912 if (rc < 0)
731 return false; 913 return false;
732 buf_widx += rc; 914 buf_widx += rc;
733 codecbufused += rc; 915 filebufused += rc;
734 fill_bytesleft -= rc; 916 fill_bytesleft -= rc;
735 if (buf_widx >= codecbuflen) 917 if (buf_widx >= filebuflen)
736 buf_widx -= codecbuflen; 918 buf_widx -= filebuflen;
737 i += rc; 919 i += rc;
738 } 920 }
739 close(fd); 921 close(fd);
@@ -840,20 +1022,23 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
840 tracks[track_widx].playlist_offset = peek_offset; 1022 tracks[track_widx].playlist_offset = peek_offset;
841 last_peek_offset = peek_offset; 1023 last_peek_offset = peek_offset;
842 1024
843 if (buf_widx >= codecbuflen) 1025 if (buf_widx >= filebuflen)
844 buf_widx -= codecbuflen; 1026 buf_widx -= filebuflen;
845 1027
846 /* Set default values */ 1028 /* Set default values */
847 if (start_play) { 1029 if (start_play) {
1030 int last_codec = current_codec;
1031 current_codec = CODEC_IDX_AUDIO;
848 conf_bufferlimit = 0; 1032 conf_bufferlimit = 0;
849 conf_watermark = AUDIO_DEFAULT_WATERMARK; 1033 conf_watermark = AUDIO_DEFAULT_WATERMARK;
850 conf_filechunk = AUDIO_DEFAULT_FILECHUNK; 1034 conf_filechunk = AUDIO_DEFAULT_FILECHUNK;
851 dsp_configure(DSP_RESET, 0); 1035 dsp_configure(DSP_RESET, 0);
852 ci.configure(CODEC_DSP_ENABLE, false); 1036 ci.configure(CODEC_DSP_ENABLE, false);
1037 current_codec = last_codec;
853 } 1038 }
854 1039
855 /* Load the codec. */ 1040 /* Load the codec. */
856 tracks[track_widx].codecbuf = &codecbuf[buf_widx]; 1041 tracks[track_widx].codecbuf = &filebuf[buf_widx];
857 if (!loadcodec(trackname, start_play)) { 1042 if (!loadcodec(trackname, start_play)) {
858 close(fd); 1043 close(fd);
859 /* Stop buffer filling if codec load failed. */ 1044 /* Stop buffer filling if codec load failed. */
@@ -870,7 +1055,7 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
870 } 1055 }
871 return false; 1056 return false;
872 } 1057 }
873 // tracks[track_widx].filebuf = &codecbuf[buf_widx]; 1058 // tracks[track_widx].filebuf = &filebuf[buf_widx];
874 tracks[track_widx].start_pos = 0; 1059 tracks[track_widx].start_pos = 0;
875 1060
876 /* Get track metadata if we don't already have it. */ 1061 /* Get track metadata if we don't already have it. */
@@ -933,10 +1118,10 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
933 if (fill_bytesleft == 0) 1118 if (fill_bytesleft == 0)
934 break ; 1119 break ;
935 1120
936 copy_n = MIN(conf_filechunk, codecbuflen - buf_widx); 1121 copy_n = MIN(conf_filechunk, filebuflen - buf_widx);
937 copy_n = MIN(size - i, copy_n); 1122 copy_n = MIN(size - i, copy_n);
938 copy_n = MIN((int)fill_bytesleft, copy_n); 1123 copy_n = MIN((int)fill_bytesleft, copy_n);
939 rc = read(fd, &codecbuf[buf_widx], copy_n); 1124 rc = read(fd, &filebuf[buf_widx], copy_n);
940 if (rc < copy_n) { 1125 if (rc < copy_n) {
941 logf("File error!"); 1126 logf("File error!");
942 tracks[track_widx].filesize = 0; 1127 tracks[track_widx].filesize = 0;
@@ -945,12 +1130,12 @@ bool audio_load_track(int offset, bool start_play, int peek_offset)
945 return false; 1130 return false;
946 } 1131 }
947 buf_widx += rc; 1132 buf_widx += rc;
948 if (buf_widx >= codecbuflen) 1133 if (buf_widx >= filebuflen)
949 buf_widx -= codecbuflen; 1134 buf_widx -= filebuflen;
950 i += rc; 1135 i += rc;
951 tracks[track_widx].available += rc; 1136 tracks[track_widx].available += rc;
952 tracks[track_widx].filerem -= rc; 1137 tracks[track_widx].filerem -= rc;
953 codecbufused += rc; 1138 filebufused += rc;
954 fill_bytesleft -= rc; 1139 fill_bytesleft -= rc;
955 } 1140 }
956 1141
@@ -997,10 +1182,10 @@ void audio_play_start(int offset)
997 track_ridx = 0; 1182 track_ridx = 0;
998 buf_ridx = 0; 1183 buf_ridx = 0;
999 buf_widx = 0; 1184 buf_widx = 0;
1000 codecbufused = 0; 1185 filebufused = 0;
1001 pcmbuf_set_boost_mode(true); 1186 pcmbuf_set_boost_mode(true);
1002 1187
1003 fill_bytesleft = codecbuflen; 1188 fill_bytesleft = filebuflen;
1004 filling = true; 1189 filling = true;
1005 last_peek_offset = -1; 1190 last_peek_offset = -1;
1006 if (audio_load_track(offset, true, 0)) { 1191 if (audio_load_track(offset, true, 0)) {
@@ -1089,7 +1274,7 @@ void initialize_buffer_fill(void)
1089 int cur_idx, i; 1274 int cur_idx, i;
1090 1275
1091 1276
1092 fill_bytesleft = codecbuflen - codecbufused; 1277 fill_bytesleft = filebuflen - filebufused;
1093 cur_ti->start_pos = ci.curpos; 1278 cur_ti->start_pos = ci.curpos;
1094 1279
1095 pcmbuf_set_boost_mode(true); 1280 pcmbuf_set_boost_mode(true);
@@ -1124,7 +1309,7 @@ void initialize_buffer_fill(void)
1124void audio_check_buffer(void) 1309void audio_check_buffer(void)
1125{ 1310{
1126 /* Start buffer filling as necessary. */ 1311 /* Start buffer filling as necessary. */
1127 if ((codecbufused > conf_watermark || !queue_empty(&audio_queue) 1312 if ((filebufused > conf_watermark || !queue_empty(&audio_queue)
1128 || !playing || ci.stop_codec || ci.reload_codec) && !filling) 1313 || !playing || ci.stop_codec || ci.reload_codec) && !filling)
1129 return ; 1314 return ;
1130 1315
@@ -1132,8 +1317,8 @@ void audio_check_buffer(void)
1132 1317
1133 /* Limit buffering size at first run. */ 1318 /* Limit buffering size at first run. */
1134 if (conf_bufferlimit && fill_bytesleft > conf_bufferlimit 1319 if (conf_bufferlimit && fill_bytesleft > conf_bufferlimit
1135 - codecbufused) { 1320 - filebufused) {
1136 fill_bytesleft = MAX(0, conf_bufferlimit - codecbufused); 1321 fill_bytesleft = MAX(0, conf_bufferlimit - filebufused);
1137 } 1322 }
1138 1323
1139 /* Try to load remainings of the file. */ 1324 /* Try to load remainings of the file. */
@@ -1169,27 +1354,27 @@ void audio_update_trackinfo(void)
1169{ 1354{
1170 if (new_track >= 0) { 1355 if (new_track >= 0) {
1171 buf_ridx += cur_ti->available; 1356 buf_ridx += cur_ti->available;
1172 codecbufused -= cur_ti->available; 1357 filebufused -= cur_ti->available;
1173 1358
1174 cur_ti = &tracks[track_ridx]; 1359 cur_ti = &tracks[track_ridx];
1175 buf_ridx += cur_ti->codecsize; 1360 buf_ridx += cur_ti->codecsize;
1176 codecbufused -= cur_ti->codecsize; 1361 filebufused -= cur_ti->codecsize;
1177 if (buf_ridx >= codecbuflen) 1362 if (buf_ridx >= filebuflen)
1178 buf_ridx -= codecbuflen; 1363 buf_ridx -= filebuflen;
1179 1364
1180 if (!filling) 1365 if (!filling)
1181 pcmbuf_set_boost_mode(false); 1366 pcmbuf_set_boost_mode(false);
1182 } else { 1367 } else {
1183 buf_ridx -= ci.curpos + cur_ti->codecsize; 1368 buf_ridx -= ci.curpos + cur_ti->codecsize;
1184 codecbufused += ci.curpos + cur_ti->codecsize; 1369 filebufused += ci.curpos + cur_ti->codecsize;
1185 cur_ti->available = cur_ti->filesize; 1370 cur_ti->available = cur_ti->filesize;
1186 1371
1187 cur_ti = &tracks[track_ridx]; 1372 cur_ti = &tracks[track_ridx];
1188 buf_ridx -= cur_ti->filesize; 1373 buf_ridx -= cur_ti->filesize;
1189 codecbufused += cur_ti->filesize; 1374 filebufused += cur_ti->filesize;
1190 cur_ti->available = cur_ti->filesize; 1375 cur_ti->available = cur_ti->filesize;
1191 if (buf_ridx < 0) 1376 if (buf_ridx < 0)
1192 buf_ridx = codecbuflen + buf_ridx; 1377 buf_ridx = filebuflen + buf_ridx;
1193 } 1378 }
1194 1379
1195 ci.filesize = cur_ti->filesize; 1380 ci.filesize = cur_ti->filesize;
@@ -1220,7 +1405,7 @@ static void audio_stop_playback(void)
1220 current_fd = -1; 1405 current_fd = -1;
1221 } 1406 }
1222 pcmbuf_play_stop(); 1407 pcmbuf_play_stop();
1223 while (codec_loaded) 1408 while (audio_codec_loaded)
1224 yield(); 1409 yield();
1225 pcm_play_pause(true); 1410 pcm_play_pause(true);
1226 track_count = 0; 1411 track_count = 0;
@@ -1267,6 +1452,11 @@ static int get_codec_base_type(int type)
1267 1452
1268bool codec_request_next_track_callback(void) 1453bool codec_request_next_track_callback(void)
1269{ 1454{
1455 if (current_codec == CODEC_IDX_VOICE) {
1456 voice_remaining = 0;
1457 return !ci_voice.stop_codec;
1458 }
1459
1270 if (ci.stop_codec || !playing) 1460 if (ci.stop_codec || !playing)
1271 return false; 1461 return false;
1272 1462
@@ -1309,8 +1499,8 @@ bool codec_request_next_track_callback(void)
1309 if (--track_ridx < 0) 1499 if (--track_ridx < 0)
1310 track_ridx = MAX_TRACK-1; 1500 track_ridx = MAX_TRACK-1;
1311 if (tracks[track_ridx].filesize == 0 || 1501 if (tracks[track_ridx].filesize == 0 ||
1312 codecbufused+ci.curpos+tracks[track_ridx].filesize 1502 filebufused+ci.curpos+tracks[track_ridx].filesize
1313 /*+ (off_t)tracks[track_ridx].codecsize*/ > codecbuflen) { 1503 /*+ (off_t)tracks[track_ridx].codecsize*/ > filebuflen) {
1314 logf("Loading from disk..."); 1504 logf("Loading from disk...");
1315 new_track = 0; 1505 new_track = 0;
1316 last_index = -1; 1506 last_index = -1;
@@ -1379,10 +1569,10 @@ void audio_invalidate_tracks(void)
1379 track_widx = track_ridx; 1569 track_widx = track_ridx;
1380 /* Mark all other entries null (also buffered wrong metadata). */ 1570 /* Mark all other entries null (also buffered wrong metadata). */
1381 audio_clear_track_entries(false); 1571 audio_clear_track_entries(false);
1382 codecbufused = cur_ti->available; 1572 filebufused = cur_ti->available;
1383 buf_widx = buf_ridx + cur_ti->available; 1573 buf_widx = buf_ridx + cur_ti->available;
1384 if (buf_widx >= codecbuflen) 1574 if (buf_widx >= filebuflen)
1385 buf_widx -= codecbuflen; 1575 buf_widx -= filebuflen;
1386 read_next_metadata(); 1576 read_next_metadata();
1387} 1577}
1388 1578
@@ -1436,7 +1626,7 @@ void audio_thread(void)
1436 ci.reload_codec = false; 1626 ci.reload_codec = false;
1437 ci.seek_time = 0; 1627 ci.seek_time = 0;
1438 pcmbuf_crossfade_init(CROSSFADE_MODE_CROSSFADE); 1628 pcmbuf_crossfade_init(CROSSFADE_MODE_CROSSFADE);
1439 while (codec_loaded) 1629 while (audio_codec_loaded)
1440 yield(); 1630 yield();
1441 audio_play_start((int)ev.data); 1631 audio_play_start((int)ev.data);
1442 playlist_update_resume_info(audio_current_track()); 1632 playlist_update_resume_info(audio_current_track());
@@ -1462,11 +1652,13 @@ void audio_thread(void)
1462 1652
1463 case AUDIO_NEXT: 1653 case AUDIO_NEXT:
1464 logf("audio_next"); 1654 logf("audio_next");
1655 pcmbuf_beep(5000, 100, 5000);
1465 initiate_track_change(1); 1656 initiate_track_change(1);
1466 break ; 1657 break ;
1467 1658
1468 case AUDIO_PREV: 1659 case AUDIO_PREV:
1469 logf("audio_prev"); 1660 logf("audio_prev");
1661 pcmbuf_beep(5000, 100, 5000);
1470 initiate_track_change(-1); 1662 initiate_track_change(-1);
1471 break; 1663 break;
1472 1664
@@ -1514,8 +1706,11 @@ void codec_thread(void)
1514 switch (ev.id) { 1706 switch (ev.id) {
1515 case CODEC_LOAD_DISK: 1707 case CODEC_LOAD_DISK:
1516 ci.stop_codec = false; 1708 ci.stop_codec = false;
1517 codec_loaded = true; 1709 audio_codec_loaded = true;
1518 status = codec_load_file((char *)ev.data); 1710 mutex_lock(&mutex_codecthread);
1711 current_codec = CODEC_IDX_AUDIO;
1712 status = codec_load_file((char *)ev.data, &ci);
1713 mutex_unlock(&mutex_codecthread);
1519 break ; 1714 break ;
1520 1715
1521 case CODEC_LOAD: 1716 case CODEC_LOAD:
@@ -1531,10 +1726,13 @@ void codec_thread(void)
1531 } 1726 }
1532 1727
1533 ci.stop_codec = false; 1728 ci.stop_codec = false;
1534 wrap = (int)&codecbuf[codecbuflen] - (int)cur_ti->codecbuf; 1729 wrap = (int)&filebuf[filebuflen] - (int)cur_ti->codecbuf;
1535 codec_loaded = true; 1730 audio_codec_loaded = true;
1536 status = codec_load_ram(cur_ti->codecbuf, codecsize, 1731 mutex_lock(&mutex_codecthread);
1537 &codecbuf[0], wrap); 1732 current_codec = CODEC_IDX_AUDIO;
1733 status = codec_load_ram(cur_ti->codecbuf, codecsize,
1734 &filebuf[0], wrap, &ci);
1735 mutex_unlock(&mutex_codecthread);
1538 break ; 1736 break ;
1539 1737
1540#ifndef SIMULATOR 1738#ifndef SIMULATOR
@@ -1545,7 +1743,7 @@ void codec_thread(void)
1545#endif 1743#endif
1546 } 1744 }
1547 1745
1548 codec_loaded = false; 1746 audio_codec_loaded = false;
1549 1747
1550 switch (ev.id) { 1748 switch (ev.id) {
1551 case CODEC_LOAD_DISK: 1749 case CODEC_LOAD_DISK:
@@ -1569,6 +1767,83 @@ void codec_thread(void)
1569 } 1767 }
1570} 1768}
1571 1769
1770static void reset_buffer(void)
1771{
1772 filebuf = &audiobuf[MALLOC_BUFSIZE];
1773 filebuflen = audiobufend - audiobuf - pcmbuf_get_bufsize()
1774 - PCMBUF_GUARD - MALLOC_BUFSIZE - GUARD_BUFSIZE;
1775
1776 if (talk_get_bufsize() && voice_codec_loaded)
1777 {
1778 filebuf = &filebuf[talk_get_bufsize()];
1779 filebuflen -= 2*CODEC_IRAM_SIZE + 2*CODEC_SIZE + talk_get_bufsize();
1780 }
1781}
1782
1783void voice_codec_thread(void)
1784{
1785 struct event ev;
1786 int status;
1787
1788 current_codec = CODEC_IDX_AUDIO;
1789 voice_codec_loaded = false;
1790 while (1) {
1791 status = 0;
1792 queue_wait(&voice_codec_queue, &ev);
1793 switch (ev.id) {
1794 case CODEC_LOAD_DISK:
1795 logf("Loading voice codec");
1796 audio_stop_playback();
1797 mutex_lock(&mutex_codecthread);
1798 current_codec = CODEC_IDX_VOICE;
1799 dsp_configure(DSP_RESET, 0);
1800 ci.configure(CODEC_DSP_ENABLE, (bool *)true);
1801 voice_remaining = 0;
1802 voice_getmore = NULL;
1803 voice_codec_loaded = true;
1804 reset_buffer();
1805 ci_voice.stop_codec = false;
1806
1807 status = codec_load_file((char *)ev.data, &ci_voice);
1808
1809 logf("Voice codec finished");
1810 audio_stop_playback();
1811 mutex_unlock(&mutex_codecthread);
1812 current_codec = CODEC_IDX_AUDIO;
1813 voice_codec_loaded = false;
1814 reset_buffer();
1815 break ;
1816
1817#ifndef SIMULATOR
1818 case SYS_USB_CONNECTED:
1819 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1820 usb_wait_for_disconnect(&voice_codec_queue);
1821 break ;
1822#endif
1823 }
1824 }
1825}
1826
1827void voice_init(void)
1828{
1829 while (voice_codec_loaded)
1830 {
1831 logf("Terminating voice codec");
1832 ci_voice.stop_codec = true;
1833 if (current_codec != CODEC_IDX_VOICE)
1834 swap_codec();
1835 sleep(1);
1836 }
1837
1838 if (!talk_get_bufsize())
1839 return ;
1840
1841 logf("Starting voice codec");
1842 queue_post(&voice_codec_queue, CODEC_LOAD_DISK, (void *)CODEC_MPA_L3);
1843 while (!voice_codec_loaded)
1844 sleep(1);
1845}
1846
1572struct mp3entry* audio_current_track(void) 1847struct mp3entry* audio_current_track(void)
1573{ 1848{
1574 // logf("audio_current_track"); 1849 // logf("audio_current_track");
@@ -1620,7 +1895,7 @@ void audio_stop(void)
1620{ 1895{
1621 logf("audio_stop"); 1896 logf("audio_stop");
1622 queue_post(&audio_queue, AUDIO_STOP, 0); 1897 queue_post(&audio_queue, AUDIO_STOP, 0);
1623 while (playing || codec_loaded) 1898 while (playing || audio_codec_loaded)
1624 yield(); 1899 yield();
1625} 1900}
1626 1901
@@ -1805,6 +2080,16 @@ int mp3_get_file_pos(void)
1805 return pos; 2080 return pos;
1806} 2081}
1807 2082
2083void mp3_play_data(const unsigned char* start, int size,
2084 void (*get_more)(unsigned char** start, int* size))
2085{
2086 voice_getmore = get_more;
2087 voicebuf = (unsigned char *)start;
2088 voice_remaining = size;
2089 voice_is_playing = true;
2090 pcmbuf_reset_mixpos();
2091}
2092
1808void audio_set_buffer_margin(int setting) 2093void audio_set_buffer_margin(int setting)
1809{ 2094{
1810 int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600}; 2095 int lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
@@ -1827,7 +2112,7 @@ void audio_set_crossfade(int type)
1827 offset = cur_ti->id3.offset; 2112 offset = cur_ti->id3.offset;
1828 2113
1829 if (type == CROSSFADE_MODE_OFF) 2114 if (type == CROSSFADE_MODE_OFF)
1830 seconds = 0; 2115 seconds = 1;
1831 2116
1832 /* Buffer has to be at least 2s long. */ 2117 /* Buffer has to be at least 2s long. */
1833 seconds += 2; 2118 seconds += 2;
@@ -1843,12 +2128,13 @@ void audio_set_crossfade(int type)
1843 if (was_playing) 2128 if (was_playing)
1844 splash(0, true, str(LANG_RESTARTING_PLAYBACK)); 2129 splash(0, true, str(LANG_RESTARTING_PLAYBACK));
1845 pcmbuf_init(size); 2130 pcmbuf_init(size);
1846 pcmbuf_crossfade_enable(seconds > 2); 2131 pcmbuf_crossfade_enable(type != CROSSFADE_MODE_OFF);
1847 codecbuflen = audiobufend - audiobuf - pcmbuf_get_bufsize() 2132 reset_buffer();
1848 - PCMBUF_GUARD - MALLOC_BUFSIZE - GUARD_BUFSIZE;
1849 logf("abuf:%dB", pcmbuf_get_bufsize()); 2133 logf("abuf:%dB", pcmbuf_get_bufsize());
1850 logf("fbuf:%dB", codecbuflen); 2134 logf("fbuf:%dB", filebuflen);
1851 2135
2136 voice_init();
2137
1852 /* Restart playback. */ 2138 /* Restart playback. */
1853 if (was_playing) { 2139 if (was_playing) {
1854 audio_play(offset); 2140 audio_play(offset);
@@ -1856,7 +2142,7 @@ void audio_set_crossfade(int type)
1856 /* Wait for the playback to start again (and display the splash 2142 /* Wait for the playback to start again (and display the splash
1857 screen during that period. */ 2143 screen during that period. */
1858 playing = true; 2144 playing = true;
1859 while (playing && !codec_loaded) 2145 while (playing && !audio_codec_loaded)
1860 yield(); 2146 yield();
1861 } 2147 }
1862} 2148}
@@ -1884,13 +2170,17 @@ void test_unbuffer_event(struct mp3entry *id3, bool last_track)
1884 2170
1885void audio_init(void) 2171void audio_init(void)
1886{ 2172{
2173 static bool voicetagtrue = true;
2174
1887 logf("audio api init"); 2175 logf("audio api init");
1888 pcm_init(); 2176 pcm_init();
1889 codecbufused = 0; 2177 filebufused = 0;
1890 filling = false; 2178 filling = false;
1891 codecbuf = &audiobuf[MALLOC_BUFSIZE]; 2179 current_codec = CODEC_IDX_AUDIO;
2180 filebuf = &audiobuf[MALLOC_BUFSIZE];
1892 playing = false; 2181 playing = false;
1893 codec_loaded = false; 2182 audio_codec_loaded = false;
2183 voice_is_playing = false;
1894 paused = false; 2184 paused = false;
1895 track_changed = false; 2185 track_changed = false;
1896 current_fd = -1; 2186 current_fd = -1;
@@ -1918,12 +2208,25 @@ void audio_init(void)
1918 ci.set_offset = codec_set_offset_callback; 2208 ci.set_offset = codec_set_offset_callback;
1919 ci.configure = codec_configure_callback; 2209 ci.configure = codec_configure_callback;
1920 2210
2211 memcpy(&ci_voice, &ci, sizeof(struct codec_api));
2212 memset(&id3_voice, 0, sizeof(struct mp3entry));
2213 ci_voice.taginfo_ready = &voicetagtrue;
2214 ci_voice.id3 = &id3_voice;
2215 ci_voice.pcmbuf_insert = codec_pcmbuf_insert_callback;
2216 id3_voice.frequency = 11200;
2217 id3_voice.length = 1000000L;
2218
1921 mutex_init(&mutex_bufferfill); 2219 mutex_init(&mutex_bufferfill);
2220 mutex_init(&mutex_codecthread);
2221
1922 queue_init(&audio_queue); 2222 queue_init(&audio_queue);
1923 queue_init(&codec_queue); 2223 queue_init(&codec_queue);
2224 queue_init(&voice_codec_queue);
1924 2225
1925 create_thread(codec_thread, codec_stack, sizeof(codec_stack), 2226 create_thread(codec_thread, codec_stack, sizeof(codec_stack),
1926 codec_thread_name); 2227 codec_thread_name);
2228 create_thread(voice_codec_thread, voice_codec_stack,
2229 sizeof(voice_codec_stack), voice_codec_thread_name);
1927 create_thread(audio_thread, audio_stack, sizeof(audio_stack), 2230 create_thread(audio_thread, audio_stack, sizeof(audio_stack),
1928 audio_thread_name); 2231 audio_thread_name);
1929} 2232}
diff --git a/apps/playback.h b/apps/playback.h
index 7ed9a4b700..a5b64ba0e3 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -72,6 +72,7 @@ void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3,
72void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, 72void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3,
73 bool last_track)); 73 bool last_track));
74void audio_invalidate_tracks(void); 74void audio_invalidate_tracks(void);
75void voice_init(void);
75 76
76#endif 77#endif
77 78
diff --git a/apps/playlist.c b/apps/playlist.c
index 68fd8be369..bd443e4f38 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -1413,9 +1413,14 @@ int playlist_resume(void)
1413 }; 1413 };
1414 1414
1415 /* use mp3 buffer for maximum load speed */ 1415 /* use mp3 buffer for maximum load speed */
1416#if CONFIG_HWCODEC != MASNONE
1416 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ 1417 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
1417 buflen = (audiobufend - audiobuf); 1418 buflen = (audiobufend - audiobuf);
1418 buffer = audiobuf; 1419 buffer = audiobuf;
1420#else
1421 buflen = (audiobufend - audiobuf - talk_get_bufsize());
1422 buffer = &audiobuf[talk_get_bufsize()];
1423#endif
1419 1424
1420 empty_playlist(playlist, true); 1425 empty_playlist(playlist, true);
1421 1426
@@ -1827,7 +1832,9 @@ int playlist_start(int start_index, int offset)
1827 struct playlist_info* playlist = &current_playlist; 1832 struct playlist_info* playlist = &current_playlist;
1828 1833
1829 playlist->index = start_index; 1834 playlist->index = start_index;
1835#if CONFIG_HWCODEC != MASNONE
1830 talk_buffer_steal(); /* will use the mp3 buffer */ 1836 talk_buffer_steal(); /* will use the mp3 buffer */
1837#endif
1831 audio_play(offset); 1838 audio_play(offset);
1832 1839
1833 return 0; 1840 return 0;
diff --git a/apps/talk.c b/apps/talk.c
index a896ca3a1a..b417046a61 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -32,7 +32,11 @@
32#include "lang.h" 32#include "lang.h"
33#include "talk.h" 33#include "talk.h"
34#include "id3.h" 34#include "id3.h"
35#include "logf.h"
35#include "bitswap.h" 36#include "bitswap.h"
37#if CONFIG_HWCODEC == MASNONE
38#include "playback.h"
39#endif
36 40
37/***************** Constants *****************/ 41/***************** Constants *****************/
38 42
@@ -88,6 +92,7 @@ static int filehandle; /* global, so the MMC variant can keep the file open */
88static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */ 92static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */
89static long silence_len; /* length of the VOICE_PAUSE clip */ 93static long silence_len; /* length of the VOICE_PAUSE clip */
90static unsigned char* p_lastclip; /* address of latest clip, for silence add */ 94static unsigned char* p_lastclip; /* address of latest clip, for silence add */
95static unsigned long voicefile_size = 0; /* size of the loaded voice file */
91 96
92 97
93/***************** Private prototypes *****************/ 98/***************** Private prototypes *****************/
@@ -114,10 +119,28 @@ static int open_voicefile(void)
114 } 119 }
115 120
116 snprintf(buf, sizeof(buf), ROCKBOX_DIR LANG_DIR "/%s.voice", p_lang); 121 snprintf(buf, sizeof(buf), ROCKBOX_DIR LANG_DIR "/%s.voice", p_lang);
117 122
118 return open(buf, O_RDONLY); 123 return open(buf, O_RDONLY);
119} 124}
120 125
126int talk_get_bufsize(void)
127{
128 return voicefile_size;
129}
130
131#ifdef SIMULATOR
132static unsigned short BSWAP16(unsigned short value)
133{
134 return (value >> 8) | (value << 8);
135}
136
137static unsigned long BSWAP32(unsigned long value)
138{
139 unsigned long hi = BSWAP16(value >> 16);
140 unsigned long lo = BSWAP16(value & 0xffff);
141 return (lo << 16) | hi;
142}
143#endif
121 144
122/* load the voice file into the mp3 buffer */ 145/* load the voice file into the mp3 buffer */
123static void load_voicefile(void) 146static void load_voicefile(void)
@@ -125,6 +148,10 @@ static void load_voicefile(void)
125 int load_size; 148 int load_size;
126 int got_size; 149 int got_size;
127 int file_size; 150 int file_size;
151#if CONFIG_HWCODEC == MASNONE
152 int length, i;
153 unsigned char *buf, temp;
154#endif
128 155
129 filehandle = open_voicefile(); 156 filehandle = open_voicefile();
130 if (filehandle < 0) /* failed to open */ 157 if (filehandle < 0) /* failed to open */
@@ -141,8 +168,20 @@ static void load_voicefile(void)
141#endif 168#endif
142 169
143 got_size = read(filehandle, audiobuf, load_size); 170 got_size = read(filehandle, audiobuf, load_size);
144 if (got_size == load_size /* success */ 171 if (got_size != load_size /* failure */)
145 && ((struct voicefile*)audiobuf)->table /* format check */ 172 goto load_err;
173
174#ifdef SIMULATOR
175 logf("Byte swapping voice file");
176 p_voicefile = (struct voicefile*)audiobuf;
177 p_voicefile->version = BSWAP32(p_voicefile->version);
178 p_voicefile->table = BSWAP32(p_voicefile->table);
179 p_voicefile->id1_max = BSWAP32(p_voicefile->id1_max);
180 p_voicefile->id2_max = BSWAP32(p_voicefile->id2_max);
181 p_voicefile = NULL;
182#endif
183
184 if (((struct voicefile*)audiobuf)->table /* format check */
146 == offsetof(struct voicefile, index)) 185 == offsetof(struct voicefile, index))
147 { 186 {
148 p_voicefile = (struct voicefile*)audiobuf; 187 p_voicefile = (struct voicefile*)audiobuf;
@@ -155,7 +194,42 @@ static void load_voicefile(void)
155 else 194 else
156 goto load_err; 195 goto load_err;
157 196
158#ifdef HAVE_MMC 197#ifdef SIMULATOR
198 for (i = 0; i < p_voicefile->id1_max + p_voicefile->id2_max; i++)
199 {
200 struct clip_entry *ce;
201 ce = &p_voicefile->index[i];
202 ce->offset = BSWAP32(ce->offset);
203 ce->size = BSWAP32(ce->size);
204 }
205#endif
206
207 /* Do a bitswap as necessary. */
208#if CONFIG_HWCODEC == MASNONE
209 logf("Bitswapping voice file.");
210 cpu_boost(true);
211 buf = (unsigned char *)(&p_voicefile->index) +
212 (p_voicefile->id1_max + p_voicefile->id2_max) * sizeof(struct clip_entry);
213 length = file_size - offsetof(struct voicefile, index) -
214 (p_voicefile->id1_max - p_voicefile->id2_max) * sizeof(struct clip_entry);
215
216 for (i = 0; i < length; i++)
217 {
218 temp = buf[i];
219 buf[i] = ((temp >> 7) & 0x01)
220 | ((temp >> 5) & 0x02)
221 | ((temp >> 3) & 0x04)
222 | ((temp >> 1) & 0x08)
223 | ((temp << 1) & 0x10)
224 | ((temp << 3) & 0x20)
225 | ((temp << 5) & 0x40)
226 | ((temp << 7) & 0x80);
227 }
228 cpu_boost(false);
229
230#endif
231
232#ifdef HAVE_MMC
159 /* load the index table, now that we know its size from the header */ 233 /* load the index table, now that we know its size from the header */
160 load_size = (p_voicefile->id1_max + p_voicefile->id2_max) 234 load_size = (p_voicefile->id1_max + p_voicefile->id2_max)
161 * sizeof(struct clip_entry); 235 * sizeof(struct clip_entry);
@@ -193,7 +267,11 @@ static void mp3_callback(unsigned char** start, int* size)
193 267
194 if (queue[queue_read].len > 0) /* current clip not finished? */ 268 if (queue[queue_read].len > 0) /* current clip not finished? */
195 { /* feed the next 64K-1 chunk */ 269 { /* feed the next 64K-1 chunk */
270#if CONFIG_HWCODEC != MASNONE
196 sent = MIN(queue[queue_read].len, 0xFFFF); 271 sent = MIN(queue[queue_read].len, 0xFFFF);
272#else
273 sent = queue[queue_read].len;
274#endif
197 *start = queue[queue_read].buf; 275 *start = queue[queue_read].buf;
198 *size = sent; 276 *size = sent;
199 return; 277 return;
@@ -207,7 +285,11 @@ re_check:
207 285
208 if (QUEUE_LEVEL) /* queue is not empty? */ 286 if (QUEUE_LEVEL) /* queue is not empty? */
209 { /* start next clip */ 287 { /* start next clip */
288#if CONFIG_HWCODEC != MASNONE
210 sent = MIN(queue[queue_read].len, 0xFFFF); 289 sent = MIN(queue[queue_read].len, 0xFFFF);
290#else
291 sent = queue[queue_read].len;
292#endif
211 *start = p_lastclip = queue[queue_read].buf; 293 *start = p_lastclip = queue[queue_read].buf;
212 *size = sent; 294 *size = sent;
213 curr_hd[0] = p_lastclip[1]; 295 curr_hd[0] = p_lastclip[1];
@@ -286,7 +368,7 @@ static int shutup(void)
286 /* nothing to do, was frame boundary or not our clip */ 368 /* nothing to do, was frame boundary or not our clip */
287 mp3_play_stop(); 369 mp3_play_stop();
288 queue_write = queue_read = 0; /* reset the queue */ 370 queue_write = queue_read = 0; /* reset the queue */
289 371
290 return 0; 372 return 0;
291} 373}
292 374
@@ -317,7 +399,11 @@ static int queue_clip(unsigned char* buf, long size, bool enqueue)
317 if (queue_level == 0) 399 if (queue_level == 0)
318 { /* queue was empty, we have to do the initial start */ 400 { /* queue was empty, we have to do the initial start */
319 p_lastclip = buf; 401 p_lastclip = buf;
402#if CONFIG_HWCODEC != MASNONE
320 sent = MIN(size, 0xFFFF); /* DMA can do no more */ 403 sent = MIN(size, 0xFFFF); /* DMA can do no more */
404#else
405 sent = size;
406#endif
321 mp3_play_data(buf, sent, mp3_callback); 407 mp3_play_data(buf, sent, mp3_callback);
322 curr_hd[0] = buf[1]; 408 curr_hd[0] = buf[1];
323 curr_hd[1] = buf[2]; 409 curr_hd[1] = buf[2];
@@ -400,12 +486,19 @@ void talk_init(void)
400#else 486#else
401 filehandle = open_voicefile(); 487 filehandle = open_voicefile();
402 has_voicefile = (filehandle >= 0); /* test if we can open it */ 488 has_voicefile = (filehandle >= 0); /* test if we can open it */
489 voicefile_size = 0;
490
403 if (has_voicefile) 491 if (has_voicefile)
404 { 492 {
493 voicefile_size = filesize(filehandle);
494#if CONFIG_HWCODEC == MASNONE
495 voice_init();
496#endif
405 close(filehandle); /* close again, this was just to detect presence */ 497 close(filehandle); /* close again, this was just to detect presence */
406 filehandle = -1; 498 filehandle = -1;
407 } 499 }
408#endif 500#endif
501
409} 502}
410 503
411 504
@@ -432,8 +525,10 @@ int talk_id(long id, bool enqueue)
432 unsigned char* clipbuf; 525 unsigned char* clipbuf;
433 int unit; 526 int unit;
434 527
528#if CONFIG_HWCODEC != MASNONE
435 if (audio_status()) /* busy, buffer in use */ 529 if (audio_status()) /* busy, buffer in use */
436 return -1; 530 return -1;
531#endif
437 532
438 if (p_voicefile == NULL && has_voicefile) 533 if (p_voicefile == NULL && has_voicefile)
439 load_voicefile(); /* reload needed */ 534 load_voicefile(); /* reload needed */
@@ -514,8 +609,10 @@ int talk_number(long n, bool enqueue)
514 int level = 0; /* mille count */ 609 int level = 0; /* mille count */
515 long mil = 1000000000; /* highest possible "-illion" */ 610 long mil = 1000000000; /* highest possible "-illion" */
516 611
612#if CONFIG_HWCODEC != MASNONE
517 if (audio_status()) /* busy, buffer in use */ 613 if (audio_status()) /* busy, buffer in use */
518 return -1; 614 return -1;
615#endif
519 616
520 if (!enqueue) 617 if (!enqueue)
521 shutup(); /* cut off all the pending stuff */ 618 shutup(); /* cut off all the pending stuff */
@@ -593,8 +690,10 @@ int talk_value(long n, int unit, bool enqueue)
593 VOICE_HERTZ, 690 VOICE_HERTZ,
594 }; 691 };
595 692
693#if CONFIG_HWCODEC != MASNONE
596 if (audio_status()) /* busy, buffer in use */ 694 if (audio_status()) /* busy, buffer in use */
597 return -1; 695 return -1;
696#endif
598 697
599 if (unit < 0 || unit >= UNIT_LAST) 698 if (unit < 0 || unit >= UNIT_LAST)
600 unit_id = -1; 699 unit_id = -1;
@@ -625,8 +724,10 @@ int talk_spell(const char* spell, bool enqueue)
625{ 724{
626 char c; /* currently processed char */ 725 char c; /* currently processed char */
627 726
727#if CONFIG_HWCODEC != MASNONE
628 if (audio_status()) /* busy, buffer in use */ 728 if (audio_status()) /* busy, buffer in use */
629 return -1; 729 return -1;
730#endif
630 731
631 if (!enqueue) 732 if (!enqueue)
632 shutup(); /* cut off all the pending stuff */ 733 shutup(); /* cut off all the pending stuff */
diff --git a/apps/talk.h b/apps/talk.h
index 213e1803d4..18314e52c5 100644
--- a/apps/talk.h
+++ b/apps/talk.h
@@ -59,6 +59,7 @@ extern const char* const dir_thumbnail_name; /* "_dirname.talk" */
59extern const char* const file_thumbnail_ext; /* ".talk" for file voicing */ 59extern const char* const file_thumbnail_ext; /* ".talk" for file voicing */
60 60
61void talk_init(void); 61void talk_init(void);
62int talk_get_bufsize(void); /* get the loaded voice file size */
62int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ 63int talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */
63int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */ 64int talk_id(long id, bool enqueue); /* play a voice ID from voicefont */
64int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */ 65int talk_file(const char* filename, bool enqueue); /* play a thumbnail from file */
diff --git a/firmware/mp3_playback.c b/firmware/mp3_playback.c
index dfe08e5d3a..3a2fdb4f1a 100644
--- a/firmware/mp3_playback.c
+++ b/firmware/mp3_playback.c
@@ -576,7 +576,6 @@ void mp3_reset_playtime(void)
576 playstart_tick = current_tick; 576 playstart_tick = current_tick;
577} 577}
578 578
579
580bool mp3_is_playing(void) 579bool mp3_is_playing(void)
581{ 580{
582 return playing; 581 return playing;
@@ -624,18 +623,11 @@ void mp3_init(int volume, int bass, int treble, int balance, int loudness,
624 audio_is_initialized = true; 623 audio_is_initialized = true;
625#endif 624#endif
626} 625}
626
627void mp3_shutdown(void) 627void mp3_shutdown(void)
628{ 628{
629 /* a dummy */ 629 /* a dummy */
630} 630}
631void mp3_play_data(const unsigned char* start, int size,
632 void (*get_more)(unsigned char** start, int* size))
633{
634 /* a dummy */
635 (void)start;
636 (void)size;
637 (void)get_more;
638}
639 631
640void mp3_play_stop(void) 632void mp3_play_stop(void)
641{ 633{
@@ -653,4 +645,10 @@ unsigned char* mp3_get_pos(void)
653 /* a dummy */ 645 /* a dummy */
654 return (unsigned char *)0x1234; 646 return (unsigned char *)0x1234;
655} 647}
648
649bool mp3_is_playing(void)
650{
651 return playing;
652}
653
656#endif /* CONFIG_HWCODEC == MASNONE */ 654#endif /* CONFIG_HWCODEC == MASNONE */
diff --git a/firmware/sound.c b/firmware/sound.c
index 8fb015c27a..cd772f5e9f 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -704,10 +704,3 @@ int sound_get_pitch(void)
704} 704}
705#endif 705#endif
706 706
707#if CONFIG_HWCODEC == MASNONE
708bool mp3_is_playing(void)
709{
710 /* a dummy */
711 return false;
712}
713#endif
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index af6f9653fe..2357f9baea 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -273,6 +273,7 @@ void button_set_flip(bool yesno)
273 (void)yesno; 273 (void)yesno;
274} 274}
275 275
276#if CONFIG_HWCODEC != MASNONE
276void talk_init(void) 277void talk_init(void)
277{ 278{
278} 279}
@@ -320,6 +321,7 @@ int talk_spell(char* spell, bool enqueue)
320 321
321const char* const dir_thumbnail_name = "_dirname.talk"; 322const char* const dir_thumbnail_name = "_dirname.talk";
322const char* const file_thumbnail_ext = ".talk"; 323const char* const file_thumbnail_ext = ".talk";
324#endif
323 325
324/* FIXME: this shoudn't be a stub, rather the real thing. 326/* FIXME: this shoudn't be a stub, rather the real thing.
325 I'm afraid on Win32/X11 it'll be hard to kill a thread from outside. */ 327 I'm afraid on Win32/X11 it'll be hard to kill a thread from outside. */