forked from len0rd/rockbox
Get the NSF internal playlists working again. Fix a few wrongdoings in the metadata parser. Use the larger of track or playlist count to determine 'duration' so that the repeat-one switching to access the raw tracks works.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29793 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
fa65362a42
commit
ac724cca19
2 changed files with 87 additions and 55 deletions
|
|
@ -4294,12 +4294,18 @@ jammed:
|
||||||
|
|
||||||
/****************** rockbox interface ******************/
|
/****************** rockbox interface ******************/
|
||||||
|
|
||||||
|
/** Operational info **/
|
||||||
|
static int track = 0;
|
||||||
|
static char last_path[MAX_PATH];
|
||||||
|
static int dontresettrack = 0;
|
||||||
|
static bool repeat_one = false;
|
||||||
|
|
||||||
static void set_codec_track(int t, int d) {
|
static void set_codec_track(int t, int d) {
|
||||||
int track,fade,def=0;
|
int track,fade,def=0;
|
||||||
SetTrack(t);
|
SetTrack(t);
|
||||||
|
|
||||||
/* for REPEAT_ONE we disable track limits */
|
/* for REPEAT_ONE we disable track limits */
|
||||||
if (ci->global_settings->repeat_mode!=REPEAT_ONE) {
|
if (!repeat_one) {
|
||||||
if (!bIsExtended || nTrackTime[t]==-1) {track=60*2*1000; def=1;}
|
if (!bIsExtended || nTrackTime[t]==-1) {track=60*2*1000; def=1;}
|
||||||
else track=nTrackTime[t];
|
else track=nTrackTime[t];
|
||||||
if (!bIsExtended || nTrackFade[t]==-1) fade=5*1000;
|
if (!bIsExtended || nTrackFade[t]==-1) fade=5*1000;
|
||||||
|
|
@ -4310,11 +4316,6 @@ static void set_codec_track(int t, int d) {
|
||||||
ci->set_elapsed(d*1000); /* d is track no to display */
|
ci->set_elapsed(d*1000); /* d is track no to display */
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Operational info **/
|
|
||||||
static int track = 0;
|
|
||||||
static char last_path[MAX_PATH];
|
|
||||||
static int dontresettrack = 0;
|
|
||||||
|
|
||||||
/* this is the codec entry point */
|
/* this is the codec entry point */
|
||||||
enum codec_status codec_main(enum codec_entry_call_reason reason)
|
enum codec_status codec_main(enum codec_entry_call_reason reason)
|
||||||
{
|
{
|
||||||
|
|
@ -4357,6 +4358,8 @@ enum codec_status codec_run(void)
|
||||||
return CODEC_ERROR;
|
return CODEC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repeat_one = ci->global_settings->repeat_mode == REPEAT_ONE;
|
||||||
|
|
||||||
init_nsf:
|
init_nsf:
|
||||||
if(!NSFCore_Initialize()) {
|
if(!NSFCore_Initialize()) {
|
||||||
DEBUGF("NSF: NSFCore_Initialize failed\n"); return CODEC_ERROR;}
|
DEBUGF("NSF: NSFCore_Initialize failed\n"); return CODEC_ERROR;}
|
||||||
|
|
@ -4368,21 +4371,11 @@ init_nsf:
|
||||||
if(!LoadNSF(nDataBufferSize)) {
|
if(!LoadNSF(nDataBufferSize)) {
|
||||||
DEBUGF("NSF: LoadNSF failed\n"); return CODEC_ERROR;}
|
DEBUGF("NSF: LoadNSF failed\n"); return CODEC_ERROR;}
|
||||||
|
|
||||||
ci->id3->title=szGameTitle;
|
|
||||||
ci->id3->artist=szArtist;
|
|
||||||
ci->id3->album=szCopyright;
|
|
||||||
if (usingplaylist) {
|
|
||||||
ci->id3->length=nPlaylistSize*1000;
|
|
||||||
} else {
|
|
||||||
ci->id3->length=nTrackCount*1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dontresettrack||strcmp(ci->id3->path,last_path)) {
|
if (!dontresettrack||strcmp(ci->id3->path,last_path)) {
|
||||||
/* if this is the first time we're seeing this file, or if we haven't
|
/* if this is the first time we're seeing this file, or if we haven't
|
||||||
been asked to preserve the track number, default to the proper
|
been asked to preserve the track number, default to the proper
|
||||||
initial track */
|
initial track */
|
||||||
if (bIsExtended &&
|
if (bIsExtended && !repeat_one && nPlaylistSize>0) {
|
||||||
ci->global_settings->repeat_mode!=REPEAT_ONE && nPlaylistSize>0) {
|
|
||||||
/* decide to use the playlist */
|
/* decide to use the playlist */
|
||||||
usingplaylist=1;
|
usingplaylist=1;
|
||||||
track=0;
|
track=0;
|
||||||
|
|
@ -4447,7 +4440,7 @@ init_nsf:
|
||||||
|
|
||||||
print_timers(last_path,track);
|
print_timers(last_path,track);
|
||||||
|
|
||||||
if (ci->global_settings->repeat_mode==REPEAT_ONE) {
|
if (repeat_one) {
|
||||||
/* in repeat one mode just advance to the next track */
|
/* in repeat one mode just advance to the next track */
|
||||||
track++;
|
track++;
|
||||||
if (track>=nTrackCount) track=0;
|
if (track>=nTrackCount) track=0;
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,21 @@ struct NSFE_INFOCHUNK
|
||||||
|
|
||||||
|
|
||||||
#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
|
#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
|
||||||
|
#define CHUNK_INFO 0x0001
|
||||||
|
#define CHUNK_DATA 0x0002
|
||||||
|
#define CHUNK_NEND 0x0004
|
||||||
|
#define CHUNK_plst 0x0008
|
||||||
|
#define CHUNK_time 0x0010
|
||||||
|
#define CHUNK_fade 0x0020
|
||||||
|
#define CHUNK_tlbl 0x0040
|
||||||
|
#define CHUNK_auth 0x0080
|
||||||
|
#define CHUNK_BANK 0x0100
|
||||||
|
|
||||||
static bool parse_nsfe(int fd, struct mp3entry *id3)
|
static bool parse_nsfe(int fd, struct mp3entry *id3)
|
||||||
{
|
{
|
||||||
bool info_found = false;
|
unsigned int chunks_found = 0;
|
||||||
bool end_found = false;
|
long track_count = 0;
|
||||||
bool data_found = false;
|
long playlist_count = 0;
|
||||||
|
|
||||||
struct NSFE_INFOCHUNK info;
|
struct NSFE_INFOCHUNK info;
|
||||||
memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
|
memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
|
||||||
|
|
@ -60,9 +69,9 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
|
||||||
id3->length = 2*1000*60;
|
id3->length = 2*1000*60;
|
||||||
|
|
||||||
/* begin reading chunks */
|
/* begin reading chunks */
|
||||||
while (!end_found)
|
while (!(chunks_found & CHUNK_NEND))
|
||||||
{
|
{
|
||||||
int32_t chunk_size, chunk_type;
|
uint32_t chunk_size, chunk_type;
|
||||||
|
|
||||||
if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
|
if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -72,35 +81,62 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
|
||||||
|
|
||||||
switch (chunk_type)
|
switch (chunk_type)
|
||||||
{
|
{
|
||||||
|
/* first three types are mandatory (but don't worry about NEND
|
||||||
|
anyway) */
|
||||||
case CHAR4_CONST('I', 'N', 'F', 'O'):
|
case CHAR4_CONST('I', 'N', 'F', 'O'):
|
||||||
{
|
{
|
||||||
/* only one info chunk permitted */
|
if (chunks_found & CHUNK_INFO)
|
||||||
if (info_found)
|
return false; /* only one info chunk permitted */
|
||||||
return false;
|
|
||||||
|
|
||||||
info_found = true;
|
chunks_found |= CHUNK_INFO;
|
||||||
|
|
||||||
/* minimum size */
|
/* minimum size */
|
||||||
if (chunk_size < 8)
|
if (chunk_size < 8)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK),
|
ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);
|
||||||
chunk_size);
|
|
||||||
|
|
||||||
if (read(fd, &info, size) != size)
|
if (read(fd, &info, size) != size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (size >= 9)
|
if (size >= 9)
|
||||||
id3->length = info.nTrackCount*1000;
|
track_count = info.nTrackCount;
|
||||||
|
|
||||||
lseek(fd, chunk_size - size, SEEK_CUR);
|
chunk_size -= size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CHAR4_CONST('D', 'A', 'T', 'A'):
|
||||||
|
{
|
||||||
|
if (!(chunks_found & CHUNK_INFO))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (chunks_found & CHUNK_DATA)
|
||||||
|
return false; /* only one may exist */
|
||||||
|
|
||||||
|
if (chunk_size < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
chunks_found |= CHUNK_DATA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CHAR4_CONST('N', 'E', 'N', 'D'):
|
||||||
|
{
|
||||||
|
/* just end parsing regardless of whether or not this really is the
|
||||||
|
last chunk/data (but it _should_ be) */
|
||||||
|
chunks_found |= CHUNK_NEND;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remaining types are optional */
|
||||||
|
|
||||||
case CHAR4_CONST('a', 'u', 't', 'h'):
|
case CHAR4_CONST('a', 'u', 't', 'h'):
|
||||||
{
|
{
|
||||||
if (!info_found)
|
if (chunks_found & CHUNK_auth)
|
||||||
return false;
|
return false; /* only one may exist */
|
||||||
|
|
||||||
|
chunks_found |= CHUNK_auth;
|
||||||
|
|
||||||
/* szGameTitle, szArtist, szCopyright */
|
/* szGameTitle, szArtist, szCopyright */
|
||||||
char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
|
char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
|
||||||
|
|
@ -120,39 +156,37 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
|
||||||
p += len;
|
p += len;
|
||||||
buf_rem -= len;
|
buf_rem -= len;
|
||||||
|
|
||||||
if (chunk_size >= len)
|
if (chunk_size >= (uint32_t)len)
|
||||||
chunk_size -= len;
|
chunk_size -= len;
|
||||||
else
|
else
|
||||||
chunk_size = 0;
|
chunk_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lseek(fd, chunk_size, SEEK_CUR);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case CHAR4_CONST('D', 'A', 'T', 'A'):
|
|
||||||
if (chunk_size < 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
data_found = true;
|
|
||||||
/* fall through */
|
|
||||||
case CHAR4_CONST('f', 'a', 'd', 'e'):
|
|
||||||
case CHAR4_CONST('t', 'i', 'm', 'e'):
|
|
||||||
case CHAR4_CONST('B', 'A', 'N', 'K'):
|
|
||||||
case CHAR4_CONST('p', 'l', 's', 't'):
|
case CHAR4_CONST('p', 'l', 's', 't'):
|
||||||
|
{
|
||||||
|
if (chunks_found & CHUNK_plst)
|
||||||
|
return false; /* only one may exist */
|
||||||
|
|
||||||
|
chunks_found |= CHUNK_plst;
|
||||||
|
|
||||||
|
/* each byte is the index of one track */
|
||||||
|
playlist_count = chunk_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CHAR4_CONST('t', 'i', 'm', 'e'):
|
||||||
|
case CHAR4_CONST('f', 'a', 'd', 'e'):
|
||||||
case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
|
case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
|
||||||
{
|
{
|
||||||
if (!info_found)
|
/* don't care how many of these there are even though there should
|
||||||
|
be only one */
|
||||||
|
if (!(chunks_found & CHUNK_INFO))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
lseek(fd, chunk_size, SEEK_CUR);
|
case CHAR4_CONST('B', 'A', 'N', 'K'):
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case CHAR4_CONST('N', 'E', 'N', 'D'):
|
|
||||||
{
|
|
||||||
end_found = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,19 +200,24 @@ static bool parse_nsfe(int fd, struct mp3entry *id3)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* otherwise, just skip it */
|
/* otherwise, just skip it */
|
||||||
lseek(fd, chunk_size, SEEK_CUR);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} /* end switch */
|
} /* end switch */
|
||||||
|
|
||||||
|
lseek(fd, chunk_size, SEEK_CUR);
|
||||||
} /* end while */
|
} /* end while */
|
||||||
|
|
||||||
|
if (track_count | playlist_count)
|
||||||
|
id3->length = MAX(track_count, playlist_count)*1000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we exited the while loop without a 'return', we must have hit an NEND
|
* if we exited the while loop without a 'return', we must have hit an NEND
|
||||||
* chunk if this is the case, the file was layed out as it was expected.
|
* chunk if this is the case, the file was layed out as it was expected.
|
||||||
* now.. make sure we found both an info chunk, AND a data chunk... since
|
* now.. make sure we found both an info chunk, AND a data chunk... since
|
||||||
* these are minimum requirements for a valid NSFE file
|
* these are minimum requirements for a valid NSFE file
|
||||||
*/
|
*/
|
||||||
return info_found && data_found;
|
return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
|
||||||
|
(CHUNK_INFO | CHUNK_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_nesm(int fd, struct mp3entry *id3)
|
static bool parse_nesm(int fd, struct mp3entry *id3)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue