summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Wenger <domonoky@googlemail.com>2008-07-26 15:16:10 +0000
committerDominik Wenger <domonoky@googlemail.com>2008-07-26 15:16:10 +0000
commit25bb37bb6851c85e21fb0cecfd9617eebe6c7a56 (patch)
tree14800e46724f8fa90c2ea1cb7100ac89423cde4e
parent4e4bf82fb756f36dca6af333357a54e09b9f4cca (diff)
downloadrockbox-25bb37bb6851c85e21fb0cecfd9617eebe6c7a56.tar.gz
rockbox-25bb37bb6851c85e21fb0cecfd9617eebe6c7a56.zip
commit asap codec. plays .sap files. At the moment it only plays the default song. So subSongs are ignored.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18121 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/codecs.c2
-rw-r--r--apps/codecs.h1
-rw-r--r--apps/codecs/Makefile12
-rw-r--r--apps/codecs/SOURCES1
-rw-r--r--apps/codecs/asap.c131
-rw-r--r--apps/codecs/asap/README.rockbox25
-rw-r--r--apps/codecs/asap/SOURCES3
-rw-r--r--apps/codecs/asap/apokeysnd.c3
-rw-r--r--apps/codecs/asap/asap.c14
-rw-r--r--apps/codecs/asap/asap.h2
-rw-r--r--apps/filetypes.c1
-rw-r--r--apps/metadata.c12
-rw-r--r--apps/metadata/asap.c256
-rw-r--r--apps/metadata/metadata_parsers.h1
-rw-r--r--apps/plugins/test_codec.c2
-rw-r--r--firmware/export/id3.h1
-rw-r--r--firmware/id3.c3
18 files changed, 461 insertions, 10 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index e70e32b73d..74535bfb0c 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -141,6 +141,7 @@ metadata/vorbis.c
141metadata/wave.c 141metadata/wave.c
142metadata/wavpack.c 142metadata/wavpack.c
143metadata/a52.c 143metadata/a52.c
144metadata/asap.c
144#endif 145#endif
145#ifdef HAVE_TAGCACHE 146#ifdef HAVE_TAGCACHE
146tagcache.c 147tagcache.c
diff --git a/apps/codecs.c b/apps/codecs.c
index aa3f81d2e6..c31fd843b3 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -124,7 +124,7 @@ struct codec_api ci = {
124 memmove, 124 memmove,
125 memcmp, 125 memcmp,
126 memchr, 126 memchr,
127 127 strcasestr,
128#if defined(DEBUG) || defined(SIMULATOR) 128#if defined(DEBUG) || defined(SIMULATOR)
129 debugf, 129 debugf,
130#endif 130#endif
diff --git a/apps/codecs.h b/apps/codecs.h
index b0cf187097..bfa0de72d9 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -196,6 +196,7 @@ struct codec_api {
196 void* (*memmove)(void *out, const void *in, size_t n); 196 void* (*memmove)(void *out, const void *in, size_t n);
197 int (*memcmp)(const void *s1, const void *s2, size_t n); 197 int (*memcmp)(const void *s1, const void *s2, size_t n);
198 void *(*memchr)(const void *s1, int c, size_t n); 198 void *(*memchr)(const void *s1, int c, size_t n);
199 char *(*strcasestr) (const char* phaystack, const char* pneedle);
199 200
200#if defined(DEBUG) || defined(SIMULATOR) 201#if defined(DEBUG) || defined(SIMULATOR)
201 void (*debugf)(const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2); 202 void (*debugf)(const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
diff --git a/apps/codecs/Makefile b/apps/codecs/Makefile
index 7c066d284d..9dd88e5e7d 100644
--- a/apps/codecs/Makefile
+++ b/apps/codecs/Makefile
@@ -17,8 +17,8 @@ ifdef APPEXTRA
17endif 17endif
18 18
19ifdef SOFTWARECODECS 19ifdef SOFTWARECODECS
20 CODECLIBS = -lspc -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a -lspeex -ldemac -lwma 20 CODECLIBS = -lspc -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a -lspeex -ldemac -lwma -lasap
21 OUTPUT = libspc libmad liba52 libffmpegFLAC libwma libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac 21 OUTPUT = libspc libmad liba52 libffmpegFLAC libwma libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac libasap
22endif 22endif
23 23
24# we "borrow" the plugin LDS file 24# we "borrow" the plugin LDS file
@@ -40,7 +40,7 @@ DIRS = .
40 40
41CODECDEPS = $(LINKCODEC) $(BUILDDIR)/libcodec.a 41CODECDEPS = $(LINKCODEC) $(BUILDDIR)/libcodec.a
42 42
43.PHONY: libspc libmad liba52 libffmpegFLAC libTremor libspeex libwavpack libmusepack libalac libfaad libm4a libdemac libwma 43.PHONY: libspc libmad liba52 libffmpegFLAC libTremor libspeex libwavpack libmusepack libalac libfaad libm4a libdemac libwma libasap
44 44
45all: $(LINKCODEC) $(ROCKS) 45all: $(LINKCODEC) $(ROCKS)
46 46
@@ -70,6 +70,7 @@ $(OBJDIR)/aiff_enc.elf: $(OBJDIR)/aiff_enc.o $(OBJDIR)/codec_crt0.o
70$(OBJDIR)/mp3_enc.elf: $(OBJDIR)/mp3_enc.o $(OBJDIR)/codec_crt0.o 70$(OBJDIR)/mp3_enc.elf: $(OBJDIR)/mp3_enc.o $(OBJDIR)/codec_crt0.o
71$(OBJDIR)/wav_enc.elf: $(OBJDIR)/wav_enc.o $(OBJDIR)/codec_crt0.o 71$(OBJDIR)/wav_enc.elf: $(OBJDIR)/wav_enc.o $(OBJDIR)/codec_crt0.o
72$(OBJDIR)/wavpack_enc.elf: $(OBJDIR)/wavpack_enc.o $(BUILDDIR)/libwavpack.a $(OBJDIR)/codec_crt0.o 72$(OBJDIR)/wavpack_enc.elf: $(OBJDIR)/wavpack_enc.o $(BUILDDIR)/libwavpack.a $(OBJDIR)/codec_crt0.o
73$(OBJDIR)/asap.elf : $(OBJDIR)/asap.o $(BUILDDIR)/libasap.a $(OBJDIR)/codec_crt0.o
73 74
74$(OBJDIR)/%.elf: $(OBJDIR)/codec_crt0.o 75$(OBJDIR)/%.elf: $(OBJDIR)/codec_crt0.o
75 $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $^ -L$(BUILDDIR) -lcodec -lgcc \ 76 $(call PRINTS,LD $(@F))$(CC) $(CFLAGS) -o $@ $^ -L$(BUILDDIR) -lcodec -lgcc \
@@ -218,6 +219,11 @@ libdemac:
218 $(SILENT)mkdir -p $(OBJDIR)/libdemac 219 $(SILENT)mkdir -p $(OBJDIR)/libdemac
219 $(call PRINTS,MAKE in libdemac)$(MAKE) -C demac/libdemac OBJDIR=$(OBJDIR)/libdemac OUTPUT=$(BUILDDIR)/libdemac.a 220 $(call PRINTS,MAKE in libdemac)$(MAKE) -C demac/libdemac OBJDIR=$(OBJDIR)/libdemac OUTPUT=$(BUILDDIR)/libdemac.a
220 221
222$(BUILDDIR)/libasap.a: libasap
223
224libasap:
225 $(SILENT)mkdir -p $(OBJDIR)/asap
226 $(call PRINTS,MAKE in asap)$(MAKE) -C asap OBJDIR=$(OBJDIR)/asap OUTPUT=$(BUILDDIR)/libasap.a
221clean: 227clean:
222 $(call PRINTS,cleaning codecs)rm -fr $(OBJDIR)/spc $(BUILDDIR)/libspc.a $(OBJDIR)/libmad $(BUILDDIR)/libmad.a $(OBJDIR)/liba52 $(BUILDDIR)/liba52.a $(OBJDIR)/libffmpegFLAC $(BUILDDIR)/libffmpegFLAC.a $(OBJDIR)/Tremor $(BUILDDIR)/libTremor.a $(OBJDIR)/libspeex $(BUILDDIR)/libSpeex.a $(OBJDIR)/libwavpack $(BUILDDIR)/libwavpack.a $(OBJDIR)/libmusepack $(BUILDDIR)/libmusepack.a $(OBJDIR)/libalac $(BUILDDIR)/libalac.a $(OBJDIR)/libfaad $(BUILDDIR)/libfaad.a $(OBJDIR)/libm4a $(BUILDDIR)/libm4a.a $(OBJDIR)/libdemac $(BUILDDIR)/libdemac.a $(OBJDIR)/libwma $(BUILDDIR)/libwma.a 228 $(call PRINTS,cleaning codecs)rm -fr $(OBJDIR)/spc $(BUILDDIR)/libspc.a $(OBJDIR)/libmad $(BUILDDIR)/libmad.a $(OBJDIR)/liba52 $(BUILDDIR)/liba52.a $(OBJDIR)/libffmpegFLAC $(BUILDDIR)/libffmpegFLAC.a $(OBJDIR)/Tremor $(BUILDDIR)/libTremor.a $(OBJDIR)/libspeex $(BUILDDIR)/libSpeex.a $(OBJDIR)/libwavpack $(BUILDDIR)/libwavpack.a $(OBJDIR)/libmusepack $(BUILDDIR)/libmusepack.a $(OBJDIR)/libalac $(BUILDDIR)/libalac.a $(OBJDIR)/libfaad $(BUILDDIR)/libfaad.a $(OBJDIR)/libm4a $(BUILDDIR)/libm4a.a $(OBJDIR)/libdemac $(BUILDDIR)/libdemac.a $(OBJDIR)/libwma $(BUILDDIR)/libwma.a
223 $(SILENT)$(MAKE) -C spc clean OBJDIR=$(OBJDIR)/spc 229 $(SILENT)$(MAKE) -C spc clean OBJDIR=$(OBJDIR)/spc
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES
index 3c0118c1ce..25ca5490d4 100644
--- a/apps/codecs/SOURCES
+++ b/apps/codecs/SOURCES
@@ -21,6 +21,7 @@ sid.c
21adx.c 21adx.c
22nsf.c 22nsf.c
23spc.c 23spc.c
24asap.c
24#if defined(HAVE_RECORDING) && !defined(SIMULATOR) 25#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
25/* encoders */ 26/* encoders */
26aiff_enc.c 27aiff_enc.c
diff --git a/apps/codecs/asap.c b/apps/codecs/asap.c
new file mode 100644
index 0000000000..f6fa68f4f4
--- /dev/null
+++ b/apps/codecs/asap.c
@@ -0,0 +1,131 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: asap.c 17847 2008-06-28 18:10:04Z domonoky $
9 *
10 * Copyright (C) 2008 Dominik Wenger
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "codeclib.h"
23#include "asap/asap.h"
24
25CODEC_HEADER
26
27#define CHUNK_SIZE (1024*8)
28
29static byte samples[CHUNK_SIZE]; /* The sample buffer */
30static ASAP_State asap; /* asap codec state */
31
32/* this is the codec entry point */
33enum codec_status codec_main(void)
34{
35 int n_bytes;
36 int song;
37 int duration;
38 char* module;
39
40 /* Generic codec initialisation */
41 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
42
43next_track:
44 if (codec_init()) {
45 DEBUGF("codec init failed\n");
46 return CODEC_ERROR;
47 }
48
49 while (!*ci->taginfo_ready && !ci->stop_codec)
50 ci->sleep(1);
51
52 codec_set_replaygain(ci->id3);
53
54 int bytes_done =0;
55 int filesize;
56 ci->seek_buffer(0);
57 module = ci->request_buffer(&filesize, ci->filesize);
58 if (!module || (size_t)filesize < (size_t)ci->filesize)
59 {
60 DEBUGF("loading error\n");
61 return CODEC_ERROR;
62 }
63
64 /*Init ASAP */
65 if (!ASAP_Load(&asap, ci->id3->path, module, filesize))
66 {
67 DEBUGF("%s: format not supported",ci->id3->path);
68 return CODEC_ERROR;
69 }
70
71 /* Make use of 44.1khz */
72 ci->configure(DSP_SET_FREQUENCY, 44100);
73 /* Sample depth is 16 bit little endian */
74 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
75 /* Stereo or Mono output ? */
76 if(asap.module_info.channels ==1)
77 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
78 else
79 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
80
81 /* reset eleapsed */
82 ci->set_elapsed(0);
83
84 song = asap.module_info.default_song;
85 duration = asap.module_info.durations[song];
86 if (duration < 0)
87 duration = 180 * 1000;
88
89 ASAP_PlaySong(&asap, song, duration);
90 ASAP_MutePokeyChannels(&asap, 0);
91
92 /* The main decoder loop */
93 while (1) {
94 ci->yield();
95 if (ci->stop_codec || ci->new_track)
96 break;
97
98 if (ci->seek_time) {
99 /* New time is ready in ci->seek_time */
100
101 /* seek to pos */
102 ASAP_Seek(&asap,ci->seek_time);
103 /* update elapsed */
104 ci->set_elapsed(ci->seek_time);
105 /* update bytes_done */
106 bytes_done = ci->seek_time*44.1*2;
107 /* seek ready */
108 ci->seek_complete();
109 }
110
111 /* Generate a buffer full of Audio */
112 #ifdef ROCKBOX_LITTLE_ENDIAN
113 n_bytes = ASAP_Generate(&asap, samples, sizeof(samples), ASAP_FORMAT_S16_LE);
114 #else
115 n_bytes = ASAP_Generate(&asap, samples, sizeof(samples), ASAP_FORMAT_S16_BE);
116 #endif
117
118 ci->pcmbuf_insert(samples, NULL, n_bytes /2);
119
120 bytes_done += n_bytes;
121 ci->set_elapsed((bytes_done / 2) / 44.1);
122
123 if(n_bytes != sizeof(samples))
124 break;
125 }
126
127 if (ci->request_next_track())
128 goto next_track;
129
130 return CODEC_OK;
131}
diff --git a/apps/codecs/asap/README.rockbox b/apps/codecs/asap/README.rockbox
new file mode 100644
index 0000000000..322c130358
--- /dev/null
+++ b/apps/codecs/asap/README.rockbox
@@ -0,0 +1,25 @@
1Library: asap-1.2.0
2Imported: 2008-26-07 by Dominik Wenger
3
4This directory contains a local version of asap (http://asap.sourceforge.net/) for decoding Atari 8bit .sap
5audio streams.
6
7LICENSING INFORMATION
8
9Asap is available under the terms of the GPL v2 or later
10license, which is both an open source and free software license.
11The Licence is the same as the rest of Rockbox.
12
13
14IMPORT DETAILS
15
16The .[ch] files in apps/codec/asap are copied from ASAP.
17Some #defines were added, so it uses the ci-> Pointer.
18
19A small modification was needed in asap.h Line 120.
20(changed the delta buffer to signed char)
21
22Also players.h (contains binarys of players) was generated and copied
23into Rockbox.
24
25
diff --git a/apps/codecs/asap/SOURCES b/apps/codecs/asap/SOURCES
new file mode 100644
index 0000000000..0d1f1f46fa
--- /dev/null
+++ b/apps/codecs/asap/SOURCES
@@ -0,0 +1,3 @@
1acpu.c
2asap.c
3apokeysnd.c
diff --git a/apps/codecs/asap/apokeysnd.c b/apps/codecs/asap/apokeysnd.c
index d0a4b1bd91..1d48bc20d2 100644
--- a/apps/codecs/asap/apokeysnd.c
+++ b/apps/codecs/asap/apokeysnd.c
@@ -20,13 +20,14 @@
20 * along with ASAP; if not, write to the Free Software Foundation, Inc., 20 * along with ASAP; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */ 22 */
23 23#include "codeclib.h"
24#if !defined(JAVA) && !defined(CSHARP) 24#if !defined(JAVA) && !defined(CSHARP)
25#include <string.h> 25#include <string.h>
26#endif 26#endif
27 27
28#include "asap_internal.h" 28#include "asap_internal.h"
29 29
30#define memset ci->memset
30#define ULTRASOUND_CYCLES 112 31#define ULTRASOUND_CYCLES 112
31 32
32#define MUTE_FREQUENCY 1 33#define MUTE_FREQUENCY 1
diff --git a/apps/codecs/asap/asap.c b/apps/codecs/asap/asap.c
index 084708af4c..31de730d93 100644
--- a/apps/codecs/asap/asap.c
+++ b/apps/codecs/asap/asap.c
@@ -20,7 +20,7 @@
20 * along with ASAP; if not, write to the Free Software Foundation, Inc., 20 * along with ASAP; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */ 22 */
23 23#include "codeclib.h"
24#if !defined(JAVA) && !defined(CSHARP) 24#if !defined(JAVA) && !defined(CSHARP)
25#include <string.h> 25#include <string.h>
26#endif 26#endif
@@ -30,6 +30,14 @@
30#include "players.h" 30#include "players.h"
31#endif 31#endif
32 32
33#define memcpy ci->memcpy
34#define memcmp ci->memcmp
35#define memset ci->memset
36#define strcpy ci->strcpy
37#define strcmp ci->strcmp
38#define strstr ci->strcasestr
39
40
33#define CMR_BASS_TABLE_OFFSET 0x70f 41#define CMR_BASS_TABLE_OFFSET 0x70f
34 42
35CONST_LOOKUP(byte, cmr_bass_table) = { 43CONST_LOOKUP(byte, cmr_bass_table) = {
@@ -1012,7 +1020,7 @@ FILE_FUNC abool parse_sap_header(ASAP_ModuleInfo PTR module_info,
1012 i = 0; 1020 i = 0;
1013 while (module[module_index] != 0x0d) { 1021 while (module[module_index] != 0x0d) {
1014 line[i++] = (char) module[module_index++]; 1022 line[i++] = (char) module[module_index++];
1015 if (module_index >= module_len || i >= sizeof(line) - 1) 1023 if (module_index >= module_len || (unsigned)i >= sizeof(line) - 1)
1016 return FALSE; 1024 return FALSE;
1017 } 1025 }
1018 if (++module_index >= module_len || module[module_index++] != 0x0a) 1026 if (++module_index >= module_len || module[module_index++] != 0x0a)
@@ -1719,6 +1727,7 @@ int ASAP_SetModuleInfo(const ASAP_ModuleInfo *module_info, const byte ARRAY modu
1719const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_info, 1727const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_info,
1720 const byte ARRAY module, int module_len) 1728 const byte ARRAY module, int module_len)
1721{ 1729{
1730 (void)filename;
1722 switch (module_info->type) { 1731 switch (module_info->type) {
1723 case 'B': 1732 case 'B':
1724 if (module_info->init == 0x4f3 || module_info->init == 0xf4f3 || module_info->init == 0x4ef) 1733 if (module_info->init == 0x4f3 || module_info->init == 0xf4f3 || module_info->init == 0x4ef)
@@ -1755,6 +1764,7 @@ const char *ASAP_CanConvert(const char *filename, const ASAP_ModuleInfo *module_
1755int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info, 1764int ASAP_Convert(const char *filename, const ASAP_ModuleInfo *module_info,
1756 const byte ARRAY module, int module_len, byte ARRAY out_module) 1765 const byte ARRAY module, int module_len, byte ARRAY out_module)
1757{ 1766{
1767 (void) filename;
1758 int out_len; 1768 int out_len;
1759 byte *dest; 1769 byte *dest;
1760 int addr; 1770 int addr;
diff --git a/apps/codecs/asap/asap.h b/apps/codecs/asap/asap.h
index 194d4168eb..783d628019 100644
--- a/apps/codecs/asap/asap.h
+++ b/apps/codecs/asap/asap.h
@@ -117,7 +117,7 @@ typedef struct {
117 int delta3; 117 int delta3;
118 int delta4; 118 int delta4;
119 int skctl; 119 int skctl;
120 char delta_buffer[888]; 120 signed char delta_buffer[888];
121} PokeyState; 121} PokeyState;
122 122
123/* Player state. 123/* Player state.
diff --git a/apps/filetypes.c b/apps/filetypes.c
index 460c6ab6c2..b05942f324 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -81,6 +81,7 @@ static const struct filetype inbuilt_filetypes[] = {
81 { "spc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 81 { "spc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
82 { "ape", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 82 { "ape", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
83 { "mac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, 83 { "mac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
84 { "sap" ,FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
84#endif 85#endif
85 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 86 { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
86 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, 87 { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
diff --git a/apps/metadata.c b/apps/metadata.c
index ffa19bafd7..6d8443b63d 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -249,7 +249,17 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
249 } 249 }
250 250
251 break; 251 break;
252 252
253 case AFMT_SAP:
254 if (!get_asap_metadata(fd, id3))
255 {
256 DEBUGF("get_sap_metadata error\n");
257 return false;
258 }
259 id3->filesize = filesize(fd);
260 id3->genre_string = id3_get_num_genre(36);
261 break;
262
253#endif /* CONFIG_CODEC == SWCODEC */ 263#endif /* CONFIG_CODEC == SWCODEC */
254 264
255 default: 265 default:
diff --git a/apps/metadata/asap.c b/apps/metadata/asap.c
new file mode 100644
index 0000000000..7e635a30e8
--- /dev/null
+++ b/apps/metadata/asap.c
@@ -0,0 +1,256 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: asap.c 17847 2008-06-28 18:10:04Z domonoky $
9 *
10 * Copyright (C) 2008 Dominik Wenger
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "id3.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32#include "debug.h"
33
34#define MAX_SONGS 32
35
36struct module_info
37{
38 char name[255];
39 char author[255];
40 char date[255];
41 int numSongs;
42 int defSong;
43 int numChannels;
44 int durations[32];
45 int loops[32];
46};
47
48static bool parse_dec(int *retval, const char *p, int minval, int maxval)
49{
50 int r = 0;
51 do {
52 char c = *p;
53 if (c >= '0' && c <= '9')
54 r = 10 * r + c - '0';
55 else
56 return false;
57 if (r > maxval)
58 return false;
59 } while (*++p != '\0');
60 if (r < minval)
61 return false;
62 *retval = r;
63 return true;
64}
65
66static bool parse_text(char *retval, const char *p)
67{
68 int i;
69 if (*p != '"')
70 return false;
71 p++;
72 if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"')
73 return true;
74 i = 0;
75 while (*p != '"') {
76 if (i >= 127)
77 return false;
78 if (*p == '\0')
79 return false;
80 retval[i++] = *p++;
81 }
82 retval[i] = '\0';
83 return true;
84}
85
86static int ASAP_ParseDuration(const char *s)
87{
88 int r;
89 if (*s < '0' || *s > '9')
90 return -1;
91 r = *s++ - '0';
92 if (*s >= '0' && *s <= '9')
93 r = 10 * r + *s++ - '0';
94 if (*s == ':') {
95 s++;
96 if (*s < '0' || *s > '5')
97 return -1;
98 r = 60 * r + (*s++ - '0') * 10;
99 if (*s < '0' || *s > '9')
100 return -1;
101 r += *s++ - '0';
102 }
103 r *= 1000;
104 if (*s != '.')
105 return r;
106 s++;
107 if (*s < '0' || *s > '9')
108 return r;
109 r += 100 * (*s++ - '0');
110 if (*s < '0' || *s > '9')
111 return r;
112 r += 10 * (*s++ - '0');
113 if (*s < '0' || *s > '9')
114 return r;
115 r += *s - '0';
116 return r;
117}
118
119static bool parse_sap_header(int fd,struct module_info* info,int file_len)
120{
121 int module_index = 0;
122 int sap_signature = -1;
123 int duration_index = 0;
124 unsigned char cur_char = 0;
125 int i;
126
127 /* set defaults */
128
129 info->numSongs=1;
130 info->defSong=0;
131 info->numChannels=1;
132 for (i = 0; i < MAX_SONGS; i++) {
133 info->durations[i] = -1;
134 info->loops[i] = 0;
135 }
136
137 /* parse file */
138 while (1)
139 {
140 char line[256];
141 char *p;
142
143 if (module_index + 8 >= file_len)
144 return false;
145 /* read a char */
146 read(fd,&cur_char,1);
147 /* end of header */
148 if (cur_char == 0xff)
149 break;
150
151 i = 0;
152 while (cur_char != 0x0d)
153 {
154 line[i++] = cur_char;
155 module_index++;
156 if (module_index >= file_len || (unsigned)i >= sizeof(line) - 1)
157 return false;
158 /* read a char */
159 read(fd,&cur_char,1);
160 }
161 if (++module_index >= file_len )
162 return false;
163 /* read a char */
164 read(fd,&cur_char,1);
165 if ( cur_char != 0x0a)
166 return false;
167
168 line[i] = '\0';
169 for (p = line; *p != '\0'; p++) {
170 if (*p == ' ') {
171 *p++ = '\0';
172 break;
173 }
174 }
175
176 /* parse tags */
177 if(strcmp(line, "SAP") == 0)
178 sap_signature = 1;
179 if (sap_signature == -1)
180 return false;
181 if (strcmp(line,"AUTHOR") == 0)
182 {
183 if (parse_text(info->author, p) == false )
184 return false;
185 }
186 else if(strcmp(line,"NAME")==0)
187 {
188 if (parse_text(info->name, p) == false)
189 return false;
190 }
191 else if(strcmp(line,"DATE")==0)
192 {
193 if (parse_text(info->date, p) == false)
194 return false;
195 }
196 else if (strcmp(line,"SONGS")==0)
197 {
198 if (parse_dec(&info->numSongs, p,1,MAX_SONGS) == false )
199 return false;
200 }
201 else if (strcmp(line,"DEFSONG")==0)
202 {
203 if (parse_dec(&info->defSong, p,0,MAX_SONGS) == false)
204 return false;
205 }
206 else if (strcmp(line,"STEREO")==0)
207 {
208 info->numChannels = 2;
209 }
210 else if (strcmp(line,"TIME") == 0)
211 {
212 int duration = ASAP_ParseDuration(p);
213 if (duration < 0 || duration_index >= MAX_SONGS)
214 return false;
215 info->durations[duration_index] = duration;
216 if (strstr(p, "LOOP") != NULL)
217 info->loops[duration_index] = 1;
218 duration_index++;
219 }
220 }
221
222 lseek(fd,0,SEEK_SET);
223 return true;
224}
225
226
227bool get_asap_metadata(int fd, struct mp3entry* id3)
228{
229 char *buf = id3->id3v2buf;
230
231 int filelength = filesize(fd);
232 struct module_info *info;
233 info = (struct module_info *) buf;
234
235 if(parse_sap_header(fd,info,filelength) == false)
236 {
237 DEBUGF("parse sap header failed.\n");
238 return false;
239 }
240
241 id3->title = info->name;
242 id3->artist = info->author;
243 id3->year_string = info->date;
244 int length = info->durations[info->defSong];
245 if (length < 0)
246 length = 180 * 1000;
247 id3->length = length;
248
249 id3->bitrate = 706;
250 id3->frequency = 44100;
251
252 id3->vbr = false;
253 id3->filesize = filelength;
254
255 return true;
256}
diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h
index 2564a3301a..00ad112e54 100644
--- a/apps/metadata/metadata_parsers.h
+++ b/apps/metadata/metadata_parsers.h
@@ -34,3 +34,4 @@ bool get_wave_metadata(int fd, struct mp3entry* id3);
34bool get_wavpack_metadata(int fd, struct mp3entry* id3); 34bool get_wavpack_metadata(int fd, struct mp3entry* id3);
35bool get_a52_metadata(int fd, struct mp3entry* id3); 35bool get_a52_metadata(int fd, struct mp3entry* id3);
36bool get_asf_metadata(int fd, struct mp3entry* id3); 36bool get_asf_metadata(int fd, struct mp3entry* id3);
37bool get_asap_metadata(int fd, struct mp3entry* id3);
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c
index b405e09238..542f6edf2f 100644
--- a/apps/plugins/test_codec.c
+++ b/apps/plugins/test_codec.c
@@ -463,7 +463,7 @@ static void init_ci(void)
463 ci.memmove = rb->memmove; 463 ci.memmove = rb->memmove;
464 ci.memcmp = rb->memcmp; 464 ci.memcmp = rb->memcmp;
465 ci.memchr = rb->memchr; 465 ci.memchr = rb->memchr;
466 466 ci.strcasestr = rb->strcasestr;
467#if defined(DEBUG) || defined(SIMULATOR) 467#if defined(DEBUG) || defined(SIMULATOR)
468 ci.debugf = rb->debugf; 468 ci.debugf = rb->debugf;
469#endif 469#endif
diff --git a/firmware/export/id3.h b/firmware/export/id3.h
index 147d073ffe..3e4db0674f 100644
--- a/firmware/export/id3.h
+++ b/firmware/export/id3.h
@@ -60,6 +60,7 @@ enum
60 AFMT_APE, /* Monkey's Audio (APE) */ 60 AFMT_APE, /* Monkey's Audio (APE) */
61 AFMT_WMA, /* WMAV1/V2 in ASF */ 61 AFMT_WMA, /* WMAV1/V2 in ASF */
62 AFMT_MOD, /* Amiga MOD File Format */ 62 AFMT_MOD, /* Amiga MOD File Format */
63 AFMT_SAP, /* Amiga 8Bit SAP Format */
63#endif 64#endif
64 65
65 /* add new formats at any index above this line to have a sensible order - 66 /* add new formats at any index above this line to have a sensible order -
diff --git a/firmware/id3.c b/firmware/id3.c
index 55bf5a47d1..8cbf40c483 100644
--- a/firmware/id3.c
+++ b/firmware/id3.c
@@ -117,6 +117,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
117 /* Amiga MOD File */ 117 /* Amiga MOD File */
118 [AFMT_MOD] = 118 [AFMT_MOD] =
119 AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ), 119 AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ),
120 /* Amiga SAP File */
121 [AFMT_SAP] =
122 AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ),
120#endif 123#endif
121}; 124};
122 125