summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/talk.c102
1 files changed, 68 insertions, 34 deletions
diff --git a/apps/talk.c b/apps/talk.c
index 826b02d6e5..09d1727571 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -85,6 +85,10 @@ static int queue_read; /* read index of queue, by ISR context */
85static int sent; /* how many bytes handed over to playback, owned by ISR */ 85static int sent; /* how many bytes handed over to playback, owned by ISR */
86static unsigned char curr_hd[3]; /* current frame header, for re-sync */ 86static unsigned char curr_hd[3]; /* current frame header, for re-sync */
87static int filehandle; /* global, so the MMC variant can keep the file open */ 87static int filehandle; /* global, so the MMC variant can keep the file open */
88static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */
89static int silence_len; /* length of the VOICE_PAUSE clip */
90static bool silence_add; /* flag if trailing silence shall be added */
91static unsigned char* p_lastclip; /* address of latest clip, for silence add */
88 92
89 93
90/***************** Private prototypes *****************/ 94/***************** Private prototypes *****************/
@@ -94,6 +98,7 @@ static void mp3_callback(unsigned char** start, int* size);
94static int shutup(void); 98static int shutup(void);
95static int queue_clip(unsigned char* buf, int size, bool enqueue); 99static int queue_clip(unsigned char* buf, int size, bool enqueue);
96static int open_voicefile(void); 100static int open_voicefile(void);
101static unsigned char* get_clip(int id, int* p_size);
97 102
98 103
99/***************** Private implementation *****************/ 104/***************** Private implementation *****************/
@@ -164,6 +169,9 @@ static void load_voicefile(void)
164 filehandle = -1; 169 filehandle = -1;
165#endif 170#endif
166 171
172 /* make sure to have the silence clip, if available */
173 p_silence = get_clip(VOICE_PAUSE, &silence_len);
174
167 return; 175 return;
168 176
169load_err: 177load_err:
@@ -191,7 +199,7 @@ static void mp3_callback(unsigned char** start, int* size)
191 *size = sent; 199 *size = sent;
192 return; 200 return;
193 } 201 }
194 else /* go to next entry */ 202 else if (sent > 0) /* go to next entry */
195 { 203 {
196 queue_read++; 204 queue_read++;
197 if (queue_read >= QUEUE_SIZE) 205 if (queue_read >= QUEUE_SIZE)
@@ -201,12 +209,20 @@ static void mp3_callback(unsigned char** start, int* size)
201 if (QUEUE_LEVEL) /* queue is not empty? */ 209 if (QUEUE_LEVEL) /* queue is not empty? */
202 { /* start next clip */ 210 { /* start next clip */
203 sent = MIN(queue[queue_read].len, 0xFFFF); 211 sent = MIN(queue[queue_read].len, 0xFFFF);
204 *start = queue[queue_read].buf; 212 *start = p_lastclip = queue[queue_read].buf;
205 *size = sent; 213 *size = sent;
206 curr_hd[0] = *start[1]; 214 curr_hd[0] = *start[1];
207 curr_hd[1] = *start[2]; 215 curr_hd[1] = *start[2];
208 curr_hd[2] = *start[3]; 216 curr_hd[2] = *start[3];
209 } 217 }
218 else if (silence_add && p_silence != NULL /* want and can add silence */
219 && p_lastclip < p_thumbnail) /* and wasn't playing thumbnail file */
220 { /* add silence clip when queue runs empty playing a voice clip */
221 silence_add = false; /* do this only once */
222 sent = 0; /* not part of "official" data from queue */
223 *start = p_silence;
224 *size = silence_len;
225 }
210 else 226 else
211 { 227 {
212 *size = 0; /* end of data */ 228 *size = 0; /* end of data */
@@ -302,6 +318,8 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue)
302 318
303 if (queue_level == 0) 319 if (queue_level == 0)
304 { /* queue was empty, we have to do the initial start */ 320 { /* queue was empty, we have to do the initial start */
321 silence_add = true;
322 p_lastclip = buf;
305 sent = MIN(size, 0xFFFF); /* DMA can do no more */ 323 sent = MIN(size, 0xFFFF); /* DMA can do no more */
306 mp3_play_data(buf, sent, mp3_callback); 324 mp3_play_data(buf, sent, mp3_callback);
307 curr_hd[0] = buf[1]; 325 curr_hd[0] = buf[1];
@@ -317,6 +335,50 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue)
317 return 0; 335 return 0;
318} 336}
319 337
338/* fetch a clip from the voice file */
339static unsigned char* get_clip(int id, int* p_size)
340{
341 int clipsize;
342 unsigned char* clipbuf;
343
344 if (id > VOICEONLY_DELIMITER)
345 { /* voice-only entries use the second part of the table */
346 id -= VOICEONLY_DELIMITER + 1;
347 if (id >= p_voicefile->id2_max)
348 return NULL; /* must be newer than we have */
349 id += p_voicefile->id1_max; /* table 2 is behind table 1 */
350 }
351 else
352 { /* normal use of the first table */
353 if (id >= p_voicefile->id1_max)
354 return NULL; /* must be newer than we have */
355 }
356
357 clipsize = p_voicefile->index[id].size;
358 if (clipsize == 0) /* clip not included in voicefile */
359 return NULL;
360 clipbuf = mp3buf + p_voicefile->index[id].offset;
361
362#ifdef HAVE_MMC /* dynamic loading, on demand */
363 if (!(clipsize & LOADED_MASK))
364 { /* clip used for the first time, needs loading */
365 lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
366 if (read(filehandle, clipbuf, clipsize) != clipsize)
367 return NULL; /* read error */
368
369 p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
370 }
371 else
372 { /* clip is in memory already */
373 clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
374 }
375#endif
376
377 *p_size = clipsize;
378 return clipbuf;
379}
380
381
320/* common code for talk_init() and talk_buffer_steal() */ 382/* common code for talk_init() and talk_buffer_steal() */
321static void reset_state(void) 383static void reset_state(void)
322{ 384{
@@ -324,6 +386,7 @@ static void reset_state(void)
324 p_voicefile = NULL; /* indicate no voicefile (trashed) */ 386 p_voicefile = NULL; /* indicate no voicefile (trashed) */
325 p_thumbnail = mp3buf; /* whole space for thumbnail */ 387 p_thumbnail = mp3buf; /* whole space for thumbnail */
326 size_for_thumbnail = mp3end - mp3buf; 388 size_for_thumbnail = mp3end - mp3buf;
389 p_silence = NULL; /* pause clip not accessible */
327} 390}
328 391
329/***************** Public implementation *****************/ 392/***************** Public implementation *****************/
@@ -392,38 +455,9 @@ int talk_id(int id, bool enqueue)
392 return 0; /* and stop, end of special case */ 455 return 0; /* and stop, end of special case */
393 } 456 }
394 457
395 if (id > VOICEONLY_DELIMITER) 458 clipbuf = get_clip(id, &clipsize);
396 { /* voice-only entries use the second part of the table */ 459 if (clipbuf == NULL)
397 id -= VOICEONLY_DELIMITER + 1; 460 return -1; /* not present */
398 if (id >= p_voicefile->id2_max)
399 return -1; /* must be newer than we have */
400 id += p_voicefile->id1_max; /* table 2 is behind table 1 */
401 }
402 else
403 { /* normal use of the first table */
404 if (id >= p_voicefile->id1_max)
405 return -1; /* must be newer than we have */
406 }
407
408 clipsize = p_voicefile->index[id].size;
409 if (clipsize == 0) /* clip not included in voicefile */
410 return -1;
411 clipbuf = mp3buf + p_voicefile->index[id].offset;
412
413#ifdef HAVE_MMC /* dynamic loading, on demand */
414 if (!(clipsize & LOADED_MASK))
415 { /* clip used for the first time, needs loading */
416 lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
417 if (read(filehandle, clipbuf, clipsize) != clipsize)
418 return -1; /* read error */
419
420 p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
421 }
422 else
423 { /* clip is in memory already */
424 clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
425 }
426#endif
427 461
428 queue_clip(clipbuf, clipsize, enqueue); 462 queue_clip(clipbuf, clipsize, enqueue);
429 463