summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/talk.c120
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 */
81static int queue_read; /* read index of queue, by ISR context */ 83static int queue_read; /* read index of queue, by ISR context */
82static int sent; /* how many bytes handed over to playback, owned by ISR */ 84static int sent; /* how many bytes handed over to playback, owned by ISR */
83static unsigned char curr_hd[3]; /* current frame header, for re-sync */ 85static unsigned char curr_hd[3]; /* current frame header, for re-sync */
86static int filehandle; /* global, so the MMC variant can keep the file open */
84 87
85 88
86/***************** Private prototypes *****************/ 89/***************** Private prototypes *****************/
87 90
88static int load_voicefile(void); 91static void load_voicefile(void);
89static void mp3_callback(unsigned char** start, int* size); 92static void mp3_callback(unsigned char** start, int* size);
90static int shutup(void); 93static int shutup(void);
91static int queue_clip(unsigned char* buf, int size, bool enqueue); 94static 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 */
115static int load_voicefile(void) 118static 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
168load_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() */
293static void reset_state(void) 320static 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
303void talk_init(void) 330void 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)
323int talk_buffer_steal(void) 350int 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;