summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/pcmbuf.c41
-rw-r--r--apps/playback.c241
2 files changed, 173 insertions, 109 deletions
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index f8fd2af82a..0aaa49f825 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -232,7 +232,7 @@ static inline void pcmbuf_add_chunk(void)
232 pcmbuf_current->link = NULL; 232 pcmbuf_current->link = NULL;
233 /* This is single use only */ 233 /* This is single use only */
234 pcmbuf_event_handler = NULL; 234 pcmbuf_event_handler = NULL;
235 if (pcmbuf_read) { 235 if (pcmbuf_read != NULL) {
236 if (pcmbuf_flush) 236 if (pcmbuf_flush)
237 { 237 {
238 pcmbuf_write_end->link = pcmbuf_read->link; 238 pcmbuf_write_end->link = pcmbuf_read->link;
@@ -305,14 +305,14 @@ bool pcmbuf_is_lowdata(void)
305/* Amount of bytes left in the buffer. */ 305/* Amount of bytes left in the buffer. */
306inline size_t pcmbuf_free(void) 306inline size_t pcmbuf_free(void)
307{ 307{
308 if (pcmbuf_read) 308 if (pcmbuf_read != NULL)
309 { 309 {
310 size_t read = (size_t)pcmbuf_read->addr; 310 void *read = pcmbuf_read->addr;
311 size_t write = 311 void *write = &audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
312 (size_t)&audiobuffer[audiobuffer_pos + audiobuffer_fillpos];
313 if (read < write) 312 if (read < write)
314 read += pcmbuf_size; 313 return (size_t)(read - write) + pcmbuf_size;
315 return read - write; 314 else
315 return (size_t) (read - write);
316 } 316 }
317 return pcmbuf_size; 317 return pcmbuf_size;
318} 318}
@@ -335,7 +335,6 @@ bool pcmbuf_crossfade_init(bool manual_skip)
335 return false; 335 return false;
336 } 336 }
337 337
338 logf("pcmbuf_crossfade_init");
339 pcmbuf_boost(true); 338 pcmbuf_boost(true);
340 339
341 /* Don't enable mix mode when skipping tracks manually. */ 340 /* Don't enable mix mode when skipping tracks manually. */
@@ -444,10 +443,13 @@ void pcmbuf_play_start(void)
444 * until dma has been initialized. */ 443 * until dma has been initialized. */
445 pcm_mute(true); 444 pcm_mute(true);
446 445
447 last_chunksize = pcmbuf_read->size; 446 if (pcmbuf_read != NULL)
448 pcmbuf_unplayed_bytes -= last_chunksize; 447 {
449 pcm_play_data(pcmbuf_callback, 448 last_chunksize = pcmbuf_read->size;
449 pcmbuf_unplayed_bytes -= last_chunksize;
450 pcm_play_data(pcmbuf_callback,
450 (unsigned char *)pcmbuf_read->addr, last_chunksize); 451 (unsigned char *)pcmbuf_read->addr, last_chunksize);
452 }
451 453
452 /* Now unmute the audio. */ 454 /* Now unmute the audio. */
453 pcm_mute(false); 455 pcm_mute(false);
@@ -462,7 +464,6 @@ static bool pcmbuf_flush_fillpos(void)
462 if (audiobuffer_fillpos) { 464 if (audiobuffer_fillpos) {
463 /* Never use the last buffer descriptor */ 465 /* Never use the last buffer descriptor */
464 while (pcmbuf_write == pcmbuf_write_end) { 466 while (pcmbuf_write == pcmbuf_write_end) {
465 logf("pcmbuf_flush_fillpos no descriptors");
466 /* Deboost to let the playback catchup */ 467 /* Deboost to let the playback catchup */
467 pcmbuf_boost(false); 468 pcmbuf_boost(false);
468 /* If this happens, something is being stupid */ 469 /* If this happens, something is being stupid */
@@ -511,7 +512,7 @@ static void crossfade_process_buffer(size_t fade_in_delay,
511 fade_out_rem -= block_rem; 512 fade_out_rem -= block_rem;
512 513
513 /* Fade this block */ 514 /* Fade this block */
514 while (block_rem > 0) 515 while (block_rem > 0 && fade_out_chunk != NULL)
515 { 516 {
516 /* Fade one sample */ 517 /* Fade one sample */
517 short *buf = (short *)(fade_out_chunk->addr); 518 short *buf = (short *)(fade_out_chunk->addr);
@@ -777,7 +778,8 @@ static bool prepare_insert(size_t length)
777 logf("pcm starting"); 778 logf("pcm starting");
778 pcmbuf_play_start(); 779 pcmbuf_play_start();
779 } 780 }
780 } else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark) 781 }
782 else if (pcmbuf_unplayed_bytes <= pcmbuf_watermark)
781 pcmbuf_under_watermark(); 783 pcmbuf_under_watermark();
782 784
783 return true; 785 return true;
@@ -823,7 +825,12 @@ void* pcmbuf_request_voice_buffer(size_t length, size_t *realsize, bool mix)
823{ 825{
824 if (mix) 826 if (mix)
825 { 827 {
826 if (pcmbuf_mix_chunk || pcmbuf_read->link) 828 if (pcmbuf_read == NULL)
829 {
830 *realsize = 0;
831 return NULL;
832 }
833 else if (pcmbuf_mix_chunk || pcmbuf_read->link)
827 { 834 {
828 *realsize = MIN(length, PCMBUF_MIX_CHUNK); 835 *realsize = MIN(length, PCMBUF_MIX_CHUNK);
829 return voicebuf; 836 return voicebuf;
@@ -888,7 +895,7 @@ void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude)
888 short *pcmbuf_end = (short *)fadebuf; 895 short *pcmbuf_end = (short *)fadebuf;
889 size_t samples = NATIVE_FREQUENCY / 1000 * duration; 896 size_t samples = NATIVE_FREQUENCY / 1000 * duration;
890 897
891 if (pcm_is_playing()) 898 if (pcm_is_playing() && pcmbuf_read != NULL)
892 { 899 {
893 if (pcmbuf_read->link) 900 if (pcmbuf_read->link)
894 { 901 {
@@ -971,7 +978,7 @@ void pcmbuf_mix_voice(size_t length)
971 short *obuf; 978 short *obuf;
972 size_t chunk_samples; 979 size_t chunk_samples;
973 980
974 if (!pcmbuf_mix_chunk && pcmbuf_read) 981 if (pcmbuf_mix_chunk == NULL && pcmbuf_read != NULL)
975 { 982 {
976 pcmbuf_mix_chunk = pcmbuf_read->link; 983 pcmbuf_mix_chunk = pcmbuf_read->link;
977 /* Start 1/8s into the next chunk */ 984 /* Start 1/8s into the next chunk */
diff --git a/apps/playback.c b/apps/playback.c
index 33667cc656..d5f2b9024e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -22,6 +22,8 @@
22/* TODO: Also play, stop ^^ */ 22/* TODO: Also play, stop ^^ */
23/* TODO: Can use the track changed callback to detect end of track and seek 23/* TODO: Can use the track changed callback to detect end of track and seek
24 * in the previous track until this happens */ 24 * in the previous track until this happens */
25/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
26 * play whilst audio is paused */
25/* Design: we have prev_ti already, have a conditional for what type of seek 27/* Design: we have prev_ti already, have a conditional for what type of seek
26 * to do on a seek request, if it is a previous track seek, skip previous, 28 * to do on a seek request, if it is a previous track seek, skip previous,
27 * and in the request_next_track callback set the offset up the same way that 29 * and in the request_next_track callback set the offset up the same way that
@@ -39,7 +41,6 @@
39#include "file.h" 41#include "file.h"
40#include "lcd.h" 42#include "lcd.h"
41#include "font.h" 43#include "font.h"
42#include "backlight.h"
43#include "button.h" 44#include "button.h"
44#include "kernel.h" 45#include "kernel.h"
45#include "tree.h" 46#include "tree.h"
@@ -81,10 +82,7 @@
81#include "recording.h" 82#include "recording.h"
82#endif 83#endif
83 84
84static volatile bool audio_codec_loaded; 85#define PLAYBACK_VOICE
85static volatile bool voice_codec_loaded;
86static volatile bool playing;
87static volatile bool paused;
88 86
89 87
90/* default point to start buffer refill */ 88/* default point to start buffer refill */
@@ -99,10 +97,10 @@ static volatile bool paused;
99 97
100/* macros to enable logf for queues */ 98/* macros to enable logf for queues */
101#ifdef SIMULATOR 99#ifdef SIMULATOR
102#define LOGF_QUEUES /* Define this for logf output of all queuing */ 100#define PLAYBACK_LOGQUEUES /* Define this for logf output of all queuing */
103#endif 101#endif
104 102
105#ifdef LOGF_QUEUES 103#ifdef PLAYBACK_LOGQUEUES
106#define LOGFQUEUE(s) logf("%s", s) 104#define LOGFQUEUE(s) logf("%s", s)
107#else 105#else
108#define LOGFQUEUE(s) 106#define LOGFQUEUE(s)
@@ -159,6 +157,14 @@ enum {
159#endif 157#endif
160#define CODEC_IRAM_SIZE 0xc000 158#define CODEC_IRAM_SIZE 0xc000
161 159
160#ifdef PLAYBACK_VOICE
161#ifdef SIMULATOR
162static unsigned char sim_iram[CODEC_IRAM_SIZE];
163#undef CODEC_IRAM_ORIGIN
164#define CODEC_IRAM_ORIGIN sim_iram
165#endif
166#endif
167
162#ifndef SIMULATOR 168#ifndef SIMULATOR
163extern bool audio_is_initialized; 169extern bool audio_is_initialized;
164#else 170#else
@@ -170,13 +176,9 @@ static bool audio_is_initialized = false;
170static struct mutex mutex_codecthread; 176static struct mutex mutex_codecthread;
171static struct event_queue codec_callback_queue; 177static struct event_queue codec_callback_queue;
172 178
173static struct mp3entry id3_voice; 179static volatile bool audio_codec_loaded;
174 180static volatile bool playing;
175static char *voicebuf; 181static volatile bool paused;
176static size_t voice_remaining;
177static bool voice_is_playing;
178static void (*voice_getmore)(unsigned char** start, int* size);
179static struct thread_entry *voice_thread_p = NULL;
180 182
181/* Is file buffer currently being refilled? */ 183/* Is file buffer currently being refilled? */
182static volatile bool filling IDATA_ATTR; 184static volatile bool filling IDATA_ATTR;
@@ -197,9 +199,7 @@ size_t filebufused;
197static volatile size_t buf_ridx IDATA_ATTR; 199static volatile size_t buf_ridx IDATA_ATTR;
198static volatile size_t buf_widx IDATA_ATTR; 200static volatile size_t buf_widx IDATA_ATTR;
199 201
200#ifndef SIMULATOR
201static unsigned char *iram_buf[2]; 202static unsigned char *iram_buf[2];
202#endif
203static unsigned char *dram_buf[2]; 203static unsigned char *dram_buf[2];
204 204
205/* Step count to the next unbuffered track. */ 205/* Step count to the next unbuffered track. */
@@ -209,7 +209,7 @@ static int last_peek_offset;
209 track ring structure. */ 209 track ring structure. */
210static int track_ridx; 210static int track_ridx;
211static int track_widx; 211static int track_widx;
212static bool track_changed; 212static bool track_changed; /* Audio and codec threads */
213 213
214/* Partially loaded song's file handle to continue buffering later. */ 214/* Partially loaded song's file handle to continue buffering later. */
215static int current_fd; 215static int current_fd;
@@ -218,23 +218,20 @@ static int current_fd;
218static size_t fill_bytesleft; 218static size_t fill_bytesleft;
219 219
220/* Track info structure about songs in the file buffer. */ 220/* Track info structure about songs in the file buffer. */
221static struct track_info tracks[MAX_TRACK]; 221static struct track_info tracks[MAX_TRACK]; /* Audio thread */
222 222
223/* Pointer to track info structure about current song playing. */ 223/* Pointer to track info structure about current song playing. */
224static struct track_info *cur_ti; 224static struct track_info *cur_ti; /* Audio and codec threads */
225static struct track_info *prev_ti; 225static struct track_info *prev_ti; /* Audio and codec threads */
226 226
227/* Have we reached end of the current playlist. */ 227/* Have we reached end of the current playlist. */
228static bool playlist_end = false; 228static bool playlist_end = false; /* Audio thread */
229
230/* Codec API including function callbacks. */
231extern struct codec_api ci;
232extern struct codec_api ci_voice;
233 229
234/* Was the skip being executed manual or automatic? */ 230/* Was the skip being executed manual or automatic? */
235static bool automatic_skip; 231static bool automatic_skip = false; /* Audio and codec threads */
236static bool dir_skip = false; 232static bool dir_skip = false; /* Audio thread */
237static bool new_playlist = false; 233static bool new_playlist = false; /* Audio thread */
234static int wps_offset = 0;
238 235
239/* Callback function to call when current track has really changed. */ 236/* Callback function to call when current track has really changed. */
240void (*track_changed_callback)(struct mp3entry *id3); 237void (*track_changed_callback)(struct mp3entry *id3);
@@ -250,6 +247,7 @@ static bool v1first = false;
250 247
251/* Multiple threads */ 248/* Multiple threads */
252static const char * get_codec_filename(int enc_spec); 249static const char * get_codec_filename(int enc_spec);
250static void set_filebuf_watermark(int seconds);
253 251
254/* Audio thread */ 252/* Audio thread */
255static struct event_queue audio_queue; 253static struct event_queue audio_queue;
@@ -257,12 +255,12 @@ static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
257static const char audio_thread_name[] = "audio"; 255static const char audio_thread_name[] = "audio";
258 256
259static void audio_thread(void); 257static void audio_thread(void);
260static void set_filebuf_watermark(int seconds);
261static void audio_initiate_track_change(long direction); 258static void audio_initiate_track_change(long direction);
262static bool audio_have_tracks(void); 259static bool audio_have_tracks(void);
263static void audio_reset_buffer(void); 260static void audio_reset_buffer(void);
264 261
265/* Codec thread */ 262/* Codec thread */
263extern struct codec_api ci;
266static struct event_queue codec_queue; 264static struct event_queue codec_queue;
267static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 265static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
268IBSS_ATTR; 266IBSS_ATTR;
@@ -271,6 +269,17 @@ static const char codec_thread_name[] = "codec";
271struct thread_entry *codec_thread_p; 269struct thread_entry *codec_thread_p;
272 270
273/* Voice thread */ 271/* Voice thread */
272#ifdef PLAYBACK_VOICE
273extern struct codec_api ci_voice;
274
275static volatile bool voice_thread_start;
276static volatile bool voice_is_playing;
277static volatile bool voice_codec_loaded;
278static void (*voice_getmore)(unsigned char** start, int* size);
279static char *voicebuf;
280static size_t voice_remaining;
281static struct thread_entry *voice_thread_p = NULL;
282
274static struct event_queue voice_queue; 283static struct event_queue voice_queue;
275static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 284static long voice_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)]
276IBSS_ATTR; 285IBSS_ATTR;
@@ -286,30 +295,39 @@ static void voice_boost_cpu(bool state);
286#else 295#else
287#define voice_boost_cpu(state) do { } while(0) 296#define voice_boost_cpu(state) do { } while(0)
288#endif 297#endif
289
290static void voice_thread(void); 298static void voice_thread(void);
291 299
300#endif /* PLAYBACK_VOICE */
301
292/* --- External interfaces --- */ 302/* --- External interfaces --- */
293 303
294void mp3_play_data(const unsigned char* start, int size, 304void mp3_play_data(const unsigned char* start, int size,
295 void (*get_more)(unsigned char** start, int* size)) 305 void (*get_more)(unsigned char** start, int* size))
296{ 306{
307#ifdef PLAYBACK_VOICE
297 static struct voice_info voice_clip; 308 static struct voice_info voice_clip;
298 voice_clip.callback = get_more; 309 voice_clip.callback = get_more;
299 voice_clip.buf = (char *)start; 310 voice_clip.buf = (char *)start;
300 voice_clip.size = size; 311 voice_clip.size = size;
301 logf("mp3 > voice Q_VOICE_STOP"); 312 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
302 queue_post(&voice_queue, Q_VOICE_STOP, 0); 313 queue_post(&voice_queue, Q_VOICE_STOP, 0);
303 logf("mp3 > voice Q_VOICE_PLAY"); 314 LOGFQUEUE("mp3 > voice Q_VOICE_PLAY");
304 queue_post(&voice_queue, Q_VOICE_PLAY, &voice_clip); 315 queue_post(&voice_queue, Q_VOICE_PLAY, &voice_clip);
305 voice_is_playing = true; 316 voice_thread_start = true;
306 voice_boost_cpu(true); 317 voice_boost_cpu(true);
318#else
319 (void) start;
320 (void) size;
321 (void) get_more;
322#endif
307} 323}
308 324
309void mp3_play_stop(void) 325void mp3_play_stop(void)
310{ 326{
311 logf("mp3 > voice Q_VOICE_STOP"); 327#ifdef PLAYBACK_VOICE
328 LOGFQUEUE("mp3 > voice Q_VOICE_STOP");
312 queue_post(&voice_queue, Q_VOICE_STOP, 0); 329 queue_post(&voice_queue, Q_VOICE_STOP, 0);
330#endif
313} 331}
314 332
315bool mp3_pause_done(void) 333bool mp3_pause_done(void)
@@ -360,8 +378,9 @@ struct mp3entry* audio_current_track(void)
360 const char *p; 378 const char *p;
361 static struct mp3entry temp_id3; 379 static struct mp3entry temp_id3;
362 int cur_idx; 380 int cur_idx;
381 int offset = ci.new_track + wps_offset;
363 382
364 cur_idx = track_ridx + ci.new_track; 383 cur_idx = track_ridx + offset;
365 cur_idx &= MAX_TRACK_MASK; 384 cur_idx &= MAX_TRACK_MASK;
366 385
367 if (tracks[cur_idx].taginfo_ready) 386 if (tracks[cur_idx].taginfo_ready)
@@ -369,7 +388,7 @@ struct mp3entry* audio_current_track(void)
369 388
370 memset(&temp_id3, 0, sizeof(struct mp3entry)); 389 memset(&temp_id3, 0, sizeof(struct mp3entry));
371 390
372 filename = playlist_peek(ci.new_track); 391 filename = playlist_peek(offset);
373 if (!filename) 392 if (!filename)
374 filename = "No file!"; 393 filename = "No file!";
375 394
@@ -427,10 +446,7 @@ void audio_play(long offset)
427 } 446 }
428 else 447 else
429 { 448 {
430 if (playing) 449 audio_stop();
431 audio_stop();
432
433 playing = true;
434 LOGFQUEUE("audio > audio Q_AUDIO_PLAY"); 450 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
435 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset); 451 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
436 } 452 }
@@ -440,8 +456,6 @@ void audio_stop(void)
440{ 456{
441 LOGFQUEUE("audio > audio Q_AUDIO_STOP"); 457 LOGFQUEUE("audio > audio Q_AUDIO_STOP");
442 queue_post(&audio_queue, Q_AUDIO_STOP, 0); 458 queue_post(&audio_queue, Q_AUDIO_STOP, 0);
443 while (playing || audio_codec_loaded)
444 yield();
445} 459}
446 460
447void audio_pause(void) 461void audio_pause(void)
@@ -461,10 +475,21 @@ void audio_next(void)
461 if (global_settings.beep) 475 if (global_settings.beep)
462 pcmbuf_beep(5000, 100, 2500*global_settings.beep); 476 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
463 477
464 /* Should be safe to do outside of thread, that way we get 478 if (playlist_check(ci.new_track + wps_offset + 1))
465 * the instant wps response at least. */ 479 {
466 audio_initiate_track_change(1); 480 LOGFQUEUE("audio > audio Q_AUDIO_SKIP 1");
467 // queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1); 481 queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)1);
482 /* Keep wps fast while our message travels inside deep playback queues. */
483 wps_offset++;
484 track_changed = true;
485 }
486 else
487 {
488 /* No more tracks. */
489 if (global_settings.beep)
490 pcmbuf_beep(3000, 300, 2500*global_settings.beep);
491
492 }
468} 493}
469 494
470void audio_prev(void) 495void audio_prev(void)
@@ -472,8 +497,21 @@ void audio_prev(void)
472 if (global_settings.beep) 497 if (global_settings.beep)
473 pcmbuf_beep(5000, 100, 2500*global_settings.beep); 498 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
474 499
475 audio_initiate_track_change(-1); 500 if (playlist_check(ci.new_track + wps_offset - 1))
476 // queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1); 501 {
502 LOGFQUEUE("audio > audio Q_AUDIO_SKIP -1");
503 queue_post(&audio_queue, Q_AUDIO_SKIP, (void *)-1);
504 /* Keep wps fast while our message travels inside deep playback queues. */
505 wps_offset--;
506 track_changed = true;
507 }
508 else
509 {
510 /* No more tracks. */
511 if (global_settings.beep)
512 pcmbuf_beep(3000, 300, 2500*global_settings.beep);
513
514 }
477} 515}
478 516
479void audio_next_dir(void) 517void audio_next_dir(void)
@@ -598,7 +636,6 @@ void audio_set_crossfade(int enable)
598 636
599 /* Restart playback. */ 637 /* Restart playback. */
600 if (was_playing) { 638 if (was_playing) {
601 playing = true;
602 LOGFQUEUE("audio > audio Q_AUDIO_PLAY"); 639 LOGFQUEUE("audio > audio Q_AUDIO_PLAY");
603 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset); 640 queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset);
604 641
@@ -619,7 +656,11 @@ void audio_preinit(void)
619 playing = false; 656 playing = false;
620 paused = false; 657 paused = false;
621 audio_codec_loaded = false; 658 audio_codec_loaded = false;
659#ifdef PLAYBACK_VOICE
622 voice_is_playing = false; 660 voice_is_playing = false;
661 voice_thread_start = false;
662 voice_codec_loaded = false;
663#endif
623 track_changed = false; 664 track_changed = false;
624 current_fd = -1; 665 current_fd = -1;
625 track_buffer_callback = NULL; 666 track_buffer_callback = NULL;
@@ -647,6 +688,7 @@ void audio_init(void)
647 688
648void voice_init(void) 689void voice_init(void)
649{ 690{
691#ifdef PLAYBACK_VOICE
650 if (!filebuf) 692 if (!filebuf)
651 return; /* Audio buffers not yet set up */ 693 return; /* Audio buffers not yet set up */
652 694
@@ -672,10 +714,12 @@ void voice_init(void)
672 714
673 while (!voice_codec_loaded) 715 while (!voice_codec_loaded)
674 yield(); 716 yield();
717#endif
675} /* voice_init */ 718} /* voice_init */
676 719
677void voice_stop(void) 720void voice_stop(void)
678{ 721{
722#ifdef PLAYBACK_VOICE
679 /* Messages should not be posted to voice codec queue unless it is the 723 /* Messages should not be posted to voice codec queue unless it is the
680 current codec or deadlocks happen. This will be addressed globally soon. 724 current codec or deadlocks happen. This will be addressed globally soon.
681 -- jhMikeS */ 725 -- jhMikeS */
@@ -683,14 +727,14 @@ void voice_stop(void)
683 return; 727 return;
684 728
685 mp3_play_stop(); 729 mp3_play_stop();
686 while (voice_is_playing && !queue_empty(&voice_queue)) 730#endif
687 yield();
688} /* voice_stop */ 731} /* voice_stop */
689 732
690 733
691 734
692/* --- Routines called from multiple threads --- */ 735/* --- Routines called from multiple threads --- */
693 736
737#ifdef PLAYBACK_VOICE
694static void swap_codec(void) 738static void swap_codec(void)
695{ 739{
696 int my_codec = current_codec; 740 int my_codec = current_codec;
@@ -698,31 +742,34 @@ static void swap_codec(void)
698 logf("swapping out codec:%d", my_codec); 742 logf("swapping out codec:%d", my_codec);
699 743
700 /* Save our current IRAM and DRAM */ 744 /* Save our current IRAM and DRAM */
701#ifndef SIMULATOR
702 memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN, 745 memcpy(iram_buf[my_codec], (unsigned char *)CODEC_IRAM_ORIGIN,
703 CODEC_IRAM_SIZE); 746 CODEC_IRAM_SIZE);
704#endif
705 memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE); 747 memcpy(dram_buf[my_codec], codecbuf, CODEC_SIZE);
706 748
749 /* Release my semaphore */
750 mutex_unlock(&mutex_codecthread);
751
752 /* Loop until the other codec has locked and run */
707 do { 753 do {
708 /* Release my semaphore and force a task switch. */ 754 /* Release my semaphore and force a task switch. */
709 mutex_unlock(&mutex_codecthread);
710 yield(); 755 yield();
711 mutex_lock(&mutex_codecthread);
712 /* Loop until the other codec has locked and run */
713 } while (my_codec == current_codec); 756 } while (my_codec == current_codec);
757
758 /* Wait for other codec to unlock */
759 mutex_lock(&mutex_codecthread);
760
761 /* Take control */
714 current_codec = my_codec; 762 current_codec = my_codec;
715 763
716 /* Reload our IRAM and DRAM */ 764 /* Reload our IRAM and DRAM */
717#ifndef SIMULATOR
718 memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec], 765 memcpy((unsigned char *)CODEC_IRAM_ORIGIN, iram_buf[my_codec],
719 CODEC_IRAM_SIZE); 766 CODEC_IRAM_SIZE);
720#endif
721 invalidate_icache(); 767 invalidate_icache();
722 memcpy(codecbuf, dram_buf[my_codec], CODEC_SIZE); 768 memcpy(codecbuf, dram_buf[my_codec], CODEC_SIZE);
723 769
724 logf("resuming codec:%d", my_codec); 770 logf("resuming codec:%d", my_codec);
725} 771}
772#endif
726 773
727static void set_filebuf_watermark(int seconds) 774static void set_filebuf_watermark(int seconds)
728{ 775{
@@ -761,6 +808,8 @@ static const char * get_codec_filename(int enc_spec)
761 808
762/* --- Voice thread --- */ 809/* --- Voice thread --- */
763 810
811#ifdef PLAYBACK_VOICE
812
764#ifdef HAVE_ADJUSTABLE_CPU_FREQ 813#ifdef HAVE_ADJUSTABLE_CPU_FREQ
765static void voice_boost_cpu(bool state) 814static void voice_boost_cpu(bool state)
766{ 815{
@@ -768,8 +817,8 @@ static void voice_boost_cpu(bool state)
768 817
769 if (state != voice_cpu_boosted) 818 if (state != voice_cpu_boosted)
770 { 819 {
771 cpu_boost(state);
772 voice_cpu_boosted = state; 820 voice_cpu_boosted = state;
821 cpu_boost(state);
773 } 822 }
774} 823}
775#endif 824#endif
@@ -795,7 +844,7 @@ static bool voice_pcmbuf_insert_split_callback(
795 while ((dest = pcmbuf_request_voice_buffer(est_output_size, 844 while ((dest = pcmbuf_request_voice_buffer(est_output_size,
796 &output_size, playing)) == NULL) 845 &output_size, playing)) == NULL)
797 { 846 {
798 if (playing) 847 if (playing && audio_codec_loaded)
799 swap_codec(); 848 swap_codec();
800 else 849 else
801 yield(); 850 yield();
@@ -823,7 +872,7 @@ static bool voice_pcmbuf_insert_split_callback(
823 if (playing) 872 if (playing)
824 { 873 {
825 pcmbuf_mix_voice(output_size); 874 pcmbuf_mix_voice(output_size);
826 if (pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) 875 if ((pcmbuf_usage() < 10 || pcmbuf_mix_free() < 30) && audio_codec_loaded)
827 swap_codec(); 876 swap_codec();
828 } 877 }
829 else 878 else
@@ -902,13 +951,19 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
902 case Q_AUDIO_PLAY: 951 case Q_AUDIO_PLAY:
903 LOGFQUEUE("voice < Q_AUDIO_PLAY"); 952 LOGFQUEUE("voice < Q_AUDIO_PLAY");
904 if (playing) 953 if (playing)
905 swap_codec(); 954 {
955 if (audio_codec_loaded)
956 swap_codec();
957 else
958 yield();
959 }
906 break; 960 break;
907 961
908#if defined(HAVE_RECORDING) && !defined(SIMULATOR) 962#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
909 case Q_ENCODER_RECORD: 963 case Q_ENCODER_RECORD:
910 LOGFQUEUE("voice < Q_ENCODER_RECORD"); 964 LOGFQUEUE("voice < Q_ENCODER_RECORD");
911 swap_codec(); 965 if (audio_codec_loaded)
966 swap_codec();
912 break; 967 break;
913#endif 968#endif
914 969
@@ -940,6 +995,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
940 995
941 case Q_VOICE_PLAY: 996 case Q_VOICE_PLAY:
942 LOGFQUEUE("voice < Q_VOICE_PLAY"); 997 LOGFQUEUE("voice < Q_VOICE_PLAY");
998 if (!voice_is_playing)
943 { 999 {
944 struct voice_info *voice_data; 1000 struct voice_info *voice_data;
945 voice_is_playing = true; 1001 voice_is_playing = true;
@@ -949,6 +1005,7 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize)
949 voicebuf = voice_data->buf; 1005 voicebuf = voice_data->buf;
950 voice_getmore = voice_data->callback; 1006 voice_getmore = voice_data->callback;
951 } 1007 }
1008 goto voice_play_clip;
952 1009
953 case SYS_TIMEOUT: 1010 case SYS_TIMEOUT:
954 LOGFQUEUE("voice < SYS_TIMEOUT"); 1011 LOGFQUEUE("voice < SYS_TIMEOUT");
@@ -967,7 +1024,7 @@ voice_play_clip:
967 voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining); 1024 voice_getmore((unsigned char **)&voicebuf, (int *)&voice_remaining);
968 1025
969 /* If this clip is done */ 1026 /* If this clip is done */
970 if (!voice_remaining) 1027 if (voice_remaining == 0)
971 { 1028 {
972 LOGFQUEUE("voice > voice Q_VOICE_STOP"); 1029 LOGFQUEUE("voice > voice Q_VOICE_STOP");
973 queue_post(&voice_queue, Q_VOICE_STOP, 0); 1030 queue_post(&voice_queue, Q_VOICE_STOP, 0);
@@ -1044,6 +1101,7 @@ static void voice_thread(void)
1044 } 1101 }
1045} /* voice_thread */ 1102} /* voice_thread */
1046 1103
1104#endif /* PLAYBACK_VOICE */
1047 1105
1048/* --- Codec thread --- */ 1106/* --- Codec thread --- */
1049 1107
@@ -1097,11 +1155,15 @@ static bool codec_pcmbuf_insert_split_callback(
1097 1155
1098 pcmbuf_write_complete(output_size); 1156 pcmbuf_write_complete(output_size);
1099 1157
1100 if (voice_is_playing && pcm_is_playing() && 1158#ifdef PLAYBACK_VOICE
1101 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80) 1159 if ((voice_is_playing || voice_thread_start)
1160 && pcm_is_playing() && voice_codec_loaded &&
1161 pcmbuf_usage() > 30 && pcmbuf_mix_free() > 80)
1102 { 1162 {
1163 voice_thread_start = false;
1103 swap_codec(); 1164 swap_codec();
1104 } 1165 }
1166#endif
1105 1167
1106 length -= input_size; 1168 length -= input_size;
1107 } 1169 }
@@ -1684,11 +1746,13 @@ static void codec_thread(void)
1684 case Q_CODEC_LOAD_DISK: 1746 case Q_CODEC_LOAD_DISK:
1685 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK"); 1747 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK");
1686 audio_codec_loaded = true; 1748 audio_codec_loaded = true;
1749#ifdef PLAYBACK_VOICE
1687 if (voice_codec_loaded) 1750 if (voice_codec_loaded)
1688 { 1751 {
1689 LOGFQUEUE("codec > voice Q_AUDIO_PLAY"); 1752 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1690 queue_post(&voice_queue, Q_AUDIO_PLAY, 0); 1753 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
1691 } 1754 }
1755#endif
1692 mutex_lock(&mutex_codecthread); 1756 mutex_lock(&mutex_codecthread);
1693 current_codec = CODEC_IDX_AUDIO; 1757 current_codec = CODEC_IDX_AUDIO;
1694 ci.stop_codec = false; 1758 ci.stop_codec = false;
@@ -1711,11 +1775,13 @@ static void codec_thread(void)
1711 } 1775 }
1712 1776
1713 audio_codec_loaded = true; 1777 audio_codec_loaded = true;
1778#ifdef PLAYBACK_VOICE
1714 if (voice_codec_loaded) 1779 if (voice_codec_loaded)
1715 { 1780 {
1716 LOGFQUEUE("codec > voice Q_AUDIO_PLAY"); 1781 LOGFQUEUE("codec > voice Q_AUDIO_PLAY");
1717 queue_post(&voice_queue, Q_AUDIO_PLAY, 0); 1782 queue_post(&voice_queue, Q_AUDIO_PLAY, 0);
1718 } 1783 }
1784#endif
1719 mutex_lock(&mutex_codecthread); 1785 mutex_lock(&mutex_codecthread);
1720 current_codec = CODEC_IDX_AUDIO; 1786 current_codec = CODEC_IDX_AUDIO;
1721 ci.stop_codec = false; 1787 ci.stop_codec = false;
@@ -1729,11 +1795,13 @@ static void codec_thread(void)
1729 case Q_ENCODER_LOAD_DISK: 1795 case Q_ENCODER_LOAD_DISK:
1730 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); 1796 LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK");
1731 audio_codec_loaded = false; 1797 audio_codec_loaded = false;
1798#ifdef PLAYBACK_VOICE
1732 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE) 1799 if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE)
1733 { 1800 {
1734 LOGFQUEUE("codec > voice Q_ENCODER_RECORD"); 1801 LOGFQUEUE("codec > voice Q_ENCODER_RECORD");
1735 queue_post(&voice_queue, Q_ENCODER_RECORD, NULL); 1802 queue_post(&voice_queue, Q_ENCODER_RECORD, NULL);
1736 } 1803 }
1804#endif
1737 mutex_lock(&mutex_codecthread); 1805 mutex_lock(&mutex_codecthread);
1738 current_codec = CODEC_IDX_AUDIO; 1806 current_codec = CODEC_IDX_AUDIO;
1739 ci.stop_codec = false; 1807 ci.stop_codec = false;
@@ -1747,8 +1815,10 @@ static void codec_thread(void)
1747 LOGFQUEUE("codec < SYS_USB_CONNECTED"); 1815 LOGFQUEUE("codec < SYS_USB_CONNECTED");
1748 queue_clear(&codec_queue); 1816 queue_clear(&codec_queue);
1749 usb_acknowledge(SYS_USB_CONNECTED_ACK); 1817 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1750 if (voice_codec_loaded) 1818#ifdef PLAYBACK_VOICE
1819 if(voice_codec_loaded)
1751 swap_codec(); 1820 swap_codec();
1821#endif
1752 usb_wait_for_disconnect(&codec_queue); 1822 usb_wait_for_disconnect(&codec_queue);
1753 break; 1823 break;
1754#endif 1824#endif
@@ -2199,7 +2269,6 @@ static bool audio_loadcodec(bool start_play)
2199 ci.id3 = &cur_ti->id3; 2269 ci.id3 = &cur_ti->id3;
2200 ci.taginfo_ready = &cur_ti->taginfo_ready; 2270 ci.taginfo_ready = &cur_ti->taginfo_ready;
2201 ci.curpos = 0; 2271 ci.curpos = 0;
2202 playing = true;
2203 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); 2272 LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK");
2204 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_fn); 2273 queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_fn);
2205 return true; 2274 return true;
@@ -2260,9 +2329,7 @@ static bool audio_loadcodec(bool start_play)
2260 if (buf_widx >= filebuflen) 2329 if (buf_widx >= filebuflen)
2261 buf_widx -= filebuflen; 2330 buf_widx -= filebuflen;
2262 2331
2263 tracks[track_widx].codecsize += rc; 2332 tracks[track_widx].codecsize += rc;
2264
2265 audio_yield_codecs();
2266 } 2333 }
2267 2334
2268 tracks[track_widx].has_codec = true; 2335 tracks[track_widx].has_codec = true;
@@ -2941,9 +3008,6 @@ static void audio_stop_playback(void)
2941 (playlist_end && ci.stop_codec)?NULL:audio_current_track()); 3008 (playlist_end && ci.stop_codec)?NULL:audio_current_track());
2942 } 3009 }
2943 3010
2944 while (voice_is_playing && !queue_empty(&voice_queue))
2945 yield();
2946
2947 filebufused = 0; 3011 filebufused = 0;
2948 playing = false; 3012 playing = false;
2949 filling = false; 3013 filling = false;
@@ -2968,8 +3032,7 @@ static void audio_play_start(size_t offset)
2968#endif 3032#endif
2969 3033
2970 /* Wait for any previously playing audio to flush - TODO: Not necessary? */ 3034 /* Wait for any previously playing audio to flush - TODO: Not necessary? */
2971 while (audio_codec_loaded) 3035 audio_stop_codec_flush();
2972 audio_stop_codec_flush();
2973 3036
2974 track_changed = true; 3037 track_changed = true;
2975 playlist_end = false; 3038 playlist_end = false;
@@ -2977,7 +3040,8 @@ static void audio_play_start(size_t offset)
2977 playing = true; 3040 playing = true;
2978 ci.new_track = 0; 3041 ci.new_track = 0;
2979 ci.seek_time = 0; 3042 ci.seek_time = 0;
2980 3043 wps_offset = 0;
3044
2981 if (current_fd >= 0) 3045 if (current_fd >= 0)
2982 { 3046 {
2983 close(current_fd); 3047 close(current_fd);
@@ -3057,15 +3121,9 @@ static void audio_new_playlist(void)
3057 3121
3058static void audio_initiate_track_change(long direction) 3122static void audio_initiate_track_change(long direction)
3059{ 3123{
3060 if (playlist_check(direction)) 3124 playlist_end = false;
3061 { 3125 ci.new_track += direction;
3062 playlist_end = false; 3126 wps_offset -= direction;
3063 /* Flag track changed immediately so wps can update instantly.
3064 * No need to wait for disk to spin up or message to travel
3065 * through the deep queues as this info is only for the wps. */
3066 track_changed = true;
3067 ci.new_track += direction;
3068 }
3069} 3127}
3070 3128
3071static void audio_initiate_dir_change(long direction) 3129static void audio_initiate_dir_change(long direction)
@@ -3090,10 +3148,8 @@ static void audio_reset_buffer(void)
3090 /* Allow 2 codecs at end of file buffer */ 3148 /* Allow 2 codecs at end of file buffer */
3091 filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE); 3149 filebuflen -= 2 * (CODEC_IRAM_SIZE + CODEC_SIZE);
3092 3150
3093#ifndef SIMULATOR
3094 iram_buf[0] = &filebuf[filebuflen]; 3151 iram_buf[0] = &filebuf[filebuflen];
3095 iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE]; 3152 iram_buf[1] = &filebuf[filebuflen+CODEC_IRAM_SIZE];
3096#endif
3097 dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2]; 3153 dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2];
3098 dram_buf[1] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE]; 3154 dram_buf[1] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE*2+CODEC_SIZE];
3099 } 3155 }
@@ -3102,10 +3158,8 @@ static void audio_reset_buffer(void)
3102 /* Allow for 1 codec at end of file buffer */ 3158 /* Allow for 1 codec at end of file buffer */
3103 filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE; 3159 filebuflen -= CODEC_IRAM_SIZE + CODEC_SIZE;
3104 3160
3105#ifndef SIMULATOR
3106 iram_buf[0] = &filebuf[filebuflen]; 3161 iram_buf[0] = &filebuf[filebuflen];
3107 iram_buf[1] = NULL; 3162 iram_buf[1] = NULL;
3108#endif
3109 dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE]; 3163 dram_buf[0] = (unsigned char *)&filebuf[filebuflen+CODEC_IRAM_SIZE];
3110 dram_buf[1] = NULL; 3164 dram_buf[1] = NULL;
3111 } 3165 }
@@ -3129,7 +3183,10 @@ static void audio_test_track_changed_event(struct mp3entry *id3)
3129 3183
3130static void audio_playback_init(void) 3184static void audio_playback_init(void)
3131{ 3185{
3186#ifdef PLAYBACK_VOICE
3132 static bool voicetagtrue = true; 3187 static bool voicetagtrue = true;
3188 static struct mp3entry id3_voice;
3189#endif
3133 struct event ev; 3190 struct event ev;
3134 3191
3135 logf("playback api init"); 3192 logf("playback api init");
@@ -3162,6 +3219,7 @@ static void audio_playback_init(void)
3162 ci.discard_codec = codec_discard_codec_callback; 3219 ci.discard_codec = codec_discard_codec_callback;
3163 3220
3164 /* Initialize voice codec api. */ 3221 /* Initialize voice codec api. */
3222#ifdef PLAYBACK_VOICE
3165 memcpy(&ci_voice, &ci, sizeof(struct codec_api)); 3223 memcpy(&ci_voice, &ci, sizeof(struct codec_api));
3166 memset(&id3_voice, 0, sizeof(struct mp3entry)); 3224 memset(&id3_voice, 0, sizeof(struct mp3entry));
3167 ci_voice.read_filebuf = voice_filebuf_callback; 3225 ci_voice.read_filebuf = voice_filebuf_callback;
@@ -3182,6 +3240,7 @@ static void audio_playback_init(void)
3182 ci_voice.id3 = &id3_voice; 3240 ci_voice.id3 = &id3_voice;
3183 id3_voice.frequency = 11200; 3241 id3_voice.frequency = 11200;
3184 id3_voice.length = 1000000L; 3242 id3_voice.length = 1000000L;
3243#endif
3185 3244
3186 codec_thread_p = create_thread(codec_thread, codec_stack, 3245 codec_thread_p = create_thread(codec_thread, codec_stack,
3187 sizeof(codec_stack), 3246 sizeof(codec_stack),
@@ -3288,8 +3347,6 @@ static void audio_thread(void)
3288 case Q_AUDIO_DIR_SKIP: 3347 case Q_AUDIO_DIR_SKIP:
3289 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP"); 3348 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
3290 playlist_end = false; 3349 playlist_end = false;
3291 if (global_settings.beep)
3292 pcmbuf_beep(5000, 100, 2500*global_settings.beep);
3293 audio_initiate_dir_change((long)ev.data); 3350 audio_initiate_dir_change((long)ev.data);
3294 break; 3351 break;
3295 3352