summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2004-11-17 22:30:38 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2004-11-17 22:30:38 +0000
commit24e6dffa50ce702034185e1df6bdd238b3cf21ce (patch)
treef7f8ebc016a5cabe44643926684506c3d86c5574 /apps
parent605cf4c779f214c8a6f413d401e14a192352e62d (diff)
downloadrockbox-24e6dffa50ce702034185e1df6bdd238b3cf21ce.tar.gz
rockbox-24e6dffa50ce702034185e1df6bdd238b3cf21ce.zip
append the "silence" clip at the end of voice output, this avoids clicks and missing ends especially with low bitrates
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5423 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-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 */
static int sent; /* how many bytes handed over to playback, owned by ISR */
static unsigned char curr_hd[3]; /* current frame header, for re-sync */
static int filehandle; /* global, so the MMC variant can keep the file open */
+static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */
+static int silence_len; /* length of the VOICE_PAUSE clip */
+static bool silence_add; /* flag if trailing silence shall be added */
+static unsigned char* p_lastclip; /* address of latest clip, for silence add */
/***************** Private prototypes *****************/
@@ -94,6 +98,7 @@ static void mp3_callback(unsigned char** start, int* size);
static int shutup(void);
static int queue_clip(unsigned char* buf, int size, bool enqueue);
static int open_voicefile(void);
+static unsigned char* get_clip(int id, int* p_size);
/***************** Private implementation *****************/
@@ -164,6 +169,9 @@ static void load_voicefile(void)
filehandle = -1;
#endif
+ /* make sure to have the silence clip, if available */
+ p_silence = get_clip(VOICE_PAUSE, &silence_len);
+
return;
load_err:
@@ -191,7 +199,7 @@ static void mp3_callback(unsigned char** start, int* size)
*size = sent;
return;
}
- else /* go to next entry */
+ else if (sent > 0) /* go to next entry */
{
queue_read++;
if (queue_read >= QUEUE_SIZE)
@@ -201,12 +209,20 @@ static void mp3_callback(unsigned char** start, int* size)
if (QUEUE_LEVEL) /* queue is not empty? */
{ /* start next clip */
sent = MIN(queue[queue_read].len, 0xFFFF);
- *start = queue[queue_read].buf;
+ *start = p_lastclip = queue[queue_read].buf;
*size = sent;
curr_hd[0] = *start[1];
curr_hd[1] = *start[2];
curr_hd[2] = *start[3];
}
+ else if (silence_add && p_silence != NULL /* want and can add silence */
+ && p_lastclip < p_thumbnail) /* and wasn't playing thumbnail file */
+ { /* add silence clip when queue runs empty playing a voice clip */
+ silence_add = false; /* do this only once */
+ sent = 0; /* not part of "official" data from queue */
+ *start = p_silence;
+ *size = silence_len;
+ }
else
{
*size = 0; /* end of data */
@@ -302,6 +318,8 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue)
if (queue_level == 0)
{ /* queue was empty, we have to do the initial start */
+ silence_add = true;
+ p_lastclip = buf;
sent = MIN(size, 0xFFFF); /* DMA can do no more */
mp3_play_data(buf, sent, mp3_callback);
curr_hd[0] = buf[1];
@@ -317,6 +335,50 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue)
return 0;
}
+/* fetch a clip from the voice file */
+static unsigned char* get_clip(int id, int* p_size)
+{
+ int clipsize;
+ unsigned char* clipbuf;
+
+ if (id > VOICEONLY_DELIMITER)
+ { /* voice-only entries use the second part of the table */
+ id -= VOICEONLY_DELIMITER + 1;
+ if (id >= p_voicefile->id2_max)
+ return NULL; /* must be newer than we have */
+ id += p_voicefile->id1_max; /* table 2 is behind table 1 */
+ }
+ else
+ { /* normal use of the first table */
+ if (id >= p_voicefile->id1_max)
+ return NULL; /* must be newer than we have */
+ }
+
+ clipsize = p_voicefile->index[id].size;
+ if (clipsize == 0) /* clip not included in voicefile */
+ return NULL;
+ clipbuf = mp3buf + p_voicefile->index[id].offset;
+
+#ifdef HAVE_MMC /* dynamic loading, on demand */
+ if (!(clipsize & LOADED_MASK))
+ { /* clip used for the first time, needs loading */
+ lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
+ if (read(filehandle, clipbuf, clipsize) != clipsize)
+ return NULL; /* read error */
+
+ p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
+ }
+ else
+ { /* clip is in memory already */
+ clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
+ }
+#endif
+
+ *p_size = clipsize;
+ return clipbuf;
+}
+
+
/* common code for talk_init() and talk_buffer_steal() */
static void reset_state(void)
{
@@ -324,6 +386,7 @@ static void reset_state(void)
p_voicefile = NULL; /* indicate no voicefile (trashed) */
p_thumbnail = mp3buf; /* whole space for thumbnail */
size_for_thumbnail = mp3end - mp3buf;
+ p_silence = NULL; /* pause clip not accessible */
}
/***************** Public implementation *****************/
@@ -392,38 +455,9 @@ int talk_id(int id, bool enqueue)
return 0; /* and stop, end of special case */
}
- if (id > VOICEONLY_DELIMITER)
- { /* voice-only entries use the second part of the table */
- id -= VOICEONLY_DELIMITER + 1;
- if (id >= p_voicefile->id2_max)
- return -1; /* must be newer than we have */
- id += p_voicefile->id1_max; /* table 2 is behind table 1 */
- }
- else
- { /* normal use of the first table */
- if (id >= p_voicefile->id1_max)
- return -1; /* must be newer than we have */
- }
-
- clipsize = p_voicefile->index[id].size;
- if (clipsize == 0) /* clip not included in voicefile */
- return -1;
- clipbuf = mp3buf + p_voicefile->index[id].offset;
-
-#ifdef HAVE_MMC /* dynamic loading, on demand */
- if (!(clipsize & LOADED_MASK))
- { /* clip used for the first time, needs loading */
- lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
- if (read(filehandle, clipbuf, clipsize) != clipsize)
- return -1; /* read error */
-
- p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
- }
- else
- { /* clip is in memory already */
- clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
- }
-#endif
+ clipbuf = get_clip(id, &clipsize);
+ if (clipbuf == NULL)
+ return -1; /* not present */
queue_clip(clipbuf, clipsize, enqueue);