summaryrefslogtreecommitdiff
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
parent08bedf83051064c7dc9a7bb903ab9a34afe8d725 (diff)
downloadrockbox-3d9c0628220175603757ea1fabce7a9d34a75739.tar.gz
rockbox-3d9c0628220175603757ea1fabce7a9d34a75739.zip
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
-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;
4319enum codec_status codec_main(enum codec_entry_call_reason reason) 4319enum codec_status codec_main(enum codec_entry_call_reason reason)
4320{ 4320{
4321 if (reason == CODEC_LOAD) { 4321 if (reason == CODEC_LOAD) {
4322 /* we only render 16 bits, 44.1KHz, Stereo */ 4322 /* we only render 16 bits, 44.1KHz, Mono */
4323 ci->configure(DSP_SET_SAMPLE_DEPTH, 16); 4323 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
4324 ci->configure(DSP_SET_FREQUENCY, 44100); 4324 ci->configure(DSP_SET_FREQUENCY, 44100);
4325 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 4325 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
@@ -4338,6 +4338,7 @@ enum codec_status codec_run(void)
4338 size_t n; 4338 size_t n;
4339 int endofstream; /* end of stream flag */ 4339 int endofstream; /* end of stream flag */
4340 int usingplaylist = 0; 4340 int usingplaylist = 0;
4341 intptr_t param;
4341 4342
4342 DEBUGF("NSF: next_track\n"); 4343 DEBUGF("NSF: next_track\n");
4343 if (codec_init()) { 4344 if (codec_init()) {
@@ -4406,27 +4407,21 @@ init_nsf:
4406 reset_profile_timers(); 4407 reset_profile_timers();
4407 4408
4408 while (!endofstream) { 4409 while (!endofstream) {
4409 intptr_t param;
4410 enum codec_command_action action = ci->get_command(&param); 4410 enum codec_command_action action = ci->get_command(&param);
4411 4411
4412 if (action == CODEC_ACTION_HALT) 4412 if (action == CODEC_ACTION_HALT)
4413 break; 4413 break;
4414 4414
4415 if (action == CODEC_ACTION_SEEK_TIME) { 4415 if (action == CODEC_ACTION_SEEK_TIME) {
4416 if (param > 0) { 4416 track=param/1000;
4417 track=param/1000; 4417 if (usingplaylist) {
4418 if (usingplaylist) { 4418 if (track>=nPlaylistSize) break;
4419 if (track>=nPlaylistSize) break; 4419 } else {
4420 } else { 4420 if (track>=nTrackCount) break;
4421 if (track>=nTrackCount) break;
4422 }
4423 dontresettrack=1;
4424 ci->seek_complete();
4425 goto init_nsf;
4426 }
4427 else {
4428 ci->seek_complete();
4429 } 4421 }
4422 dontresettrack=1;
4423 ci->seek_complete();
4424 goto init_nsf;
4430 } 4425 }
4431 4426
4432 ENTER_TIMER(total); 4427 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 @@
10#include "metadata_parsers.h" 10#include "metadata_parsers.h"
11#include "rbunicode.h" 11#include "rbunicode.h"
12 12
13bool get_nsf_metadata(int fd, struct mp3entry* id3) 13struct NESM_HEADER
14{ 14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */ 15 uint32_t nHeader;
16 unsigned char* buf = (unsigned char *)id3->path; 16 uint8_t nHeaderExtra;
17 char *p; 17 uint8_t nVersion;
18 18 uint8_t nTrackCount;
19 if ((lseek(fd, 0, SEEK_SET) < 0) 19 uint8_t nInitialTrack;
20 || (read(fd, buf, 110) < 110)) 20 uint16_t nLoadAddress;
21 { 21 uint16_t nInitAddress;
22 return false; 22 uint16_t nPlayAddress;
23 } 23 uint8_t szGameTitle[32];
24 uint8_t szArtist[32];
25 uint8_t szCopyright[32];
26 uint16_t nSpeedNTSC;
27 uint8_t nBankSwitch[8];
28 uint16_t nSpeedPAL;
29 uint8_t nNTSC_PAL;
30 uint8_t nExtraChip;
31 uint8_t nExpansion[4];
32} __attribute__((packed));
33
34struct NSFE_INFOCHUNK
35{
36 uint16_t nLoadAddress;
37 uint16_t nInitAddress;
38 uint16_t nPlayAddress;
39 uint8_t nIsPal;
40 uint8_t nExt;
41 uint8_t nTrackCount;
42 uint8_t nStartingTrack;
43} __attribute__((packed));
24 44
25 id3->length = 120*1000;
26 id3->vbr = false;
27 id3->filesize = filesize(fd);
28 45
29 if (memcmp(buf,"NSFE",4) == 0) /* only NESM contain metadata */ 46#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
47
48static bool parse_nsfe(int fd, struct mp3entry *id3)
49{
50 bool info_found = false;
51 bool end_found = false;
52 bool data_found = false;
53
54 struct NSFE_INFOCHUNK info;
55 memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
56
57 /* default values */
58 info.nTrackCount = 1;
59 id3->length = 2*1000*60;
60
61 /* begin reading chunks */
62 while (!end_found)
30 { 63 {
31 return true; 64 int32_t chunk_size, chunk_type;
32 } 65
33 else 66 if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
34 { 67 return false;
35 if (memcmp(buf, "NESM",4) != 0) /* not a valid format*/ 68
36 { 69 if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
37 return false; 70 return false;
38 }
39 }
40 71
41 p = id3->id3v2buf; 72 switch (chunk_type)
73 {
74 case CHAR4_CONST('I', 'N', 'F', 'O'):
75 {
76 /* only one info chunk permitted */
77 if (info_found)
78 return false;
79
80 info_found = true;
81
82 /* minimum size */
83 if (chunk_size < 8)
84 return false;
85
86 ssize_t size = MIN((ssize_t)sizeof(struct NSFE_INFOCHUNK),
87 chunk_size);
88
89 if (read(fd, &info, size) != size)
90 return false;
91
92 if (size >= 9)
93 id3->length = info.nTrackCount*1000;
94
95 lseek(fd, chunk_size - size, SEEK_CUR);
96 break;
97 }
98
99 case CHAR4_CONST('a', 'u', 't', 'h'):
100 {
101 if (!info_found)
102 return false;
103
104 /* szGameTitle, szArtist, szCopyright */
105 char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
106
107 char *p = id3->id3v2buf;
108 long buf_rem = sizeof (id3->id3v2buf);
109 unsigned int i;
110
111 for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
112 {
113 long len = read_string(fd, p, buf_rem, '\0', chunk_size);
114
115 if (len < 0)
116 return false;
117
118 *ar[i] = p;
119 p += len;
120 buf_rem -= len;
121
122 if (chunk_size >= len)
123 chunk_size -= len;
124 else
125 chunk_size = 0;
126 }
127
128 lseek(fd, chunk_size, SEEK_CUR);
129 break;
130 }
131
132
133 case CHAR4_CONST('D', 'A', 'T', 'A'):
134 if (chunk_size < 1)
135 return false;
136
137 data_found = true;
138 /* fall through */
139 case CHAR4_CONST('f', 'a', 'd', 'e'):
140 case CHAR4_CONST('t', 'i', 'm', 'e'):
141 case CHAR4_CONST('B', 'A', 'N', 'K'):
142 case CHAR4_CONST('p', 'l', 's', 't'):
143 case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
144 {
145 if (!info_found)
146 return false;
147
148 lseek(fd, chunk_size, SEEK_CUR);
149 break;
150 }
151
152 case CHAR4_CONST('N', 'E', 'N', 'D'):
153 {
154 end_found = true;
155 break;
156 }
157
158 default: /* unknown chunk */
159 {
160 /* check the first byte */
161 chunk_type = (uint8_t)chunk_type;
162
163 /* chunk is vital... don't continue */
164 if(chunk_type >= 'A' && chunk_type <= 'Z')
165 return false;
166
167 /* otherwise, just skip it */
168 lseek(fd, chunk_size, SEEK_CUR);
169 break;
170 }
171 } /* end switch */
172 } /* end while */
173
174 /*
175 * if we exited the while loop without a 'return', we must have hit an NEND
176 * chunk if this is the case, the file was layed out as it was expected.
177 * now.. make sure we found both an info chunk, AND a data chunk... since
178 * these are minimum requirements for a valid NSFE file
179 */
180 return info_found && data_found;
181}
182
183static bool parse_nesm(int fd, struct mp3entry *id3)
184{
185 struct NESM_HEADER hdr;
186 char *p = id3->id3v2buf;
187
188 lseek(fd, 0, SEEK_SET);
189 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
190 return false;
42 191
43 /* Length */ 192 /* Length */
44 id3->length = buf[6]*1000; 193 id3->length = hdr.nTrackCount*1000;
45 194
46 /* Title */ 195 /* Title */
47 memcpy(p, &buf[14], 32);
48 id3->title = p; 196 id3->title = p;
49 p += strlen(p)+1; 197 p += strlcpy(p, hdr.szGameTitle, 32) + 1;
50 198
51 /* Artist */ 199 /* Artist */
52 memcpy(p, &buf[46], 32);
53 id3->artist = p; 200 id3->artist = p;
54 p += strlen(p)+1; 201 p += strlcpy(p, hdr.szArtist, 32) + 1;
55 202
56 /* Copyright (per codec) */ 203 /* Copyright (per codec) */
57 memcpy(p, &buf[78], 32);
58 id3->album = p; 204 id3->album = p;
205 strlcpy(p, hdr.szCopyright, 32);
59 206
60 return true; 207 return true;
61} 208}
62 209
210bool get_nsf_metadata(int fd, struct mp3entry* id3)
211{
212 uint32_t nsf_type;
213
214 if (lseek(fd, 0, SEEK_SET) < 0 ||
215 read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
216 return false;
217
218 id3->vbr = false;
219 id3->filesize = filesize(fd);
220 /* we only render 16 bits, 44.1KHz, Mono */
221 id3->bitrate = 706;
222 id3->frequency = 44100;
223
224 if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E'))
225 return parse_nsfe(fd, id3);
226 else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M'))
227 return parse_nesm(fd, id3);
228
229 /* not a valid format*/
230 return false;
231}
232