summaryrefslogtreecommitdiff
path: root/apps/talk.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/talk.c')
-rw-r--r--apps/talk.c761
1 files changed, 430 insertions, 331 deletions
diff --git a/apps/talk.c b/apps/talk.c
index b94dcf18ee..baf854fce3 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -79,8 +79,8 @@ const char* const file_thumbnail_ext = ".talk";
79 79
80#define LOADED_MASK 0x80000000 /* MSB */ 80#define LOADED_MASK 0x80000000 /* MSB */
81 81
82/* swcodec: cap p_thumnail to MAX_THUMNAIL_BUFSIZE since audio keeps playing 82/* swcodec: cap thumbnail buffer to MAX_THUMNAIL_BUFSIZE since audio keeps
83 * while voice 83 * playing while voice
84 * hwcodec: just use whatever is left in the audiobuffer, music 84 * hwcodec: just use whatever is left in the audiobuffer, music
85 * playback is impossible => no cap */ 85 * playback is impossible => no cap */
86#if CONFIG_CODEC == SWCODEC 86#if CONFIG_CODEC == SWCODEC
@@ -95,25 +95,17 @@ struct clip_entry /* one entry of the index table */
95 int size; /* size of the clip */ 95 int size; /* size of the clip */
96}; 96};
97 97
98struct voicefile /* file format of our voice file */ 98struct voicefile_header /* file format of our voice file */
99{ 99{
100 int version; /* version of the voicefile */ 100 int version; /* version of the voicefile */
101 int target_id; /* the rockbox target the file was made for */ 101 int target_id; /* the rockbox target the file was made for */
102 int table; /* offset to index table, (=header size) */ 102 int table; /* offset to index table, (=header size) */
103 int id1_max; /* number of "normal" clips contained in above index */ 103 int id1_max; /* number of "normal" clips contained in above index */
104 int id2_max; /* number of "voice only" clips contained in above index */ 104 int id2_max; /* number of "voice only" clips contained in above index */
105 struct clip_entry index[]; /* followed by the index tables */ 105 /* The header is folled by the index tables (n*struct clip_entry),
106 /* and finally the mp3 clips, not visible here, bitswapped 106 * which is followed by the mp3/speex encoded clip data */
107 for SH based players */
108}; 107};
109 108
110struct queue_entry /* one entry of the internal queue */
111{
112 unsigned char* buf;
113 long len;
114};
115
116
117/***************** Globals *****************/ 109/***************** Globals *****************/
118 110
119#if (CONFIG_CODEC == SWCODEC && MEMORYSIZE <= 2) || defined(ONDIO_SERIES) 111#if (CONFIG_CODEC == SWCODEC && MEMORYSIZE <= 2) || defined(ONDIO_SERIES)
@@ -125,7 +117,6 @@ struct queue_entry /* one entry of the internal queue */
125#endif 117#endif
126 118
127#ifdef TALK_PARTIAL_LOAD 119#ifdef TALK_PARTIAL_LOAD
128static unsigned char *clip_buffer;
129static long max_clipsize; /* size of the biggest clip */ 120static long max_clipsize; /* size of the biggest clip */
130static long buffered_id[QUEUE_SIZE]; /* IDs of the talk clips */ 121static long buffered_id[QUEUE_SIZE]; /* IDs of the talk clips */
131static uint8_t clip_age[QUEUE_SIZE]; 122static uint8_t clip_age[QUEUE_SIZE];
@@ -134,16 +125,13 @@ static uint8_t clip_age[QUEUE_SIZE];
134#endif 125#endif
135#endif 126#endif
136 127
137static char* voicebuf; /* root pointer to our buffer */
138static unsigned char* p_thumbnail = NULL; /* buffer for thumbnails */
139/* Multiple thumbnails can be loaded back-to-back in this buffer. */ 128/* Multiple thumbnails can be loaded back-to-back in this buffer. */
140static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in 129static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in
141 thumbnail buffer */ 130 thumbnail buffer */
142static long size_for_thumbnail; /* total thumbnail buffer size */ 131static long size_for_thumbnail; /* total thumbnail buffer size */
143static struct voicefile* p_voicefile; /* loaded voicefile */ 132static struct voicefile_header voicefile; /* loaded voicefile */
144static bool has_voicefile; /* a voicefile file is present */ 133static bool has_voicefile; /* a voicefile file is present */
145static bool need_shutup; /* is there possibly any voice playing to be shutup */ 134static bool need_shutup; /* is there possibly any voice playing to be shutup */
146static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
147static bool force_enqueue_next; /* enqueue next utterance even if enqueue is false */ 135static bool force_enqueue_next; /* enqueue next utterance even if enqueue is false */
148static int queue_write; /* write index of queue, by application */ 136static int queue_write; /* write index of queue, by application */
149static int queue_read; /* read index of queue, by ISR context */ 137static int queue_read; /* read index of queue, by ISR context */
@@ -158,18 +146,126 @@ static struct mutex queue_mutex SHAREDBSS_ATTR;
158#endif /* CONFIG_CODEC */ 146#endif /* CONFIG_CODEC */
159static int sent; /* how many bytes handed over to playback, owned by ISR */ 147static int sent; /* how many bytes handed over to playback, owned by ISR */
160static unsigned char curr_hd[3]; /* current frame header, for re-sync */ 148static unsigned char curr_hd[3]; /* current frame header, for re-sync */
161static int filehandle = -1; /* global, so we can keep the file open if needed */ 149static int silence_offset; /* VOICE_PAUSE clip, used for termination */
162static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */ 150static long silence_length; /* length of the VOICE_PAUSE clip */
163static long silence_len; /* length of the VOICE_PAUSE clip */ 151static unsigned long lastclip_offset; /* address of latest clip, for silence add */
164static unsigned char* p_lastclip; /* address of latest clip, for silence add */
165static unsigned long voicefile_size = 0; /* size of the loaded voice file */
166static unsigned char last_lang[MAX_FILENAME+1]; /* name of last used lang file (in talk_init) */ 152static unsigned char last_lang[MAX_FILENAME+1]; /* name of last used lang file (in talk_init) */
167static bool talk_initialized; /* true if talk_init has been called */ 153static bool talk_initialized; /* true if talk_init has been called */
154static bool give_buffer_away; /* true if we should give the buffers away in shrink_callback if requested */
168static int talk_temp_disable_count; /* if positive, temporarily disable voice UI (not saved) */ 155static int talk_temp_disable_count; /* if positive, temporarily disable voice UI (not saved) */
156 /* size of the loaded voice file
157 * offsets smaller than this denote a clip from teh voice file,
158 * offsets larger than this denote a thumbnail clip */
159static unsigned long voicefile_size;
160
161struct queue_entry /* one entry of the internal queue */
162{
163 int offset, length;
164};
165
166static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
169 167
170 168
171/***************** Private implementation *****************/ 169/***************** Private implementation *****************/
172 170
171static int thumb_handle;
172static int talk_handle, talk_handle_locked;
173
174#if CONFIG_CODEC != SWCODEC
175
176/* on HWCODEC only voice xor audio can be active at a time */
177static bool check_audio_status(void)
178{
179 if (audio_status()) /* busy, buffer in use */
180 return false;
181 /* ensure playback is given up on the buffer */
182 audio_hard_stop();
183 return true;
184}
185
186/* ISR (mp3_callback()) must not run during moving of the clip buffer,
187 * because the MAS may get out-of-sync */
188static void sync_callback(int handle, bool sync_on)
189{
190 (void) handle;
191 (void) sync_on;
192#if CONFIG_CPU == SH7034
193 if (sync_on)
194 CHCR3 &= ~0x0001; /* disable the DMA (and therefore the interrupt also) */
195 else
196 CHCR3 |= 0x0001; /* re-enable the DMA */
197#endif
198}
199#else
200#define check_audio_status() (true)
201#endif
202
203static int move_callback(int handle, void *current, void *new)
204{
205 (void)handle;(void)current;(void)new;
206 if (UNLIKELY(talk_handle_locked))
207 return BUFLIB_CB_CANNOT_MOVE;
208 return BUFLIB_CB_OK;
209}
210
211static int shrink_callback(int handle, unsigned hints, void *start, size_t old_size)
212{
213 (void)start;(void)old_size;
214 int *h;
215 if (handle == talk_handle)
216 h = &talk_handle;
217 else // if (handle == thumb_handle)
218 h = &thumb_handle;
219
220 if (LIKELY(!talk_handle_locked)
221 && give_buffer_away
222 && (hints & BUFLIB_SHRINK_POS_MASK) == BUFLIB_SHRINK_POS_MASK)
223 {
224 *h = core_free(handle);
225 return BUFLIB_CB_OK;
226 }
227 return BUFLIB_CB_CANNOT_SHRINK;
228}
229
230static struct buflib_callbacks talk_ops = {
231 .move_callback = move_callback,
232#if CONFIG_CODEC != SWCODEC
233 .sync_callback = sync_callback,
234#endif
235 .shrink_callback = shrink_callback,
236};
237
238
239static int index_handle, index_handle_locked;
240static int index_move_callback(int handle, void *current, void *new)
241{
242 (void)handle;(void)current;(void)new;
243 if (UNLIKELY(index_handle_locked))
244 return BUFLIB_CB_CANNOT_MOVE;
245 return BUFLIB_CB_OK;
246}
247
248static int index_shrink_callback(int handle, unsigned hints, void *start, size_t old_size)
249{
250 (void)start;(void)old_size;
251 if (LIKELY(!index_handle_locked)
252 && give_buffer_away
253 && (hints & BUFLIB_SHRINK_POS_MASK) == BUFLIB_SHRINK_POS_MASK)
254 {
255 index_handle = core_free(handle);
256 /* the clip buffer isn't usable without index table */
257 if (LIKELY(!talk_handle_locked))
258 talk_handle = core_free(talk_handle);
259 return BUFLIB_CB_OK;
260 }
261 return BUFLIB_CB_CANNOT_SHRINK;
262}
263
264static struct buflib_callbacks index_ops = {
265 .move_callback = index_move_callback,
266 .shrink_callback = index_shrink_callback,
267};
268
173static int open_voicefile(void) 269static int open_voicefile(void)
174{ 270{
175 char buf[64]; 271 char buf[64];
@@ -188,38 +284,41 @@ static int open_voicefile(void)
188 284
189 285
190/* fetch a clip from the voice file */ 286/* fetch a clip from the voice file */
191static unsigned char* get_clip(long id, long* p_size) 287static int get_clip(long id, long* p_size)
192{ 288{
193 long clipsize; 289 int retval = -1;
194 unsigned char* clipbuf; 290 struct clip_entry* clipbuf;
195 291 size_t clipsize;
292
196 if (id > VOICEONLY_DELIMITER) 293 if (id > VOICEONLY_DELIMITER)
197 { /* voice-only entries use the second part of the table. 294 { /* voice-only entries use the second part of the table.
198 The first string comes after VOICEONLY_DELIMITER so we need to 295 The first string comes after VOICEONLY_DELIMITER so we need to
199 substract VOICEONLY_DELIMITER + 1 */ 296 substract VOICEONLY_DELIMITER + 1 */
200 id -= VOICEONLY_DELIMITER + 1; 297 id -= VOICEONLY_DELIMITER + 1;
201 if (id >= p_voicefile->id2_max) 298 if (id >= voicefile.id2_max)
202 return NULL; /* must be newer than we have */ 299 return -1; /* must be newer than we have */
203 id += p_voicefile->id1_max; /* table 2 is behind table 1 */ 300 id += voicefile.id1_max; /* table 2 is behind table 1 */
204 } 301 }
205 else 302 else
206 { /* normal use of the first table */ 303 { /* normal use of the first table */
207 if (id >= p_voicefile->id1_max) 304 if (id >= voicefile.id1_max)
208 return NULL; /* must be newer than we have */ 305 return -1; /* must be newer than we have */
209 } 306 }
210 307
211 clipsize = p_voicefile->index[id].size; 308 clipbuf = core_get_data(index_handle);
309 clipsize = clipbuf[id].size;
212 if (clipsize == 0) /* clip not included in voicefile */ 310 if (clipsize == 0) /* clip not included in voicefile */
213 return NULL; 311 return -1;
214 312
215#ifndef TALK_PARTIAL_LOAD 313#ifndef TALK_PARTIAL_LOAD
216 clipbuf = (unsigned char *) p_voicefile + p_voicefile->index[id].offset; 314 retval = clipbuf[id].offset;
217#endif
218 315
219#ifdef TALK_PARTIAL_LOAD 316#else
220 if (!(clipsize & LOADED_MASK)) 317 if (!(clipsize & LOADED_MASK))
221 { /* clip needs loading */ 318 { /* clip needs loading */
222 int idx = 0; 319 ssize_t ret;
320 int fd, idx = 0;
321 unsigned char *voicebuf;
223 if (id == VOICE_PAUSE) { 322 if (id == VOICE_PAUSE) {
224 idx = QUEUE_SIZE; /* we keep VOICE_PAUSE loaded */ 323 idx = QUEUE_SIZE; /* we keep VOICE_PAUSE loaded */
225 } else { 324 } else {
@@ -243,18 +342,29 @@ static unsigned char* get_clip(long id, long* p_size)
243 } 342 }
244 clip_age[idx] = 0; /* reset clip's age */ 343 clip_age[idx] = 0; /* reset clip's age */
245 } 344 }
246 clipbuf = clip_buffer + idx * max_clipsize; 345 retval = idx * max_clipsize;
346 fd = open_voicefile();
347 if (fd < 0)
348 return -1; /* open error */
349
350 talk_handle_locked++;
351 voicebuf = core_get_data(talk_handle);
352 clipbuf = core_get_data(index_handle);
353 lseek(fd, clipbuf[id].offset, SEEK_SET);
354 ret = read(fd, &voicebuf[retval], clipsize);
355 close(fd);
356 talk_handle_locked--;
247 357
248 lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET); 358 if (ret < 0 || clipsize != (size_t)ret)
249 if (read(filehandle, clipbuf, clipsize) != clipsize) 359 return -1; /* read error */
250 return NULL; /* read error */
251 360
252 p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */ 361 clipbuf = core_get_data(index_handle);
362 clipbuf[id].size |= LOADED_MASK; /* mark as loaded */
253 363
254 if (id != VOICE_PAUSE) { 364 if (id != VOICE_PAUSE) {
255 if (buffered_id[idx] >= 0) { 365 if (buffered_id[idx] >= 0) {
256 /* mark previously loaded clip as unloaded */ 366 /* mark previously loaded clip as unloaded */
257 p_voicefile->index[buffered_id[idx]].size &= ~LOADED_MASK; 367 clipbuf[buffered_id[idx]].size &= ~LOADED_MASK;
258 } 368 }
259 buffered_id[idx] = id; 369 buffered_id[idx] = id;
260 } 370 }
@@ -262,14 +372,13 @@ static unsigned char* get_clip(long id, long* p_size)
262 else 372 else
263 { /* clip is in memory already */ 373 { /* clip is in memory already */
264 /* Find where it was loaded */ 374 /* Find where it was loaded */
265 clipbuf = clip_buffer;
266 if (id == VOICE_PAUSE) { 375 if (id == VOICE_PAUSE) {
267 clipbuf += QUEUE_SIZE * max_clipsize; 376 retval = QUEUE_SIZE * max_clipsize;
268 } else { 377 } else {
269 int idx; 378 int idx;
270 for (idx=0; idx<QUEUE_SIZE; idx++) 379 for (idx=0; idx<QUEUE_SIZE; idx++)
271 if (buffered_id[idx] == id) { 380 if (buffered_id[idx] == id) {
272 clipbuf += idx * max_clipsize; 381 retval = idx * max_clipsize;
273 clip_age[idx] = 0; /* reset clip's age */ 382 clip_age[idx] = 0; /* reset clip's age */
274 break; 383 break;
275 } 384 }
@@ -279,153 +388,200 @@ static unsigned char* get_clip(long id, long* p_size)
279#endif /* TALK_PARTIAL_LOAD */ 388#endif /* TALK_PARTIAL_LOAD */
280 389
281 *p_size = clipsize; 390 *p_size = clipsize;
282 return clipbuf; 391 return retval;
283} 392}
284 393
285 394static bool load_index_table(int fd, const struct voicefile_header *hdr)
286/* load the voice file into the mp3 buffer */
287static void load_voicefile(bool probe, char* buf, size_t bufsize)
288{ 395{
289 union voicebuf { 396 ssize_t ret;
290 unsigned char* buf; 397 struct clip_entry *buf;
291 struct voicefile* file;
292 };
293 union voicebuf voicebuf;
294 398
295 size_t load_size, alloc_size; 399 if (index_handle > 0) /* nothing to do? */
296 ssize_t got_size; 400 return true;
297#ifdef ROCKBOX_LITTLE_ENDIAN
298 int i;
299#endif
300 401
301 if (!probe) 402 ssize_t alloc_size = (hdr->id1_max + hdr->id2_max) * sizeof(struct clip_entry);
302 filehandle = open_voicefile(); 403 index_handle = core_alloc_ex("voice index", alloc_size, &index_ops);
303 if (filehandle < 0) /* failed to open */ 404 if (index_handle < 0)
304 goto load_err; 405 return false;
305 406
306 voicebuf.buf = buf; 407 index_handle_locked++;
307 if (!voicebuf.buf) 408 buf = core_get_data(index_handle);
308 goto load_err; 409 ret = read(fd, buf, alloc_size);
309 410
310#ifdef TALK_PARTIAL_LOAD 411#ifndef TALK_PARTIAL_LOAD
311 /* load only the header for now */ 412 int clips_offset, num_clips;
312 load_size = sizeof(struct voicefile); 413 /* adjust the offsets of the clips, they are relative to the file
313#else 414 * TALK_PARTUAL_LOAD needs the file offset instead as it loads
314 /* load the entire file */ 415 * the clips later */
315 load_size = filesize(filehandle); 416 clips_offset = hdr->table;
417 num_clips = hdr->id1_max + hdr->id2_max;
418 clips_offset += num_clips * sizeof(struct clip_entry); /* skip index */
419#endif
420 if (ret == alloc_size)
421 for (int i = 0; i < hdr->id1_max + hdr->id2_max; i++)
422 {
423#ifdef ROCKBOX_LITTLE_ENDIAN
424 structec_convert(&buf[i], "ll", 1, true);
316#endif 425#endif
317 if (load_size > bufsize) /* won't fit? */ 426#ifndef TALK_PARTIAL_LOAD
318 goto load_err; 427 buf[i].offset -= clips_offset;
428#endif
429 }
430
431 index_handle_locked--;
319 432
320 got_size = read(filehandle, voicebuf.buf, load_size); 433 if (ret != alloc_size)
321 if (got_size != (ssize_t)load_size /* failure */) 434 index_handle = core_free(index_handle);
322 goto load_err;
323 435
324 alloc_size = load_size; 436 return ret == alloc_size;
437}
438
439static bool load_header(int fd, struct voicefile_header *hdr)
440{
441 ssize_t got_size = read(fd, hdr, sizeof(*hdr));
442 if (got_size != sizeof(*hdr))
443 return false;
325 444
326#ifdef ROCKBOX_LITTLE_ENDIAN 445#ifdef ROCKBOX_LITTLE_ENDIAN
327 logf("Byte swapping voice file"); 446 logf("Byte swapping voice file");
328 structec_convert(voicebuf.buf, "lllll", 1, true); 447 structec_convert(&voicefile, "lllll", 1, true);
329#endif 448#endif
449 return true;
450}
330 451
331 /* format check */ 452#ifndef TALK_PARTIAL_LOAD
332 if (voicebuf.file->table == sizeof(struct voicefile)) 453static bool load_data(int fd, ssize_t size_to_read)
333 { 454{
334 p_voicefile = voicebuf.file; 455 unsigned char *buf;
335 456 ssize_t ret;
336 if (p_voicefile->version != VOICE_VERSION ||
337 p_voicefile->target_id != TARGET_ID)
338 {
339 logf("Incompatible voice file");
340 goto load_err;
341 }
342 }
343 else
344 goto load_err;
345 457
346#ifdef TALK_PARTIAL_LOAD 458 if (size_to_read < 0)
347 /* load the index table, now that we know its size from the header */ 459 return false;
348 load_size = (p_voicefile->id1_max + p_voicefile->id2_max)
349 * sizeof(struct clip_entry);
350 460
351 if (load_size > bufsize) /* won't fit? */ 461 talk_handle = core_alloc_ex("voice data", size_to_read, &talk_ops);
352 goto load_err; 462 if (talk_handle < 0)
463 return false;
353 464
354 got_size = read(filehandle, &p_voicefile->index[0], load_size); 465 talk_handle_locked++;
355 if (got_size != (ssize_t)load_size) /* read error */ 466 buf = core_get_data(talk_handle);
356 goto load_err; 467 ret = read(fd, buf, size_to_read);
468 talk_handle_locked--;
357 469
358 alloc_size += load_size; 470 if (ret != size_to_read)
359#else 471 talk_handle = core_free(talk_handle);
360 close(filehandle);
361 filehandle = -1;
362#endif /* TALK_PARTIAL_LOAD */
363 472
364#ifdef ROCKBOX_LITTLE_ENDIAN 473 return ret == size_to_read;
365 for (i = 0; i < p_voicefile->id1_max + p_voicefile->id2_max; i++) 474}
366 structec_convert(&p_voicefile->index[i], "ll", 1, true);
367#endif 475#endif
368 476
369#ifdef TALK_PARTIAL_LOAD 477static bool alloc_thumbnail_buf(void)
370 clip_buffer = (unsigned char *) p_voicefile + p_voicefile->table; 478{
371 unsigned clips = p_voicefile->id1_max + p_voicefile->id2_max; 479 int handle;
372 clip_buffer += clips * sizeof(struct clip_entry); /* skip index */ 480 size_t size;
481 if (thumb_handle > 0)
482 return true; /* nothing to do? */
483#if CONFIG_CODEC == SWCODEC
484 /* try to allocate the max. first, and take whatever we can get if that
485 * fails */
486 size = MAX_THUMBNAIL_BUFSIZE;
487 handle = core_alloc_ex("voice thumb", MAX_THUMBNAIL_BUFSIZE, &talk_ops);
488 if (handle < 0)
489 {
490 size = core_allocatable();
491 handle = core_alloc_ex("voice thumb", size, &talk_ops);
492 }
493#else
494 /* on HWCODEC, just use the rest of the remaining buffer,
495 * normal playback cannot happen anyway */
496 handle = core_alloc_maximum("voice thumb", &size, &talk_ops);
373#endif 497#endif
374 if (!probe) { 498 thumb_handle = handle;
375 /* make sure to have the silence clip, if available */ 499 size_for_thumbnail = (handle > 0) ? size : 0;
376 p_silence = get_clip(VOICE_PAUSE, &silence_len); 500 return handle > 0;
501}
502
503/* load the voice file into the mp3 buffer */
504static bool load_voicefile_index(int fd)
505{
506 if (fd < 0) /* failed to open */
507 return false;
508
509 /* load the header first */
510 if (!load_header(fd, &voicefile))
511 return false;
512
513 /* format check */
514 if (voicefile.table == sizeof(struct voicefile_header))
515 {
516 if (voicefile.version == VOICE_VERSION &&
517 voicefile.target_id == TARGET_ID)
518 {
519 if (load_index_table(fd, &voicefile))
520 return true;
521 }
377 } 522 }
378 523
524 logf("Incompatible voice file");
525 return false;
526}
527
528static bool load_voicefile_data(int fd, size_t max_size)
529{
379#ifdef TALK_PARTIAL_LOAD 530#ifdef TALK_PARTIAL_LOAD
380 alloc_size += silence_len + QUEUE_SIZE; 531 /* just allocate, populate on an as-needed basis later */
532 talk_handle = core_alloc_ex("voice data", max_size, &talk_ops);
533 if (talk_handle < 0)
534 goto load_err_free;
535#else
536 size_t load_size, clips_size;
537 /* load the entire file into memory */
538 clips_size = (voicefile.id1_max+voicefile.id2_max) * sizeof(struct clip_entry);
539 load_size = max_size - voicefile.table - clips_size;
540 if (!load_data(fd, load_size))
541 goto load_err_free;
381#endif 542#endif
382 543
383 if (alloc_size > bufsize) 544 /* make sure to have the silence clip, if available
384 goto load_err; 545 * return value can be cached globally even for TALK_PARTIAL_LOAD because
546 * the VOICE_PAUSE clip is specially handled */
547 silence_offset = get_clip(VOICE_PAUSE, &silence_length);
385 548
386 /* now move p_thumbnail behind the voice clip buffer */ 549 /* not an error if this fails here, might try again when the
387 p_thumbnail = voicebuf.buf + alloc_size; 550 * actual thumbnails are attempted to be played back */
388 p_thumbnail += (long)p_thumbnail % 2; /* 16-bit align */ 551 alloc_thumbnail_buf();
389 size_for_thumbnail = voicebuf.buf + bufsize - p_thumbnail;
390#if CONFIG_CODEC == SWCODEC
391 size_for_thumbnail = MIN(size_for_thumbnail, MAX_THUMBNAIL_BUFSIZE);
392#endif
393 if (size_for_thumbnail <= 0)
394 p_thumbnail = NULL;
395 552
396 return; 553 return true;
397load_err: 554
398 p_voicefile = NULL; 555load_err_free:
399 has_voicefile = false; /* don't try again */ 556 index_handle = core_free(index_handle);
400 if (filehandle >= 0) 557 return false;
401 {
402 close(filehandle);
403 filehandle = -1;
404 }
405 return;
406} 558}
407 559
408 560
409/* called in ISR context (on HWCODEC) if mp3 data got consumed */ 561/* called in ISR context (on HWCODEC) if mp3 data got consumed */
410static void mp3_callback(const void** start, size_t* size) 562static void mp3_callback(const void** start, size_t* size)
411{ 563{
412 queue[queue_read].len -= sent; /* we completed this */ 564 queue[queue_read].length -= sent; /* we completed this */
413 queue[queue_read].buf += sent; 565 queue[queue_read].offset += sent;
414 566
415 if (queue[queue_read].len > 0) /* current clip not finished? */ 567 if (queue[queue_read].length > 0) /* current clip not finished? */
416 { /* feed the next 64K-1 chunk */ 568 { /* feed the next 64K-1 chunk */
569 int offset;
417#if CONFIG_CODEC != SWCODEC 570#if CONFIG_CODEC != SWCODEC
418 sent = MIN(queue[queue_read].len, 0xFFFF); 571 sent = MIN(queue[queue_read].length, 0xFFFF);
419#else 572#else
420 sent = queue[queue_read].len; 573 sent = queue[queue_read].length;
421#endif 574#endif
422 *start = queue[queue_read].buf; 575 offset = queue[queue_read].offset;
576 if ((unsigned long)offset >= voicefile_size)
577 *start = core_get_data(thumb_handle) + offset - voicefile_size;
578 else
579 *start = core_get_data(talk_handle) + offset;
423 *size = sent; 580 *size = sent;
424 return; 581 return;
425 } 582 }
426 talk_queue_lock(); 583 talk_queue_lock();
427 if(p_thumbnail 584 if(thumb_handle && (unsigned long)queue[queue_read].offset == voicefile_size+thumbnail_buf_used)
428 && queue[queue_read].buf == p_thumbnail +thumbnail_buf_used)
429 thumbnail_buf_used = 0; 585 thumbnail_buf_used = 0;
430 if (sent > 0) /* go to next entry */ 586 if (sent > 0) /* go to next entry */
431 { 587 {
@@ -436,24 +592,31 @@ re_check:
436 592
437 if (QUEUE_LEVEL != 0) /* queue is not empty? */ 593 if (QUEUE_LEVEL != 0) /* queue is not empty? */
438 { /* start next clip */ 594 { /* start next clip */
595 unsigned char *buf;
439#if CONFIG_CODEC != SWCODEC 596#if CONFIG_CODEC != SWCODEC
440 sent = MIN(queue[queue_read].len, 0xFFFF); 597 sent = MIN(queue[queue_read].length, 0xFFFF);
441#else 598#else
442 sent = queue[queue_read].len; 599 sent = queue[queue_read].length;
443#endif 600#endif
444 *start = p_lastclip = queue[queue_read].buf; 601 lastclip_offset = queue[queue_read].offset;
602 /* offsets larger than voicefile_size denote thumbnail clips */
603 if (lastclip_offset >= voicefile_size)
604 buf = core_get_data(thumb_handle) + lastclip_offset - voicefile_size;
605 else
606 buf = core_get_data(talk_handle) + lastclip_offset;
607 *start = buf;
445 *size = sent; 608 *size = sent;
446 curr_hd[0] = p_lastclip[1]; 609 curr_hd[0] = buf[1];
447 curr_hd[1] = p_lastclip[2]; 610 curr_hd[1] = buf[2];
448 curr_hd[2] = p_lastclip[3]; 611 curr_hd[2] = buf[3];
449 } 612 }
450 else if (p_silence != NULL /* silence clip available */ 613 else if (silence_offset > 0 /* silence clip available */
451 && p_lastclip != p_silence /* previous clip wasn't silence */ 614 && lastclip_offset != (unsigned long)silence_offset /* previous clip wasn't silence */
452 && !(p_lastclip >= p_thumbnail /* ..or thumbnail */ 615 && !(lastclip_offset >= voicefile_size /* ..or thumbnail */
453 && p_lastclip < p_thumbnail +size_for_thumbnail)) 616 && lastclip_offset < voicefile_size +size_for_thumbnail))
454 { /* add silence clip when queue runs empty playing a voice clip */ 617 { /* add silence clip when queue runs empty playing a voice clip */
455 queue[queue_write].buf = p_silence; 618 queue[queue_write].offset = silence_offset;
456 queue[queue_write].len = silence_len; 619 queue[queue_write].length = silence_length;
457 queue_write = (queue_write + 1) & QUEUE_MASK; 620 queue_write = (queue_write + 1) & QUEUE_MASK;
458 621
459 goto re_check; 622 goto re_check;
@@ -461,6 +624,7 @@ re_check:
461 else 624 else
462 { 625 {
463 *size = 0; /* end of data */ 626 *size = 0; /* end of data */
627 talk_handle_locked--;
464 } 628 }
465 talk_queue_unlock(); 629 talk_queue_unlock();
466} 630}
@@ -478,6 +642,8 @@ void talk_force_shutup(void)
478 unsigned char* pos; 642 unsigned char* pos;
479 unsigned char* search; 643 unsigned char* search;
480 unsigned char* end; 644 unsigned char* end;
645 int len;
646 unsigned clip_offset;
481 if (QUEUE_LEVEL == 0) /* has ended anyway */ 647 if (QUEUE_LEVEL == 0) /* has ended anyway */
482 return; 648 return;
483 649
@@ -486,13 +652,17 @@ void talk_force_shutup(void)
486#endif /* CONFIG_CPU == SH7034 */ 652#endif /* CONFIG_CPU == SH7034 */
487 /* search next frame boundary and continue up to there */ 653 /* search next frame boundary and continue up to there */
488 pos = search = mp3_get_pos(); 654 pos = search = mp3_get_pos();
489 end = queue[queue_read].buf + queue[queue_read].len; 655 clip_offset = queue[queue_read].offset;
656 if (clip_offset >= voicefile_size)
657 end = core_get_data(thumb_handle) + clip_offset - voicefile_size;
658 else
659 end = core_get_data(talk_handle) + clip_offset;
660 len = queue[queue_read].length;
490 661
491 if (pos >= queue[queue_read].buf 662 if (pos >= end && pos <= (end+len)) /* really our clip? */
492 && pos <= end) /* really our clip? */
493 { /* (for strange reasons this isn't nesessarily the case) */ 663 { /* (for strange reasons this isn't nesessarily the case) */
494 /* find the next frame boundary */ 664 /* find the next frame boundary */
495 while (search < end) /* search the remaining data */ 665 while (search < (end+len)) /* search the remaining data */
496 { 666 {
497 if (*search++ != 0xFF) /* quick search for frame sync byte */ 667 if (*search++ != 0xFF) /* quick search for frame sync byte */
498 continue; /* (this does the majority of the job) */ 668 continue; /* (this does the majority of the job) */
@@ -512,7 +682,7 @@ void talk_force_shutup(void)
512 sent = search-pos; 682 sent = search-pos;
513 683
514 queue_write = (queue_read + 1) & QUEUE_MASK; /* will be empty after next callback */ 684 queue_write = (queue_read + 1) & QUEUE_MASK; /* will be empty after next callback */
515 queue[queue_read].len = sent; /* current one ends after this */ 685 queue[queue_read].length = sent; /* current one ends after this */
516 686
517#if CONFIG_CPU == SH7034 687#if CONFIG_CPU == SH7034
518 DTCR3 = sent; /* let the DMA finish this frame */ 688 DTCR3 = sent; /* let the DMA finish this frame */
@@ -528,6 +698,7 @@ void talk_force_shutup(void)
528 mp3_play_stop(); 698 mp3_play_stop();
529 talk_queue_lock(); 699 talk_queue_lock();
530 queue_write = queue_read = 0; /* reset the queue */ 700 queue_write = queue_read = 0; /* reset the queue */
701 talk_handle_locked = MAX(talk_handle_locked-1, 0);
531 thumbnail_buf_used = 0; 702 thumbnail_buf_used = 0;
532 talk_queue_unlock(); 703 talk_queue_unlock();
533 need_shutup = false; 704 need_shutup = false;
@@ -541,8 +712,9 @@ void talk_shutup(void)
541} 712}
542 713
543/* schedule a clip, at the end or discard the existing queue */ 714/* schedule a clip, at the end or discard the existing queue */
544static void queue_clip(unsigned char* buf, long size, bool enqueue) 715static void queue_clip(unsigned long clip_offset, long size, bool enqueue)
545{ 716{
717 unsigned char *buf;
546 int queue_level; 718 int queue_level;
547 719
548 if (!enqueue) 720 if (!enqueue)
@@ -562,20 +734,25 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
562 734
563 if (queue_level < QUEUE_SIZE - 1) /* space left? */ 735 if (queue_level < QUEUE_SIZE - 1) /* space left? */
564 { 736 {
565 queue[queue_write].buf = buf; /* populate an entry */ 737 queue[queue_write].offset = clip_offset; /* populate an entry */
566 queue[queue_write].len = size; 738 queue[queue_write].length = size;
567 queue_write = (queue_write + 1) & QUEUE_MASK; 739 queue_write = (queue_write + 1) & QUEUE_MASK;
568 } 740 }
569 talk_queue_unlock(); 741 talk_queue_unlock();
570 742
571 if (queue_level == 0) 743 if (queue_level == 0)
572 { /* queue was empty, we have to do the initial start */ 744 { /* queue was empty, we have to do the initial start */
573 p_lastclip = buf; 745 lastclip_offset = clip_offset;
574#if CONFIG_CODEC != SWCODEC 746#if CONFIG_CODEC != SWCODEC
575 sent = MIN(size, 0xFFFF); /* DMA can do no more */ 747 sent = MIN(size, 0xFFFF); /* DMA can do no more */
576#else 748#else
577 sent = size; 749 sent = size;
578#endif 750#endif
751 talk_handle_locked++;
752 if (clip_offset >= voicefile_size)
753 buf = core_get_data(thumb_handle) + clip_offset - voicefile_size;
754 else
755 buf = core_get_data(talk_handle) + clip_offset;
579 mp3_play_data(buf, sent, mp3_callback); 756 mp3_play_data(buf, sent, mp3_callback);
580 curr_hd[0] = buf[1]; 757 curr_hd[0] = buf[1];
581 curr_hd[1] = buf[2]; 758 curr_hd[1] = buf[2];
@@ -594,53 +771,11 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue)
594 return; 771 return;
595} 772}
596 773
597static void alloc_thumbnail_buf(void)
598{
599 /* use the audio buffer now, need to release before loading a voice */
600 p_thumbnail = voicebuf;
601#if CONFIG_CODEC == SWCODEC
602 size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE;
603#endif
604 thumbnail_buf_used = 0;
605}
606
607/* common code for talk_init() and talk_buffer_steal() */
608static void reset_state(void)
609{
610 queue_write = queue_read = 0; /* reset the queue */
611 p_voicefile = NULL; /* indicate no voicefile (trashed) */
612 p_thumbnail = NULL; /* no thumbnails either */
613
614#ifdef TALK_PARTIAL_LOAD
615 int i;
616 for(i=0; i<QUEUE_SIZE; i++)
617 buffered_id[i] = -1;
618#endif
619
620 p_silence = NULL; /* pause clip not accessible */
621 voicebuf = NULL; /* voice buffer is gone */
622}
623
624#if CONFIG_CODEC == SWCODEC
625static bool restore_state(void)
626{
627 if (!voicebuf)
628 {
629 size_t size;
630 audio_restore_playback(AUDIO_WANT_VOICE);
631 voicebuf = audio_get_buffer(true, &size);
632 audio_get_buffer(false, &size);
633 }
634
635 return !!voicebuf;
636}
637#endif /* CONFIG_CODEC == SWCODEC */
638
639
640/***************** Public implementation *****************/ 774/***************** Public implementation *****************/
641 775
642void talk_init(void) 776void talk_init(void)
643{ 777{
778 int filehandle;
644 talk_temp_disable_count = 0; 779 talk_temp_disable_count = 0;
645 if (talk_initialized && !strcasecmp(last_lang, global_settings.lang_file)) 780 if (talk_initialized && !strcasecmp(last_lang, global_settings.lang_file))
646 { 781 {
@@ -648,14 +783,6 @@ void talk_init(void)
648 return; 783 return;
649 } 784 }
650 785
651#if defined(TALK_PROGRESSIVE_LOAD) || defined(TALK_PARTIAL_LOAD)
652 if (filehandle >= 0)
653 {
654 close(filehandle);
655 filehandle = -1;
656 }
657#endif
658
659#if CONFIG_CODEC == SWCODEC 786#if CONFIG_CODEC == SWCODEC
660 if(!talk_initialized) 787 if(!talk_initialized)
661 mutex_init(&queue_mutex); 788 mutex_init(&queue_mutex);
@@ -665,138 +792,118 @@ void talk_init(void)
665 strlcpy((char *)last_lang, (char *)global_settings.lang_file, 792 strlcpy((char *)last_lang, (char *)global_settings.lang_file,
666 MAX_FILENAME); 793 MAX_FILENAME);
667 794
795 /* reset some states */
796 queue_write = queue_read = 0; /* reset the queue */
797 memset(&voicefile, 0, sizeof(voicefile));
798
799#ifdef TALK_PARTIAL_LOAD
800 for(int i=0; i<QUEUE_SIZE; i++)
801 buffered_id[i] = -1;
802#endif
803
804 silence_offset = -1; /* pause clip not accessible */
805 voicefile_size = has_voicefile = 0;
806 /* need to free these as their size depends on the voice file, and
807 * this function is called when the talk voice file changes */
808 if (index_handle > 0) index_handle = core_free(index_handle);
809 if (talk_handle > 0) talk_handle = core_free(talk_handle);
810 /* don't free thumb handle, it doesn't depend on the actual voice file
811 * and so we can re-use it if it's already allocated in any event */
812
668 filehandle = open_voicefile(); 813 filehandle = open_voicefile();
669 if (filehandle < 0) { 814 if (filehandle < 0)
670 has_voicefile = false;
671 voicefile_size = 0;
672 return; 815 return;
673 }
674 816
675 voicefile_size = filesize(filehandle); 817 if (!load_voicefile_index(filehandle))
676 818 goto out;
677 audio_get_buffer(false, NULL); /* Must tell audio to reinitialize */
678 reset_state(); /* use this for most of our inits */
679 819
680#ifdef TALK_PARTIAL_LOAD 820#ifdef TALK_PARTIAL_LOAD
681 size_t bufsize; 821 /* TALK_PARTIAL_LOAD loads the actual clip data later, and not all
682 char* buf = plugin_get_buffer(&bufsize); 822 * at once */
683 /* we won't load the full file, we only need the index */ 823 unsigned num_clips = voicefile.id1_max + voicefile.id2_max;
684 load_voicefile(true, buf, bufsize); 824 struct clip_entry *clips = core_get_data(index_handle);
685 if (!p_voicefile)
686 return;
687
688 unsigned clips = p_voicefile->id1_max + p_voicefile->id2_max;
689 unsigned i;
690 int silence_size = 0; 825 int silence_size = 0;
691 826
692 for(i=0; i<clips; i++) { 827 for(unsigned i=0; i<num_clips; i++) {
693 int size = p_voicefile->index[i].size; 828 int size = clips[i].size;
694 if (size > max_clipsize) 829 if (size > max_clipsize)
695 max_clipsize = size; 830 max_clipsize = size;
696 if (i == VOICE_PAUSE) 831 if (i == VOICE_PAUSE)
697 silence_size = size; 832 silence_size = size;
698 } 833 }
699 834
700 voicefile_size = p_voicefile->table + clips * sizeof(struct clip_entry); 835 voicefile_size = voicefile.table + num_clips * sizeof(struct clip_entry);
701 voicefile_size += max_clipsize * QUEUE_SIZE + silence_size; 836 voicefile_size += max_clipsize * QUEUE_SIZE + silence_size;
702 p_voicefile = NULL; /* Don't pretend we can load talk clips just yet */
703#endif
704
705 837
706 /* test if we can open and if it fits in the audiobuffer */ 838 /* test if we can open and if it fits in the audiobuffer */
707 size_t audiobufsz = audio_buffer_available(); 839 size_t audiobufsz = audio_buffer_available();
708 if (voicefile_size <= audiobufsz) { 840 has_voicefile = audiobufsz >= voicefile_size;
709 has_voicefile = true; 841
710 } else { 842#else
711 has_voicefile = false; 843 /* load the compressed clip data into memory, in its entirety */
844 voicefile_size = filesize(filehandle);
845 if (!load_voicefile_data(filehandle, voicefile_size))
846 {
712 voicefile_size = 0; 847 voicefile_size = 0;
848 goto out;
713 } 849 }
714 850 has_voicefile = true;
715 close(filehandle); /* close again, this was just to detect presence */ 851#endif
716 filehandle = -1;
717 852
718#if CONFIG_CODEC == SWCODEC 853#if CONFIG_CODEC == SWCODEC
719 /* Safe to init voice playback engine now since we now know if talk is 854 /* Safe to init voice playback engine now since we now know if talk is
720 required or not */ 855 required or not */
721 voice_thread_init(); 856 voice_thread_init();
722#endif 857#endif
858
859out:
860 close(filehandle); /* close again, this was just to detect presence */
861 filehandle = -1;
723} 862}
724 863
725#if CONFIG_CODEC == SWCODEC 864#if CONFIG_CODEC == SWCODEC
726/* return if a voice codec is required or not */ 865/* return if a voice codec is required or not */
727bool talk_voice_required(void) 866bool talk_voice_required(void)
728{ 867{
729 return (voicefile_size != 0) /* Voice file is available */ 868 return (has_voicefile) /* Voice file is available */
730 || (global_settings.talk_dir_clip) /* Thumbnail clips are required */ 869 || (global_settings.talk_dir_clip) /* Thumbnail clips are required */
731 || (global_settings.talk_file_clip); 870 || (global_settings.talk_file_clip);
732} 871}
733#endif 872#endif
734 873
735/* return size of voice file */
736static size_t talk_get_buffer_size(void)
737{
738#if CONFIG_CODEC == SWCODEC
739 return voicefile_size + MAX_THUMBNAIL_BUFSIZE;
740#else
741 return audio_buffer_available();
742#endif
743}
744
745/* Sets the buffer for the voicefile and returns how many bytes of this
746 * buffer we will use for the voicefile */
747size_t talkbuf_init(char *bufstart)
748{
749 bool changed = voicebuf != bufstart;
750
751 if (changed) /* must reload voice file */
752 reset_state();
753
754 if (bufstart)
755 voicebuf = bufstart;
756
757 return talk_get_buffer_size();
758}
759
760/* somebody else claims the mp3 buffer, e.g. for regular play/record */ 874/* somebody else claims the mp3 buffer, e.g. for regular play/record */
761void talk_buffer_steal(void) 875void talk_buffer_set_policy(int policy)
762{ 876{
763#if CONFIG_CODEC != SWCODEC 877 switch(policy)
764 mp3_play_stop();
765#endif
766#if defined(TALK_PROGRESSIVE_LOAD) || defined(TALK_PARTIAL_LOAD)
767 if (filehandle >= 0)
768 { 878 {
769 close(filehandle); 879 case TALK_BUFFER_DEFAULT:
770 filehandle = -1; 880 case TALK_BUFFER_HOLD: give_buffer_away = false; break;
881 case TALK_BUFFER_LOOSE: give_buffer_away = true; break;
882 default: DEBUGF("Ignoring unknown policy\n"); break;
771 } 883 }
772#endif
773 reset_state();
774} 884}
775 885
776/* play a voice ID from voicefile */ 886/* play a voice ID from voicefile */
777int talk_id(int32_t id, bool enqueue) 887int talk_id(int32_t id, bool enqueue)
778{ 888{
889 int clip;
779 long clipsize; 890 long clipsize;
780 unsigned char* clipbuf;
781 int32_t unit; 891 int32_t unit;
782 int decimals; 892 int decimals;
783 893
784 if (talk_temp_disable_count > 0) 894 if (talk_temp_disable_count > 0)
785 return -1; /* talking has been disabled */ 895 return -1; /* talking has been disabled */
786#if CONFIG_CODEC == SWCODEC 896 if (!check_audio_status())
787 /* If talk buffer was stolen, it must be restored for voicefile's sake */
788 if (!restore_state())
789 return -1; /* cannot get any space */
790#else
791 if (audio_status()) /* busy, buffer in use */
792 return -1; 897 return -1;
793#endif
794
795 if (p_voicefile == NULL && has_voicefile) /* reload needed? */
796 load_voicefile(false, voicebuf, talk_get_buffer_size());
797 898
798 if (p_voicefile == NULL) /* still no voices? */ 899 if (has_voicefile && (talk_handle <= 0 || index_handle <= 0)) /* reload needed? */
799 return -1; 900 {
901 int fd = open_voicefile();
902 if (fd < 0
903 || !load_voicefile_index(fd)
904 || !load_voicefile_data(fd, voicefile_size))
905 return -1;
906 }
800 907
801 if (id == -1) /* -1 is an indication for silence */ 908 if (id == -1) /* -1 is an indication for silence */
802 return -1; 909 return -1;
@@ -814,8 +921,8 @@ int talk_id(int32_t id, bool enqueue)
814 return 0; /* and stop, end of special case */ 921 return 0; /* and stop, end of special case */
815 } 922 }
816 923
817 clipbuf = get_clip(id, &clipsize); 924 clip = get_clip(id, &clipsize);
818 if (clipbuf == NULL) 925 if (clip < 0)
819 return -1; /* not present */ 926 return -1; /* not present */
820 927
821#ifdef LOGF_ENABLE 928#ifdef LOGF_ENABLE
@@ -825,7 +932,7 @@ int talk_id(int32_t id, bool enqueue)
825 logf("\ntalk_id: Say '%s'\n", str(id)); 932 logf("\ntalk_id: Say '%s'\n", str(id));
826#endif 933#endif
827 934
828 queue_clip(clipbuf, clipsize, enqueue); 935 queue_clip(clip, clipsize, enqueue);
829 936
830 return 0; 937 return 0;
831} 938}
@@ -859,23 +966,18 @@ static int _talk_file(const char* filename,
859 int fd; 966 int fd;
860 int size; 967 int size;
861 int thumb_used; 968 int thumb_used;
969 char *buf;
862#if CONFIG_CODEC != SWCODEC 970#if CONFIG_CODEC != SWCODEC
863 struct mp3entry info; 971 struct mp3entry info;
864#endif 972#endif
865 973
866 if (talk_temp_disable_count > 0) 974 if (talk_temp_disable_count > 0)
867 return -1; /* talking has been disabled */ 975 return -1; /* talking has been disabled */
868#if CONFIG_CODEC == SWCODEC 976 if (!check_audio_status())
869 /* If talk buffer was stolen, it must be restored for thumbnail's sake */ 977 return -1;
870 if (!restore_state())
871 return -1; /* cannot get any space */
872#else
873 if (audio_status()) /* busy, buffer in use */
874 return -1;
875#endif
876 978
877 if (p_thumbnail == NULL || size_for_thumbnail <= 0) 979 if (!alloc_thumbnail_buf())
878 alloc_thumbnail_buf(); 980 return -1;
879 981
880#if CONFIG_CODEC != SWCODEC 982#if CONFIG_CODEC != SWCODEC
881 if(mp3info(&info, filename)) /* use this to find real start */ 983 if(mp3info(&info, filename)) /* use this to find real start */
@@ -905,8 +1007,10 @@ static int _talk_file(const char* filename,
905 lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */ 1007 lseek(fd, info.first_frame_offset, SEEK_SET); /* behind ID data */
906#endif 1008#endif
907 1009
908 size = read(fd, p_thumbnail +thumb_used, 1010 talk_handle_locked++;
909 size_for_thumbnail -thumb_used); 1011 buf = core_get_data(thumb_handle);
1012 size = read(fd, buf+thumb_used, size_for_thumbnail - thumb_used);
1013 talk_handle_locked--;
910 close(fd); 1014 close(fd);
911 1015
912 /* ToDo: find audio, skip ID headers and trailers */ 1016 /* ToDo: find audio, skip ID headers and trailers */
@@ -914,7 +1018,8 @@ static int _talk_file(const char* filename,
914 if (size > 0) /* Don't play missing clips */ 1018 if (size > 0) /* Don't play missing clips */
915 { 1019 {
916#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) 1020#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
917 bitswap(p_thumbnail, size); 1021 /* bitswap doesnt yield() */
1022 bitswap(core_get_data(thumb_handle), size);
918#endif 1023#endif
919 if(prefix_ids) 1024 if(prefix_ids)
920 /* prefix thumbnail by speaking these ids, but only now 1025 /* prefix thumbnail by speaking these ids, but only now
@@ -922,9 +1027,9 @@ static int _talk_file(const char* filename,
922 spoken. */ 1027 spoken. */
923 talk_idarray(prefix_ids, true); 1028 talk_idarray(prefix_ids, true);
924 talk_queue_lock(); 1029 talk_queue_lock();
925 thumbnail_buf_used = thumb_used +size; 1030 thumbnail_buf_used = thumb_used + size;
926 talk_queue_unlock(); 1031 talk_queue_unlock();
927 queue_clip(p_thumbnail +thumb_used, size, true); 1032 queue_clip(voicefile_size + thumb_used, size, true);
928 } 1033 }
929 1034
930 return size; 1035 return size;
@@ -1012,10 +1117,8 @@ int talk_number(long n, bool enqueue)
1012 1117
1013 if (talk_temp_disable_count > 0) 1118 if (talk_temp_disable_count > 0)
1014 return -1; /* talking has been disabled */ 1119 return -1; /* talking has been disabled */
1015#if CONFIG_CODEC != SWCODEC 1120 if (!check_audio_status())
1016 if (audio_status()) /* busy, buffer in use */ 1121 return -1;
1017 return -1;
1018#endif
1019 1122
1020 if (!enqueue) 1123 if (!enqueue)
1021 talk_shutup(); /* cut off all the pending stuff */ 1124 talk_shutup(); /* cut off all the pending stuff */
@@ -1160,10 +1263,8 @@ int talk_value_decimal(long n, int unit, int decimals, bool enqueue)
1160 1263
1161 if (talk_temp_disable_count > 0) 1264 if (talk_temp_disable_count > 0)
1162 return -1; /* talking has been disabled */ 1265 return -1; /* talking has been disabled */
1163#if CONFIG_CODEC != SWCODEC 1266 if (!check_audio_status())
1164 if (audio_status()) /* busy, buffer in use */ 1267 return -1;
1165 return -1;
1166#endif
1167 1268
1168 /* special case for time duration */ 1269 /* special case for time duration */
1169 if (unit == UNIT_TIME) 1270 if (unit == UNIT_TIME)
@@ -1217,10 +1318,8 @@ int talk_spell(const char* spell, bool enqueue)
1217 1318
1218 if (talk_temp_disable_count > 0) 1319 if (talk_temp_disable_count > 0)
1219 return -1; /* talking has been disabled */ 1320 return -1; /* talking has been disabled */
1220#if CONFIG_CODEC != SWCODEC 1321 if (!check_audio_status())
1221 if (audio_status()) /* busy, buffer in use */ 1322 return -1;
1222 return -1;
1223#endif
1224 1323
1225 if (!enqueue) 1324 if (!enqueue)
1226 talk_shutup(); /* cut off all the pending stuff */ 1325 talk_shutup(); /* cut off all the pending stuff */