summaryrefslogtreecommitdiff
path: root/apps/talk.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/talk.c')
-rw-r--r--apps/talk.c194
1 files changed, 88 insertions, 106 deletions
diff --git a/apps/talk.c b/apps/talk.c
index 47410121ba..ede0aff66b 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -80,10 +80,6 @@ const char* const file_thumbnail_ext = ".talk";
80#define MAX_THUMBNAIL_BUFSIZE 0x10000 80#define MAX_THUMBNAIL_BUFSIZE 0x10000
81#endif 81#endif
82 82
83#ifndef SIMULATOR
84extern bool audio_is_initialized;
85#endif
86
87/***************** Data types *****************/ 83/***************** Data types *****************/
88 84
89struct clip_entry /* one entry of the index table */ 85struct clip_entry /* one entry of the index table */
@@ -118,8 +114,7 @@ static long size_for_thumbnail; /* leftover buffer size for it */
118static struct voicefile* p_voicefile; /* loaded voicefile */ 114static struct voicefile* p_voicefile; /* loaded voicefile */
119static bool has_voicefile; /* a voicefile file is present */ 115static bool has_voicefile; /* a voicefile file is present */
120static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ 116static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
121/* enqueue next utterance even if enqueue is false. */ 117static bool force_enqueue_next; /* enqueue next utterance even if enqueue is false */
122static bool force_enqueue_next;
123static int queue_write; /* write index of queue, by application */ 118static int queue_write; /* write index of queue, by application */
124static int queue_read; /* read index of queue, by ISR context */ 119static int queue_read; /* read index of queue, by ISR context */
125static int sent; /* how many bytes handed over to playback, owned by ISR */ 120static int sent; /* how many bytes handed over to playback, owned by ISR */
@@ -131,16 +126,8 @@ static unsigned char* p_lastclip; /* address of latest clip, for silence add */
131static unsigned long voicefile_size = 0; /* size of the loaded voice file */ 126static unsigned long voicefile_size = 0; /* size of the loaded voice file */
132static unsigned char last_lang[MAX_FILENAME+1]; /* name of last used lang file (in talk_init) */ 127static unsigned char last_lang[MAX_FILENAME+1]; /* name of last used lang file (in talk_init) */
133static bool talk_initialized; /* true if talk_init has been called */ 128static bool talk_initialized; /* true if talk_init has been called */
134static int talk_menu_disable; /* if non-zero, temporarily disable voice UI (not saved) */ 129static int talk_temp_disable_count; /* if positive, temporarily disable voice UI (not saved) */
135 130
136/***************** Private prototypes *****************/
137
138static void load_voicefile(void);
139static void mp3_callback(unsigned char** start, size_t* size);
140static int queue_clip(unsigned char* buf, long size, bool enqueue);
141static int open_voicefile(void);
142static unsigned char* get_clip(long id, long* p_size);
143int shutup(void); /* Interrupt voice, as when enqueue is false */
144 131
145/***************** Private implementation *****************/ 132/***************** Private implementation *****************/
146 133
@@ -161,6 +148,50 @@ static int open_voicefile(void)
161} 148}
162 149
163 150
151/* fetch a clip from the voice file */
152static unsigned char* get_clip(long id, long* p_size)
153{
154 long clipsize;
155 unsigned char* clipbuf;
156
157 if (id > VOICEONLY_DELIMITER)
158 { /* voice-only entries use the second part of the table */
159 id -= VOICEONLY_DELIMITER + 1;
160 if (id >= p_voicefile->id2_max)
161 return NULL; /* must be newer than we have */
162 id += p_voicefile->id1_max; /* table 2 is behind table 1 */
163 }
164 else
165 { /* normal use of the first table */
166 if (id >= p_voicefile->id1_max)
167 return NULL; /* must be newer than we have */
168 }
169
170 clipsize = p_voicefile->index[id].size;
171 if (clipsize == 0) /* clip not included in voicefile */
172 return NULL;
173 clipbuf = (unsigned char *) p_voicefile + p_voicefile->index[id].offset;
174
175#ifdef HAVE_MMC /* dynamic loading, on demand */
176 if (!(clipsize & LOADED_MASK))
177 { /* clip used for the first time, needs loading */
178 lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
179 if (read(filehandle, clipbuf, clipsize) != clipsize)
180 return NULL; /* read error */
181
182 p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
183 }
184 else
185 { /* clip is in memory already */
186 clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
187 }
188#endif
189
190 *p_size = clipsize;
191 return clipbuf;
192}
193
194
164/* load the voice file into the mp3 buffer */ 195/* load the voice file into the mp3 buffer */
165static void load_voicefile(void) 196static void load_voicefile(void)
166{ 197{
@@ -252,7 +283,7 @@ load_err:
252/* Are more voice clips queued and waiting? */ 283/* Are more voice clips queued and waiting? */
253bool is_voice_queued() 284bool is_voice_queued()
254{ 285{
255 return !!QUEUE_LEVEL; 286 return (QUEUE_LEVEL != 0);
256} 287}
257 288
258 289
@@ -280,7 +311,7 @@ static void mp3_callback(unsigned char** start, size_t* size)
280 311
281re_check: 312re_check:
282 313
283 if (QUEUE_LEVEL) /* queue is not empty? */ 314 if (QUEUE_LEVEL != 0) /* queue is not empty? */
284 { /* start next clip */ 315 { /* start next clip */
285#if CONFIG_CODEC != SWCODEC 316#if CONFIG_CODEC != SWCODEC
286 sent = MIN(queue[queue_read].len, 0xFFFF); 317 sent = MIN(queue[queue_read].len, 0xFFFF);
@@ -309,26 +340,22 @@ re_check:
309 } 340 }
310} 341}
311 342
343/***************** Public routines *****************/
344
312/* stop the playback and the pending clips */ 345/* stop the playback and the pending clips */
313int do_shutup(void) 346void talk_force_shutup(void)
314{ 347{
348 /* Most of this is MAS only */
315#if CONFIG_CODEC != SWCODEC 349#if CONFIG_CODEC != SWCODEC
316 unsigned char* pos; 350 unsigned char* pos;
317 unsigned char* search; 351 unsigned char* search;
318 unsigned char* end; 352 unsigned char* end;
319#endif
320
321 if (QUEUE_LEVEL == 0) /* has ended anyway */ 353 if (QUEUE_LEVEL == 0) /* has ended anyway */
322 { 354 return;
323#if CONFIG_CODEC == SWCODEC 355
324 mp3_play_stop();
325#endif
326 return 0;
327 }
328#if CONFIG_CODEC != SWCODEC
329#if CONFIG_CPU == SH7034 356#if CONFIG_CPU == SH7034
330 CHCR3 &= ~0x0001; /* disable the DMA (and therefore the interrupt also) */ 357 CHCR3 &= ~0x0001; /* disable the DMA (and therefore the interrupt also) */
331#endif 358#endif /* CONFIG_CPU == SH7034 */
332 /* search next frame boundary and continue up to there */ 359 /* search next frame boundary and continue up to there */
333 pos = search = mp3_get_pos(); 360 pos = search = mp3_get_pos();
334 end = queue[queue_read].buf + queue[queue_read].len; 361 end = queue[queue_read].buf + queue[queue_read].len;
@@ -362,41 +389,38 @@ int do_shutup(void)
362#if CONFIG_CPU == SH7034 389#if CONFIG_CPU == SH7034
363 DTCR3 = sent; /* let the DMA finish this frame */ 390 DTCR3 = sent; /* let the DMA finish this frame */
364 CHCR3 |= 0x0001; /* re-enable DMA */ 391 CHCR3 |= 0x0001; /* re-enable DMA */
365#endif 392#endif /* CONFIG_CPU == SH7034 */
366 return 0; 393 return;
367 } 394 }
368 } 395 }
369#endif 396#endif /* CONFIG_CODEC != SWCODEC */
370 397
371 /* nothing to do, was frame boundary or not our clip */ 398 /* Either SWCODEC, or MAS had nothing to do (was frame boundary or not our clip) */
372 mp3_play_stop(); 399 mp3_play_stop();
373
374 queue_write = queue_read = 0; /* reset the queue */ 400 queue_write = queue_read = 0; /* reset the queue */
375 401 return;
376 return 0;
377} 402}
378 403
379/* Shutup the voice, except if force_enqueue_next is set. */ 404/* Shutup the voice, except if force_enqueue_next is set. */
380int shutup(void) 405void talk_shutup(void)
381{ 406{
382 if (!force_enqueue_next) 407 if (!force_enqueue_next)
383 return do_shutup(); 408 talk_force_shutup();
384 return 0;
385} 409}
386 410
387/* schedule a clip, at the end or discard the existing queue */ 411/* schedule a clip, at the end or discard the existing queue */
388static int queue_clip(unsigned char* buf, long size, bool enqueue) 412static void queue_clip(unsigned char* buf, long size, bool enqueue)
389{ 413{
390 int queue_level; 414 int queue_level;
391 415
392 if (!enqueue) 416 if (!enqueue)
393 shutup(); /* cut off all the pending stuff */ 417 talk_shutup(); /* cut off all the pending stuff */
394 /* Something is being enqueued, force_enqueue_next override is no 418 /* Something is being enqueued, force_enqueue_next override is no
395 longer in effect. */ 419 longer in effect. */
396 force_enqueue_next = false; 420 force_enqueue_next = false;
397 421
398 if (!size) 422 if (!size)
399 return 0; /* safety check */ 423 return; /* safety check */
400#if CONFIG_CPU == SH7034 424#if CONFIG_CPU == SH7034
401 /* disable the DMA temporarily, to be safe of race condition */ 425 /* disable the DMA temporarily, to be safe of race condition */
402 CHCR3 &= ~0x0001; 426 CHCR3 &= ~0x0001;
@@ -431,50 +455,7 @@ static int queue_clip(unsigned char* buf, long size, bool enqueue)
431#endif 455#endif
432 } 456 }
433 457
434 return 0; 458 return;
435}
436
437/* fetch a clip from the voice file */
438static unsigned char* get_clip(long id, long* p_size)
439{
440 long clipsize;
441 unsigned char* clipbuf;
442
443 if (id > VOICEONLY_DELIMITER)
444 { /* voice-only entries use the second part of the table */
445 id -= VOICEONLY_DELIMITER + 1;
446 if (id >= p_voicefile->id2_max)
447 return NULL; /* must be newer than we have */
448 id += p_voicefile->id1_max; /* table 2 is behind table 1 */
449 }
450 else
451 { /* normal use of the first table */
452 if (id >= p_voicefile->id1_max)
453 return NULL; /* must be newer than we have */
454 }
455
456 clipsize = p_voicefile->index[id].size;
457 if (clipsize == 0) /* clip not included in voicefile */
458 return NULL;
459 clipbuf = (unsigned char *) p_voicefile + p_voicefile->index[id].offset;
460
461#ifdef HAVE_MMC /* dynamic loading, on demand */
462 if (!(clipsize & LOADED_MASK))
463 { /* clip used for the first time, needs loading */
464 lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
465 if (read(filehandle, clipbuf, clipsize) != clipsize)
466 return NULL; /* read error */
467
468 p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
469 }
470 else
471 { /* clip is in memory already */
472 clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
473 }
474#endif
475
476 *p_size = clipsize;
477 return clipbuf;
478} 459}
479 460
480 461
@@ -500,11 +481,12 @@ static void reset_state(void)
500 p_silence = NULL; /* pause clip not accessible */ 481 p_silence = NULL; /* pause clip not accessible */
501} 482}
502 483
484
503/***************** Public implementation *****************/ 485/***************** Public implementation *****************/
504 486
505void talk_init(void) 487void talk_init(void)
506{ 488{
507 talk_menu_disable = 0; 489 talk_temp_disable_count = 0;
508 if (talk_initialized && !strcasecmp(last_lang, global_settings.lang_file)) 490 if (talk_initialized && !strcasecmp(last_lang, global_settings.lang_file))
509 { 491 {
510 /* not a new file, nothing to do */ 492 /* not a new file, nothing to do */
@@ -558,7 +540,7 @@ int talk_get_bufsize(void)
558} 540}
559 541
560/* somebody else claims the mp3 buffer, e.g. for regular play/record */ 542/* somebody else claims the mp3 buffer, e.g. for regular play/record */
561int talk_buffer_steal(void) 543void talk_buffer_steal(void)
562{ 544{
563#if CONFIG_CODEC != SWCODEC 545#if CONFIG_CODEC != SWCODEC
564 mp3_play_stop(); 546 mp3_play_stop();
@@ -570,9 +552,7 @@ int talk_buffer_steal(void)
570 filehandle = -1; 552 filehandle = -1;
571 } 553 }
572#endif 554#endif
573 reset_state(); 555 reset_state();;
574
575 return 0;
576} 556}
577 557
578 558
@@ -583,6 +563,8 @@ int talk_id(long id, bool enqueue)
583 unsigned char* clipbuf; 563 unsigned char* clipbuf;
584 int unit; 564 int unit;
585 565
566 if (talk_temp_disable_count > 0)
567 return -1; /* talking has been disabled */
586#if CONFIG_CODEC != SWCODEC 568#if CONFIG_CODEC != SWCODEC
587 if (audio_status()) /* busy, buffer in use */ 569 if (audio_status()) /* busy, buffer in use */
588 return -1; 570 return -1;
@@ -644,6 +626,8 @@ int talk_file(const char* filename, bool enqueue)
644 int size; 626 int size;
645 struct mp3entry info; 627 struct mp3entry info;
646 628
629 if (talk_temp_disable_count > 0)
630 return -1; /* talking has been disabled */
647#if CONFIG_CODEC != SWCODEC 631#if CONFIG_CODEC != SWCODEC
648 if (audio_status()) /* busy, buffer in use */ 632 if (audio_status()) /* busy, buffer in use */
649 return -1; 633 return -1;
@@ -689,13 +673,15 @@ int talk_number(long n, bool enqueue)
689 int level = 2; /* mille count */ 673 int level = 2; /* mille count */
690 long mil = 1000000000; /* highest possible "-illion" */ 674 long mil = 1000000000; /* highest possible "-illion" */
691 675
676 if (talk_temp_disable_count > 0)
677 return -1; /* talking has been disabled */
692#if CONFIG_CODEC != SWCODEC 678#if CONFIG_CODEC != SWCODEC
693 if (audio_status()) /* busy, buffer in use */ 679 if (audio_status()) /* busy, buffer in use */
694 return -1; 680 return -1;
695#endif 681#endif
696 682
697 if (!enqueue) 683 if (!enqueue)
698 shutup(); /* cut off all the pending stuff */ 684 talk_shutup(); /* cut off all the pending stuff */
699 685
700 if (n==0) 686 if (n==0)
701 { /* special case */ 687 { /* special case */
@@ -785,6 +771,8 @@ int talk_value(long n, int unit, bool enqueue)
785 = VOICE_PM_UNITS_PER_TICK, 771 = VOICE_PM_UNITS_PER_TICK,
786 }; 772 };
787 773
774 if (talk_temp_disable_count > 0)
775 return -1; /* talking has been disabled */
788#if CONFIG_CODEC != SWCODEC 776#if CONFIG_CODEC != SWCODEC
789 if (audio_status()) /* busy, buffer in use */ 777 if (audio_status()) /* busy, buffer in use */
790 return -1; 778 return -1;
@@ -819,13 +807,15 @@ int talk_spell(const char* spell, bool enqueue)
819{ 807{
820 char c; /* currently processed char */ 808 char c; /* currently processed char */
821 809
810 if (talk_temp_disable_count > 0)
811 return -1; /* talking has been disabled */
822#if CONFIG_CODEC != SWCODEC 812#if CONFIG_CODEC != SWCODEC
823 if (audio_status()) /* busy, buffer in use */ 813 if (audio_status()) /* busy, buffer in use */
824 return -1; 814 return -1;
825#endif 815#endif
826 816
827 if (!enqueue) 817 if (!enqueue)
828 shutup(); /* cut off all the pending stuff */ 818 talk_shutup(); /* cut off all the pending stuff */
829 819
830 while ((c = *spell++) != '\0') 820 while ((c = *spell++) != '\0')
831 { 821 {
@@ -849,26 +839,18 @@ int talk_spell(const char* spell, bool enqueue)
849 return 0; 839 return 0;
850} 840}
851 841
852bool talk_menus_enabled(void) 842void talk_disable(bool disable)
853{ 843{
854 return (global_settings.talk_menu && talk_menu_disable == 0); 844 if (disable)
855} 845 talk_temp_disable_count++;
856 846 else
857 847 talk_temp_disable_count--;
858void talk_disable_menus(void)
859{
860 talk_menu_disable++;
861}
862
863void talk_enable_menus(void)
864{
865 talk_menu_disable--;
866} 848}
867 849
868#if CONFIG_RTC 850#if CONFIG_RTC
869void talk_date_time(struct tm *tm, bool speak_current_time_string) 851void talk_date_time(struct tm *tm, bool speak_current_time_string)
870{ 852{
871 if(talk_menus_enabled ()) 853 if(global_settings.talk_menu)
872 { 854 {
873 if(speak_current_time_string) 855 if(speak_current_time_string)
874 talk_id(VOICE_CURRENT_TIME, true); 856 talk_id(VOICE_CURRENT_TIME, true);