summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoshihisa Uchida <uchida@rockbox.org>2010-03-13 05:53:54 +0000
committerYoshihisa Uchida <uchida@rockbox.org>2010-03-13 05:53:54 +0000
commit0996bbd27895874ce8b7738e839fb82e068a30fc (patch)
tree0e22744757cf4c268ea272d8087683e8e6f4647e
parent4446d1bc857b41e491d04b05eeccc873a206fd18 (diff)
downloadrockbox-0996bbd27895874ce8b7738e839fb82e068a30fc.tar.gz
rockbox-0996bbd27895874ce8b7738e839fb82e068a30fc.zip
corrects the smaf parser the following.
- It is normally retrieved even if the position of wave data is not in given position from the head. - The problem that artist/title/composer cannot be given normally when the character code != iso8859-1, utf-8. - The problem that the position of chunk does not given correctly some mmf files. - artist/title/composer stored in not id3v1buf but id3v2buf. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25141 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/libpcm/yamaha_adpcm.c6
-rw-r--r--apps/codecs/smaf.c348
-rw-r--r--apps/metadata/smaf.c578
3 files changed, 536 insertions, 396 deletions
diff --git a/apps/codecs/libpcm/yamaha_adpcm.c b/apps/codecs/libpcm/yamaha_adpcm.c
index 9f1a4742ee..0b997ad776 100644
--- a/apps/codecs/libpcm/yamaha_adpcm.c
+++ b/apps/codecs/libpcm/yamaha_adpcm.c
@@ -82,6 +82,12 @@ static bool set_format(struct pcm_format *format)
82{ 82{
83 fmt = format; 83 fmt = format;
84 84
85 if (fmt->channels == 0)
86 {
87 DEBUGF("CODEC_ERROR: channels is 0\n");
88 return false;
89 }
90
85 if (fmt->bitspersample != 4) 91 if (fmt->bitspersample != 4)
86 { 92 {
87 DEBUGF("CODEC_ERROR: yamaha adpcm must be 4 bitspersample: %d\n", 93 DEBUGF("CODEC_ERROR: yamaha adpcm must be 4 bitspersample: %d\n",
diff --git a/apps/codecs/smaf.c b/apps/codecs/smaf.c
index 8349d394ac..33a2a4b403 100644
--- a/apps/codecs/smaf.c
+++ b/apps/codecs/smaf.c
@@ -32,8 +32,8 @@ CODEC_HEADER
32 */ 32 */
33 33
34enum { 34enum {
35 SMAF_TRACK_CHUNK_SCORE = 0, /* Score Track */ 35 SMAF_AUDIO_TRACK_CHUNK = 0, /* PCM Audio Track */
36 SMAF_TRACK_CHUNK_AUDIO, /* PCM Audio Track */ 36 SMAF_SCORE_TRACK_CHUNK, /* Score Track */
37}; 37};
38 38
39/* SMAF supported codec formats */ 39/* SMAF supported codec formats */
@@ -44,9 +44,9 @@ enum {
44 SMAF_FORMAT_ADPCM, /* YAMAHA ADPCM */ 44 SMAF_FORMAT_ADPCM, /* YAMAHA ADPCM */
45}; 45};
46 46
47static int support_formats[2][3] = { 47static const int support_formats[2][3] = {
48 {SMAF_FORMAT_SIGNED_PCM, SMAF_FORMAT_UNSIGNED_PCM, SMAF_FORMAT_ADPCM },
49 {SMAF_FORMAT_SIGNED_PCM, SMAF_FORMAT_ADPCM, SMAF_FORMAT_UNSUPPORT }, 48 {SMAF_FORMAT_SIGNED_PCM, SMAF_FORMAT_ADPCM, SMAF_FORMAT_UNSUPPORT },
49 {SMAF_FORMAT_SIGNED_PCM, SMAF_FORMAT_UNSIGNED_PCM, SMAF_FORMAT_ADPCM },
50}; 50};
51 51
52static const struct pcm_entry pcm_codecs[] = { 52static const struct pcm_entry pcm_codecs[] = {
@@ -57,7 +57,7 @@ static const struct pcm_entry pcm_codecs[] = {
57 57
58#define NUM_FORMATS 3 58#define NUM_FORMATS 3
59 59
60static int basebits[4] = { 4, 8, 12, 16 }; 60static const int basebits[4] = { 4, 8, 12, 16 };
61 61
62#define PCM_SAMPLE_SIZE (2048*2) 62#define PCM_SAMPLE_SIZE (2048*2)
63 63
@@ -79,183 +79,243 @@ static const struct pcm_codec *get_codec(uint32_t formattag)
79 return 0; 79 return 0;
80} 80}
81 81
82static unsigned int get_be32(uint8_t *buf) 82static unsigned int get_be32(const uint8_t *buf)
83{ 83{
84 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 84 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
85} 85}
86 86
87static int convert_smaf_audio_format(int track_chunk, unsigned int audio_format) 87static int convert_smaf_channels(unsigned int ch)
88{
89 return (ch >> 7) + 1;
90}
91
92static int convert_smaf_audio_format(unsigned int chunk, unsigned int audio_format)
88{ 93{
89 if (audio_format > 3) 94 int idx = (audio_format & 0x70) >> 4;
90 return SMAF_FORMAT_UNSUPPORT; 95
96 if (idx < 3)
97 return support_formats[chunk][idx];
91 98
92 return support_formats[track_chunk][audio_format]; 99 DEBUGF("CODEC_ERROR: unsupport audio format: %d\n", audio_format);
100 return SMAF_FORMAT_UNSUPPORT;
93} 101}
94 102
95static int convert_smaf_audio_basebit(unsigned int basebit) 103static int convert_smaf_audio_basebit(unsigned int basebit)
96{ 104{
97 if (basebit > 4) 105 if (basebit < 4)
98 return 0; 106 return basebits[basebit];
99 return basebits[basebit]; 107
108 DEBUGF("CODEC_ERROR: illegal basebit: %d\n", basebit);
109 return 0;
110}
111
112static unsigned int search_chunk(const unsigned char *name, int nlen, off_t *pos)
113{
114 const unsigned char *buf;
115 unsigned int chunksize;
116 size_t size;
117
118 while (true)
119 {
120 buf = ci->request_buffer(&size, 8);
121 if (size < 8)
122 break;
123
124 chunksize = get_be32(buf + 4);
125 ci->advance_buffer(8);
126 *pos += 8;
127 if (memcmp(buf, name, nlen) == 0)
128 return chunksize;
129
130 ci->advance_buffer(chunksize);
131 *pos += chunksize;
132 }
133 DEBUGF("CODEC_ERROR: missing '%s' chunk\n", name);
134 return 0;
100} 135}
101 136
102static bool parse_audio_track(struct pcm_format *fmt, 137static bool parse_audio_track(struct pcm_format *fmt, unsigned int chunksize, off_t *pos)
103 unsigned char **stbuf, unsigned char *endbuf)
104{ 138{
105 unsigned char *buf = *stbuf; 139 const unsigned char *buf;
106 int chunksize; 140 size_t size;
107 141
108 buf += 8; 142 /* search PCM Audio Track Chunk */
109 fmt->channels = ((buf[2] & 0x80) >> 7) + 1; 143 ci->advance_buffer(chunksize);
110 fmt->formattag = convert_smaf_audio_format(SMAF_TRACK_CHUNK_AUDIO, 144 *pos += chunksize;
111 (buf[2] >> 4) & 0x07); 145 if (search_chunk("ATR", 3, pos) == 0)
112 if (fmt->formattag == SMAF_FORMAT_UNSUPPORT)
113 { 146 {
114 DEBUGF("CODEC_ERROR: unsupport pcm data format : %d\n", (buf[2] >> 4) & 0x07); 147 DEBUGF("CODEC_ERROR: missing PCM Audio Track Chunk\n");
115 return false; 148 return false;
116 } 149 }
117 fmt->bitspersample = convert_smaf_audio_basebit(buf[3] >> 4); 150
118 if (fmt->bitspersample == 0) 151 /*
152 * get format
153 * buf
154 * +0: Format Type
155 * +1: Sequence Type
156 * +2: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: frequency
157 * +3: bit 4-7: base bit
158 * +4: TimeBase_D
159 * +5: TimeBase_G
160 *
161 * Note: If PCM Audio Track does not include Sequence Data Chunk,
162 * tmp+6 is the start position of Wave Data Chunk.
163 */
164 buf = ci->request_buffer(&size, 6);
165 if (size < 6)
119 { 166 {
120 DEBUGF("CODEC_ERROR: unsupport pcm data basebit : %d\n", buf[3] >> 4); 167 DEBUGF("CODEC_ERROR: smaf is too small\n");
121 return false; 168 return false;
122 } 169 }
123 buf += 6; 170
124 while (buf < endbuf) 171 fmt->formattag = convert_smaf_audio_format(SMAF_AUDIO_TRACK_CHUNK, buf[2]);
172 fmt->channels = convert_smaf_channels(buf[2]);
173 fmt->bitspersample = convert_smaf_audio_basebit(buf[3] >> 4);
174
175 /* search Wave Data Chunk */
176 ci->advance_buffer(6);
177 *pos += 6;
178 fmt->numbytes = search_chunk("Awa", 3, pos);
179 if (fmt->numbytes == 0)
125 { 180 {
126 chunksize = get_be32(buf + 4) + 8; 181 DEBUGF("CODEC_ERROR: missing Wave Data Chunk\n");
127 if (memcmp(buf, "Awa", 3) == 0) 182 return false;
128 {
129 fmt->numbytes = get_be32(buf + 4);
130 buf += 8;
131 return true;
132 }
133 buf += chunksize;
134 } 183 }
135 DEBUGF("CODEC_ERROR: smaf does not include stream pcm data\n"); 184
136 return false; 185 return true;
137} 186}
138 187
139static bool parse_score_track(struct pcm_format *fmt, 188static bool parse_score_track(struct pcm_format *fmt, off_t *pos)
140 unsigned char **stbuf, unsigned char *endbuf)
141{ 189{
142 unsigned char *buf = *stbuf; 190 const unsigned char *buf;
143 int chunksize; 191 unsigned int chunksize;
192 size_t size;
193
194 /* parse Optional Data Chunk */
195 buf = ci->request_buffer(&size, 13);
196 if (size < 13)
197 {
198 DEBUGF("CODEC_ERROR: smaf is too small\n");
199 return false;
200 }
201
202 if (memcmp(buf + 5, "OPDA", 4) != 0)
203 {
204 DEBUGF("CODEC_ERROR: missing Optional Data Chunk\n");
205 return false;
206 }
144 207
145 if (buf[9] != 0x00) 208 /* Optional Data Chunk size */
209 chunksize = get_be32(buf + 9);
210
211 /* search Score Track Chunk */
212 ci->advance_buffer(13 + chunksize);
213 *pos += (13 + chunksize);
214 if (search_chunk("MTR", 3, pos) == 0)
146 { 215 {
147 DEBUGF("CODEC_ERROR: score track chunk unsupport sequence type %d\n", buf[9]); 216 DEBUGF("CODEC_ERROR: missing Score Track Chunk\n");
148 return false; 217 return false;
149 } 218 }
150 219
151 /* 220 /*
152 * skip to the next chunk. 221 * search next chunk
153 * MA-2/MA-3/MA-5: padding 16 bytes 222 * usually, next chunk ('M***') found within 40 bytes.
154 * MA-7: padding 32 bytes
155 */ 223 */
156 if (buf[3] < 7) 224 buf = ci->request_buffer(&size, 40);
157 buf += 28; 225 if (size < 40)
158 else
159 buf += 44;
160
161 while (buf < endbuf)
162 { 226 {
163 chunksize = get_be32(buf + 4) + 8; 227 DEBUGF("CODEC_ERROR: smaf is too small\n");
164 if (memcmp(buf, "Mtsp", 4) == 0) 228 return false;
165 {
166 buf += 8;
167 if (memcmp(buf, "Mwa", 3) != 0)
168 {
169 DEBUGF("CODEC_ERROR: smaf does not include stream pcm data\n");
170 return false;
171 }
172 fmt->numbytes = get_be32(buf + 4) - 3;
173 fmt->channels = ((buf[8] & 0x80) >> 7) + 1;
174 fmt->formattag = convert_smaf_audio_format(SMAF_TRACK_CHUNK_SCORE,
175 (buf[8] >> 4) & 0x07);
176 if (fmt->formattag == SMAF_FORMAT_UNSUPPORT)
177 {
178 DEBUGF("CODEC_ERROR: unsupport pcm data format : %d\n",
179 (buf[8] >> 4) & 0x07);
180 return false;
181 }
182 fmt->bitspersample = convert_smaf_audio_basebit(buf[8] & 0x0f);
183 if (fmt->bitspersample == 0)
184 {
185 DEBUGF("CODEC_ERROR: unsupport pcm data basebit : %d\n",
186 buf[8] & 0x0f);
187 return false;
188 }
189 buf += 11;
190 return true;
191 }
192 buf += chunksize;
193 } 229 }
194 230
195 DEBUGF("CODEC_ERROR: smaf does not include stream pcm data\n"); 231 size = 0;
196 return false; 232 while (size < 40 && buf[size] != 'M')
197} 233 size++;
198 234
199static bool parse_header(struct pcm_format *fmt, size_t *pos) 235 if (size >= 40)
200{ 236 {
201 unsigned char *buf, *stbuf, *endbuf; 237 DEBUGF("CODEC_ERROR: missing Score Track Stream PCM Data Chunk");
202 size_t chunksize; 238 return false;
239 }
203 240
204 ci->memset(fmt, 0, sizeof(struct pcm_format)); 241 /* search Score Track Stream PCM Data Chunk */
242 ci->advance_buffer(size);
243 *pos += size;
244 if (search_chunk("Mtsp", 4, pos) == 0)
245 {
246 DEBUGF("CODEC_ERROR: missing Score Track Stream PCM Data Chunk\n");
247 return false;
248 }
205 249
206 /* assume the SMAF pcm data position is less than 1024 bytes */ 250 /*
207 stbuf = ci->request_buffer(&chunksize, 1024); 251 * parse Score Track Stream Wave Data Chunk
208 if (chunksize < 1024) 252 * buf
253 * +4-7: chunk size (WaveType(3bytes) + wave data count)
254 * +8: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: base bit
255 * +9: frequency (MSB)
256 * +10: frequency (LSB)
257 */
258 buf = ci->request_buffer(&size, 9);
259 if (size < 9)
260 {
261 DEBUGF("CODEC_ERROR: smaf is too small\n");
209 return false; 262 return false;
263 }
210 264
211 buf = stbuf; 265 if (memcmp(buf, "Mwa", 3) != 0)
212 endbuf = stbuf + chunksize;
213
214 if (memcmp(buf, "MMMD", 4) != 0)
215 { 266 {
216 DEBUGF("CODEC_ERROR: does not smaf format %c%c%c%c\n", 267 DEBUGF("CODEC_ERROR: missing Score Track Stream Wave Data Chunk\n");
217 buf[0], buf[1], buf[2], buf[3]);
218 return false; 268 return false;
219 } 269 }
220 buf += 8;
221 270
222 while (buf < endbuf) 271 fmt->formattag = convert_smaf_audio_format(SMAF_SCORE_TRACK_CHUNK, buf[8]);
272 fmt->channels = convert_smaf_channels(buf[8]);
273 fmt->bitspersample = convert_smaf_audio_basebit(buf[8] & 0xf);
274 fmt->numbytes = get_be32(buf + 4) - 3;
275
276 *pos += 11;
277 return true;
278}
279
280static bool parse_header(struct pcm_format *fmt, off_t *pos)
281{
282 const unsigned char *buf;
283 unsigned int chunksize;
284 size_t size;
285
286 ci->memset(fmt, 0, sizeof(struct pcm_format));
287
288 /* check File Chunk and Contents Info Chunk */
289 buf = ci->request_buffer(&size, 16);
290 if (size < 16)
223 { 291 {
224 chunksize = get_be32(buf + 4) + 8; 292 DEBUGF("CODEC_ERROR: smaf is too small\n");
225 if (memcmp(buf, "ATR", 3) == 0) 293 return false;
226 {
227 if (!parse_audio_track(fmt, &buf, endbuf))
228 return false;
229 break;
230 }
231 if (memcmp(buf, "MTR", 3) == 0)
232 {
233 if (!parse_score_track(fmt, &buf, endbuf))
234 return false;
235 break;
236 }
237 buf += chunksize;
238 } 294 }
239 295
240 if (buf >= endbuf) 296 if ((memcmp(buf, "MMMD", 4) != 0) || (memcmp(buf + 8, "CNTI", 4) != 0))
241 { 297 {
242 DEBUGF("CODEC_ERROR: unsupported smaf format\n"); 298 DEBUGF("CODEC_ERROR: does not smaf format\n");
243 return false; 299 return false;
244 } 300 }
245 301
246 /* blockalign */ 302 chunksize = get_be32(buf + 12);
247 if (fmt->formattag == SMAF_FORMAT_SIGNED_PCM || 303 ci->advance_buffer(16);
248 fmt->formattag == SMAF_FORMAT_UNSIGNED_PCM) 304 *pos = 16;
249 fmt->blockalign = fmt->channels * fmt->bitspersample >> 3; 305 if (chunksize > 5)
306 {
307 if (!parse_audio_track(fmt, chunksize, pos))
308 return false;
309 }
310 else if (!parse_score_track(fmt, pos))
311 return false;
250 312
251 /* data signess (default signed) */ 313 /* data signess (default signed) */
252 fmt->is_signed = (fmt->formattag != SMAF_FORMAT_UNSIGNED_PCM); 314 fmt->is_signed = (fmt->formattag != SMAF_FORMAT_UNSIGNED_PCM);
253 315
316 /* data is always big endian */
254 fmt->is_little_endian = false; 317 fmt->is_little_endian = false;
255 318
256 /* sets pcm data position */
257 *pos = buf - stbuf;
258
259 return true; 319 return true;
260} 320}
261 321
@@ -297,14 +357,13 @@ next_track:
297 357
298 codec_set_replaygain(ci->id3); 358 codec_set_replaygain(ci->id3);
299 359
300 ci->memset(&format, 0, sizeof(struct pcm_format)); 360 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
301 format.is_signed = true; 361 bytesdone = ci->id3->offset;
302 format.is_little_endian = false;
303 362
304 decodedsamples = 0; 363 decodedsamples = 0;
305 codec = 0; 364 codec = 0;
306 365
307 if (!parse_header(&format, &n)) 366 if (!parse_header(&format, &firstblockposn))
308 { 367 {
309 status = CODEC_ERROR; 368 status = CODEC_ERROR;
310 goto done; 369 goto done;
@@ -324,29 +383,6 @@ next_track:
324 goto done; 383 goto done;
325 } 384 }
326 385
327 /* common format check */
328 if (format.channels == 0) {
329 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
330 status = CODEC_ERROR;
331 goto done;
332 }
333 if (format.samplesperblock == 0) {
334 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
335 status = CODEC_ERROR;
336 goto done;
337 }
338 if (format.blockalign == 0)
339 {
340 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
341 status = CODEC_ERROR;
342 goto done;
343 }
344 if (format.numbytes == 0) {
345 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
346 status = CODEC_ERROR;
347 goto done;
348 }
349
350 /* check chunksize */ 386 /* check chunksize */
351 if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels 387 if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels
352 > PCM_SAMPLE_SIZE) 388 > PCM_SAMPLE_SIZE)
@@ -370,12 +406,10 @@ next_track:
370 goto done; 406 goto done;
371 } 407 }
372 408
373 firstblockposn = 1024 - n; 409 ci->seek_buffer(firstblockposn);
374 ci->advance_buffer(firstblockposn); 410 ci->seek_complete();
375 411
376 /* The main decoder loop */ 412 /* The main decoder loop */
377 bytesdone = 0;
378 ci->set_elapsed(0);
379 endofstream = 0; 413 endofstream = 0;
380 414
381 while (!endofstream) { 415 while (!endofstream) {
diff --git a/apps/metadata/smaf.c b/apps/metadata/smaf.c
index 586802b7b5..ca5b690e0b 100644
--- a/apps/metadata/smaf.c
+++ b/apps/metadata/smaf.c
@@ -18,10 +18,7 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h> 21#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h> 22#include <inttypes.h>
26 23
27#include "system.h" 24#include "system.h"
@@ -31,339 +28,442 @@
31#include "rbunicode.h" 28#include "rbunicode.h"
32#include "logf.h" 29#include "logf.h"
33 30
34static int basebits[4] = { 4, 8, 12, 16 }; 31static const int basebits[4] = { 4, 8, 12, 16 };
35 32
36static int frequency[5] = { 4000, 8000, 11025, 22050, 44100 }; 33static const int frequency[5] = { 4000, 8000, 11025, 22050, 44100 };
37 34
38static int support_codepages[7] = { 35static const int support_codepages[5] = {
39 SJIS, ISO_8859_1, -1, GB_2312, BIG_5, -1, -1, 36#ifdef HAVE_LCD_BITMAP
37 SJIS, ISO_8859_1, -1, GB_2312, BIG_5,
38#else
39 -1, ISO_8859_1, -1, -1, -1,
40#endif
40}; 41};
41 42
42/* extra codepage */ 43/* extra codepage */
43#define UCS_2 (NUM_CODEPAGES + 1) 44#define UCS2 (NUM_CODEPAGES + 1)
44#define UTF_16 (NUM_CODEPAGES + 2)
45 45
46/* support id3 tag */ 46/* support id3 tag */
47#define TAG_TITLE (('S'<<8)|'T') 47#define TAG_TITLE (('S'<<8)|'T')
48#define TAG_ARTIST (('A'<<8)|'N') 48#define TAG_ARTIST (('A'<<8)|'N')
49#define TAG_COMPOSER (('S'<<8)|'W') 49#define TAG_COMPOSER (('S'<<8)|'W')
50 50
51static bool read_datachunk(unsigned char *src, int size, unsigned short tag, 51/* convert functions */
52 int codepage, unsigned char *dst) 52#define CONVERT_SMAF_CHANNELS(c) (((c) >> 7) + 1)
53{
54 int datasize = 0;
55 unsigned char *utf8;
56 53
57 while(size > datasize + 4)
58 {
59 datasize = (src[2] << 8) | src[3];
60 if (tag == ((src[0] << 8) | src[1]))
61 {
62 src += 4;
63 if (codepage < NUM_CODEPAGES)
64 utf8 = iso_decode(src, dst, codepage, datasize);
65 else /* codepage == UTF_16, UCS_2 */
66 utf8 = utf16BEdecode(src, dst, datasize);
67 *utf8 = '\0';
68
69 return true;
70 }
71 src += (datasize + 4);
72 }
73 return false;
74}
75 54
76static bool read_option(unsigned char *src, int size, unsigned short tag, 55static inline int convert_smaf_audio_basebit(unsigned int basebit)
77 int codepage, unsigned char *dst)
78{ 56{
79 int datasize = 0; 57 if (basebit > 3)
80 unsigned char *endsrc = src + size; 58 return 0;
81 unsigned char *utf8; 59 return basebits[basebit];
82
83 while(src < endsrc)
84 {
85 utf8 = src;
86 src += 3;
87 datasize = 0;
88 while (*src != ',' || *(src-1) == '\\')
89 {
90 datasize++;
91 src++;
92 }
93 if (tag == ((utf8[0] << 8) | utf8[1]) && utf8[2] == ':')
94 {
95 utf8 += 3;
96 if (codepage < NUM_CODEPAGES)
97 utf8 = iso_decode(utf8, dst, codepage, datasize);
98 else /* codepage == UTF_16, UCS_2 */
99 utf8 = utf16BEdecode(utf8, dst, datasize);
100 *utf8 = '\0';
101
102 return true;
103 }
104 src++;
105 }
106 return false;
107} 60}
108 61
109static int convert_smaf_audio_frequency(unsigned int freq) 62static inline int convert_smaf_audio_frequency(unsigned int freq)
110{ 63{
111 if (freq > 4) 64 if (freq > 4)
112 return 0; 65 return 0;
113 return frequency[freq]; 66 return frequency[freq];
114} 67}
115 68
116static int convert_smaf_audio_basebit(unsigned int basebit)
117{
118 if (basebit > 4)
119 return 0;
120 return basebits[basebit];
121}
122
123static int convert_smaf_codetype(unsigned int codetype) 69static int convert_smaf_codetype(unsigned int codetype)
124{ 70{
125 if (codetype < 7) 71 if (codetype < 5)
126 return support_codepages[codetype]; 72 return support_codepages[codetype];
127 else if (codetype < 0x20) 73 else if (codetype == 0x20 || codetype == 0x24) /* In Rockbox, UCS2 and UTF-16 are same. */
128 return -1; 74 return UCS2;
129 else if (codetype == 0x20)
130 return UCS_2;
131 else if (codetype == 0x23) 75 else if (codetype == 0x23)
132 return UTF_8; 76 return UTF_8;
133 else if (codetype == 0x24)
134 return UTF_16;
135 else if (codetype == 0xff) 77 else if (codetype == 0xff)
136 return ISO_8859_1; 78 return ISO_8859_1;
137 return -1; 79 return -1;
138} 80}
139 81
140static bool get_smaf_metadata_audio_track(struct mp3entry *id3, 82static void set_length(struct mp3entry *id3, unsigned int ch, unsigned int basebit,
141 unsigned char* buf, unsigned char *endbuf) 83 unsigned int numbytes)
142{ 84{
143 int bitspersample; 85 int bitspersample = convert_smaf_audio_basebit(basebit);
144 int channels; 86
145 int chunksize; 87 if (bitspersample != 0 && id3->frequency != 0)
146 long numbytes;
147 unsigned long totalsamples;
148
149 channels = ((buf[10] & 0x80) >> 7) + 1;
150 bitspersample = convert_smaf_audio_basebit(buf[11] >> 4);
151 if (bitspersample == 0)
152 { 88 {
153 DEBUGF("metada error: smaf unsupport basebit %d\n", buf[11] >> 4); 89 /* Calculate track length [ms] and bitrate [kbit/s] */
154 return false; 90 id3->length = (uint64_t)numbytes * 8000LL
91 / (bitspersample * CONVERT_SMAF_CHANNELS(ch) * id3->frequency);
92 id3->bitrate = bitspersample * id3->frequency / 1000;
155 } 93 }
156 id3->frequency = convert_smaf_audio_frequency(buf[10] & 0x0f);
157 94
158 buf += 14; 95 /* output contents/wave data/id3 info (for debug) */
159 while (buf < endbuf) 96 DEBUGF("contents info ----\n");
160 { 97 DEBUGF(" TITLE: %s\n", (id3->title)? id3->title : "(NULL)");
161 chunksize = get_long_be(buf + 4) + 8; 98 DEBUGF(" ARTIST: %s\n", (id3->artist)? id3->artist : "(NULL)");
162 if (memcmp(buf, "Awa", 3) == 0) 99 DEBUGF(" COMPOSER: %s\n", (id3->composer)? id3->composer : "(NULL)");
163 { 100 DEBUGF("wave data info ----\n");
164 numbytes = get_long_be(buf + 4) - 3; 101 DEBUGF(" channels: %u\n", CONVERT_SMAF_CHANNELS(ch));
165 totalsamples = (numbytes << 3) / (bitspersample * channels); 102 DEBUGF(" bitspersample: %d\n", bitspersample);
103 DEBUGF(" numbytes; %u\n", numbytes);
104 DEBUGF("id3 info ----\n");
105 DEBUGF(" frquency: %u\n", (unsigned int)id3->frequency);
106 DEBUGF(" bitrate: %d\n", id3->bitrate);
107 DEBUGF(" length: %u\n", (unsigned int)id3->length);
108}
166 109
167 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ 110/* contents parse functions */
168 id3->length = ((int64_t)totalsamples * 1000LL) / id3->frequency;
169 111
170 return true; 112/* Note:
171 } 113 * 1) When the codepage is UTF-8 or UCS2, contents data do not start BOM.
172 buf += chunksize; 114 * 2) The byte order of contents data is big endian.
115 */
116
117static void decode2utf8(const unsigned char *src, unsigned char **dst,
118 int srcsize, int *dstsize, int codepage)
119{
120 unsigned char tmpbuf[srcsize * 3 + 1];
121 unsigned char *p;
122 int utf8size;
123
124 if (codepage < NUM_CODEPAGES)
125 p = iso_decode(src, tmpbuf, codepage, srcsize);
126 else /* codepage == UCS2 */
127 p = utf16BEdecode(src, tmpbuf, srcsize);
128
129 *p = '\0';
130
131 strlcpy(*dst, tmpbuf, *dstsize);
132 utf8size = (p - tmpbuf) + 1;
133 if (utf8size > *dstsize)
134 {
135 DEBUGF("metadata warning: data length: %d > contents store buffer size: %d\n",
136 utf8size, *dstsize);
137 utf8size = *dstsize;
173 } 138 }
174 DEBUGF("metada error: smaf does not include pcm audio data\n"); 139 *dst += utf8size;
175 return false; 140 *dstsize -= utf8size;
176} 141}
177 142
178static bool get_smaf_metadata_score_track(struct mp3entry *id3, 143static int read_audio_track_contets(int fd, int codepage, unsigned char **dst,
179 unsigned char* buf, unsigned char *endbuf) 144 int *dstsize)
180{ 145{
181 int bitspersample; 146 /* value length <= 256 bytes */
182 int channels; 147 unsigned char buf[256];
183 int chunksize; 148 unsigned char *p = buf;
184 long numbytes; 149 unsigned char *q = buf;
185 unsigned long totalsamples; 150 int datasize;
186 151
187 /* 152 read(fd, buf, 256);
188 * skip to the next chunk.
189 * MA-2/MA-3/MA-5: padding 16 bytes
190 * MA-7: padding 32 bytes
191 */
192 if (buf[3] < 7)
193 buf += 28;
194 else
195 buf += 44;
196 153
197 while (buf + 10 < endbuf) 154 while (p - buf < 256 && *p != ',')
198 { 155 {
199 chunksize = get_long_be(buf + 4) + 8; 156 /* skip yen mark */
200 if (memcmp(buf, "Mtsp", 4) == 0) 157 if (codepage != UCS2)
201 { 158 {
202 buf += 8; 159 if (*p == '\\')
203 if (memcmp(buf, "Mwa", 3) != 0) 160 p++;
161 }
162 else if (*p == '\0' && *(p+1) == '\\')
163 p += 2;
164
165 if (*p > 0x7f)
166 {
167 if (codepage == UTF_8)
204 { 168 {
205 DEBUGF("metada error: smaf unsupport format: %c%c%c%c\n", 169 while ((*p & MASK) != COMP)
206 buf[0], buf[1], buf[2], buf[3]); 170 *q++ = *p++;
207 return false;
208 } 171 }
209 172#ifdef HAVE_LCD_BITMAP
210 channels = ((buf[8] & 0x80) >> 7) + 1; 173 else if (codepage == SJIS)
211 bitspersample = convert_smaf_audio_basebit(buf[8] & 0x0f);
212 if (bitspersample == 0)
213 { 174 {
214 DEBUGF("metada error: smaf unsupport basebit %d\n", buf[8] & 0x0f); 175 if (*p <= 0xa0 || *p >= 0xe0)
215 return false; 176 *q++ = *p++;
216 } 177 }
178#endif
179 }
217 180
218 numbytes = get_long_be(buf + 4) - 3; 181 *q++ = *p++;
219 totalsamples = numbytes * 8 / (bitspersample * channels); 182 if (codepage == UCS2)
220 183 *q++ = *p++;
221 id3->frequency = (buf[9] << 8) | buf[10]; 184 }
185 datasize = p - buf + 1;
186 lseek(fd, datasize - 256, SEEK_CUR);
222 187
223 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */ 188 if (dst != NULL)
224 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; 189 decode2utf8(buf, dst, q - buf, dstsize, codepage);
225 190
226 return true; 191 return datasize;
227 }
228 buf += chunksize;
229 }
230 DEBUGF("metada error: smaf does not include pcm audio data\n");
231 return false;
232} 192}
233 193
234bool get_smaf_metadata(int fd, struct mp3entry* id3) 194static void read_score_track_contets(int fd, int codepage, int datasize,
195 unsigned char **dst, int *dstsize)
235{ 196{
236 unsigned char smafbuf[1024]; 197 unsigned char buf[datasize];
237 198
238 /* Use the trackname part of the id3 structure as a temporary buffer */ 199 read(fd, buf, datasize);
239 unsigned char* buf = (unsigned char *)id3->path; 200 decode2utf8(buf, dst, datasize, dstsize, codepage);
240 unsigned char *endbuf = smafbuf + sizeof(smafbuf); 201}
241 int i;
242 int contents_size;
243 int codepage = ISO_8859_1;
244 202
245 id3->title = NULL; 203/* traverse chunk functions */
246 id3->artist = NULL;
247 id3->composer = NULL;
248 204
249 id3->vbr = false; /* All SMAF files are CBR */ 205static unsigned int search_chunk(int fd, const unsigned char *name, int nlen)
250 id3->filesize = filesize(fd); 206{
207 unsigned char buf[8];
208 unsigned int chunksize;
251 209
252 /* get RIFF chunk header */ 210 while (read(fd, buf, 8) > 0)
253 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 21) < 21))
254 { 211 {
255 return false; 212 chunksize = get_long_be(buf + 4);
256 } 213 if (memcmp(buf, name, nlen) == 0)
214 return chunksize;
257 215
258 if ((memcmp(buf, "MMMD", 4) != 0) || (memcmp(&buf[8], "CNTI", 4) != 0)) 216 lseek(fd, chunksize, SEEK_CUR);
259 {
260 DEBUGF("metada error: does not smaf format\n");
261 return false;
262 } 217 }
218 DEBUGF("metadata error: missing '%s' chunk\n", name);
219 return 0;
220}
221
222static bool parse_smaf_audio_track(int fd, struct mp3entry *id3, unsigned int datasize)
223{
224 /* temporary buffer */
225 unsigned char *tmp = (unsigned char*)id3->path;
226 /* contents stored buffer */
227 unsigned char *buf = id3->id3v2buf;
228 int bufsize = sizeof(id3->id3v2buf);
229
230 unsigned int chunksize = datasize;
231 int valsize;
263 232
264 contents_size = get_long_be(buf + 12); 233 int codepage;
265 if (contents_size < 5) 234
235 /* parse contents info */
236 read(fd, tmp, 5);
237 codepage = convert_smaf_codetype(tmp[2]);
238 if (codepage < 0)
266 { 239 {
267 DEBUGF("metada error: CNTI chunk size is small %d\n", contents_size); 240 DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[2]);
268 return false; 241 return false;
269 } 242 }
270 243
271 contents_size -= 5; 244 datasize -= 5;
272 i = contents_size; 245 while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL)
273 if (i == 0) 246 && (datasize > 0 && bufsize > 0))
274 { 247 {
275 read(fd, buf, 16); 248 if (read(fd, tmp, 3) <= 0)
276 if (memcmp(buf, "OPDA", 4) != 0)
277 {
278 DEBUGF("metada error: smaf does not include OPDA chunk\n");
279 return false; 249 return false;
280 }
281 contents_size = get_long_be(buf + 4) - 8;
282 250
283 if (memcmp(buf + 8, "Dch", 3) != 0) 251 if (tmp[2] != ':')
284 { 252 {
285 DEBUGF("metada error: smaf does not include Dch chunk\n"); 253 DEBUGF("metadata error: illegal tag: %c%c%c\n", tmp[0], tmp[1], tmp[2]);
286 return false; 254 return false;
287 } 255 }
288 codepage = convert_smaf_codetype(buf[11]); 256 switch ((tmp[0]<<8)|tmp[1])
289 if (codepage < 0)
290 { 257 {
291 DEBUGF("metada error: smaf unsupport codetype: %d\n", buf[11]); 258 case TAG_TITLE:
292 return false; 259 id3->title = buf;
260 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
261 break;
262 case TAG_ARTIST:
263 id3->artist = buf;
264 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
265 break;
266 case TAG_COMPOSER:
267 id3->composer = buf;
268 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
269 break;
270 default:
271 valsize = read_audio_track_contets(fd, codepage, NULL, &bufsize);
272 break;
293 } 273 }
274 datasize -= (valsize + 3);
275 }
294 276
295 i = get_long_be(buf + 12); 277 /* search PCM Audio Track Chunk */
278 lseek(fd, 16 + chunksize, SEEK_SET);
296 279
297 if (i > MAX_PATH) 280 chunksize = search_chunk(fd, "ATR", 3);
298 { 281 if (chunksize == 0)
299 DEBUGF("metada warning: smaf contents size is big %d\n", i); 282 {
300 i = MAX_PATH; 283 DEBUGF("metadata error: missing PCM Audio Track Chunk\n");
301 } 284 return false;
302 if (read(fd, buf, i) < i) 285 }
303 return false; 286
287 /*
288 * get format
289 * tmp
290 * +0: Format Type
291 * +1: Sequence Type
292 * +2: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: frequency
293 * +3: bit 4-7: base bit
294 * +4: TimeBase_D
295 * +5: TimeBase_G
296 *
297 * Note: If PCM Audio Track does not include Sequence Data Chunk,
298 * tmp+6 is the start position of Wave Data Chunk.
299 */
300 read(fd, tmp, 6);
301
302 /* search Wave Data Chunk */
303 chunksize = search_chunk(fd, "Awa", 3);
304 if (chunksize == 0)
305 {
306 DEBUGF("metadata error: missing Wave Data Chunk\n");
307 return false;
308 }
304 309
305 /* title */ 310 /* set track length and bitrate */
306 if (read_datachunk(buf, i, TAG_TITLE, codepage, id3->id3v1buf[0])) 311 id3->frequency = convert_smaf_audio_frequency(tmp[2] & 0x0f);
307 id3->title = id3->id3v1buf[0]; 312 set_length(id3, tmp[2], tmp[3] >> 4, chunksize);
313 return true;
314}
315
316static bool parse_smaf_score_track(int fd, struct mp3entry *id3)
317{
318 /* temporary buffer */
319 unsigned char *tmp = (unsigned char*)id3->path;
320 unsigned char *p = tmp;
321 /* contents stored buffer */
322 unsigned char *buf = id3->id3v2buf;
323 int bufsize = sizeof(id3->id3v2buf);
324
325 unsigned int chunksize;
326 unsigned int datasize;
327 int valsize;
328
329 int codepage;
330
331 /* parse Optional Data Chunk */
332 read(fd, tmp, 21);
333 if (memcmp(tmp + 5, "OPDA", 4) != 0)
334 {
335 DEBUGF("metadata error: missing Optional Data Chunk\n");
336 return false;
337 }
308 338
309 /* artist */ 339 /* Optional Data Chunk size */
310 if (read_datachunk(buf, i, TAG_ARTIST, codepage, id3->id3v1buf[1])) 340 chunksize = get_long_be(tmp + 9);
311 id3->artist = id3->id3v1buf[1];
312 341
313 /* composer */ 342 /* parse Data Chunk */
314 if (read_datachunk(buf, i, TAG_COMPOSER, codepage, id3->id3v1buf[2])) 343 if (memcmp(tmp + 13, "Dch", 3) != 0)
315 id3->composer = id3->id3v1buf[2]; 344 {
345 DEBUGF("metadata error: missing Data Chunk\n");
346 return false;
316 } 347 }
317 else 348
349 codepage = convert_smaf_codetype(tmp[16]);
350 if (codepage < 0)
318 { 351 {
319 codepage = convert_smaf_codetype(buf[14]); 352 DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[16]);
320 if (codepage < 0) 353 return false;
321 { 354 }
322 DEBUGF("metada error: smaf unsupport codetype: %d\n", buf[11]); 355
356 /* Data Chunk size */
357 datasize = get_long_be(tmp + 17);
358 while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL)
359 && (datasize > 0 && bufsize > 0))
360 {
361 if (read(fd, tmp, 4) <= 0)
323 return false; 362 return false;
324 }
325 363
326 if (i > MAX_PATH) 364 valsize = (tmp[2] << 8) | tmp[3];
365 datasize -= (valsize + 4);
366 switch ((tmp[0]<<8)|tmp[1])
327 { 367 {
328 DEBUGF("metada warning: smaf contents size is big %d\n", i); 368 case TAG_TITLE:
329 i = MAX_PATH; 369 id3->title = buf;
370 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
371 break;
372 case TAG_ARTIST:
373 id3->artist = buf;
374 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
375 break;
376 case TAG_COMPOSER:
377 id3->composer = buf;
378 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
379 break;
380 default:
381 lseek(fd, valsize, SEEK_CUR);
382 break;
330 } 383 }
331 if (read(fd, buf, i) < i) 384 }
332 return false;
333
334 /* title */
335 if (read_option(buf, i, TAG_TITLE, codepage, id3->id3v1buf[0]))
336 id3->title = id3->id3v1buf[0];
337 385
338 /* artist */ 386 /* search Score Track Chunk */
339 if (read_option(buf, i, TAG_ARTIST, codepage, id3->id3v1buf[1])) 387 lseek(fd, 29 + chunksize, SEEK_SET);
340 id3->artist = id3->id3v1buf[1];
341 388
342 /* composer */ 389 if (search_chunk(fd, "MTR", 3) == 0)
343 if (read_option(buf, i, TAG_COMPOSER, codepage, id3->id3v1buf[2])) 390 {
344 id3->composer = id3->id3v1buf[2]; 391 DEBUGF("metadata error: missing Score Track Chunk\n");
392 return false;
345 } 393 }
346 394
347 if (contents_size > i) 395 /*
348 lseek(fd, contents_size - i, SEEK_CUR); 396 * search next chunk
397 * usually, next chunk ('M***') found within 40 bytes.
398 */
399 chunksize = 40;
400 read(fd, tmp, chunksize);
401
402 tmp[chunksize] = 'M'; /* stopper */
403 while (*p != 'M')
404 p++;
349 405
350 /* assume the SMAF pcm data position is near the start */ 406 chunksize -= (p - tmp);
351 if (read(fd, smafbuf, sizeof(smafbuf)) < (ssize_t)sizeof(smafbuf)) 407 if (chunksize == 0)
408 {
409 DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk");
352 return false; 410 return false;
411 }
353 412
354 buf = smafbuf; 413 /* search Score Track Stream PCM Data Chunk */
355 while (buf + 8 < endbuf) 414 lseek(fd, -chunksize, SEEK_CUR);
415 if (search_chunk(fd, "Mtsp", 4) == 0)
356 { 416 {
357 i = get_long_be(buf + 4) + 8; 417 DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk\n");
418 return false;
419 }
358 420
359 if (memcmp(buf, "ATR", 3) == 0) 421 /*
360 return get_smaf_metadata_audio_track(id3, buf, endbuf); 422 * parse Score Track Stream Wave Data Chunk
361 else if (memcmp(buf, "MTR", 3) == 0) 423 * tmp
362 return get_smaf_metadata_score_track(id3, buf, endbuf); 424 * +4-7: chunk size (WaveType(3bytes) + wave data count)
425 * +8: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: base bit
426 * +9: frequency (MSB)
427 * +10: frequency (LSB)
428 */
429 read(fd, tmp, 11);
430 if (memcmp(tmp, "Mwa", 3) != 0)
431 {
432 DEBUGF("metadata error: missing Score Track Stream Wave Data Chunk\n");
433 return false;
434 }
435
436 /* set track length and bitrate */
437 id3->frequency = (tmp[9] << 8) | tmp[10];
438 set_length(id3, tmp[8], tmp[8] & 0x0f, get_long_be(tmp + 4) - 3);
439 return true;
440}
441
442bool get_smaf_metadata(int fd, struct mp3entry* id3)
443{
444 /* temporary buffer */
445 unsigned char *tmp = (unsigned char *)id3->path;
446 unsigned int chunksize;
363 447
364 buf += i; 448 id3->title = NULL;
449 id3->artist = NULL;
450 id3->composer = NULL;
451
452 id3->vbr = false; /* All SMAF files are CBR */
453 id3->filesize = filesize(fd);
454
455 /* check File Chunk and Contents Info Chunk */
456 lseek(fd, 0, SEEK_SET);
457 read(fd, tmp, 16);
458 if ((memcmp(tmp, "MMMD", 4) != 0) || (memcmp(tmp + 8, "CNTI", 4) != 0))
459 {
460 DEBUGF("metadata error: does not smaf format\n");
461 return false;
365 } 462 }
366 463
367 DEBUGF("metada error: smaf does not include track chunk\n"); 464 chunksize = get_long_be(tmp + 12);
368 return false; 465 if (chunksize > 5)
466 return parse_smaf_audio_track(fd, id3, chunksize);
467
468 return parse_smaf_score_track(fd, id3);
369} 469}