summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/talk.c56
1 files changed, 29 insertions, 27 deletions
diff --git a/apps/talk.c b/apps/talk.c
index a13dd60ec3..47c3e6db58 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -77,6 +77,8 @@ static bool is_playing; /* we're currently playing */
77static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ 77static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */
78static int queue_write; /* write index of queue, by application */ 78static int queue_write; /* write index of queue, by application */
79static int queue_read; /* read index of queue, by ISR context */ 79static int queue_read; /* read index of queue, by ISR context */
80static unsigned char curr_hd[3]; /* current frame header, for re-sync */
81
80 82
81/***************** Private prototypes *****************/ 83/***************** Private prototypes *****************/
82 84
@@ -170,6 +172,9 @@ static void mp3_callback(unsigned char** start, int* size)
170 play_now = MIN(queue[queue_read].len, 0xFFFF); 172 play_now = MIN(queue[queue_read].len, 0xFFFF);
171 *start = queue[queue_read].buf; 173 *start = queue[queue_read].buf;
172 *size = play_now; 174 *size = play_now;
175 curr_hd[0] = *start[1];
176 curr_hd[1] = *start[2];
177 curr_hd[2] = *start[3];
173 queue[queue_read].buf += play_now; 178 queue[queue_read].buf += play_now;
174 queue[queue_read].len -= play_now; 179 queue[queue_read].len -= play_now;
175 } 180 }
@@ -187,17 +192,12 @@ static int shutup(void)
187 unsigned char* pos; 192 unsigned char* pos;
188 unsigned char* search; 193 unsigned char* search;
189 unsigned char* end; 194 unsigned char* end;
190 /* one silent bitswapped mp3 frame (22kHz), without bit reservoir */
191 static const unsigned char silent_frame[] = {
192 0xFF,0xCF,0x08,0x23,0x00,0x00,0x00,0xC0,0x12,0x80,0x01,0x00,0x00,
193 0x32,0x82,0xB2,0xA2,0xCC,0x74,0x9C,0xCC,0xAA,0xAA,0xAA,0xAA,0xAA,
194 };
195
196 mp3_play_pause(false); /* pause */
197 195
198 if (!is_playing) /* has ended anyway */ 196 if (!is_playing) /* has ended anyway */
199 return 0; 197 return 0;
200 198
199 CHCR3 &= ~0x0001; /* disable the DMA */
200
201 /* search next frame boundary and continue up to there */ 201 /* search next frame boundary and continue up to there */
202 pos = search = mp3_get_pos(); 202 pos = search = mp3_get_pos();
203 end = queue[queue_read].buf + queue[queue_read].len; 203 end = queue[queue_read].buf + queue[queue_read].len;
@@ -205,34 +205,32 @@ static int shutup(void)
205 /* Find the next frame boundary */ 205 /* Find the next frame boundary */
206 while (search < end) /* search the remaining data */ 206 while (search < end) /* search the remaining data */
207 { 207 {
208 if (*search++ != 0xFF) /* search for frame sync byte */ 208 if (*search++ != 0xFF) /* quick search for frame sync byte */
209 { 209 continue; /* (this does the majority of the job) */
210 continue;
211 }
212 210
213 /* look at the (bitswapped) 2nd byte of header candidate */ 211 /* look at the (bitswapped) rest of header candidate */
214 if ((*search & 0x07) == 0x07 /* rest of frame sync */ 212 if (search[0] == curr_hd[0] /* do the quicker checks first */
215 && (*search & 0x18) != 0x10 /* version != reserved */ 213 && search[2] == curr_hd[2]
216 && (*search & 0x60) != 0x00) /* layer != reserved */ 214 && (search[1] & 0x30) == (curr_hd[1] & 0x30)) /* sample rate */
217 { 215 {
218 search--; /* back to the sync byte */ 216 search--; /* back to the sync byte */
219 break; /* From looking at the first 2 bytes, this is a header. */ 217 break; /* From looking at it, this is a header. */
220 /* this is not a sufficient condition to find header, 218 /* This is not a sufficient condition to find header, may
221 may give "false alert" (end too early), but a start */ 219 give "false alert" (end too early), but a good start. */
222 } 220 }
223 } 221 }
224 222 queue_write = queue_read + 1; /* reset the queue */
225 queue_write = queue_read; /* reset the queue */ 223 if (queue_write >= QUEUE_SIZE)
226 is_playing = false; 224 queue_write = 0;
225 queue[queue_read].len = 0;
227 226
228 /* play old data until the frame end, to keep the MAS in sync */ 227 /* play old data until the frame end, to keep the MAS in sync */
229 if (search-pos) 228 if (search-pos)
230 queue_clip(pos, search-pos, true); 229 {
230 DTCR3 = search-pos;
231 CHCR3 |= 0x0001; /* re-enable DMA */
232 }
231 233
232 /* If the voice clips contain dependent frames (currently they don't),
233 it may be a good idea to insert an independent dummy frame here. */
234 queue_clip((unsigned char*)silent_frame, sizeof(silent_frame), true);
235
236 return 0; 234 return 0;
237} 235}
238 236
@@ -253,6 +251,9 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue)
253 int size_now = MIN(size, 0xFFFF); /* DMA can do no more */ 251 int size_now = MIN(size, 0xFFFF); /* DMA can do no more */
254 is_playing = true; 252 is_playing = true;
255 mp3_play_data(buf, size_now, mp3_callback); 253 mp3_play_data(buf, size_now, mp3_callback);
254 curr_hd[0] = buf[1];
255 curr_hd[1] = buf[2];
256 curr_hd[2] = buf[3];
256 mp3_play_pause(true); /* kickoff audio */ 257 mp3_play_pause(true); /* kickoff audio */
257 queue[queue_write].buf += size_now; 258 queue[queue_write].buf += size_now;
258 queue[queue_write].len -= size_now; 259 queue[queue_write].len -= size_now;
@@ -458,6 +459,7 @@ int talk_number(int n, bool enqueue)
458 return 0; 459 return 0;
459} 460}
460 461
462/* singular/plural aware saying of a value */
461int talk_value(int n, int unit, bool enqueue) 463int talk_value(int n, int unit, bool enqueue)
462{ 464{
463 int unit_id; 465 int unit_id;