From ac724cca19b8e0564c921db7a2e1a1fc52ccbe18 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Thu, 28 Apr 2011 02:56:28 +0000 Subject: 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 --- apps/codecs/nsf.c | 29 ++++++-------- apps/metadata/nsf.c | 109 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 85 insertions(+), 53 deletions(-) diff --git a/apps/codecs/nsf.c b/apps/codecs/nsf.c index b1bfb82dcd..92d0240200 100644 --- a/apps/codecs/nsf.c +++ b/apps/codecs/nsf.c @@ -4294,12 +4294,18 @@ jammed: /****************** 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) { int track,fade,def=0; SetTrack(t); /* 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;} else track=nTrackTime[t]; 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 */ } -/** Operational info **/ -static int track = 0; -static char last_path[MAX_PATH]; -static int dontresettrack = 0; - /* this is the codec entry point */ enum codec_status codec_main(enum codec_entry_call_reason reason) { @@ -4356,6 +4357,8 @@ enum codec_status codec_run(void) DEBUGF("NSF: file load failed\n"); return CODEC_ERROR; } + + repeat_one = ci->global_settings->repeat_mode == REPEAT_ONE; init_nsf: if(!NSFCore_Initialize()) { @@ -4368,21 +4371,11 @@ init_nsf: if(!LoadNSF(nDataBufferSize)) { 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 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 initial track */ - if (bIsExtended && - ci->global_settings->repeat_mode!=REPEAT_ONE && nPlaylistSize>0) { + if (bIsExtended && !repeat_one && nPlaylistSize>0) { /* decide to use the playlist */ usingplaylist=1; track=0; @@ -4447,7 +4440,7 @@ init_nsf: 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 */ track++; if (track>=nTrackCount) track=0; diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c index daffeb27ed..29fd8475bb 100644 --- a/apps/metadata/nsf.c +++ b/apps/metadata/nsf.c @@ -45,12 +45,21 @@ struct NSFE_INFOCHUNK #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) { - bool info_found = false; - bool end_found = false; - bool data_found = false; + unsigned int chunks_found = 0; + long track_count = 0; + long playlist_count = 0; struct NSFE_INFOCHUNK info; 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; /* 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)) return false; @@ -72,36 +81,63 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) switch (chunk_type) { + /* first three types are mandatory (but don't worry about NEND + anyway) */ case CHAR4_CONST('I', 'N', 'F', 'O'): { - /* only one info chunk permitted */ - if (info_found) - return false; + if (chunks_found & CHUNK_INFO) + return false; /* only one info chunk permitted */ - info_found = true; + chunks_found |= CHUNK_INFO; /* minimum size */ if (chunk_size < 8) return false; - ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK), - chunk_size); + ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size); if (read(fd, &info, size) != size) return false; if (size >= 9) - id3->length = info.nTrackCount*1000; + track_count = info.nTrackCount; - lseek(fd, chunk_size - size, SEEK_CUR); + chunk_size -= size; break; } - case CHAR4_CONST('a', 'u', 't', 'h'): + case CHAR4_CONST('D', 'A', 'T', 'A'): { - if (!info_found) + 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'): + { + if (chunks_found & CHUNK_auth) + return false; /* only one may exist */ + + chunks_found |= CHUNK_auth; + /* szGameTitle, szArtist, szCopyright */ char ** const ar[] = { &id3->title, &id3->artist, &id3->album }; @@ -120,39 +156,37 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) p += len; buf_rem -= len; - if (chunk_size >= len) + if (chunk_size >= (uint32_t)len) chunk_size -= len; else chunk_size = 0; } - lseek(fd, chunk_size, SEEK_CUR); 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('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */ { - if (!info_found) - return false; + if (chunks_found & CHUNK_plst) + return false; /* only one may exist */ + + chunks_found |= CHUNK_plst; - lseek(fd, chunk_size, SEEK_CUR); + /* each byte is the index of one track */ + playlist_count = chunk_size; break; } - case CHAR4_CONST('N', 'E', 'N', 'D'): + 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 */ { - end_found = true; + /* don't care how many of these there are even though there should + be only one */ + if (!(chunks_found & CHUNK_INFO)) + return false; + + case CHAR4_CONST('B', 'A', 'N', 'K'): break; } @@ -166,19 +200,24 @@ static bool parse_nsfe(int fd, struct mp3entry *id3) return false; /* otherwise, just skip it */ - lseek(fd, chunk_size, SEEK_CUR); break; } } /* end switch */ + + lseek(fd, chunk_size, SEEK_CUR); } /* 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 * 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 * 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) -- cgit