diff options
Diffstat (limited to 'apps/talk.c')
-rw-r--r-- | apps/talk.c | 111 |
1 files changed, 106 insertions, 5 deletions
diff --git a/apps/talk.c b/apps/talk.c index a896ca3a1a..b417046a61 100644 --- a/apps/talk.c +++ b/apps/talk.c | |||
@@ -32,7 +32,11 @@ | |||
32 | #include "lang.h" | 32 | #include "lang.h" |
33 | #include "talk.h" | 33 | #include "talk.h" |
34 | #include "id3.h" | 34 | #include "id3.h" |
35 | #include "logf.h" | ||
35 | #include "bitswap.h" | 36 | #include "bitswap.h" |
37 | #if CONFIG_HWCODEC == MASNONE | ||
38 | #include "playback.h" | ||
39 | #endif | ||
36 | 40 | ||
37 | /***************** Constants *****************/ | 41 | /***************** Constants *****************/ |
38 | 42 | ||
@@ -88,6 +92,7 @@ static int filehandle; /* global, so the MMC variant can keep the file open */ | |||
88 | static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */ | 92 | static unsigned char* p_silence; /* VOICE_PAUSE clip, used for termination */ |
89 | static long silence_len; /* length of the VOICE_PAUSE clip */ | 93 | static long silence_len; /* length of the VOICE_PAUSE clip */ |
90 | static unsigned char* p_lastclip; /* address of latest clip, for silence add */ | 94 | static unsigned char* p_lastclip; /* address of latest clip, for silence add */ |
95 | static unsigned long voicefile_size = 0; /* size of the loaded voice file */ | ||
91 | 96 | ||
92 | 97 | ||
93 | /***************** Private prototypes *****************/ | 98 | /***************** Private prototypes *****************/ |
@@ -114,10 +119,28 @@ static int open_voicefile(void) | |||
114 | } | 119 | } |
115 | 120 | ||
116 | snprintf(buf, sizeof(buf), ROCKBOX_DIR LANG_DIR "/%s.voice", p_lang); | 121 | snprintf(buf, sizeof(buf), ROCKBOX_DIR LANG_DIR "/%s.voice", p_lang); |
117 | 122 | ||
118 | return open(buf, O_RDONLY); | 123 | return open(buf, O_RDONLY); |
119 | } | 124 | } |
120 | 125 | ||
126 | int talk_get_bufsize(void) | ||
127 | { | ||
128 | return voicefile_size; | ||
129 | } | ||
130 | |||
131 | #ifdef SIMULATOR | ||
132 | static unsigned short BSWAP16(unsigned short value) | ||
133 | { | ||
134 | return (value >> 8) | (value << 8); | ||
135 | } | ||
136 | |||
137 | static unsigned long BSWAP32(unsigned long value) | ||
138 | { | ||
139 | unsigned long hi = BSWAP16(value >> 16); | ||
140 | unsigned long lo = BSWAP16(value & 0xffff); | ||
141 | return (lo << 16) | hi; | ||
142 | } | ||
143 | #endif | ||
121 | 144 | ||
122 | /* load the voice file into the mp3 buffer */ | 145 | /* load the voice file into the mp3 buffer */ |
123 | static void load_voicefile(void) | 146 | static void load_voicefile(void) |
@@ -125,6 +148,10 @@ static void load_voicefile(void) | |||
125 | int load_size; | 148 | int load_size; |
126 | int got_size; | 149 | int got_size; |
127 | int file_size; | 150 | int file_size; |
151 | #if CONFIG_HWCODEC == MASNONE | ||
152 | int length, i; | ||
153 | unsigned char *buf, temp; | ||
154 | #endif | ||
128 | 155 | ||
129 | filehandle = open_voicefile(); | 156 | filehandle = open_voicefile(); |
130 | if (filehandle < 0) /* failed to open */ | 157 | if (filehandle < 0) /* failed to open */ |
@@ -141,8 +168,20 @@ static void load_voicefile(void) | |||
141 | #endif | 168 | #endif |
142 | 169 | ||
143 | got_size = read(filehandle, audiobuf, load_size); | 170 | got_size = read(filehandle, audiobuf, load_size); |
144 | if (got_size == load_size /* success */ | 171 | if (got_size != load_size /* failure */) |
145 | && ((struct voicefile*)audiobuf)->table /* format check */ | 172 | goto load_err; |
173 | |||
174 | #ifdef SIMULATOR | ||
175 | logf("Byte swapping voice file"); | ||
176 | p_voicefile = (struct voicefile*)audiobuf; | ||
177 | p_voicefile->version = BSWAP32(p_voicefile->version); | ||
178 | p_voicefile->table = BSWAP32(p_voicefile->table); | ||
179 | p_voicefile->id1_max = BSWAP32(p_voicefile->id1_max); | ||
180 | p_voicefile->id2_max = BSWAP32(p_voicefile->id2_max); | ||
181 | p_voicefile = NULL; | ||
182 | #endif | ||
183 | |||
184 | if (((struct voicefile*)audiobuf)->table /* format check */ | ||
146 | == offsetof(struct voicefile, index)) | 185 | == offsetof(struct voicefile, index)) |
147 | { | 186 | { |
148 | p_voicefile = (struct voicefile*)audiobuf; | 187 | p_voicefile = (struct voicefile*)audiobuf; |
@@ -155,7 +194,42 @@ static void load_voicefile(void) | |||
155 | else | 194 | else |
156 | goto load_err; | 195 | goto load_err; |
157 | 196 | ||
158 | #ifdef HAVE_MMC | 197 | #ifdef SIMULATOR |
198 | for (i = 0; i < p_voicefile->id1_max + p_voicefile->id2_max; i++) | ||
199 | { | ||
200 | struct clip_entry *ce; | ||
201 | ce = &p_voicefile->index[i]; | ||
202 | ce->offset = BSWAP32(ce->offset); | ||
203 | ce->size = BSWAP32(ce->size); | ||
204 | } | ||
205 | #endif | ||
206 | |||
207 | /* Do a bitswap as necessary. */ | ||
208 | #if CONFIG_HWCODEC == MASNONE | ||
209 | logf("Bitswapping voice file."); | ||
210 | cpu_boost(true); | ||
211 | buf = (unsigned char *)(&p_voicefile->index) + | ||
212 | (p_voicefile->id1_max + p_voicefile->id2_max) * sizeof(struct clip_entry); | ||
213 | length = file_size - offsetof(struct voicefile, index) - | ||
214 | (p_voicefile->id1_max - p_voicefile->id2_max) * sizeof(struct clip_entry); | ||
215 | |||
216 | for (i = 0; i < length; i++) | ||
217 | { | ||
218 | temp = buf[i]; | ||
219 | buf[i] = ((temp >> 7) & 0x01) | ||
220 | | ((temp >> 5) & 0x02) | ||
221 | | ((temp >> 3) & 0x04) | ||
222 | | ((temp >> 1) & 0x08) | ||
223 | | ((temp << 1) & 0x10) | ||
224 | | ((temp << 3) & 0x20) | ||
225 | | ((temp << 5) & 0x40) | ||
226 | | ((temp << 7) & 0x80); | ||
227 | } | ||
228 | cpu_boost(false); | ||
229 | |||
230 | #endif | ||
231 | |||
232 | #ifdef HAVE_MMC | ||
159 | /* load the index table, now that we know its size from the header */ | 233 | /* load the index table, now that we know its size from the header */ |
160 | load_size = (p_voicefile->id1_max + p_voicefile->id2_max) | 234 | load_size = (p_voicefile->id1_max + p_voicefile->id2_max) |
161 | * sizeof(struct clip_entry); | 235 | * sizeof(struct clip_entry); |
@@ -193,7 +267,11 @@ static void mp3_callback(unsigned char** start, int* size) | |||
193 | 267 | ||
194 | if (queue[queue_read].len > 0) /* current clip not finished? */ | 268 | if (queue[queue_read].len > 0) /* current clip not finished? */ |
195 | { /* feed the next 64K-1 chunk */ | 269 | { /* feed the next 64K-1 chunk */ |
270 | #if CONFIG_HWCODEC != MASNONE | ||
196 | sent = MIN(queue[queue_read].len, 0xFFFF); | 271 | sent = MIN(queue[queue_read].len, 0xFFFF); |
272 | #else | ||
273 | sent = queue[queue_read].len; | ||
274 | #endif | ||
197 | *start = queue[queue_read].buf; | 275 | *start = queue[queue_read].buf; |
198 | *size = sent; | 276 | *size = sent; |
199 | return; | 277 | return; |
@@ -207,7 +285,11 @@ re_check: | |||
207 | 285 | ||
208 | if (QUEUE_LEVEL) /* queue is not empty? */ | 286 | if (QUEUE_LEVEL) /* queue is not empty? */ |
209 | { /* start next clip */ | 287 | { /* start next clip */ |
288 | #if CONFIG_HWCODEC != MASNONE | ||
210 | sent = MIN(queue[queue_read].len, 0xFFFF); | 289 | sent = MIN(queue[queue_read].len, 0xFFFF); |
290 | #else | ||
291 | sent = queue[queue_read].len; | ||
292 | #endif | ||
211 | *start = p_lastclip = queue[queue_read].buf; | 293 | *start = p_lastclip = queue[queue_read].buf; |
212 | *size = sent; | 294 | *size = sent; |
213 | curr_hd[0] = p_lastclip[1]; | 295 | curr_hd[0] = p_lastclip[1]; |
@@ -286,7 +368,7 @@ static int shutup(void) | |||
286 | /* nothing to do, was frame boundary or not our clip */ | 368 | /* nothing to do, was frame boundary or not our clip */ |
287 | mp3_play_stop(); | 369 | mp3_play_stop(); |
288 | queue_write = queue_read = 0; /* reset the queue */ | 370 | queue_write = queue_read = 0; /* reset the queue */ |
289 | 371 | ||
290 | return 0; | 372 | return 0; |
291 | } | 373 | } |
292 | 374 | ||
@@ -317,7 +399,11 @@ static int queue_clip(unsigned char* buf, long size, bool enqueue) | |||
317 | if (queue_level == 0) | 399 | if (queue_level == 0) |
318 | { /* queue was empty, we have to do the initial start */ | 400 | { /* queue was empty, we have to do the initial start */ |
319 | p_lastclip = buf; | 401 | p_lastclip = buf; |
402 | #if CONFIG_HWCODEC != MASNONE | ||
320 | sent = MIN(size, 0xFFFF); /* DMA can do no more */ | 403 | sent = MIN(size, 0xFFFF); /* DMA can do no more */ |
404 | #else | ||
405 | sent = size; | ||
406 | #endif | ||
321 | mp3_play_data(buf, sent, mp3_callback); | 407 | mp3_play_data(buf, sent, mp3_callback); |
322 | curr_hd[0] = buf[1]; | 408 | curr_hd[0] = buf[1]; |
323 | curr_hd[1] = buf[2]; | 409 | curr_hd[1] = buf[2]; |
@@ -400,12 +486,19 @@ void talk_init(void) | |||
400 | #else | 486 | #else |
401 | filehandle = open_voicefile(); | 487 | filehandle = open_voicefile(); |
402 | has_voicefile = (filehandle >= 0); /* test if we can open it */ | 488 | has_voicefile = (filehandle >= 0); /* test if we can open it */ |
489 | voicefile_size = 0; | ||
490 | |||
403 | if (has_voicefile) | 491 | if (has_voicefile) |
404 | { | 492 | { |
493 | voicefile_size = filesize(filehandle); | ||
494 | #if CONFIG_HWCODEC == MASNONE | ||
495 | voice_init(); | ||
496 | #endif | ||
405 | close(filehandle); /* close again, this was just to detect presence */ | 497 | close(filehandle); /* close again, this was just to detect presence */ |
406 | filehandle = -1; | 498 | filehandle = -1; |
407 | } | 499 | } |
408 | #endif | 500 | #endif |
501 | |||
409 | } | 502 | } |
410 | 503 | ||
411 | 504 | ||
@@ -432,8 +525,10 @@ int talk_id(long id, bool enqueue) | |||
432 | unsigned char* clipbuf; | 525 | unsigned char* clipbuf; |
433 | int unit; | 526 | int unit; |
434 | 527 | ||
528 | #if CONFIG_HWCODEC != MASNONE | ||
435 | if (audio_status()) /* busy, buffer in use */ | 529 | if (audio_status()) /* busy, buffer in use */ |
436 | return -1; | 530 | return -1; |
531 | #endif | ||
437 | 532 | ||
438 | if (p_voicefile == NULL && has_voicefile) | 533 | if (p_voicefile == NULL && has_voicefile) |
439 | load_voicefile(); /* reload needed */ | 534 | load_voicefile(); /* reload needed */ |
@@ -514,8 +609,10 @@ int talk_number(long n, bool enqueue) | |||
514 | int level = 0; /* mille count */ | 609 | int level = 0; /* mille count */ |
515 | long mil = 1000000000; /* highest possible "-illion" */ | 610 | long mil = 1000000000; /* highest possible "-illion" */ |
516 | 611 | ||
612 | #if CONFIG_HWCODEC != MASNONE | ||
517 | if (audio_status()) /* busy, buffer in use */ | 613 | if (audio_status()) /* busy, buffer in use */ |
518 | return -1; | 614 | return -1; |
615 | #endif | ||
519 | 616 | ||
520 | if (!enqueue) | 617 | if (!enqueue) |
521 | shutup(); /* cut off all the pending stuff */ | 618 | shutup(); /* cut off all the pending stuff */ |
@@ -593,8 +690,10 @@ int talk_value(long n, int unit, bool enqueue) | |||
593 | VOICE_HERTZ, | 690 | VOICE_HERTZ, |
594 | }; | 691 | }; |
595 | 692 | ||
693 | #if CONFIG_HWCODEC != MASNONE | ||
596 | if (audio_status()) /* busy, buffer in use */ | 694 | if (audio_status()) /* busy, buffer in use */ |
597 | return -1; | 695 | return -1; |
696 | #endif | ||
598 | 697 | ||
599 | if (unit < 0 || unit >= UNIT_LAST) | 698 | if (unit < 0 || unit >= UNIT_LAST) |
600 | unit_id = -1; | 699 | unit_id = -1; |
@@ -625,8 +724,10 @@ int talk_spell(const char* spell, bool enqueue) | |||
625 | { | 724 | { |
626 | char c; /* currently processed char */ | 725 | char c; /* currently processed char */ |
627 | 726 | ||
727 | #if CONFIG_HWCODEC != MASNONE | ||
628 | if (audio_status()) /* busy, buffer in use */ | 728 | if (audio_status()) /* busy, buffer in use */ |
629 | return -1; | 729 | return -1; |
730 | #endif | ||
630 | 731 | ||
631 | if (!enqueue) | 732 | if (!enqueue) |
632 | shutup(); /* cut off all the pending stuff */ | 733 | shutup(); /* cut off all the pending stuff */ |