diff options
author | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-04-20 21:47:07 +0000 |
---|---|---|
committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-04-20 21:47:07 +0000 |
commit | c898a02bb4763e0cf96d99b7964d59f063262ba8 (patch) | |
tree | 33124b94a2f9ab381a7fcfe93b3722f6c49543e4 | |
parent | ffe0da5b25e3bbe6490d2e8fdd17f25277435b3f (diff) | |
download | rockbox-c898a02bb4763e0cf96d99b7964d59f063262ba8.tar.gz rockbox-c898a02bb4763e0cf96d99b7964d59f063262ba8.zip |
fixed the missing first part of voice problem when switching clips, although not very nice (messing with the DMA in application code)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4527 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/talk.c | 56 |
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 */ | |||
77 | static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ | 77 | static struct queue_entry queue[QUEUE_SIZE]; /* queue of scheduled clips */ |
78 | static int queue_write; /* write index of queue, by application */ | 78 | static int queue_write; /* write index of queue, by application */ |
79 | static int queue_read; /* read index of queue, by ISR context */ | 79 | static int queue_read; /* read index of queue, by ISR context */ |
80 | static 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 */ | ||
461 | int talk_value(int n, int unit, bool enqueue) | 463 | int talk_value(int n, int unit, bool enqueue) |
462 | { | 464 | { |
463 | int unit_id; | 465 | int unit_id; |