summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-04-27 16:46:27 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-04-27 16:46:27 +0000
commit3d9c0628220175603757ea1fabce7a9d34a75739 (patch)
treea5c5af11c6856f0f084241212e45763af412f946 /apps
parent08bedf83051064c7dc9a7bb903ab9a34afe8d725 (diff)
Get NSF fixed up a bit and parse metadata in the core.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29790 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/codecs/nsf.c25
-rw-r--r--apps/metadata/nsf.c228
2 files changed, 209 insertions, 44 deletions
diff --git a/apps/codecs/nsf.c b/apps/codecs/nsf.c
index 72f6974214..b1bfb82dcd 100644
--- a/apps/codecs/nsf.c
+++ b/apps/codecs/nsf.c
@@ -4319,7 +4319,7 @@ static int dontresettrack = 0;
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
- /* we only render 16 bits, 44.1KHz, Stereo */
+ /* we only render 16 bits, 44.1KHz, Mono */
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
ci->configure(DSP_SET_FREQUENCY, 44100);
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
@@ -4338,6 +4338,7 @@ enum codec_status codec_run(void)
size_t n;
int endofstream; /* end of stream flag */
int usingplaylist = 0;
+ intptr_t param;
DEBUGF("NSF: next_track\n");
if (codec_init()) {
@@ -4406,27 +4407,21 @@ init_nsf:
reset_profile_timers();
while (!endofstream) {
- intptr_t param;
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
- if (param > 0) {
- track=param/1000;
- if (usingplaylist) {
- if (track>=nPlaylistSize) break;
- } else {
- if (track>=nTrackCount) break;
- }
- dontresettrack=1;
- ci->seek_complete();
- goto init_nsf;
- }
- else {
- ci->seek_complete();
+ track=param/1000;
+ if (usingplaylist) {
+ if (track>=nPlaylistSize) break;
+ } else {
+ if (track>=nTrackCount) break;
}
+ dontresettrack=1;
+ ci->seek_complete();
+ goto init_nsf;
}
ENTER_TIMER(total);
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c
index 9207a14048..58fc038b42 100644
--- a/apps/metadata/nsf.c
+++ b/apps/metadata/nsf.c
@@ -10,53 +10,223 @@
#include "metadata_parsers.h"
#include "rbunicode.h"
-bool get_nsf_metadata(int fd, struct mp3entry* id3)
+struct NESM_HEADER
{
- /* Use the trackname part of the id3 structure as a temporary buffer */
- unsigned char* buf = (unsigned char *)id3->path;
- char *p;
-
- if ((lseek(fd, 0, SEEK_SET) < 0)
- || (read(fd, buf, 110) < 110))
- {
- return false;
- }
+ uint32_t nHeader;
+ uint8_t nHeaderExtra;
+ uint8_t nVersion;
+ uint8_t nTrackCount;
+ uint8_t nInitialTrack;
+ uint16_t nLoadAddress;
+ uint16_t nInitAddress;
+ uint16_t nPlayAddress;
+ uint8_t szGameTitle[32];
+ uint8_t szArtist[32];
+ uint8_t szCopyright[32];
+ uint16_t nSpeedNTSC;
+ uint8_t nBankSwitch[8];
+ uint16_t nSpeedPAL;
+ uint8_t nNTSC_PAL;
+ uint8_t nExtraChip;
+ uint8_t nExpansion[4];
+} __attribute__((packed));
+
+struct NSFE_INFOCHUNK
+{
+ uint16_t nLoadAddress;
+ uint16_t nInitAddress;
+ uint16_t nPlayAddress;
+ uint8_t nIsPal;
+ uint8_t nExt;
+ uint8_t nTrackCount;
+ uint8_t nStartingTrack;
+} __attribute__((packed));
- id3->length = 120*1000;
- id3->vbr = false;
- id3->filesize = filesize(fd);
- if (memcmp(buf,"NSFE",4) == 0) /* only NESM contain metadata */
+#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
+
+static bool parse_nsfe(int fd, struct mp3entry *id3)
+{
+ bool info_found = false;
+ bool end_found = false;
+ bool data_found = false;
+
+ struct NSFE_INFOCHUNK info;
+ memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
+
+ /* default values */
+ info.nTrackCount = 1;
+ id3->length = 2*1000*60;
+
+ /* begin reading chunks */
+ while (!end_found)
{
- return true;
- }
- else
- {
- if (memcmp(buf, "NESM",4) != 0) /* not a valid format*/
- {
+ int32_t chunk_size, chunk_type;
+
+ if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
+ return false;
+
+ if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
return false;
- }
- }
- p = id3->id3v2buf;
+ switch (chunk_type)
+ {
+ case CHAR4_CONST('I', 'N', 'F', 'O'):
+ {
+ /* only one info chunk permitted */
+ if (info_found)
+ return false;
+
+ info_found = true;
+
+ /* minimum size */
+ if (chunk_size < 8)
+ return false;
+
+ ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK),
+ chunk_size);
+
+ if (read(fd, &info, size) != size)
+ return false;
+
+ if (size >= 9)
+ id3->length = info.nTrackCount*1000;
+
+ lseek(fd, chunk_size - size, SEEK_CUR);
+ break;
+ }
+
+ case CHAR4_CONST('a', 'u', 't', 'h'):
+ {
+ if (!info_found)
+ return false;
+
+ /* szGameTitle, szArtist, szCopyright */
+ char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
+
+ char *p = id3->id3v2buf;
+ long buf_rem = sizeof (id3->id3v2buf);
+ unsigned int i;
+
+ for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
+ {
+ long len = read_string(fd, p, buf_rem, '\0', chunk_size);
+
+ if (len < 0)
+ return false;
+
+ *ar[i] = p;
+ p += len;
+ buf_rem -= len;
+
+ if (chunk_size >= 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;
+
+ lseek(fd, chunk_size, SEEK_CUR);
+ break;
+ }
+
+ case CHAR4_CONST('N', 'E', 'N', 'D'):
+ {
+ end_found = true;
+ break;
+ }
+
+ default: /* unknown chunk */
+ {
+ /* check the first byte */
+ chunk_type = (uint8_t)chunk_type;
+
+ /* chunk is vital... don't continue */
+ if(chunk_type >= 'A' && chunk_type <= 'Z')
+ return false;
+
+ /* otherwise, just skip it */
+ lseek(fd, chunk_size, SEEK_CUR);
+ break;
+ }
+ } /* end switch */
+ } /* end while */
+
+ /*
+ * 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;
+}
+
+static bool parse_nesm(int fd, struct mp3entry *id3)
+{
+ struct NESM_HEADER hdr;
+ char *p = id3->id3v2buf;
+
+ lseek(fd, 0, SEEK_SET);
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+ return false;
/* Length */
- id3->length = buf[6]*1000;
+ id3->length = hdr.nTrackCount*1000;
/* Title */
- memcpy(p, &buf[14], 32);
id3->title = p;
- p += strlen(p)+1;
+ p += strlcpy(p, hdr.szGameTitle, 32) + 1;
/* Artist */
- memcpy(p, &buf[46], 32);
id3->artist = p;
- p += strlen(p)+1;
+ p += strlcpy(p, hdr.szArtist, 32) + 1;
/* Copyright (per codec) */
- memcpy(p, &buf[78], 32);
id3->album = p;
+ strlcpy(p, hdr.szCopyright, 32);
return true;
}
+bool get_nsf_metadata(int fd, struct mp3entry* id3)
+{
+ uint32_t nsf_type;
+
+ if (lseek(fd, 0, SEEK_SET) < 0 ||
+ read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
+ return false;
+
+ id3->vbr = false;
+ id3->filesize = filesize(fd);
+ /* we only render 16 bits, 44.1KHz, Mono */
+ id3->bitrate = 706;
+ id3->frequency = 44100;
+
+ if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E'))
+ return parse_nsfe(fd, id3);
+ else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M'))
+ return parse_nesm(fd, id3);
+
+ /* not a valid format*/
+ return false;
+}
+