summaryrefslogtreecommitdiff
path: root/apps/talk.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/talk.c')
-rw-r--r--apps/talk.c111
1 files changed, 77 insertions, 34 deletions
diff --git a/apps/talk.c b/apps/talk.c
index 8c0f1f3a07..9fd6fb06ec 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -49,7 +49,7 @@
49 49
50 MASCODEC | MASCODEC | SWCODEC 50 MASCODEC | MASCODEC | SWCODEC
51 (playing) | (stopped) | 51 (playing) | (stopped) |
52 audiobuf-----------+-----------+------------ 52 voicebuf-----------+-----------+------------
53 audio | voice | thumbnail 53 audio | voice | thumbnail
54 |-----------|------------ 54 |-----------|------------
55 | thumbnail | voice 55 | thumbnail | voice
@@ -57,7 +57,7 @@
57 | | filebuf 57 | | filebuf
58 | |------------ 58 | |------------
59 | | audio 59 | | audio
60 audiobufend----------+-----------+------------ 60 voicebufend----------+-----------+------------
61 61
62 SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */ 62 SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */
63 63
@@ -128,6 +128,7 @@ static uint8_t clip_age[QUEUE_SIZE];
128#endif 128#endif
129#endif 129#endif
130 130
131static char* voicebuf; /* root pointer to our buffer */
131static unsigned char* p_thumbnail = NULL; /* buffer for thumbnails */ 132static unsigned char* p_thumbnail = NULL; /* buffer for thumbnails */
132/* Multiple thumbnails can be loaded back-to-back in this buffer. */ 133/* Multiple thumbnails can be loaded back-to-back in this buffer. */
133static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in 134static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in
@@ -281,12 +282,18 @@ static unsigned char* get_clip(long id, long* p_size)
281 282
282 283
283/* load the voice file into the mp3 buffer */ 284/* load the voice file into the mp3 buffer */
284static void load_voicefile(bool probe) 285static void load_voicefile(bool probe, char* buf, size_t bufsize)
285{ 286{
286 int load_size; 287 union voicebuf {
288 unsigned char* buf;
289 struct voicefile* file;
290 };
291 union voicebuf voicebuf;
292
293 int load_size, alloc_size;
287 int got_size; 294 int got_size;
288#ifndef TALK_PARTIAL_LOAD 295#ifndef TALK_PARTIAL_LOAD
289 int file_size; 296 size_t file_size;
290#endif 297#endif
291#ifdef ROCKBOX_LITTLE_ENDIAN 298#ifdef ROCKBOX_LITTLE_ENDIAN
292 int i; 299 int i;
@@ -297,37 +304,43 @@ static void load_voicefile(bool probe)
297 if (filehandle < 0) /* failed to open */ 304 if (filehandle < 0) /* failed to open */
298 goto load_err; 305 goto load_err;
299 306
307 voicebuf.buf = buf;
308 if (!voicebuf.buf)
309 goto load_err;
310
300#ifndef TALK_PARTIAL_LOAD 311#ifndef TALK_PARTIAL_LOAD
301 file_size = filesize(filehandle); 312 file_size = filesize(filehandle);
302 if (file_size > audiobufend - audiobuf) /* won't fit? */ 313 if (file_size > bufsize) /* won't fit? */
303 goto load_err; 314 goto load_err;
304#endif 315#endif
305 316
306#if defined(TALK_PROGRESSIVE_LOAD) || defined(TALK_PARTIAL_LOAD) 317#if defined(TALK_PROGRESSIVE_LOAD) || defined(TALK_PARTIAL_LOAD)
307 /* load only the header for now */ 318 /* load only the header for now */
308 load_size = offsetof(struct voicefile, index); 319 load_size = sizeof(struct voicefile);
309#else /* load the full file */ 320#else /* load the full file */
310 load_size = file_size; 321 load_size = file_size;
311#endif 322#endif
312 323
313#ifdef TALK_PARTIAL_LOAD 324#ifdef TALK_PARTIAL_LOAD
314 if (load_size > audiobufend - audiobuf) /* won't fit? */ 325 if (load_size > bufsize) /* won't fit? */
315 goto load_err; 326 goto load_err;
316#endif 327#endif
317 328
318 got_size = read(filehandle, audiobuf, load_size); 329 got_size = read(filehandle, voicebuf.buf, load_size);
319 if (got_size != load_size /* failure */) 330 if (got_size != load_size /* failure */)
320 goto load_err; 331 goto load_err;
321 332
333 alloc_size = load_size;
334
322#ifdef ROCKBOX_LITTLE_ENDIAN 335#ifdef ROCKBOX_LITTLE_ENDIAN
323 logf("Byte swapping voice file"); 336 logf("Byte swapping voice file");
324 structec_convert(audiobuf, "lllll", 1, true); 337 structec_convert(voicebuf.buf, "lllll", 1, true);
325#endif 338#endif
326 339
327 if (((struct voicefile*)audiobuf)->table /* format check */ 340 /* format check */
328 == offsetof(struct voicefile, index)) 341 if (voicebuf.file->table == sizeof(struct voicefile))
329 { 342 {
330 p_voicefile = (struct voicefile*)audiobuf; 343 p_voicefile = voicebuf.file;
331 344
332 if (p_voicefile->version != VOICE_VERSION || 345 if (p_voicefile->version != VOICE_VERSION ||
333 p_voicefile->target_id != TARGET_ID) 346 p_voicefile->target_id != TARGET_ID)
@@ -337,9 +350,9 @@ static void load_voicefile(bool probe)
337 } 350 }
338#if CONFIG_CODEC != SWCODEC 351#if CONFIG_CODEC != SWCODEC
339 /* MASCODEC: now use audiobuf for voice then thumbnail */ 352 /* MASCODEC: now use audiobuf for voice then thumbnail */
340 p_thumbnail = audiobuf + file_size; 353 p_thumbnail = voicebuf.buf + file_size;
341 p_thumbnail += (long)p_thumbnail % 2; /* 16-bit align */ 354 p_thumbnail += (long)p_thumbnail % 2; /* 16-bit align */
342 size_for_thumbnail = audiobufend - p_thumbnail; 355 size_for_thumbnail = voicebuf.buf + bufsize - p_thumbnail;
343#endif 356#endif
344 } 357 }
345 else 358 else
@@ -351,14 +364,15 @@ static void load_voicefile(bool probe)
351 * sizeof(struct clip_entry); 364 * sizeof(struct clip_entry);
352 365
353#ifdef TALK_PARTIAL_LOAD 366#ifdef TALK_PARTIAL_LOAD
354 if (load_size > audiobufend - audiobuf) /* won't fit? */ 367 if (load_size > bufsize) /* won't fit? */
355 goto load_err; 368 goto load_err;
356#endif 369#endif
357 370
358 got_size = read(filehandle, 371 got_size = read(filehandle, &p_voicefile->index[0], load_size);
359 (unsigned char *) p_voicefile + offsetof(struct voicefile, index), load_size);
360 if (got_size != load_size) /* read error */ 372 if (got_size != load_size) /* read error */
361 goto load_err; 373 goto load_err;
374
375 alloc_size += load_size;
362#else 376#else
363 close(filehandle); 377 close(filehandle);
364 filehandle = -1; 378 filehandle = -1;
@@ -379,6 +393,11 @@ static void load_voicefile(bool probe)
379 p_silence = get_clip(VOICE_PAUSE, &silence_len); 393 p_silence = get_clip(VOICE_PAUSE, &silence_len);
380 } 394 }
381 395
396#ifdef TALK_PARTIAL_LOAD
397 alloc_size += silence_len + QUEUE_SIZE;
398#endif
399 if ((size_t)alloc_size > bufsize)
400 goto load_err;
382 return; 401 return;
383 402
384load_err: 403load_err:
@@ -582,24 +601,31 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
582} 601}
583 602
584 603
585/* common code for talk_init() and talk_buffer_steal() */ 604static void alloc_thumbnail_buf(void)
586static void reset_state(void)
587{ 605{
588 queue_write = queue_read = 0; /* reset the queue */
589 p_voicefile = NULL; /* indicate no voicefile (trashed) */
590#if CONFIG_CODEC == SWCODEC 606#if CONFIG_CODEC == SWCODEC
591 /* Allocate a dedicated thumbnail buffer - once */ 607 /* Allocate a dedicated thumbnail buffer - once */
592 if (p_thumbnail == NULL) 608 if (p_thumbnail == NULL)
593 { 609 {
594 size_for_thumbnail = audiobufend - audiobuf; 610 size_for_thumbnail = buffer_available();
595 if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE) 611 if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE)
596 size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE; 612 size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE;
597 p_thumbnail = buffer_alloc(size_for_thumbnail); 613 p_thumbnail = buffer_alloc(size_for_thumbnail);
598 } 614 }
599#else 615#else
600 /* Just use the audiobuf, without allocating anything */ 616 /* use the audio buffer now, need to release before loading a voice */
601 p_thumbnail = audiobuf; 617 p_thumbnail = voicebuf;
602 size_for_thumbnail = audiobufend - audiobuf; 618#endif
619 thumbnail_buf_used = 0;
620}
621
622/* common code for talk_init() and talk_buffer_steal() */
623static void reset_state(void)
624{
625 queue_write = queue_read = 0; /* reset the queue */
626 p_voicefile = NULL; /* indicate no voicefile (trashed) */
627#if CONFIG_CODEC != SWCODEC
628 p_thumbnail = NULL; /* don't leak buffer_alloc() for swcodec */
603#endif 629#endif
604 630
605#ifdef TALK_PARTIAL_LOAD 631#ifdef TALK_PARTIAL_LOAD
@@ -608,8 +634,8 @@ static void reset_state(void)
608 buffered_id[i] = -1; 634 buffered_id[i] = -1;
609#endif 635#endif
610 636
611 thumbnail_buf_used = 0;
612 p_silence = NULL; /* pause clip not accessible */ 637 p_silence = NULL; /* pause clip not accessible */
638 voicebuf = NULL;
613} 639}
614 640
615 641
@@ -655,12 +681,11 @@ void talk_init(void)
655#endif 681#endif
656 reset_state(); /* use this for most of our inits */ 682 reset_state(); /* use this for most of our inits */
657 683
658 /* test if we can open and if it fits in the audiobuffer */
659 size_t audiobufsz = audiobufend - audiobuf;
660
661#ifdef TALK_PARTIAL_LOAD 684#ifdef TALK_PARTIAL_LOAD
685 size_t bufsize;
686 char* buf = plugin_get_buffer(&bufsize);
662 /* we won't load the full file, we only need the index */ 687 /* we won't load the full file, we only need the index */
663 load_voicefile(true); 688 load_voicefile(true, buf, bufsize);
664 if (!p_voicefile) 689 if (!p_voicefile)
665 return; 690 return;
666 691
@@ -681,6 +706,9 @@ void talk_init(void)
681 p_voicefile = NULL; /* Don't pretend we can load talk clips just yet */ 706 p_voicefile = NULL; /* Don't pretend we can load talk clips just yet */
682#endif 707#endif
683 708
709
710 /* test if we can open and if it fits in the audiobuffer */
711 size_t audiobufsz = buffer_available();
684 if (voicefile_size <= audiobufsz) { 712 if (voicefile_size <= audiobufsz) {
685 has_voicefile = true; 713 has_voicefile = true;
686 } else { 714 } else {
@@ -688,6 +716,7 @@ void talk_init(void)
688 voicefile_size = 0; 716 voicefile_size = 0;
689 } 717 }
690 718
719 alloc_thumbnail_buf();
691 close(filehandle); /* close again, this was just to detect presence */ 720 close(filehandle); /* close again, this was just to detect presence */
692 filehandle = -1; 721 filehandle = -1;
693} 722}
@@ -703,8 +732,22 @@ bool talk_voice_required(void)
703#endif 732#endif
704 733
705/* return size of voice file */ 734/* return size of voice file */
706int talk_get_bufsize(void) 735int talk_get_buffer(void)
736{
737 return voicefile_size;
738}
739
740/* Sets the buffer for the voicefile and returns how many bytes of this
741 * buffer we will use for the voicefile */
742size_t talkbuf_init(char *bufstart)
707{ 743{
744 bool changed = voicebuf != bufstart;
745
746 if (bufstart)
747 voicebuf = bufstart;
748 if (changed) /* must reload voice file */
749 reset_state();
750
708 return voicefile_size; 751 return voicefile_size;
709} 752}
710 753
@@ -741,7 +784,7 @@ int talk_id(int32_t id, bool enqueue)
741#endif 784#endif
742 785
743 if (p_voicefile == NULL && has_voicefile) 786 if (p_voicefile == NULL && has_voicefile)
744 load_voicefile(false); /* reload needed */ 787 load_voicefile(false, voicebuf, voicefile_size); /* reload needed */
745 788
746 if (p_voicefile == NULL) /* still no voices? */ 789 if (p_voicefile == NULL) /* still no voices? */
747 return -1; 790 return -1;
@@ -819,7 +862,7 @@ static int _talk_file(const char* filename,
819#endif 862#endif
820 863
821 if (p_thumbnail == NULL || size_for_thumbnail <= 0) 864 if (p_thumbnail == NULL || size_for_thumbnail <= 0)
822 return -1; 865 alloc_thumbnail_buf();
823 866
824#if CONFIG_CODEC != SWCODEC 867#if CONFIG_CODEC != SWCODEC
825 if(mp3info(&info, filename)) /* use this to find real start */ 868 if(mp3info(&info, filename)) /* use this to find real start */