summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/codecs/Makefile1
-rw-r--r--apps/codecs/SOURCES1
-rw-r--r--apps/metadata.c121
-rw-r--r--apps/tree.c1
-rw-r--r--docs/CREDITS1
-rw-r--r--firmware/export/id3.h1
-rw-r--r--firmware/id3.c2
7 files changed, 128 insertions, 0 deletions
diff --git a/apps/codecs/Makefile b/apps/codecs/Makefile
index fb1228d7fc..62312e2288 100644
--- a/apps/codecs/Makefile
+++ b/apps/codecs/Makefile
@@ -50,6 +50,7 @@ $(BUILDDIR)/%.a : % $(CODECDEPS)
50 50
51$(OBJDIR)/wav.elf : $(OBJDIR)/wav.o 51$(OBJDIR)/wav.elf : $(OBJDIR)/wav.o
52$(OBJDIR)/sid.elf : $(OBJDIR)/sid.o 52$(OBJDIR)/sid.elf : $(OBJDIR)/sid.o
53$(OBJDIR)/adx.elf : $(OBJDIR)/adx.o
53$(OBJDIR)/aiff.elf : $(OBJDIR)/aiff.o 54$(OBJDIR)/aiff.elf : $(OBJDIR)/aiff.o
54$(OBJDIR)/mpa.elf : $(OBJDIR)/mpa.o $(BUILDDIR)/libmad.a 55$(OBJDIR)/mpa.elf : $(OBJDIR)/mpa.o $(BUILDDIR)/libmad.a
55$(OBJDIR)/a52.elf : $(OBJDIR)/a52.o $(BUILDDIR)/liba52.a 56$(OBJDIR)/a52.elf : $(OBJDIR)/a52.o $(BUILDDIR)/liba52.a
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index 3bd09b4dae..feadcde0ac 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -14,6 +14,7 @@ aac.c
14shorten.c 14shorten.c
15aiff.c 15aiff.c
16sid.c 16sid.c
17adx.c
17#if defined(HAVE_RECORDING) && !defined(SIMULATOR) 18#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
18/* encoders */ 19/* encoders */
19mp3_enc.c 20mp3_enc.c
diff --git a/apps/metadata.c b/apps/metadata.c
index 676108116d..1b2dde3a24 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -82,6 +82,7 @@ static const struct format_list formats[] =
82 { AFMT_AIFF, "aif" }, 82 { AFMT_AIFF, "aif" },
83 { AFMT_AIFF, "aiff" }, 83 { AFMT_AIFF, "aiff" },
84 { AFMT_SID, "sid" }, 84 { AFMT_SID, "sid" },
85 { AFMT_ADX, "adx" },
85#endif 86#endif
86}; 87};
87 88
@@ -1333,6 +1334,118 @@ static bool get_sid_metadata(int fd, struct mp3entry* id3)
1333 return true; 1334 return true;
1334} 1335}
1335 1336
1337static bool get_adx_metadata(int fd, struct mp3entry* id3)
1338{
1339 /* Use the trackname part of the id3 structure as a temporary buffer */
1340 unsigned char * buf = id3->path;
1341 int chanstart, channels, read_bytes;
1342 int looping = 0, start_adr = 0, end_adr = 0;
1343
1344 /* try to get the basic header */
1345 if ((lseek(fd, 0, SEEK_SET) < 0)
1346 || ((read_bytes = read(fd, buf, 0x38)) < 0x38))
1347 {
1348 DEBUGF("lseek or read failed\n");
1349 return false;
1350 }
1351
1352 /* ADX starts with 0x80 */
1353 if (buf[0] != 0x80) {
1354 DEBUGF("get_adx_metadata: wrong first byte %c\n",buf[0]);
1355 return false;
1356 }
1357
1358 /* check for a reasonable offset */
1359 chanstart = ((buf[2] << 8) | buf[3]) + 4;
1360 if (chanstart > 4096) {
1361 DEBUGF("get_adx_metadata: bad chanstart %i\n", chanstart);
1362 return false;
1363 }
1364
1365 /* check for a workable number of channels */
1366 channels = buf[7];
1367 if (channels != 1 && channels != 2) {
1368 DEBUGF("get_adx_metadata: bad channel count %i\n",channels);
1369 return false;
1370 }
1371
1372 id3->frequency = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
1373 /* 32 samples per 18 bytes */
1374 id3->bitrate = id3->frequency * channels * 18 * 8 / 32 / 1000;
1375 id3->length = ((unsigned long)
1376 (buf[12] << 24) | (buf[13] << 16) | (buf[14] << 8) | buf[15]) /
1377 id3->frequency * 1000;
1378 id3->vbr = false;
1379 id3->filesize = filesize(fd);
1380
1381 /* get loop info */
1382 if (!memcmp(buf+0x10,"\x01\xF4\x03\x00",4)) {
1383 /* Soul Calibur 2 style (type 03) */
1384 DEBUGF("get_adx_metadata: type 03 found\n");
1385 /* check if header is too small for loop data */
1386 if (chanstart-6 < 0x2c) looping=0;
1387 else {
1388 looping = (buf[0x18]) ||
1389 (buf[0x19]) ||
1390 (buf[0x1a]) ||
1391 (buf[0x1b]);
1392 end_adr = (buf[0x28]<<24) |
1393 (buf[0x29]<<16) |
1394 (buf[0x2a]<<8) |
1395 (buf[0x2b]);
1396
1397 start_adr = (
1398 (buf[0x1c]<<24) |
1399 (buf[0x1d]<<16) |
1400 (buf[0x1e]<<8) |
1401 (buf[0x1f])
1402 )/32*channels*18+chanstart;
1403 }
1404 } else if (!memcmp(buf+0x10,"\x01\xF4\x04\x00",4)) {
1405 /* Standard (type 04) */
1406 DEBUGF("get_adx_metadata: type 04 found\n");
1407 /* check if header is too small for loop data */
1408 if (chanstart-6 < 0x38) looping=0;
1409 else {
1410 looping = (buf[0x24]) ||
1411 (buf[0x25]) ||
1412 (buf[0x26]) ||
1413 (buf[0x27]);
1414 end_adr = (buf[0x34]<<24) |
1415 (buf[0x35]<<16) |
1416 (buf[0x36]<<8) |
1417 buf[0x37];
1418 start_adr = (
1419 (buf[0x28]<<24) |
1420 (buf[0x29]<<16) |
1421 (buf[0x2a]<<8) |
1422 (buf[0x2b])
1423 )/32*channels*18+chanstart;
1424 }
1425 } else {
1426 DEBUGF("get_adx_metadata: error, couldn't determine ADX type\n");
1427 return false;
1428 }
1429
1430 if (looping) {
1431 /* 2 loops, 10 second fade */
1432 id3->length = (start_adr-chanstart + 2*(end_adr-start_adr))
1433 *8 / id3->bitrate + 10000;
1434 }
1435
1436 /* try to get the channel header */
1437 if ((lseek(fd, chanstart-6, SEEK_SET) < 0)
1438 || ((read_bytes = read(fd, buf, 6)) < 6))
1439 {
1440 return false;
1441 }
1442
1443 /* check channel header */
1444 if (memcmp(buf, "(c)CRI", 6) != 0) return false;
1445
1446 return true;
1447}
1448
1336#endif /* CONFIG_CODEC == SWCODEC */ 1449#endif /* CONFIG_CODEC == SWCODEC */
1337 1450
1338static bool get_aiff_metadata(int fd, struct mp3entry* id3) 1451static bool get_aiff_metadata(int fd, struct mp3entry* id3)
@@ -1629,6 +1742,14 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname,
1629 } 1742 }
1630 break; 1743 break;
1631 1744
1745 case AFMT_ADX:
1746 if (!get_adx_metadata(fd, &(track->id3)))
1747 {
1748 DEBUGF("get_adx_metadata error\n");
1749 return false;
1750 }
1751
1752 break;
1632#endif /* CONFIG_CODEC == SWCODEC */ 1753#endif /* CONFIG_CODEC == SWCODEC */
1633 1754
1634 case AFMT_AIFF: 1755 case AFMT_AIFF:
diff --git a/apps/tree.c b/apps/tree.c
index 8e155a96a0..3ee3061540 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -104,6 +104,7 @@ const struct filetype filetypes[] = {
104 { "aif", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, 104 { "aif", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
105 { "aiff",TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, 105 { "aiff",TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
106 { "sid", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, 106 { "sid", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
107 { "adx", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA },
107#endif 108#endif
108 { "m3u", TREE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 109 { "m3u", TREE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
109 { "m3u8", TREE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 110 { "m3u8", TREE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
diff --git a/docs/CREDITS b/docs/CREDITS
index 141f7d6d69..3fc97187c7 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -238,3 +238,4 @@ Andrew Melville
238Pengxuan Liu 238Pengxuan Liu
239Andrew Cupper 239Andrew Cupper
240Thilo-Alexander Ginkel 240Thilo-Alexander Ginkel
241Adam Gashlin
diff --git a/firmware/export/id3.h b/firmware/export/id3.h
index dc58178d50..2a42788788 100644
--- a/firmware/export/id3.h
+++ b/firmware/export/id3.h
@@ -42,6 +42,7 @@ enum {
42 AFMT_SHN, /* Shorten */ 42 AFMT_SHN, /* Shorten */
43 AFMT_AIFF, /* Audio Interchange File Format */ 43 AFMT_AIFF, /* Audio Interchange File Format */
44 AFMT_SID, /* SID File Format */ 44 AFMT_SID, /* SID File Format */
45 AFMT_ADX, /* ADX */
45 46
46 /* New formats must be added to the end of this list */ 47 /* New formats must be added to the end of this list */
47 48
diff --git a/firmware/id3.c b/firmware/id3.c
index 5dfb3fbe50..d14134f215 100644
--- a/firmware/id3.c
+++ b/firmware/id3.c
@@ -119,6 +119,8 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
119 AFMT_ENTRY("AIFF", "aiff.codec", NULL, NULL ), 119 AFMT_ENTRY("AIFF", "aiff.codec", NULL, NULL ),
120 /* SID File Format */ 120 /* SID File Format */
121 AFMT_ENTRY("SID", "sid.codec", NULL, NULL ), 121 AFMT_ENTRY("SID", "sid.codec", NULL, NULL ),
122 /* ADX File Format */
123 AFMT_ENTRY("ADX", "adx.codec", NULL, NULL ),
122#endif 124#endif
123}; 125};
124 126