First try to get a better transition from a cancelled clip to a new one, by maintaining the frame sync. Doesn't seem to have much effect, though.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4425 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/talk.c b/apps/talk.c
index bbc09a6..a543251 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -76,6 +76,12 @@
 static int queue_write; /* write index of queue, by application */
 static int queue_read; /* read index of queue, by ISR context */
 
+/***************** Private prototypes *****************/
+
+static int load_voicefont(void);
+static void mp3_callback(unsigned char** start, int* size);
+static int shutup(void);
+static int queue_clip(unsigned char* buf, int size, bool enqueue);
 
 
 /***************** Private implementation *****************/
@@ -158,14 +164,47 @@
 /* stop the playback and the pending clips, but at frame boundary */
 static int shutup(void)
 {
+    unsigned char* pos;
+    unsigned char* search;
+    unsigned char* end;
+
     mp3_play_pause(false); /* pause */
 
-    /* ToDo: search next frame boundary and continue up to there */
+    if (!is_playing) /* has ended anyway */
+        return 0;
     
-    queue_write = queue_read;
-    is_playing = false;
-    mp3_play_stop();
+    /* search next frame boundary and continue up to there */
+    pos = search = mp3_get_pos();
+    end = queue[queue_read].buf + queue[queue_read].len;
 
+    while (search < end) /* search the remaining data */
+    {
+        if (*search++ != 0xFF) /* search for frame sync byte */
+        {
+            continue;
+        }
+            
+        /* look at the (bitswapped) 2nd byte of header candidate */
+        if ((*search & 0x07) == 0x07  /* rest of frame sync */
+         && (*search & 0x18) != 0x10  /* version != reserved */
+         && (*search & 0x60) != 0x00) /* layer != reserved */
+        {
+            break; /* From looking at the first 2 bytes, this is a header. */
+            /* this is not a sufficient condition to find header,
+               may give "false alert" (end too early), but a start */
+        }
+    }
+
+    queue_write = queue_read; /* reset the queue */
+    is_playing = false;
+
+    /* play old data until the frame end, to keep the MAS in sync */
+    if (search-pos)
+        queue_clip(pos, search-pos, true);
+
+    /* If the voice clips contain dependent frames (currently they don't),
+       it may be a good idea to insert an independent dummy frame here. */
+    
     return 0;
 }
 
diff --git a/firmware/export/mp3_playback.h b/firmware/export/mp3_playback.h
index 15f5347..1eb5dc2 100644
--- a/firmware/export/mp3_playback.h
+++ b/firmware/export/mp3_playback.h
@@ -56,6 +56,7 @@
 long mp3_get_playtime(void);
 void mp3_reset_playtime(void);
 bool mp3_is_playing(void);
+unsigned char* mp3_get_pos(void);
 
 
 #define SOUND_VOLUME 0
diff --git a/firmware/mp3_playback.c b/firmware/mp3_playback.c
index a775ba4..070352c 100644
--- a/firmware/mp3_playback.c
+++ b/firmware/mp3_playback.c
@@ -1092,4 +1092,12 @@
     return playing;
 }
 
+
+/* returns the next byte position which would be transferred */
+unsigned char* mp3_get_pos(void)
+{
+    return (unsigned char*)SAR3;
+}
+
+
 #endif /* #ifndef SIMULATOR */