summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/codecs.h2
-rw-r--r--apps/codecs/lib/codeclib.c2
-rw-r--r--apps/cuesheet.h2
-rw-r--r--apps/gui/gwps.h2
-rw-r--r--apps/gui/statusbar.c2
-rw-r--r--apps/id3.h246
-rw-r--r--apps/menus/recording_menu.c2
-rw-r--r--apps/metadata.c171
-rw-r--r--apps/metadata.h219
-rw-r--r--apps/metadata/a52.c2
-rw-r--r--apps/metadata/adx.c2
-rw-r--r--apps/metadata/aiff.c2
-rw-r--r--apps/metadata/ape.c2
-rw-r--r--apps/metadata/asap.c2
-rw-r--r--apps/metadata/asf.c2
-rw-r--r--apps/metadata/flac.c2
-rw-r--r--apps/metadata/metadata_common.c3
-rw-r--r--apps/metadata/metadata_common.h2
-rw-r--r--apps/metadata/metadata_parsers.h6
-rw-r--r--apps/metadata/mod.c2
-rw-r--r--apps/metadata/monkeys.c2
-rw-r--r--apps/metadata/mp3.c (renamed from apps/id3.c)172
-rw-r--r--apps/metadata/mp4.c2
-rw-r--r--apps/metadata/mpc.c2
-rw-r--r--apps/metadata/ogg.c2
-rw-r--r--apps/metadata/sid.c2
-rw-r--r--apps/metadata/spc.c2
-rw-r--r--apps/metadata/vorbis.c2
-rw-r--r--apps/metadata/wave.c2
-rw-r--r--apps/metadata/wavpack.c2
-rw-r--r--apps/mp3data.c782
-rw-r--r--apps/mp3data.h83
-rw-r--r--apps/mpeg.c2
-rw-r--r--apps/mpeg.h2
-rw-r--r--apps/onplay.c2
-rw-r--r--apps/playlist.h2
-rw-r--r--apps/plugin.h2
-rw-r--r--apps/recorder/albumart.c2
-rw-r--r--apps/recorder/albumart.h2
-rw-r--r--apps/recorder/icons.c2
-rw-r--r--apps/recorder/icons.h5
-rw-r--r--apps/recorder/pcm_record.c2
-rw-r--r--apps/replaygain.c2
-rw-r--r--apps/replaygain.h2
-rw-r--r--apps/screens.c2
-rw-r--r--apps/scrobbler.c2
-rw-r--r--apps/tagcache.c2
-rw-r--r--apps/tagcache.h2
-rw-r--r--apps/talk.c2
50 files changed, 1305 insertions, 465 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 3fce356092..d68ca1bdfc 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -7,7 +7,6 @@ abrepeat.c
7bookmark.c 7bookmark.c
8debug_menu.c 8debug_menu.c
9filetypes.c 9filetypes.c
10id3.c
11language.c 10language.c
12main.c 11main.c
13menu.c 12menu.c
@@ -31,6 +30,7 @@ menus/recording_menu.c
31menus/settings_menu.c 30menus/settings_menu.c
32menus/sound_menu.c 31menus/sound_menu.c
33misc.c 32misc.c
33mp3data.c
34onplay.c 34onplay.c
35playlist.c 35playlist.c
36playlist_catalog.c 36playlist_catalog.c
@@ -130,6 +130,7 @@ eq_arm.S
130#endif 130#endif
131#endif 131#endif
132metadata.c 132metadata.c
133metadata/mp3.c
133#if CONFIG_CODEC == SWCODEC 134#if CONFIG_CODEC == SWCODEC
134metadata/metadata_common.c 135metadata/metadata_common.c
135metadata/aiff.c 136metadata/aiff.c
diff --git a/apps/codecs.h b/apps/codecs.h
index 2cb642c7dc..becb73c8b7 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -36,7 +36,7 @@
36#include "config.h" 36#include "config.h"
37#include "kernel.h" 37#include "kernel.h"
38#include "system.h" 38#include "system.h"
39#include "id3.h" 39#include "metadata.h"
40#include "audio.h" 40#include "audio.h"
41#ifdef RB_PROFILE 41#ifdef RB_PROFILE
42#include "profile.h" 42#include "profile.h"
diff --git a/apps/codecs/lib/codeclib.c b/apps/codecs/lib/codeclib.c
index 342e6b7799..e537995db9 100644
--- a/apps/codecs/lib/codeclib.c
+++ b/apps/codecs/lib/codeclib.c
@@ -25,7 +25,7 @@
25#include "codecs.h" 25#include "codecs.h"
26#include "dsp.h" 26#include "dsp.h"
27#include "codeclib.h" 27#include "codeclib.h"
28#include "id3.h" 28#include "metadata.h"
29 29
30long mem_ptr; 30long mem_ptr;
31long bufsize; 31long bufsize;
diff --git a/apps/cuesheet.h b/apps/cuesheet.h
index b6cf239cc7..de51512195 100644
--- a/apps/cuesheet.h
+++ b/apps/cuesheet.h
@@ -25,7 +25,7 @@
25#include <stdbool.h> 25#include <stdbool.h>
26#include "screens.h" 26#include "screens.h"
27#include "file.h" 27#include "file.h"
28#include "id3.h" 28#include "metadata.h"
29 29
30#define MAX_NAME 80 /* Max length of information strings */ 30#define MAX_NAME 80 /* Max length of information strings */
31#define MAX_TRACKS 99 /* Max number of tracks in a cuesheet */ 31#define MAX_TRACKS 99 /* Max number of tracks in a cuesheet */
diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h
index 579a3409c2..6a4849c347 100644
--- a/apps/gui/gwps.h
+++ b/apps/gui/gwps.h
@@ -23,7 +23,7 @@
23 23
24#include "screen_access.h" 24#include "screen_access.h"
25#include "statusbar.h" 25#include "statusbar.h"
26#include "id3.h" 26#include "metadata.h"
27 27
28/* constants used in line_type and as refresh_mode for wps_refresh */ 28/* constants used in line_type and as refresh_mode for wps_refresh */
29#define WPS_REFRESH_STATIC 1 /* line doesn't change over time */ 29#define WPS_REFRESH_STATIC 1 /* line doesn't change over time */
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index d426054104..1a264ee3d6 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -27,7 +27,7 @@
27#include "sound.h" 27#include "sound.h"
28#include "settings.h" 28#include "settings.h"
29#if CONFIG_CODEC == SWCODEC 29#if CONFIG_CODEC == SWCODEC
30#include "id3.h" 30#include "metadata.h"
31#endif 31#endif
32#include "icons.h" 32#include "icons.h"
33#include "powermgmt.h" 33#include "powermgmt.h"
diff --git a/apps/id3.h b/apps/id3.h
deleted file mode 100644
index da2faf1b12..0000000000
--- a/apps/id3.h
+++ /dev/null
@@ -1,246 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
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#ifndef ID3_H
22#define ID3_H
23
24#include <stdbool.h>
25#include "config.h"
26#include "file.h"
27
28#define ID3V2_BUF_SIZE 300
29
30/* Audio file types. */
31/* NOTE: The values of the AFMT_* items are used for the %fc tag in the WPS
32 - so new entries MUST be added to the end to maintain compatibility.
33 */
34enum
35{
36 AFMT_UNKNOWN = 0, /* Unknown file format */
37
38 /* start formats */
39
40 AFMT_MPA_L1, /* MPEG Audio layer 1 */
41 AFMT_MPA_L2, /* MPEG Audio layer 2 */
42 AFMT_MPA_L3, /* MPEG Audio layer 3 */
43
44#if CONFIG_CODEC == SWCODEC
45 AFMT_AIFF, /* Audio Interchange File Format */
46 AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */
47 AFMT_OGG_VORBIS, /* Ogg Vorbis */
48 AFMT_FLAC, /* FLAC */
49 AFMT_MPC, /* Musepack */
50 AFMT_A52, /* A/52 (aka AC3) audio */
51 AFMT_WAVPACK, /* WavPack */
52 AFMT_ALAC, /* Apple Lossless Audio Codec */
53 AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */
54 AFMT_SHN, /* Shorten */
55 AFMT_SID, /* SID File Format */
56 AFMT_ADX, /* ADX File Format */
57 AFMT_NSF, /* NESM (NES Sound Format) */
58 AFMT_SPEEX, /* Ogg Speex speech */
59 AFMT_SPC, /* SPC700 save state */
60 AFMT_APE, /* Monkey's Audio (APE) */
61 AFMT_WMA, /* WMAV1/V2 in ASF */
62 AFMT_MOD, /* Amiga MOD File Format */
63 AFMT_SAP, /* Amiga 8Bit SAP Format */
64#endif
65
66 /* add new formats at any index above this line to have a sensible order -
67 specified array index inits are used */
68 /* format arrays defined in id3.c */
69
70 AFMT_NUM_CODECS,
71
72#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
73 /* masks to decompose parts */
74 CODEC_AFMT_MASK = 0x0fff,
75 CODEC_TYPE_MASK = 0x7000,
76
77 /* switch for specifying codec type when requesting a filename */
78 CODEC_TYPE_DECODER = (0 << 12), /* default */
79 CODEC_TYPE_ENCODER = (1 << 12),
80#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
81};
82
83#if CONFIG_CODEC == SWCODEC
84#define CODEC_EXTENSION "codec"
85
86#ifdef HAVE_RECORDING
87#define ENCODER_SUFFIX "_enc"
88enum rec_format_indexes
89{
90 __REC_FORMAT_START_INDEX = -1,
91
92 /* start formats */
93
94 REC_FORMAT_PCM_WAV,
95 REC_FORMAT_AIFF,
96 REC_FORMAT_WAVPACK,
97 REC_FORMAT_MPA_L3,
98
99 /* add new formats at any index above this line to have a sensible order -
100 specified array index inits are used
101 REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range
102 REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes
103 */
104
105 REC_NUM_FORMATS,
106
107 REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV,
108 REC_FORMAT_CFG_NUM_BITS = 2
109};
110
111#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3"
112
113/* get REC_FORMAT_* corresponding AFMT_* */
114extern const int rec_format_afmt[REC_NUM_FORMATS];
115/* get AFMT_* corresponding REC_FORMAT_* */
116extern const int afmt_rec_format[AFMT_NUM_CODECS];
117
118#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
119 { label, root_fname, enc_root_fname, ext_list }
120#else /* !HAVE_RECORDING */
121#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
122 { label, root_fname, ext_list }
123#endif /* HAVE_RECORDING */
124#else /* !SWCODEC */
125
126#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
127 { label, ext_list }
128#endif /* CONFIG_CODEC == SWCODEC */
129
130/* record describing the audio format */
131struct afmt_entry
132{
133 char label[8]; /* format label */
134#if CONFIG_CODEC == SWCODEC
135 char *codec_root_fn; /* root codec filename (sans _enc and .codec) */
136#ifdef HAVE_RECORDING
137 char *codec_enc_root_fn; /* filename of encoder codec */
138#endif
139#endif
140 char *ext_list; /* double NULL terminated extension
141 list for type with the first as
142 the default for recording */
143};
144
145/* database of labels and codecs. add formats per above enum */
146extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS];
147
148struct mp3entry {
149 char path[MAX_PATH];
150 char* title;
151 char* artist;
152 char* album;
153 char* genre_string;
154 char* disc_string;
155 char* track_string;
156 char* year_string;
157 char* composer;
158 char* comment;
159 char* albumartist;
160 char* grouping;
161 int discnum;
162 int tracknum;
163 int version;
164 int layer;
165 int year;
166 unsigned char id3version;
167 unsigned int codectype;
168 unsigned int bitrate;
169 unsigned long frequency;
170 unsigned long id3v2len;
171 unsigned long id3v1len;
172 unsigned long first_frame_offset; /* Byte offset to first real MP3 frame.
173 Used for skipping leading garbage to
174 avoid gaps between tracks. */
175 unsigned long vbr_header_pos;
176 unsigned long filesize; /* without headers; in bytes */
177 unsigned long length; /* song length in ms */
178 unsigned long elapsed; /* ms played */
179
180 int lead_trim; /* Number of samples to skip at the beginning */
181 int tail_trim; /* Number of samples to remove from the end */
182
183 /* Added for Vorbis */
184 unsigned long samples; /* number of samples in track */
185
186 /* MP3 stream specific info */
187 unsigned long frame_count; /* number of frames in the file (if VBR) */
188
189 /* Used for A52/AC3 */
190 unsigned long bytesperframe; /* number of bytes per frame (if CBR) */
191
192 /* Xing VBR fields */
193 bool vbr;
194 bool has_toc; /* True if there is a VBR header in the file */
195 unsigned char toc[100]; /* table of contents */
196
197 /* these following two fields are used for local buffering */
198 char id3v2buf[ID3V2_BUF_SIZE];
199 char id3v1buf[4][92];
200
201 /* resume related */
202 unsigned long offset; /* bytes played */
203 int index; /* playlist index */
204
205 /* runtime database fields */
206 long tagcache_idx; /* 0=invalid, otherwise idx+1 */
207 int rating;
208 int score;
209 long playcount;
210 long lastplayed;
211 long playtime;
212
213 /* replaygain support */
214
215#if CONFIG_CODEC == SWCODEC
216 char* track_gain_string;
217 char* album_gain_string;
218 long track_gain; /* 7.24 signed fixed point. 0 for no gain. */
219 long album_gain;
220 long track_peak; /* 7.24 signed fixed point. 0 for no peak. */
221 long album_peak;
222#endif
223
224 /* Cuesheet support */
225 int cuesheet_type; /* 0: none, 1: external, 2: embedded */
226
227 /* Musicbrainz Track ID */
228 char* mb_track_id;
229};
230
231enum {
232 ID3_VER_1_0 = 1,
233 ID3_VER_1_1,
234 ID3_VER_2_2,
235 ID3_VER_2_3,
236 ID3_VER_2_4
237};
238
239bool get_mp3_metadata(int fd, struct mp3entry *entry, const char *filename);
240bool mp3info(struct mp3entry *entry, const char *filename);
241char* id3_get_num_genre(unsigned int genre_num);
242int getid3v2len(int fd);
243void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig);
244void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig);
245
246#endif
diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c
index 53cebfe144..3b5a25ebc0 100644
--- a/apps/menus/recording_menu.c
+++ b/apps/menus/recording_menu.c
@@ -55,7 +55,7 @@
55#endif 55#endif
56#include "splash.h" 56#include "splash.h"
57#if CONFIG_CODEC == SWCODEC 57#if CONFIG_CODEC == SWCODEC
58#include "id3.h" 58#include "metadata.h"
59#include "dsp.h" 59#include "dsp.h"
60#include "menus/eq_menu.h" 60#include "menus/eq_menu.h"
61#ifdef HAVE_RECORDING 61#ifdef HAVE_RECORDING
diff --git a/apps/metadata.c b/apps/metadata.c
index 17c89f17c1..8df046a518 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -24,23 +24,126 @@
24#include <ctype.h> 24#include <ctype.h>
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h"
28#include "playback.h" 27#include "playback.h"
29#include "debug.h" 28#include "debug.h"
30#include "logf.h" 29#include "logf.h"
31#include "cuesheet.h" 30#include "cuesheet.h"
32#include "metadata.h" 31#include "metadata.h"
33 32
33#include "metadata/metadata_parsers.h"
34
34#if CONFIG_CODEC == SWCODEC 35#if CONFIG_CODEC == SWCODEC
35 36
36/* For trailing tag stripping */ 37/* For trailing tag stripping */
37#include "buffering.h" 38#include "buffering.h"
38 39
39#include "metadata/metadata_common.h" 40#include "metadata/metadata_common.h"
40#include "metadata/metadata_parsers.h"
41 41
42#endif /* CONFIG_CODEC == SWCODEC */ 42#endif /* CONFIG_CODEC == SWCODEC */
43 43
44const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
45{
46 /* Unknown file format */
47 [AFMT_UNKNOWN] =
48 AFMT_ENTRY("???", NULL, NULL, NULL ),
49
50 /* MPEG Audio layer 1 */
51 [AFMT_MPA_L1] =
52 AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ),
53 /* MPEG Audio layer 2 */
54 [AFMT_MPA_L2] =
55 AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ),
56 /* MPEG Audio layer 3 */
57 [AFMT_MPA_L3] =
58 AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ),
59
60#if CONFIG_CODEC == SWCODEC
61 /* Audio Interchange File Format */
62 [AFMT_AIFF] =
63 AFMT_ENTRY("AIFF", "aiff", "aiff_enc", "aiff\0aif\0"),
64 /* Uncompressed PCM in a WAV file */
65 [AFMT_PCM_WAV] =
66 AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ),
67 /* Ogg Vorbis */
68 [AFMT_OGG_VORBIS] =
69 AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ),
70 /* FLAC */
71 [AFMT_FLAC] =
72 AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ),
73 /* Musepack */
74 [AFMT_MPC] =
75 AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ),
76 /* A/52 (aka AC3) audio */
77 [AFMT_A52] =
78 AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ),
79 /* WavPack */
80 [AFMT_WAVPACK] =
81 AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ),
82 /* Apple Lossless Audio Codec */
83 [AFMT_ALAC] =
84 AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0m4b\0" ),
85 /* Advanced Audio Coding in M4A container */
86 [AFMT_AAC] =
87 AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ),
88 /* Shorten */
89 [AFMT_SHN] =
90 AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ),
91 /* SID File Format */
92 [AFMT_SID] =
93 AFMT_ENTRY("SID", "sid", NULL, "sid\0" ),
94 /* ADX File Format */
95 [AFMT_ADX] =
96 AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ),
97 /* NESM (NES Sound Format) */
98 [AFMT_NSF] =
99 AFMT_ENTRY("NSF", "nsf", NULL, "nsf\0nsfe\0" ),
100 /* Speex File Format */
101 [AFMT_SPEEX] =
102 AFMT_ENTRY("Speex","speex", NULL, "spx\0" ),
103 /* SPC700 Save State */
104 [AFMT_SPC] =
105 AFMT_ENTRY("SPC", "spc", NULL, "spc\0" ),
106 /* APE (Monkey's Audio) */
107 [AFMT_APE] =
108 AFMT_ENTRY("APE", "ape", NULL, "ape\0mac\0" ),
109 /* WMA (WMAV1/V2 in ASF) */
110 [AFMT_WMA] =
111 AFMT_ENTRY("WMA", "wma", NULL, "wma\0wmv\0asf\0" ),
112 /* Amiga MOD File */
113 [AFMT_MOD] =
114 AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ),
115 /* Amiga SAP File */
116 [AFMT_SAP] =
117 AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ),
118#endif
119};
120
121#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
122/* get REC_FORMAT_* corresponding AFMT_* */
123const int rec_format_afmt[REC_NUM_FORMATS] =
124{
125 /* give AFMT_UNKNOWN by default */
126 [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN,
127 /* add new entries below this line */
128 [REC_FORMAT_AIFF] = AFMT_AIFF,
129 [REC_FORMAT_MPA_L3] = AFMT_MPA_L3,
130 [REC_FORMAT_WAVPACK] = AFMT_WAVPACK,
131 [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV,
132};
133
134/* get AFMT_* corresponding REC_FORMAT_* */
135const int afmt_rec_format[AFMT_NUM_CODECS] =
136{
137 /* give -1 by default */
138 [0 ... AFMT_NUM_CODECS-1] = -1,
139 /* add new entries below this line */
140 [AFMT_AIFF] = REC_FORMAT_AIFF,
141 [AFMT_MPA_L3] = REC_FORMAT_MPA_L3,
142 [AFMT_WAVPACK] = REC_FORMAT_WAVPACK,
143 [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV,
144};
145#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
146
44 147
45/* Simple file type probing by looking at the filename extension. */ 148/* Simple file type probing by looking at the filename extension. */
46unsigned int probe_file_format(const char *filename) 149unsigned int probe_file_format(const char *filename)
@@ -78,6 +181,23 @@ unsigned int probe_file_format(const char *filename)
78 return AFMT_UNKNOWN; 181 return AFMT_UNKNOWN;
79} 182}
80 183
184/* Note, that this returns false for successful, true for error! */
185bool mp3info(struct mp3entry *entry, const char *filename)
186{
187 int fd;
188 bool result;
189
190 fd = open(filename, O_RDONLY);
191 if (fd < 0)
192 return true;
193
194 result = !get_metadata(entry, fd, filename);
195
196 close(fd);
197
198 return result;
199}
200
81/* Get metadata for track - return false if parsing showed problems with the 201/* Get metadata for track - return false if parsing showed problems with the
82 * file that would prevent playback. 202 * file that would prevent playback.
83 */ 203 */
@@ -314,3 +434,50 @@ void strip_tags(int handle_id)
314 bufcuttail(handle_id, len); 434 bufcuttail(handle_id, len);
315} 435}
316#endif /* CONFIG_CODEC == SWCODEC */ 436#endif /* CONFIG_CODEC == SWCODEC */
437
438void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
439{
440 long offset;
441 if (orig > dest)
442 offset = - ((size_t)orig - (size_t)dest);
443 else
444 offset = (size_t)dest - (size_t)orig;
445
446 if (entry->title)
447 entry->title += offset;
448 if (entry->artist)
449 entry->artist += offset;
450 if (entry->album)
451 entry->album += offset;
452 if (entry->genre_string && !id3_is_genre_string(entry->genre_string))
453 /* Don't adjust that if it points to an entry of the "genres" array */
454 entry->genre_string += offset;
455 if (entry->track_string)
456 entry->track_string += offset;
457 if (entry->disc_string)
458 entry->disc_string += offset;
459 if (entry->year_string)
460 entry->year_string += offset;
461 if (entry->composer)
462 entry->composer += offset;
463 if (entry->comment)
464 entry->comment += offset;
465 if (entry->albumartist)
466 entry->albumartist += offset;
467 if (entry->grouping)
468 entry->grouping += offset;
469#if CONFIG_CODEC == SWCODEC
470 if (entry->track_gain_string)
471 entry->track_gain_string += offset;
472 if (entry->album_gain_string)
473 entry->album_gain_string += offset;
474#endif
475 if (entry->mb_track_id)
476 entry->mb_track_id += offset;
477}
478
479void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
480{
481 memcpy(dest, orig, sizeof(struct mp3entry));
482 adjust_mp3entry(dest, dest, orig);
483}
diff --git a/apps/metadata.h b/apps/metadata.h
index c496f40914..b19098621c 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -23,11 +23,228 @@
23#define _METADATA_H 23#define _METADATA_H
24 24
25#include <stdbool.h> 25#include <stdbool.h>
26#include "file.h"
26#include "config.h" 27#include "config.h"
27#include "id3.h" 28
29
30/* Audio file types. */
31/* NOTE: The values of the AFMT_* items are used for the %fc tag in the WPS
32 - so new entries MUST be added to the end to maintain compatibility.
33 */
34enum
35{
36 AFMT_UNKNOWN = 0, /* Unknown file format */
37
38 /* start formats */
39
40 AFMT_MPA_L1, /* MPEG Audio layer 1 */
41 AFMT_MPA_L2, /* MPEG Audio layer 2 */
42 AFMT_MPA_L3, /* MPEG Audio layer 3 */
43
44#if CONFIG_CODEC == SWCODEC
45 AFMT_AIFF, /* Audio Interchange File Format */
46 AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */
47 AFMT_OGG_VORBIS, /* Ogg Vorbis */
48 AFMT_FLAC, /* FLAC */
49 AFMT_MPC, /* Musepack */
50 AFMT_A52, /* A/52 (aka AC3) audio */
51 AFMT_WAVPACK, /* WavPack */
52 AFMT_ALAC, /* Apple Lossless Audio Codec */
53 AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */
54 AFMT_SHN, /* Shorten */
55 AFMT_SID, /* SID File Format */
56 AFMT_ADX, /* ADX File Format */
57 AFMT_NSF, /* NESM (NES Sound Format) */
58 AFMT_SPEEX, /* Ogg Speex speech */
59 AFMT_SPC, /* SPC700 save state */
60 AFMT_APE, /* Monkey's Audio (APE) */
61 AFMT_WMA, /* WMAV1/V2 in ASF */
62 AFMT_MOD, /* Amiga MOD File Format */
63 AFMT_SAP, /* Amiga 8Bit SAP Format */
64#endif
65
66 /* add new formats at any index above this line to have a sensible order -
67 specified array index inits are used */
68 /* format arrays defined in id3.c */
69
70 AFMT_NUM_CODECS,
71
72#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
73 /* masks to decompose parts */
74 CODEC_AFMT_MASK = 0x0fff,
75 CODEC_TYPE_MASK = 0x7000,
76
77 /* switch for specifying codec type when requesting a filename */
78 CODEC_TYPE_DECODER = (0 << 12), /* default */
79 CODEC_TYPE_ENCODER = (1 << 12),
80#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
81};
82
83#if CONFIG_CODEC == SWCODEC
84#define CODEC_EXTENSION "codec"
85
86#ifdef HAVE_RECORDING
87#define ENCODER_SUFFIX "_enc"
88enum rec_format_indexes
89{
90 __REC_FORMAT_START_INDEX = -1,
91
92 /* start formats */
93
94 REC_FORMAT_PCM_WAV,
95 REC_FORMAT_AIFF,
96 REC_FORMAT_WAVPACK,
97 REC_FORMAT_MPA_L3,
98
99 /* add new formats at any index above this line to have a sensible order -
100 specified array index inits are used
101 REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range
102 REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes
103 */
104
105 REC_NUM_FORMATS,
106
107 REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV,
108 REC_FORMAT_CFG_NUM_BITS = 2
109};
110
111#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3"
112
113/* get REC_FORMAT_* corresponding AFMT_* */
114extern const int rec_format_afmt[REC_NUM_FORMATS];
115/* get AFMT_* corresponding REC_FORMAT_* */
116extern const int afmt_rec_format[AFMT_NUM_CODECS];
117
118#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
119 { label, root_fname, enc_root_fname, ext_list }
120#else /* !HAVE_RECORDING */
121#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
122 { label, root_fname, ext_list }
123#endif /* HAVE_RECORDING */
124
125#else /* !SWCODEC */
126
127#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \
128 { label, ext_list }
129#endif /* CONFIG_CODEC == SWCODEC */
130
131/** Database of audio formats **/
132/* record describing the audio format */
133struct afmt_entry
134{
135 char label[8]; /* format label */
136#if CONFIG_CODEC == SWCODEC
137 char *codec_root_fn; /* root codec filename (sans _enc and .codec) */
138#ifdef HAVE_RECORDING
139 char *codec_enc_root_fn; /* filename of encoder codec */
140#endif
141#endif
142 char *ext_list; /* double NULL terminated extension
143 list for type with the first as
144 the default for recording */
145};
146
147/* database of labels and codecs. add formats per above enum */
148extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS];
149
150#define ID3V2_BUF_SIZE 300
151
152enum {
153 ID3_VER_1_0 = 1,
154 ID3_VER_1_1,
155 ID3_VER_2_2,
156 ID3_VER_2_3,
157 ID3_VER_2_4
158};
159
160struct mp3entry {
161 char path[MAX_PATH];
162 char* title;
163 char* artist;
164 char* album;
165 char* genre_string;
166 char* disc_string;
167 char* track_string;
168 char* year_string;
169 char* composer;
170 char* comment;
171 char* albumartist;
172 char* grouping;
173 int discnum;
174 int tracknum;
175 int version;
176 int layer;
177 int year;
178 unsigned char id3version;
179 unsigned int codectype;
180 unsigned int bitrate;
181 unsigned long frequency;
182 unsigned long id3v2len;
183 unsigned long id3v1len;
184 unsigned long first_frame_offset; /* Byte offset to first real MP3 frame.
185 Used for skipping leading garbage to
186 avoid gaps between tracks. */
187 unsigned long vbr_header_pos;
188 unsigned long filesize; /* without headers; in bytes */
189 unsigned long length; /* song length in ms */
190 unsigned long elapsed; /* ms played */
191
192 int lead_trim; /* Number of samples to skip at the beginning */
193 int tail_trim; /* Number of samples to remove from the end */
194
195 /* Added for Vorbis */
196 unsigned long samples; /* number of samples in track */
197
198 /* MP3 stream specific info */
199 unsigned long frame_count; /* number of frames in the file (if VBR) */
200
201 /* Used for A52/AC3 */
202 unsigned long bytesperframe; /* number of bytes per frame (if CBR) */
203
204 /* Xing VBR fields */
205 bool vbr;
206 bool has_toc; /* True if there is a VBR header in the file */
207 unsigned char toc[100]; /* table of contents */
208
209 /* these following two fields are used for local buffering */
210 char id3v2buf[ID3V2_BUF_SIZE];
211 char id3v1buf[4][92];
212
213 /* resume related */
214 unsigned long offset; /* bytes played */
215 int index; /* playlist index */
216
217 /* runtime database fields */
218 long tagcache_idx; /* 0=invalid, otherwise idx+1 */
219 int rating;
220 int score;
221 long playcount;
222 long lastplayed;
223 long playtime;
224
225 /* replaygain support */
226
227#if CONFIG_CODEC == SWCODEC
228 char* track_gain_string;
229 char* album_gain_string;
230 long track_gain; /* 7.24 signed fixed point. 0 for no gain. */
231 long album_gain;
232 long track_peak; /* 7.24 signed fixed point. 0 for no peak. */
233 long album_peak;
234#endif
235
236 /* Cuesheet support */
237 int cuesheet_type; /* 0: none, 1: external, 2: embedded */
238
239 /* Musicbrainz Track ID */
240 char* mb_track_id;
241};
28 242
29unsigned int probe_file_format(const char *filename); 243unsigned int probe_file_format(const char *filename);
30bool get_metadata(struct mp3entry* id3, int fd, const char* trackname); 244bool get_metadata(struct mp3entry* id3, int fd, const char* trackname);
245bool mp3info(struct mp3entry *entry, const char *filename);
246void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig);
247void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig);
31#if CONFIG_CODEC == SWCODEC 248#if CONFIG_CODEC == SWCODEC
32void strip_tags(int handle_id); 249void strip_tags(int handle_id);
33#endif 250#endif
diff --git a/apps/metadata/a52.c b/apps/metadata/a52.c
index bcfd3c7b51..c35b32dba3 100644
--- a/apps/metadata/a52.c
+++ b/apps/metadata/a52.c
@@ -19,7 +19,7 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21 21
22#include "id3.h" 22#include "metadata.h"
23#include "logf.h" 23#include "logf.h"
24 24
25#include "metadata_parsers.h" 25#include "metadata_parsers.h"
diff --git a/apps/metadata/adx.c b/apps/metadata/adx.c
index c5da0deeeb..a903a6d053 100644
--- a/apps/metadata/adx.c
+++ b/apps/metadata/adx.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "debug.h" 31#include "debug.h"
diff --git a/apps/metadata/aiff.c b/apps/metadata/aiff.c
index 74e2465523..cb18e9249a 100644
--- a/apps/metadata/aiff.c
+++ b/apps/metadata/aiff.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31 31
diff --git a/apps/metadata/ape.c b/apps/metadata/ape.c
index 7e9100a50a..dcb359799c 100644
--- a/apps/metadata/ape.c
+++ b/apps/metadata/ape.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "structec.h" 31#include "structec.h"
diff --git a/apps/metadata/asap.c b/apps/metadata/asap.c
index 9bd615afd1..128a18d642 100644
--- a/apps/metadata/asap.c
+++ b/apps/metadata/asap.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "rbunicode.h" 31#include "rbunicode.h"
diff --git a/apps/metadata/asf.c b/apps/metadata/asf.c
index 255a0bcba4..611cc2aca3 100644
--- a/apps/metadata/asf.c
+++ b/apps/metadata/asf.c
@@ -25,7 +25,7 @@
25#include <ctype.h> 25#include <ctype.h>
26#include <inttypes.h> 26#include <inttypes.h>
27 27
28#include "id3.h" 28#include "metadata.h"
29#include "replaygain.h" 29#include "replaygain.h"
30#include "debug.h" 30#include "debug.h"
31#include "rbunicode.h" 31#include "rbunicode.h"
diff --git a/apps/metadata/flac.c b/apps/metadata/flac.c
index 286d356003..a50649e54a 100644
--- a/apps/metadata/flac.c
+++ b/apps/metadata/flac.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "logf.h" 31#include "logf.h"
diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c
index e4df874cff..94ff212cea 100644
--- a/apps/metadata/metadata_common.c
+++ b/apps/metadata/metadata_common.c
@@ -25,8 +25,9 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h"
30#include "replaygain.h" 31#include "replaygain.h"
31 32
32/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the 33/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
diff --git a/apps/metadata/metadata_common.h b/apps/metadata/metadata_common.h
index 3d9a0759c6..f57690af91 100644
--- a/apps/metadata/metadata_common.h
+++ b/apps/metadata/metadata_common.h
@@ -18,7 +18,7 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "id3.h" 21#include "metadata.h"
22 22
23#ifdef ROCKBOX_BIG_ENDIAN 23#ifdef ROCKBOX_BIG_ENDIAN
24#define IS_BIG_ENDIAN 1 24#define IS_BIG_ENDIAN 1
diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h
index 00ad112e54..1521f1301d 100644
--- a/apps/metadata/metadata_parsers.h
+++ b/apps/metadata/metadata_parsers.h
@@ -18,7 +18,11 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "id3.h" 21
22char* id3_get_num_genre(unsigned int genre_num);
23bool id3_is_genre_string(const char *string);
24int getid3v2len(int fd);
25bool get_mp3_metadata(int fd, struct mp3entry* id3, const char *filename);
22 26
23bool get_adx_metadata(int fd, struct mp3entry* id3); 27bool get_adx_metadata(int fd, struct mp3entry* id3);
24bool get_aiff_metadata(int fd, struct mp3entry* id3); 28bool get_aiff_metadata(int fd, struct mp3entry* id3);
diff --git a/apps/metadata/mod.c b/apps/metadata/mod.c
index 38adeea06a..e10090499e 100644
--- a/apps/metadata/mod.c
+++ b/apps/metadata/mod.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "rbunicode.h" 31#include "rbunicode.h"
diff --git a/apps/metadata/monkeys.c b/apps/metadata/monkeys.c
index d59e7ee2b4..1cacff13af 100644
--- a/apps/metadata/monkeys.c
+++ b/apps/metadata/monkeys.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31 31
diff --git a/apps/id3.c b/apps/metadata/mp3.c
index c1541e30df..8c85c8916f 100644
--- a/apps/id3.c
+++ b/apps/metadata/mp3.c
@@ -39,117 +39,11 @@
39#include "file.h" 39#include "file.h"
40#include "logf.h" 40#include "logf.h"
41 41
42#include "id3.h"
43#include "mp3data.h" 42#include "mp3data.h"
44#include "system.h" 43#include "system.h"
45#include "replaygain.h" 44#include "replaygain.h"
46#include "rbunicode.h" 45#include "rbunicode.h"
47 46
48/** Database of audio formats **/
49const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
50{
51 /* Unknown file format */
52 [AFMT_UNKNOWN] =
53 AFMT_ENTRY("???", NULL, NULL, NULL ),
54
55 /* MPEG Audio layer 1 */
56 [AFMT_MPA_L1] =
57 AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ),
58 /* MPEG Audio layer 2 */
59 [AFMT_MPA_L2] =
60 AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ),
61 /* MPEG Audio layer 3 */
62 [AFMT_MPA_L3] =
63 AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ),
64
65#if CONFIG_CODEC == SWCODEC
66 /* Audio Interchange File Format */
67 [AFMT_AIFF] =
68 AFMT_ENTRY("AIFF", "aiff", "aiff_enc", "aiff\0aif\0"),
69 /* Uncompressed PCM in a WAV file */
70 [AFMT_PCM_WAV] =
71 AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ),
72 /* Ogg Vorbis */
73 [AFMT_OGG_VORBIS] =
74 AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ),
75 /* FLAC */
76 [AFMT_FLAC] =
77 AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ),
78 /* Musepack */
79 [AFMT_MPC] =
80 AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ),
81 /* A/52 (aka AC3) audio */
82 [AFMT_A52] =
83 AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ),
84 /* WavPack */
85 [AFMT_WAVPACK] =
86 AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ),
87 /* Apple Lossless Audio Codec */
88 [AFMT_ALAC] =
89 AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0m4b\0" ),
90 /* Advanced Audio Coding in M4A container */
91 [AFMT_AAC] =
92 AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ),
93 /* Shorten */
94 [AFMT_SHN] =
95 AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ),
96 /* SID File Format */
97 [AFMT_SID] =
98 AFMT_ENTRY("SID", "sid", NULL, "sid\0" ),
99 /* ADX File Format */
100 [AFMT_ADX] =
101 AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ),
102 /* NESM (NES Sound Format) */
103 [AFMT_NSF] =
104 AFMT_ENTRY("NSF", "nsf", NULL, "nsf\0nsfe\0" ),
105 /* Speex File Format */
106 [AFMT_SPEEX] =
107 AFMT_ENTRY("Speex","speex", NULL, "spx\0" ),
108 /* SPC700 Save State */
109 [AFMT_SPC] =
110 AFMT_ENTRY("SPC", "spc", NULL, "spc\0" ),
111 /* APE (Monkey's Audio) */
112 [AFMT_APE] =
113 AFMT_ENTRY("APE", "ape", NULL, "ape\0mac\0" ),
114 /* WMA (WMAV1/V2 in ASF) */
115 [AFMT_WMA] =
116 AFMT_ENTRY("WMA", "wma", NULL, "wma\0wmv\0asf\0" ),
117 /* Amiga MOD File */
118 [AFMT_MOD] =
119 AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ),
120 /* Amiga SAP File */
121 [AFMT_SAP] =
122 AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ),
123#endif
124};
125
126#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
127/* get REC_FORMAT_* corresponding AFMT_* */
128const int rec_format_afmt[REC_NUM_FORMATS] =
129{
130 /* give AFMT_UNKNOWN by default */
131 [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN,
132 /* add new entries below this line */
133 [REC_FORMAT_AIFF] = AFMT_AIFF,
134 [REC_FORMAT_MPA_L3] = AFMT_MPA_L3,
135 [REC_FORMAT_WAVPACK] = AFMT_WAVPACK,
136 [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV,
137};
138
139/* get AFMT_* corresponding REC_FORMAT_* */
140const int afmt_rec_format[AFMT_NUM_CODECS] =
141{
142 /* give -1 by default */
143 [0 ... AFMT_NUM_CODECS-1] = -1,
144 /* add new entries below this line */
145 [AFMT_AIFF] = REC_FORMAT_AIFF,
146 [AFMT_MPA_L3] = REC_FORMAT_MPA_L3,
147 [AFMT_WAVPACK] = REC_FORMAT_WAVPACK,
148 [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV,
149};
150#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
151/****/
152
153static unsigned long unsync(unsigned long b0, 47static unsigned long unsync(unsigned long b0,
154 unsigned long b1, 48 unsigned long b1,
155 unsigned long b2, 49 unsigned long b2,
@@ -200,7 +94,7 @@ char* id3_get_num_genre(unsigned int genre_num)
200} 94}
201 95
202/* True if the string is from the "genres" array */ 96/* True if the string is from the "genres" array */
203static bool id3_is_genre_string(const char *string) 97bool id3_is_genre_string(const char *string)
204{ 98{
205 return ( string >= genres[0] && 99 return ( string >= genres[0] &&
206 string <= genres[sizeof(genres)/sizeof(char*) - 1] ); 100 string <= genres[sizeof(genres)/sizeof(char*) - 1] );
@@ -1233,70 +1127,6 @@ bool get_mp3_metadata(int fd, struct mp3entry *entry, const char *filename)
1233 return true; 1127 return true;
1234} 1128}
1235 1129
1236/* Note, that this returns false for successful, true for error! */
1237bool mp3info(struct mp3entry *entry, const char *filename)
1238{
1239 int fd;
1240 bool result;
1241
1242 fd = open(filename, O_RDONLY);
1243 if (fd < 0)
1244 return true;
1245
1246 result = !get_mp3_metadata(fd, entry, filename);
1247
1248 close(fd);
1249
1250 return result;
1251}
1252
1253void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
1254{
1255 long offset;
1256 if (orig > dest)
1257 offset = - ((size_t)orig - (size_t)dest);
1258 else
1259 offset = (size_t)dest - (size_t)orig;
1260
1261 if (entry->title)
1262 entry->title += offset;
1263 if (entry->artist)
1264 entry->artist += offset;
1265 if (entry->album)
1266 entry->album += offset;
1267 if (entry->genre_string && !id3_is_genre_string(entry->genre_string))
1268 /* Don't adjust that if it points to an entry of the "genres" array */
1269 entry->genre_string += offset;
1270 if (entry->track_string)
1271 entry->track_string += offset;
1272 if (entry->disc_string)
1273 entry->disc_string += offset;
1274 if (entry->year_string)
1275 entry->year_string += offset;
1276 if (entry->composer)
1277 entry->composer += offset;
1278 if (entry->comment)
1279 entry->comment += offset;
1280 if (entry->albumartist)
1281 entry->albumartist += offset;
1282 if (entry->grouping)
1283 entry->grouping += offset;
1284#if CONFIG_CODEC == SWCODEC
1285 if (entry->track_gain_string)
1286 entry->track_gain_string += offset;
1287 if (entry->album_gain_string)
1288 entry->album_gain_string += offset;
1289#endif
1290 if (entry->mb_track_id)
1291 entry->mb_track_id += offset;
1292}
1293
1294void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
1295{
1296 memcpy(dest, orig, sizeof(struct mp3entry));
1297 adjust_mp3entry(dest, dest, orig);
1298}
1299
1300#ifdef DEBUG_STANDALONE 1130#ifdef DEBUG_STANDALONE
1301 1131
1302char *secs2str(int ms) 1132char *secs2str(int ms)
diff --git a/apps/metadata/mp4.c b/apps/metadata/mp4.c
index 493bc48da7..803f82f4f3 100644
--- a/apps/metadata/mp4.c
+++ b/apps/metadata/mp4.c
@@ -26,7 +26,7 @@
26 26
27#include "system.h" 27#include "system.h"
28#include "errno.h" 28#include "errno.h"
29#include "id3.h" 29#include "metadata.h"
30#include "metadata_common.h" 30#include "metadata_common.h"
31#include "metadata_parsers.h" 31#include "metadata_parsers.h"
32#include "logf.h" 32#include "logf.h"
diff --git a/apps/metadata/mpc.c b/apps/metadata/mpc.c
index dd83515246..5ab1241153 100644
--- a/apps/metadata/mpc.c
+++ b/apps/metadata/mpc.c
@@ -22,7 +22,7 @@
22#include <string.h> 22#include <string.h>
23#include <inttypes.h> 23#include <inttypes.h>
24#include "system.h" 24#include "system.h"
25#include "id3.h" 25#include "metadata.h"
26#include "metadata_common.h" 26#include "metadata_common.h"
27#include "metadata_parsers.h" 27#include "metadata_parsers.h"
28#include "logf.h" 28#include "logf.h"
diff --git a/apps/metadata/ogg.c b/apps/metadata/ogg.c
index edb55f53a3..cd4c85f46e 100644
--- a/apps/metadata/ogg.c
+++ b/apps/metadata/ogg.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "logf.h" 31#include "logf.h"
diff --git a/apps/metadata/sid.c b/apps/metadata/sid.c
index 8741ce6dcb..bab7233752 100644
--- a/apps/metadata/sid.c
+++ b/apps/metadata/sid.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "rbunicode.h" 31#include "rbunicode.h"
diff --git a/apps/metadata/spc.c b/apps/metadata/spc.c
index 094fcce96d..786c678c4c 100644
--- a/apps/metadata/spc.c
+++ b/apps/metadata/spc.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "debug.h" 31#include "debug.h"
diff --git a/apps/metadata/vorbis.c b/apps/metadata/vorbis.c
index 19b791570b..cfaa7158f1 100644
--- a/apps/metadata/vorbis.c
+++ b/apps/metadata/vorbis.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "structec.h" 31#include "structec.h"
diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c
index 229d61599e..cf676f89b0 100644
--- a/apps/metadata/wave.c
+++ b/apps/metadata/wave.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31 31
diff --git a/apps/metadata/wavpack.c b/apps/metadata/wavpack.c
index c695203292..a5a342bf04 100644
--- a/apps/metadata/wavpack.c
+++ b/apps/metadata/wavpack.c
@@ -25,7 +25,7 @@
25#include <inttypes.h> 25#include <inttypes.h>
26 26
27#include "system.h" 27#include "system.h"
28#include "id3.h" 28#include "metadata.h"
29#include "metadata_common.h" 29#include "metadata_common.h"
30#include "metadata_parsers.h" 30#include "metadata_parsers.h"
31#include "logf.h" 31#include "logf.h"
diff --git a/apps/mp3data.c b/apps/mp3data.c
new file mode 100644
index 0000000000..80870cd8cd
--- /dev/null
+++ b/apps/mp3data.c
@@ -0,0 +1,782 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Daniel Stenberg
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/*
23 * Parts of this code has been stolen from the Ample project and was written
24 * by David Härdeman. It has since been extended and enhanced pretty much by
25 * all sorts of friendly Rockbox people.
26 *
27 * A nice reference for MPEG header info:
28 * http://rockbox.haxx.se/docs/mpeghdr.html
29 *
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdbool.h>
36#include <limits.h>
37#include "debug.h"
38#include "logf.h"
39#include "mp3data.h"
40#include "file.h"
41#include "buffer.h"
42
43// #define DEBUG_VERBOSE
44
45#define SYNC_MASK (0x7ffL << 21)
46#define VERSION_MASK (3L << 19)
47#define LAYER_MASK (3L << 17)
48#define PROTECTION_MASK (1L << 16)
49#define BITRATE_MASK (0xfL << 12)
50#define SAMPLERATE_MASK (3L << 10)
51#define PADDING_MASK (1L << 9)
52#define PRIVATE_MASK (1L << 8)
53#define CHANNELMODE_MASK (3L << 6)
54#define MODE_EXT_MASK (3L << 4)
55#define COPYRIGHT_MASK (1L << 3)
56#define ORIGINAL_MASK (1L << 2)
57#define EMPHASIS_MASK 3L
58
59/* MPEG Version table, sorted by version index */
60static const signed char version_table[4] = {
61 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
62};
63
64/* Bitrate table for mpeg audio, indexed by row index and birate index */
65static const short bitrates[5][16] = {
66 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
67 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
68 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
69 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
70 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
71};
72
73/* Bitrate pointer table, indexed by version and layer */
74static const short *bitrate_table[3][3] =
75{
76 {bitrates[0], bitrates[1], bitrates[2]},
77 {bitrates[3], bitrates[4], bitrates[4]},
78 {bitrates[3], bitrates[4], bitrates[4]}
79};
80
81/* Sampling frequency table, indexed by version and frequency index */
82static const unsigned short freq_table[3][3] =
83{
84 {44100, 48000, 32000}, /* MPEG Version 1 */
85 {22050, 24000, 16000}, /* MPEG version 2 */
86 {11025, 12000, 8000}, /* MPEG version 2.5 */
87};
88
89unsigned long bytes2int(unsigned long b0,
90 unsigned long b1,
91 unsigned long b2,
92 unsigned long b3)
93{
94 return (((long)(b0 & 0xFF) << (3*8)) |
95 ((long)(b1 & 0xFF) << (2*8)) |
96 ((long)(b2 & 0xFF) << (1*8)) |
97 ((long)(b3 & 0xFF) << (0*8)));
98}
99
100/* check if 'head' is a valid mp3 frame header */
101static bool is_mp3frameheader(unsigned long head)
102{
103 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
104 return false;
105 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
106 return false;
107 if (!(head & LAYER_MASK)) /* no layer? */
108 return false;
109#if CONFIG_CODEC != SWCODEC
110 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
111 if ((head & LAYER_MASK) == LAYER_MASK)
112 return false;
113#endif
114 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
115 return false;
116 if (!(head & BITRATE_MASK)) /* no bitrate? */
117 return false;
118 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
119 return false;
120
121 return true;
122}
123
124static bool mp3headerinfo(struct mp3info *info, unsigned long header)
125{
126 int bitindex, freqindex;
127
128 /* MPEG Audio Version */
129 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
130 return false;
131
132 info->version = version_table[(header & VERSION_MASK) >> 19];
133 if (info->version < 0)
134 return false;
135
136 /* Layer */
137 info->layer = 3 - ((header & LAYER_MASK) >> 17);
138 if (info->layer == 3)
139 return false;
140
141 info->protection = (header & PROTECTION_MASK) ? true : false;
142
143 /* Bitrate */
144 bitindex = (header & BITRATE_MASK) >> 12;
145 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
146 if(info->bitrate == 0)
147 return false;
148
149 /* Sampling frequency */
150 freqindex = (header & SAMPLERATE_MASK) >> 10;
151 if (freqindex == 3)
152 return false;
153 info->frequency = freq_table[info->version][freqindex];
154
155 info->padding = (header & PADDING_MASK) ? 1 : 0;
156
157 /* Calculate number of bytes, calculation depends on layer */
158 if (info->layer == 0) {
159 info->frame_samples = 384;
160 info->frame_size = (12000 * info->bitrate / info->frequency
161 + info->padding) * 4;
162 }
163 else {
164 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
165 info->frame_samples = 576;
166 else
167 info->frame_samples = 1152;
168 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
169 / info->frequency + info->padding;
170 }
171
172 /* Frametime fraction denominator */
173 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
174 info->ft_den = 1; /* integer number of milliseconds */
175 }
176 else { /* 44.1/22.05/11.025 kHz */
177 if (info->layer == 0) /* layer 1 */
178 info->ft_den = 147;
179 else /* layer 2+3 */
180 info->ft_den = 49;
181 }
182 /* Frametime fraction numerator */
183 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
184
185 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
186 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
187 info->emphasis = header & EMPHASIS_MASK;
188
189#ifdef DEBUG_VERBOSE
190 DEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
191 "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d/%d\n",
192 header, info->version, info->layer+1, info->bitrate,
193 info->frequency, info->channel_mode, info->mode_extension,
194 info->emphasis, info->frame_size, info->ft_num, info->ft_den);
195#endif
196 return true;
197}
198
199static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
200 unsigned long last_header,
201 int(*getfunc)(int fd, unsigned char *c))
202{
203 unsigned long header=0;
204 unsigned char tmp;
205 int i;
206
207 long pos = 0;
208
209 /* We remember the last header we found, to use as a template to see if
210 the header we find has the same frequency, layer etc */
211 last_header &= 0xffff0c00;
212
213 /* Fill up header with first 24 bits */
214 for(i = 0; i < 3; i++) {
215 header <<= 8;
216 if(!getfunc(fd, &tmp))
217 return 0;
218 header |= tmp;
219 pos++;
220 }
221
222 do {
223 header <<= 8;
224 if(!getfunc(fd, &tmp))
225 return 0;
226 header |= tmp;
227 pos++;
228 if(max_offset > 0 && pos > max_offset)
229 return 0;
230 } while(!is_mp3frameheader(header) ||
231 (last_header?((header & 0xffff0c00) != last_header):false));
232
233 *offset = pos - 4;
234
235#if defined(DEBUG)
236 if(*offset)
237 DEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
238#endif
239
240 return header;
241}
242
243static int fileread(int fd, unsigned char *c)
244{
245 return read(fd, c, 1);
246}
247
248unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header)
249{
250 return __find_next_frame(fd, offset, max_offset, last_header, fileread);
251}
252
253#ifndef __PCTOOL__
254static int fnf_read_index;
255static int fnf_buf_len;
256
257static int buf_getbyte(int fd, unsigned char *c)
258{
259 if(fnf_read_index < fnf_buf_len)
260 {
261 *c = audiobuf[fnf_read_index++];
262 return 1;
263 }
264 else
265 {
266 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
267 if(fnf_buf_len < 0)
268 return -1;
269
270 fnf_read_index = 0;
271
272 if(fnf_buf_len > 0)
273 {
274 *c = audiobuf[fnf_read_index++];
275 return 1;
276 }
277 else
278 return 0;
279 }
280 return 0;
281}
282
283static int buf_seek(int fd, int len)
284{
285 fnf_read_index += len;
286 if(fnf_read_index > fnf_buf_len)
287 {
288 len = fnf_read_index - fnf_buf_len;
289
290 fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf);
291 if(fnf_buf_len < 0)
292 return -1;
293
294 fnf_read_index = 0;
295 fnf_read_index += len;
296 }
297
298 if(fnf_read_index > fnf_buf_len)
299 {
300 return -1;
301 }
302 else
303 return 0;
304}
305
306static void buf_init(void)
307{
308 fnf_buf_len = 0;
309 fnf_read_index = 0;
310}
311
312static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset,
313 unsigned long last_header)
314{
315 return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte);
316}
317
318static int audiobuflen;
319static int mem_pos;
320static int mem_cnt;
321static int mem_maxlen;
322
323static int mem_getbyte(int dummy, unsigned char *c)
324{
325 dummy = dummy;
326
327 *c = audiobuf[mem_pos++];
328 if(mem_pos >= audiobuflen)
329 mem_pos = 0;
330
331 if(mem_cnt++ >= mem_maxlen)
332 return 0;
333 else
334 return 1;
335}
336
337unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
338 unsigned long last_header)
339{
340 audiobuflen = audiobufend - audiobuf;
341 mem_pos = startpos;
342 mem_cnt = 0;
343 mem_maxlen = max_offset;
344
345 return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte);
346}
347#endif
348
349int get_mp3file_info(int fd, struct mp3info *info)
350{
351 unsigned char frame[1800];
352 unsigned char *vbrheader;
353 unsigned long header;
354 long bytecount;
355 int num_offsets;
356 int frames_per_entry;
357 int i;
358 long offset;
359 int j;
360 long tmp;
361
362 header = find_next_frame(fd, &bytecount, 0x20000, 0);
363 /* Quit if we haven't found a valid header within 128K */
364 if(header == 0)
365 return -1;
366
367 memset(info, 0, sizeof(struct mp3info));
368#if CONFIG_CODEC==SWCODEC
369 /* These two are needed for proper LAME gapless MP3 playback */
370 info->enc_delay = -1;
371 info->enc_padding = -1;
372#endif
373 if(!mp3headerinfo(info, header))
374 return -2;
375
376 /* OK, we have found a frame. Let's see if it has a Xing header */
377 if (info->frame_size-4 >= (int)sizeof(frame))
378 {
379#if defined(DEBUG)
380 DEBUGF("Error: Invalid id3 header, frame_size: %d\n", info->frame_size);
381#endif
382 return -8;
383 }
384
385 if(read(fd, frame, info->frame_size-4) < 0)
386 return -3;
387
388 /* calculate position of VBR header */
389 if ( info->version == MPEG_VERSION1 ) {
390 if (info->channel_mode == 3) /* mono */
391 vbrheader = frame + 17;
392 else
393 vbrheader = frame + 32;
394 }
395 else {
396 if (info->channel_mode == 3) /* mono */
397 vbrheader = frame + 9;
398 else
399 vbrheader = frame + 17;
400 }
401
402 if (!memcmp(vbrheader, "Xing", 4)
403 || !memcmp(vbrheader, "Info", 4))
404 {
405 int i = 8; /* Where to start parsing info */
406
407 /* DEBUGF("Xing/Info header\n"); */
408
409 /* Remember where in the file the Xing header is */
410 info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size;
411
412 /* We want to skip the Xing frame when playing the stream */
413 bytecount += info->frame_size;
414
415 /* Now get the next frame to find out the real info about
416 the mp3 stream */
417 header = find_next_frame(fd, &tmp, 0x20000, 0);
418 if(header == 0)
419 return -4;
420
421 if(!mp3headerinfo(info, header))
422 return -5;
423
424 /* Is it a VBR file? */
425 info->is_vbr = info->is_xing_vbr = !memcmp(vbrheader, "Xing", 4);
426
427 if (vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
428 {
429 info->frame_count = bytes2int(vbrheader[i], vbrheader[i+1],
430 vbrheader[i+2], vbrheader[i+3]);
431 if (info->frame_count <= ULONG_MAX / info->ft_num)
432 info->file_time = info->frame_count * info->ft_num / info->ft_den;
433 else
434 info->file_time = info->frame_count / info->ft_den * info->ft_num;
435 i += 4;
436 }
437
438 if (vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */
439 {
440 info->byte_count = bytes2int(vbrheader[i], vbrheader[i+1],
441 vbrheader[i+2], vbrheader[i+3]);
442 i += 4;
443 }
444
445 if (info->file_time && info->byte_count)
446 {
447 if (info->byte_count <= (ULONG_MAX/8))
448 info->bitrate = info->byte_count * 8 / info->file_time;
449 else
450 info->bitrate = info->byte_count / (info->file_time >> 3);
451 }
452 else
453 info->bitrate = 0;
454
455 if (vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
456 {
457 info->has_toc = true;
458 memcpy( info->toc, vbrheader+i, 100 );
459 i += 100;
460 }
461 if (vbrheader[7] & VBR_QUALITY_FLAG)
462 {
463 /* We don't care about this, but need to skip it */
464 i += 4;
465 }
466#if CONFIG_CODEC==SWCODEC
467 i += 21;
468 info->enc_delay = (vbrheader[i] << 4) | (vbrheader[i + 1] >> 4);
469 info->enc_padding = ((vbrheader[i + 1] & 0x0f) << 8) | vbrheader[i + 2];
470 /* TODO: This sanity checking is rather silly, seeing as how the LAME
471 header contains a CRC field that can be used to verify integrity. */
472 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
473 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
474 {
475 /* Invalid data */
476 info->enc_delay = -1;
477 info->enc_padding = -1;
478 }
479#endif
480 }
481
482 if (!memcmp(vbrheader, "VBRI", 4))
483 {
484 DEBUGF("VBRI header\n");
485
486 /* We want to skip the VBRI frame when playing the stream */
487 bytecount += info->frame_size;
488
489 /* Now get the next frame to find out the real info about
490 the mp3 stream */
491 header = find_next_frame(fd, &tmp, 0x20000, 0);
492 if(header == 0)
493 return -6;
494
495 bytecount += tmp;
496
497 if(!mp3headerinfo(info, header))
498 return -7;
499
500 DEBUGF("%04x: %04x %04x ", 0, (short)(header >> 16),
501 (short)(header & 0xffff));
502 for(i = 4;i < (int)sizeof(frame)-4;i+=2) {
503 if(i % 16 == 0) {
504 DEBUGF("\n%04x: ", i-4);
505 }
506 DEBUGF("%04x ", (frame[i-4] << 8) | frame[i-4+1]);
507 }
508
509 DEBUGF("\n");
510
511 /* Yes, it is a FhG VBR file */
512 info->is_vbr = true;
513 info->is_vbri_vbr = true;
514 info->has_toc = false; /* We don't parse the TOC (yet) */
515
516 info->byte_count = bytes2int(vbrheader[10], vbrheader[11],
517 vbrheader[12], vbrheader[13]);
518 info->frame_count = bytes2int(vbrheader[14], vbrheader[15],
519 vbrheader[16], vbrheader[17]);
520 if (info->frame_count <= ULONG_MAX / info->ft_num)
521 info->file_time = info->frame_count * info->ft_num / info->ft_den;
522 else
523 info->file_time = info->frame_count / info->ft_den * info->ft_num;
524
525 if (info->byte_count <= (ULONG_MAX/8))
526 info->bitrate = info->byte_count * 8 / info->file_time;
527 else
528 info->bitrate = info->byte_count / (info->file_time >> 3);
529
530 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
531 num_offsets = bytes2int(0, 0, vbrheader[18], vbrheader[19]);
532 frames_per_entry = bytes2int(0, 0, vbrheader[24], vbrheader[25]);
533 DEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
534 info->bitrate, info->frame_size, info->frame_size);
535 DEBUGF("Frame count: %lx\n", info->frame_count);
536 DEBUGF("Byte count: %lx\n", info->byte_count);
537 DEBUGF("Offsets: %d\n", num_offsets);
538 DEBUGF("Frames/entry: %d\n", frames_per_entry);
539
540 offset = 0;
541
542 for(i = 0;i < num_offsets;i++)
543 {
544 j = bytes2int(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]);
545 offset += j;
546 DEBUGF("%03d: %lx (%x)\n", i, offset - bytecount, j);
547 }
548 }
549
550 return bytecount;
551}
552
553#ifndef __PCTOOL__
554static void long2bytes(unsigned char *buf, long val)
555{
556 buf[0] = (val >> 24) & 0xff;
557 buf[1] = (val >> 16) & 0xff;
558 buf[2] = (val >> 8) & 0xff;
559 buf[3] = val & 0xff;
560}
561
562int count_mp3_frames(int fd, int startpos, int filesize,
563 void (*progressfunc)(int))
564{
565 unsigned long header = 0;
566 struct mp3info info;
567 int num_frames;
568 long bytes;
569 int cnt;
570 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
571 int progress_cnt = 0;
572 bool is_vbr = false;
573 int last_bitrate = 0;
574 int header_template = 0;
575
576 if(lseek(fd, startpos, SEEK_SET) < 0)
577 return -1;
578
579 buf_init();
580
581 /* Find out the total number of frames */
582 num_frames = 0;
583 cnt = 0;
584
585 while((header = buf_find_next_frame(fd, &bytes, -1, header_template))) {
586 mp3headerinfo(&info, header);
587
588 if(!header_template)
589 header_template = header;
590
591 /* See if this really is a VBR file */
592 if(last_bitrate && info.bitrate != last_bitrate)
593 {
594 is_vbr = true;
595 }
596 last_bitrate = info.bitrate;
597
598 buf_seek(fd, info.frame_size-4);
599 num_frames++;
600 if(progressfunc)
601 {
602 cnt += bytes + info.frame_size;
603 if(cnt > progress_chunk)
604 {
605 progress_cnt++;
606 progressfunc(progress_cnt);
607 cnt = 0;
608 }
609 }
610 }
611 DEBUGF("Total number of frames: %d\n", num_frames);
612
613 if(is_vbr)
614 return num_frames;
615 else
616 {
617 DEBUGF("Not a VBR file\n");
618 return 0;
619 }
620}
621
622static const char cooltext[] = "Rockbox - rocks your box";
623
624/* buf needs to be the audio buffer with TOC generation enabled,
625 and at least MAX_XING_HEADER_SIZE bytes otherwise */
626int create_xing_header(int fd, long startpos, long filesize,
627 unsigned char *buf, unsigned long num_frames,
628 unsigned long rec_time, unsigned long header_template,
629 void (*progressfunc)(int), bool generate_toc)
630{
631 struct mp3info info;
632 unsigned char toc[100];
633 unsigned long header = 0;
634 unsigned long xing_header_template = header_template;
635 unsigned long filepos;
636 long pos, last_pos;
637 long j;
638 long bytes;
639 int i;
640 int index;
641
642 DEBUGF("create_xing_header()\n");
643
644 if(generate_toc)
645 {
646 lseek(fd, startpos, SEEK_SET);
647 buf_init();
648
649 /* Generate filepos table */
650 last_pos = 0;
651 filepos = 0;
652 header = 0;
653 for(i = 0;i < 100;i++) {
654 /* Calculate the absolute frame number for this seek point */
655 pos = i * num_frames / 100;
656
657 /* Advance from the last seek point to this one */
658 for(j = 0;j < pos - last_pos;j++)
659 {
660 header = buf_find_next_frame(fd, &bytes, -1, header_template);
661 filepos += bytes;
662 mp3headerinfo(&info, header);
663 buf_seek(fd, info.frame_size-4);
664 filepos += info.frame_size;
665
666 if(!header_template)
667 header_template = header;
668 }
669
670 /* Save a header for later use if header_template is empty.
671 We only save one header, and we want to save one in the
672 middle of the stream, just in case the first and the last
673 headers are corrupt. */
674 if(!xing_header_template && i == 1)
675 xing_header_template = header;
676
677 if(progressfunc)
678 {
679 progressfunc(50 + i/2);
680 }
681
682 /* Fill in the TOC entry */
683 /* each toc is a single byte indicating how many 256ths of the
684 * way through the file, is that percent of the way through the
685 * song. the easy method, filepos*256/filesize, chokes when
686 * the upper 8 bits of the file position are nonzero
687 * (i.e. files over 16mb in size).
688 */
689 if (filepos > (ULONG_MAX/256))
690 {
691 /* instead of multiplying filepos by 256, we divide
692 * filesize by 256.
693 */
694 toc[i] = filepos / (filesize >> 8);
695 }
696 else
697 {
698 toc[i] = filepos * 256 / filesize;
699 }
700
701 DEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
702 i, pos, pos-last_pos, filepos, toc[i]);
703
704 last_pos = pos;
705 }
706 }
707
708 /* Use the template header and create a new one.
709 We ignore the Protection bit even if the rest of the stream is
710 protected. */
711 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
712 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
713
714 if (!mp3headerinfo(&info, header))
715 return 0; /* invalid header */
716
717 if (num_frames == 0 && rec_time) {
718 /* estimate the number of frames based on the recording time */
719 if (rec_time <= ULONG_MAX / info.ft_den)
720 num_frames = rec_time * info.ft_den / info.ft_num;
721 else
722 num_frames = rec_time / info.ft_num * info.ft_den;
723 }
724
725 /* Clear the frame */
726 memset(buf, 0, MAX_XING_HEADER_SIZE);
727
728 /* Write the header to the buffer */
729 long2bytes(buf, header);
730
731 /* Calculate position of VBR header */
732 if (info.version == MPEG_VERSION1) {
733 if (info.channel_mode == 3) /* mono */
734 index = 21;
735 else
736 index = 36;
737 }
738 else {
739 if (info.channel_mode == 3) /* mono */
740 index = 13;
741 else
742 index = 21;
743 }
744
745 /* Create the Xing data */
746 memcpy(&buf[index], "Xing", 4);
747 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
748 | (filesize ? VBR_BYTES_FLAG : 0)
749 | (generate_toc ? VBR_TOC_FLAG : 0));
750 index += 8;
751 if(num_frames)
752 {
753 long2bytes(&buf[index], num_frames);
754 index += 4;
755 }
756
757 if(filesize)
758 {
759 long2bytes(&buf[index], filesize - startpos);
760 index += 4;
761 }
762
763 /* Copy the TOC */
764 memcpy(buf + index, toc, 100);
765
766 /* And some extra cool info */
767 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
768
769#ifdef DEBUG
770 for(i = 0;i < info.frame_size;i++)
771 {
772 if(i && !(i % 16))
773 DEBUGF("\n");
774
775 DEBUGF("%02x ", buf[i]);
776 }
777#endif
778
779 return info.frame_size;
780}
781
782#endif
diff --git a/apps/mp3data.h b/apps/mp3data.h
new file mode 100644
index 0000000000..2a6a27ac2d
--- /dev/null
+++ b/apps/mp3data.h
@@ -0,0 +1,83 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
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#ifndef _MP3DATA_H_
23#define _MP3DATA_H_
24
25#define MPEG_VERSION1 0
26#define MPEG_VERSION2 1
27#define MPEG_VERSION2_5 2
28
29struct mp3info {
30 /* Standard MP3 frame header fields */
31 int version;
32 int layer;
33 bool protection;
34 int bitrate;
35 long frequency;
36 int padding;
37 int channel_mode;
38 int mode_extension;
39 int emphasis;
40 int frame_size; /* Frame size in bytes */
41 int frame_samples; /* Samples per frame */
42 int ft_num; /* Numerator of frametime in milliseconds */
43 int ft_den; /* Denominator of frametime in milliseconds */
44
45 bool is_vbr; /* True if the file is VBR */
46 bool has_toc; /* True if there is a VBR header in the file */
47 bool is_xing_vbr; /* True if the VBR header is of Xing type */
48 bool is_vbri_vbr; /* True if the VBR header is of VBRI type */
49 unsigned char toc[100];
50 unsigned long frame_count; /* Number of frames in the file (if VBR) */
51 unsigned long byte_count; /* File size in bytes */
52 unsigned long file_time; /* Length of the whole file in milliseconds */
53 unsigned long vbr_header_pos;
54 int enc_delay; /* Encoder delay, fetched from LAME header */
55 int enc_padding; /* Padded samples added to last frame. LAME header */
56};
57
58/* Xing header information */
59#define VBR_FRAMES_FLAG 0x01
60#define VBR_BYTES_FLAG 0x02
61#define VBR_TOC_FLAG 0x04
62#define VBR_QUALITY_FLAG 0x08
63
64#define MAX_XING_HEADER_SIZE 576
65
66unsigned long find_next_frame(int fd, long *offset, long max_offset,
67 unsigned long last_header);
68unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
69 unsigned long last_header);
70int get_mp3file_info(int fd, struct mp3info *info);
71int count_mp3_frames(int fd, int startpos, int filesize,
72 void (*progressfunc)(int));
73int create_xing_header(int fd, long startpos, long filesize,
74 unsigned char *buf, unsigned long num_frames,
75 unsigned long rec_time, unsigned long header_template,
76 void (*progressfunc)(int), bool generate_toc);
77
78extern unsigned long bytes2int(unsigned long b0,
79 unsigned long b1,
80 unsigned long b2,
81 unsigned long b3);
82
83#endif
diff --git a/apps/mpeg.c b/apps/mpeg.c
index b570f41b28..6056b68053 100644
--- a/apps/mpeg.c
+++ b/apps/mpeg.c
@@ -26,7 +26,7 @@
26 26
27#include "debug.h" 27#include "debug.h"
28#include "panic.h" 28#include "panic.h"
29#include "id3.h" 29#include "metadata.h"
30#include "mpeg.h" 30#include "mpeg.h"
31#include "audio.h" 31#include "audio.h"
32#include "ata.h" 32#include "ata.h"
diff --git a/apps/mpeg.h b/apps/mpeg.h
index ce2cff0069..f5ce613b8d 100644
--- a/apps/mpeg.h
+++ b/apps/mpeg.h
@@ -22,7 +22,7 @@
22#define _MPEG_H_ 22#define _MPEG_H_
23 23
24#include <stdbool.h> 24#include <stdbool.h>
25#include "id3.h" 25#include "metadata.h"
26 26
27#define MPEG_SWAP_CHUNKSIZE 0x2000 27#define MPEG_SWAP_CHUNKSIZE 0x2000
28#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we 28#define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we
diff --git a/apps/onplay.c b/apps/onplay.c
index fae86cf150..1735fdbbc2 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -37,7 +37,7 @@
37#include "kernel.h" 37#include "kernel.h"
38#include "keyboard.h" 38#include "keyboard.h"
39#include "mp3data.h" 39#include "mp3data.h"
40#include "id3.h" 40#include "metadata.h"
41#include "screens.h" 41#include "screens.h"
42#include "tree.h" 42#include "tree.h"
43#include "buffer.h" 43#include "buffer.h"
diff --git a/apps/playlist.h b/apps/playlist.h
index 345417a29a..df3bd6221a 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -25,7 +25,7 @@
25#include <stdbool.h> 25#include <stdbool.h>
26#include "file.h" 26#include "file.h"
27#include "kernel.h" 27#include "kernel.h"
28#include "id3.h" 28#include "metadata.h"
29 29
30#define PLAYLIST_ATTR_QUEUED 0x01 30#define PLAYLIST_ATTR_QUEUED 0x01
31#define PLAYLIST_ATTR_INSERTED 0x02 31#define PLAYLIST_ATTR_INSERTED 0x02
diff --git a/apps/plugin.h b/apps/plugin.h
index 20724f8706..1029431cd1 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -52,7 +52,7 @@ void* plugin_get_buffer(size_t *buffer_size);
52#include "usb.h" 52#include "usb.h"
53#include "font.h" 53#include "font.h"
54#include "lcd.h" 54#include "lcd.h"
55#include "id3.h" 55#include "metadata.h"
56#include "sound.h" 56#include "sound.h"
57#include "mpeg.h" 57#include "mpeg.h"
58#include "audio.h" 58#include "audio.h"
diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c
index 29a1ed39e9..30a4e0c49f 100644
--- a/apps/recorder/albumart.c
+++ b/apps/recorder/albumart.c
@@ -23,7 +23,7 @@
23#include "sprintf.h" 23#include "sprintf.h"
24#include "system.h" 24#include "system.h"
25#include "albumart.h" 25#include "albumart.h"
26#include "id3.h" 26#include "metadata.h"
27#include "gwps.h" 27#include "gwps.h"
28#include "buffering.h" 28#include "buffering.h"
29#include "dircache.h" 29#include "dircache.h"
diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h
index e7033c19e9..52e7c74c02 100644
--- a/apps/recorder/albumart.h
+++ b/apps/recorder/albumart.h
@@ -25,7 +25,7 @@
25#ifdef HAVE_ALBUMART 25#ifdef HAVE_ALBUMART
26 26
27#include <stdbool.h> 27#include <stdbool.h>
28#include "id3.h" 28#include "metadata.h"
29#include "gwps.h" 29#include "gwps.h"
30 30
31/* Look for albumart bitmap in the same dir as the track and in its parent dir. 31/* Look for albumart bitmap in the same dir as the track and in its parent dir.
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index c4f18e82ff..0b48c125d1 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -28,7 +28,7 @@
28 28
29#include "settings.h" 29#include "settings.h"
30 30
31#include "id3.h" 31#include "metadata.h"
32#include "icons.h" 32#include "icons.h"
33 33
34const unsigned char bitmap_icons_5x8[][5] = 34const unsigned char bitmap_icons_5x8[][5] =
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index dca5f29c90..767e0f2a14 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -24,6 +24,7 @@
24#ifndef PLUGIN 24#ifndef PLUGIN
25 25
26#include <lcd.h> 26#include <lcd.h>
27#include "metadata.h"
27 28
28#ifdef HAVE_LCD_BITMAP 29#ifdef HAVE_LCD_BITMAP
29 30
@@ -88,7 +89,7 @@ enum Glyphs_4x8 {
88extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4]; 89extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4];
89 90
90#define BM_MPA_L3_M_WIDTH 6 91#define BM_MPA_L3_M_WIDTH 6
91#ifdef ID3_H 92
92/* This enum is redundant but sort of in keeping with the style */ 93/* This enum is redundant but sort of in keeping with the style */
93enum rec_format_18x8 { 94enum rec_format_18x8 {
94 Format_18x8_AIFF = REC_FORMAT_AIFF, 95 Format_18x8_AIFF = REC_FORMAT_AIFF,
@@ -98,7 +99,7 @@ enum rec_format_18x8 {
98 Format_18x8Last = REC_NUM_FORMATS 99 Format_18x8Last = REC_NUM_FORMATS
99}; 100};
100extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18]; 101extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18];
101#endif /* ID3_H */ 102
102#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ 103#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
103 104
104extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; 105extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5];
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index b1ea535470..da4e9b7255 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -30,7 +30,7 @@
30#include "general.h" 30#include "general.h"
31#include "audio.h" 31#include "audio.h"
32#include "sound.h" 32#include "sound.h"
33#include "id3.h" 33#include "metadata.h"
34#ifdef HAVE_SPDIF_IN 34#ifdef HAVE_SPDIF_IN
35#include "spdif.h" 35#include "spdif.h"
36#endif 36#endif
diff --git a/apps/replaygain.c b/apps/replaygain.c
index e160a1b23d..e0bfc8e64e 100644
--- a/apps/replaygain.c
+++ b/apps/replaygain.c
@@ -27,7 +27,7 @@
27#include <stdlib.h> 27#include <stdlib.h>
28#include <string.h> 28#include <string.h>
29#include <system.h> 29#include <system.h>
30#include "id3.h" 30#include "metadata.h"
31#include "debug.h" 31#include "debug.h"
32#include "replaygain.h" 32#include "replaygain.h"
33 33
diff --git a/apps/replaygain.h b/apps/replaygain.h
index dbc079b1d3..02ca2e0bae 100644
--- a/apps/replaygain.h
+++ b/apps/replaygain.h
@@ -22,7 +22,7 @@
22#ifndef _REPLAYGAIN_H 22#ifndef _REPLAYGAIN_H
23#define _REPLAYGAIN_H 23#define _REPLAYGAIN_H
24 24
25#include "id3.h" 25#include "metadata.h"
26 26
27long get_replaygain_int(long int_gain); 27long get_replaygain_int(long int_gain);
28long parse_replaygain(const char* key, const char* value, 28long parse_replaygain(const char* key, const char* value,
diff --git a/apps/screens.c b/apps/screens.c
index 33c54abddc..32edae2f75 100644
--- a/apps/screens.c
+++ b/apps/screens.c
@@ -46,7 +46,7 @@
46#include "action.h" 46#include "action.h"
47#include "talk.h" 47#include "talk.h"
48#include "misc.h" 48#include "misc.h"
49#include "id3.h" 49#include "metadata.h"
50#include "screens.h" 50#include "screens.h"
51#include "debug.h" 51#include "debug.h"
52#include "led.h" 52#include "led.h"
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
index 3b35e0d66a..2c6bdf4a1f 100644
--- a/apps/scrobbler.c
+++ b/apps/scrobbler.c
@@ -27,7 +27,7 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
27#include "sprintf.h" 27#include "sprintf.h"
28#include "playback.h" 28#include "playback.h"
29#include "logf.h" 29#include "logf.h"
30#include "id3.h" 30#include "metadata.h"
31#include "kernel.h" 31#include "kernel.h"
32#include "audio.h" 32#include "audio.h"
33#include "buffer.h" 33#include "buffer.h"
diff --git a/apps/tagcache.c b/apps/tagcache.c
index ffad383b47..19469cde1a 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -69,7 +69,7 @@
69#include "string.h" 69#include "string.h"
70#include "usb.h" 70#include "usb.h"
71#include "metadata.h" 71#include "metadata.h"
72#include "id3.h" 72#include "metadata.h"
73#include "tagcache.h" 73#include "tagcache.h"
74#include "buffer.h" 74#include "buffer.h"
75#include "crc32.h" 75#include "crc32.h"
diff --git a/apps/tagcache.h b/apps/tagcache.h
index e49b65f1f3..c69e28fcaa 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -22,7 +22,7 @@
22#ifndef _TAGCACHE_H 22#ifndef _TAGCACHE_H
23#define _TAGCACHE_H 23#define _TAGCACHE_H
24 24
25#include "id3.h" 25#include "metadata.h"
26 26
27/** 27/**
28 Note: When adding new tags, make sure to update index_entry_ec in 28 Note: When adding new tags, make sure to update index_entry_ec in
diff --git a/apps/talk.c b/apps/talk.c
index 1b2b1e7631..2da4cd5c26 100644
--- a/apps/talk.c
+++ b/apps/talk.c
@@ -36,7 +36,7 @@
36#include "audio.h" 36#include "audio.h"
37#include "lang.h" 37#include "lang.h"
38#include "talk.h" 38#include "talk.h"
39#include "id3.h" 39#include "metadata.h"
40#include "logf.h" 40#include "logf.h"
41#include "bitswap.h" 41#include "bitswap.h"
42#include "structec.h" 42#include "structec.h"