diff options
author | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-10-12 16:43:22 +0000 |
---|---|---|
committer | Jörg Hohensohn <hohensoh@rockbox.org> | 2004-10-12 16:43:22 +0000 |
commit | a7aa17ac1b83d7855c896f6937887cc8fcaa959a (patch) | |
tree | 3a59568417ce79744428cd6755ca4eb61ac4cfd6 /apps | |
parent | 749187c4fd553fa3b6c2f84da54ed3fd4710a78c (diff) | |
download | rockbox-a7aa17ac1b83d7855c896f6937887cc8fcaa959a.tar.gz rockbox-a7aa17ac1b83d7855c896f6937887cc8fcaa959a.zip |
for slow MMC device (Ondio): load voice file piecewise, as needed
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5262 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r-- | apps/talk.c | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/apps/talk.c b/apps/talk.c index c0fe599b60..7cfcb46254 100644 --- a/apps/talk.c +++ b/apps/talk.c | |||
@@ -44,6 +44,8 @@ const char* const dir_thumbnail_name = "_dirname.talk"; | |||
44 | 44 | ||
45 | #define QUEUE_LEVEL ((queue_write - queue_read) & QUEUE_MASK) | 45 | #define QUEUE_LEVEL ((queue_write - queue_read) & QUEUE_MASK) |
46 | 46 | ||
47 | #define LOADED_MASK 0x80000000 /* MSB */ | ||
48 | |||
47 | 49 | ||
48 | /***************** Data types *****************/ | 50 | /***************** Data types *****************/ |
49 | 51 | ||
@@ -81,11 +83,12 @@ static int queue_write; /* write index of queue, by application */ | |||
81 | static int queue_read; /* read index of queue, by ISR context */ | 83 | static int queue_read; /* read index of queue, by ISR context */ |
82 | static int sent; /* how many bytes handed over to playback, owned by ISR */ | 84 | static int sent; /* how many bytes handed over to playback, owned by ISR */ |
83 | static unsigned char curr_hd[3]; /* current frame header, for re-sync */ | 85 | static unsigned char curr_hd[3]; /* current frame header, for re-sync */ |
86 | static int filehandle; /* global, so the MMC variant can keep the file open */ | ||
84 | 87 | ||
85 | 88 | ||
86 | /***************** Private prototypes *****************/ | 89 | /***************** Private prototypes *****************/ |
87 | 90 | ||
88 | static int load_voicefile(void); | 91 | static void load_voicefile(void); |
89 | static void mp3_callback(unsigned char** start, int* size); | 92 | static void mp3_callback(unsigned char** start, int* size); |
90 | static int shutup(void); | 93 | static int shutup(void); |
91 | static int queue_clip(unsigned char* buf, int size, bool enqueue); | 94 | static int queue_clip(unsigned char* buf, int size, bool enqueue); |
@@ -112,41 +115,65 @@ static int open_voicefile(void) | |||
112 | 115 | ||
113 | 116 | ||
114 | /* load the voice file into the mp3 buffer */ | 117 | /* load the voice file into the mp3 buffer */ |
115 | static int load_voicefile(void) | 118 | static void load_voicefile(void) |
116 | { | 119 | { |
117 | int fd; | 120 | int load_size; |
118 | int size; | 121 | int got_size; |
119 | 122 | int file_size; | |
120 | p_voicefile = NULL; /* indicate no voicefile if we fail below */ | 123 | |
121 | 124 | filehandle = open_voicefile(); | |
122 | fd = open_voicefile(); | 125 | if (filehandle < 0) /* failed to open */ |
123 | if (fd < 0) /* failed to open */ | 126 | goto load_err; |
124 | { | 127 | |
125 | p_voicefile = NULL; /* indicate no voicefile */ | 128 | file_size = filesize(filehandle); |
126 | has_voicefile = false; /* don't try again */ | 129 | if (file_size > mp3end - mp3buf) /* won't fit? */ |
127 | return 0; | 130 | goto load_err; |
128 | } | 131 | |
129 | 132 | #ifdef HAVE_MMC /* load only the header for now */ | |
130 | size = read(fd, mp3buf, mp3end - mp3buf); | 133 | load_size = offsetof(struct voicefile, index); |
131 | if (size > 10000 /* too small is probably invalid */ | 134 | #else /* load the full file */ |
132 | && size == filesize(fd) /* has to fit completely */ | 135 | load_size = file_size; |
136 | #endif | ||
137 | |||
138 | got_size = read(filehandle, mp3buf, load_size); | ||
139 | if (got_size == load_size /* success */ | ||
133 | && ((struct voicefile*)mp3buf)->table /* format check */ | 140 | && ((struct voicefile*)mp3buf)->table /* format check */ |
134 | == offsetof(struct voicefile, index)) | 141 | == offsetof(struct voicefile, index)) |
135 | { | 142 | { |
136 | p_voicefile = (struct voicefile*)mp3buf; | 143 | p_voicefile = (struct voicefile*)mp3buf; |
137 | 144 | ||
138 | /* thumbnail buffer is the remaining space behind */ | 145 | /* thumbnail buffer is the remaining space behind */ |
139 | p_thumbnail = mp3buf + size; | 146 | p_thumbnail = mp3buf + file_size; |
140 | p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */ | 147 | p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */ |
141 | size_for_thumbnail = mp3end - p_thumbnail; | 148 | size_for_thumbnail = mp3end - p_thumbnail; |
142 | } | 149 | } |
143 | else | 150 | else |
151 | goto load_err; | ||
152 | |||
153 | #ifdef HAVE_MMC | ||
154 | /* load the index table, now that we know its size from the header */ | ||
155 | load_size = (p_voicefile->id1_max + p_voicefile->id2_max) | ||
156 | * sizeof(struct clip_entry); | ||
157 | got_size = read(filehandle, | ||
158 | mp3buf + offsetof(struct voicefile, index), load_size); | ||
159 | if (got_size != load_size) /* read error */ | ||
160 | goto load_err; | ||
161 | #else | ||
162 | close(filehandle); /* only the MMC variant leaves it open */ | ||
163 | filehandle = -1; | ||
164 | #endif | ||
165 | |||
166 | return; | ||
167 | |||
168 | load_err: | ||
169 | p_voicefile = NULL; | ||
170 | has_voicefile = false; /* don't try again */ | ||
171 | if (filehandle >= 0) | ||
144 | { | 172 | { |
145 | has_voicefile = false; /* don't try again */ | 173 | close(filehandle); |
174 | filehandle = -1; | ||
146 | } | 175 | } |
147 | close(fd); | 176 | return; |
148 | |||
149 | return size; | ||
150 | } | 177 | } |
151 | 178 | ||
152 | 179 | ||
@@ -289,7 +316,7 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue) | |||
289 | return 0; | 316 | return 0; |
290 | } | 317 | } |
291 | 318 | ||
292 | 319 | /* common code for talk_init() and talk_buffer_steal() */ | |
293 | static void reset_state(void) | 320 | static void reset_state(void) |
294 | { | 321 | { |
295 | queue_write = queue_read = 0; /* reset the queue */ | 322 | queue_write = queue_read = 0; /* reset the queue */ |
@@ -302,20 +329,20 @@ static void reset_state(void) | |||
302 | 329 | ||
303 | void talk_init(void) | 330 | void talk_init(void) |
304 | { | 331 | { |
305 | int fd; | 332 | reset_state(); /* use this for most of our inits */ |
306 | 333 | ||
307 | fd = open_voicefile(); | 334 | #ifdef HAVE_MMC |
308 | if (fd >= 0) /* success */ | 335 | load_voicefile(); /* load the tables right away */ |
309 | { | 336 | has_voicefile = (p_voicefile != NULL); |
310 | close(fd); | 337 | #else |
311 | has_voicefile = true; | 338 | filehandle = open_voicefile(); |
312 | } | 339 | has_voicefile = (filehandle >= 0); /* test if we can open it */ |
313 | else | 340 | if (has_voicefile) |
314 | { | 341 | { |
315 | has_voicefile = false; /* no voice file available */ | 342 | close(filehandle); /* close again, this was just to detect presence */ |
343 | filehandle = -1; | ||
316 | } | 344 | } |
317 | 345 | #endif | |
318 | reset_state(); /* use this for most of our inits */ | ||
319 | } | 346 | } |
320 | 347 | ||
321 | 348 | ||
@@ -323,6 +350,13 @@ void talk_init(void) | |||
323 | int talk_buffer_steal(void) | 350 | int talk_buffer_steal(void) |
324 | { | 351 | { |
325 | mp3_play_stop(); | 352 | mp3_play_stop(); |
353 | #ifdef HAVE_MMC | ||
354 | if (filehandle >= 0) /* only relevant for MMC */ | ||
355 | { | ||
356 | close(filehandle); | ||
357 | filehandle = -1; | ||
358 | } | ||
359 | #endif | ||
326 | reset_state(); | 360 | reset_state(); |
327 | return 0; | 361 | return 0; |
328 | } | 362 | } |
@@ -373,9 +407,23 @@ int talk_id(int id, bool enqueue) | |||
373 | clipsize = p_voicefile->index[id].size; | 407 | clipsize = p_voicefile->index[id].size; |
374 | if (clipsize == 0) /* clip not included in voicefile */ | 408 | if (clipsize == 0) /* clip not included in voicefile */ |
375 | return -1; | 409 | return -1; |
376 | |||
377 | clipbuf = mp3buf + p_voicefile->index[id].offset; | 410 | clipbuf = mp3buf + p_voicefile->index[id].offset; |
378 | 411 | ||
412 | #ifdef HAVE_MMC /* dynamic loading, on demand */ | ||
413 | if (!(clipsize & LOADED_MASK)) | ||
414 | { /* clip used for the first time, needs loading */ | ||
415 | lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET); | ||
416 | if (read(filehandle, clipbuf, clipsize) != clipsize) | ||
417 | return -1; /* read error */ | ||
418 | |||
419 | p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */ | ||
420 | } | ||
421 | else | ||
422 | { /* clip is in memory already */ | ||
423 | clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */ | ||
424 | } | ||
425 | #endif | ||
426 | |||
379 | queue_clip(clipbuf, clipsize, enqueue); | 427 | queue_clip(clipbuf, clipsize, enqueue); |
380 | 428 | ||
381 | return 0; | 429 | return 0; |