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
This commit is contained in:
parent
749187c4fd
commit
a7aa17ac1b
1 changed files with 84 additions and 36 deletions
120
apps/talk.c
120
apps/talk.c
|
@ -44,6 +44,8 @@ const char* const dir_thumbnail_name = "_dirname.talk";
|
|||
|
||||
#define QUEUE_LEVEL ((queue_write - queue_read) & QUEUE_MASK)
|
||||
|
||||
#define LOADED_MASK 0x80000000 /* MSB */
|
||||
|
||||
|
||||
/***************** Data types *****************/
|
||||
|
||||
|
@ -81,11 +83,12 @@ static int queue_write; /* write index of queue, by application */
|
|||
static int queue_read; /* read index of queue, by ISR context */
|
||||
static int sent; /* how many bytes handed over to playback, owned by ISR */
|
||||
static unsigned char curr_hd[3]; /* current frame header, for re-sync */
|
||||
static int filehandle; /* global, so the MMC variant can keep the file open */
|
||||
|
||||
|
||||
/***************** Private prototypes *****************/
|
||||
|
||||
static int load_voicefile(void);
|
||||
static void load_voicefile(void);
|
||||
static void mp3_callback(unsigned char** start, int* size);
|
||||
static int shutup(void);
|
||||
static int queue_clip(unsigned char* buf, int size, bool enqueue);
|
||||
|
@ -112,41 +115,65 @@ static int open_voicefile(void)
|
|||
|
||||
|
||||
/* load the voice file into the mp3 buffer */
|
||||
static int load_voicefile(void)
|
||||
static void load_voicefile(void)
|
||||
{
|
||||
int fd;
|
||||
int size;
|
||||
int load_size;
|
||||
int got_size;
|
||||
int file_size;
|
||||
|
||||
p_voicefile = NULL; /* indicate no voicefile if we fail below */
|
||||
filehandle = open_voicefile();
|
||||
if (filehandle < 0) /* failed to open */
|
||||
goto load_err;
|
||||
|
||||
fd = open_voicefile();
|
||||
if (fd < 0) /* failed to open */
|
||||
{
|
||||
p_voicefile = NULL; /* indicate no voicefile */
|
||||
has_voicefile = false; /* don't try again */
|
||||
return 0;
|
||||
}
|
||||
file_size = filesize(filehandle);
|
||||
if (file_size > mp3end - mp3buf) /* won't fit? */
|
||||
goto load_err;
|
||||
|
||||
size = read(fd, mp3buf, mp3end - mp3buf);
|
||||
if (size > 10000 /* too small is probably invalid */
|
||||
&& size == filesize(fd) /* has to fit completely */
|
||||
#ifdef HAVE_MMC /* load only the header for now */
|
||||
load_size = offsetof(struct voicefile, index);
|
||||
#else /* load the full file */
|
||||
load_size = file_size;
|
||||
#endif
|
||||
|
||||
got_size = read(filehandle, mp3buf, load_size);
|
||||
if (got_size == load_size /* success */
|
||||
&& ((struct voicefile*)mp3buf)->table /* format check */
|
||||
== offsetof(struct voicefile, index))
|
||||
{
|
||||
p_voicefile = (struct voicefile*)mp3buf;
|
||||
|
||||
/* thumbnail buffer is the remaining space behind */
|
||||
p_thumbnail = mp3buf + size;
|
||||
p_thumbnail = mp3buf + file_size;
|
||||
p_thumbnail += (int)p_thumbnail % 2; /* 16-bit align */
|
||||
size_for_thumbnail = mp3end - p_thumbnail;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_voicefile = false; /* don't try again */
|
||||
}
|
||||
close(fd);
|
||||
goto load_err;
|
||||
|
||||
return size;
|
||||
#ifdef HAVE_MMC
|
||||
/* load the index table, now that we know its size from the header */
|
||||
load_size = (p_voicefile->id1_max + p_voicefile->id2_max)
|
||||
* sizeof(struct clip_entry);
|
||||
got_size = read(filehandle,
|
||||
mp3buf + offsetof(struct voicefile, index), load_size);
|
||||
if (got_size != load_size) /* read error */
|
||||
goto load_err;
|
||||
#else
|
||||
close(filehandle); /* only the MMC variant leaves it open */
|
||||
filehandle = -1;
|
||||
#endif
|
||||
|
||||
return;
|
||||
|
||||
load_err:
|
||||
p_voicefile = NULL;
|
||||
has_voicefile = false; /* don't try again */
|
||||
if (filehandle >= 0)
|
||||
{
|
||||
close(filehandle);
|
||||
filehandle = -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -289,7 +316,7 @@ static int queue_clip(unsigned char* buf, int size, bool enqueue)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* common code for talk_init() and talk_buffer_steal() */
|
||||
static void reset_state(void)
|
||||
{
|
||||
queue_write = queue_read = 0; /* reset the queue */
|
||||
|
@ -302,20 +329,20 @@ static void reset_state(void)
|
|||
|
||||
void talk_init(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open_voicefile();
|
||||
if (fd >= 0) /* success */
|
||||
{
|
||||
close(fd);
|
||||
has_voicefile = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_voicefile = false; /* no voice file available */
|
||||
}
|
||||
|
||||
reset_state(); /* use this for most of our inits */
|
||||
|
||||
#ifdef HAVE_MMC
|
||||
load_voicefile(); /* load the tables right away */
|
||||
has_voicefile = (p_voicefile != NULL);
|
||||
#else
|
||||
filehandle = open_voicefile();
|
||||
has_voicefile = (filehandle >= 0); /* test if we can open it */
|
||||
if (has_voicefile)
|
||||
{
|
||||
close(filehandle); /* close again, this was just to detect presence */
|
||||
filehandle = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -323,6 +350,13 @@ void talk_init(void)
|
|||
int talk_buffer_steal(void)
|
||||
{
|
||||
mp3_play_stop();
|
||||
#ifdef HAVE_MMC
|
||||
if (filehandle >= 0) /* only relevant for MMC */
|
||||
{
|
||||
close(filehandle);
|
||||
filehandle = -1;
|
||||
}
|
||||
#endif
|
||||
reset_state();
|
||||
return 0;
|
||||
}
|
||||
|
@ -373,9 +407,23 @@ int talk_id(int id, bool enqueue)
|
|||
clipsize = p_voicefile->index[id].size;
|
||||
if (clipsize == 0) /* clip not included in voicefile */
|
||||
return -1;
|
||||
|
||||
clipbuf = mp3buf + p_voicefile->index[id].offset;
|
||||
|
||||
#ifdef HAVE_MMC /* dynamic loading, on demand */
|
||||
if (!(clipsize & LOADED_MASK))
|
||||
{ /* clip used for the first time, needs loading */
|
||||
lseek(filehandle, p_voicefile->index[id].offset, SEEK_SET);
|
||||
if (read(filehandle, clipbuf, clipsize) != clipsize)
|
||||
return -1; /* read error */
|
||||
|
||||
p_voicefile->index[id].size |= LOADED_MASK; /* mark as loaded */
|
||||
}
|
||||
else
|
||||
{ /* clip is in memory already */
|
||||
clipsize &= ~LOADED_MASK; /* without the extra bit gives true size */
|
||||
}
|
||||
#endif
|
||||
|
||||
queue_clip(clipbuf, clipsize, enqueue);
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue