diff options
| author | Björn Stenberg <bjorn@haxx.se> | 2008-10-15 06:38:51 +0000 |
|---|---|---|
| committer | Björn Stenberg <bjorn@haxx.se> | 2008-10-15 06:38:51 +0000 |
| commit | 51b45d56029eb8b928be64fc50332f3ba10e0228 (patch) | |
| tree | 675370fb2fd6c8f09f51c214567fa82a38155ad6 /apps | |
| parent | a18ef2efd389b1874b09264d497232ccc9386e9e (diff) | |
| download | rockbox-51b45d56029eb8b928be64fc50332f3ba10e0228.zip rockbox-51b45d56029eb8b928be64fc50332f3ba10e0228.tar.gz rockbox-51b45d56029eb8b928be64fc50332f3ba10e0228.tar.bz2 rockbox-51b45d56029eb8b928be64fc50332f3ba10e0228.tar.xz | |
Split id3.c/h into metadata.c/h and metadata/mp3.c. Updated all references. Moved mp3data.c/h from firmware to apps.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18814 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
50 files changed, 1305 insertions, 465 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index 3fce356..d68ca1b 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -7,7 +7,6 @@ abrepeat.c bookmark.c debug_menu.c filetypes.c -id3.c language.c main.c menu.c @@ -31,6 +30,7 @@ menus/recording_menu.c menus/settings_menu.c menus/sound_menu.c misc.c +mp3data.c onplay.c playlist.c playlist_catalog.c @@ -130,6 +130,7 @@ eq_arm.S #endif #endif metadata.c +metadata/mp3.c #if CONFIG_CODEC == SWCODEC metadata/metadata_common.c metadata/aiff.c diff --git a/apps/codecs.h b/apps/codecs.h index 2cb642c..becb73c 100644 --- a/apps/codecs.h +++ b/apps/codecs.h @@ -36,7 +36,7 @@ #include "config.h" #include "kernel.h" #include "system.h" -#include "id3.h" +#include "metadata.h" #include "audio.h" #ifdef RB_PROFILE #include "profile.h" diff --git a/apps/codecs/lib/codeclib.c b/apps/codecs/lib/codeclib.c index 342e6b7..e537995 100644 --- a/apps/codecs/lib/codeclib.c +++ b/apps/codecs/lib/codeclib.c @@ -25,7 +25,7 @@ #include "codecs.h" #include "dsp.h" #include "codeclib.h" -#include "id3.h" +#include "metadata.h" long mem_ptr; long bufsize; diff --git a/apps/cuesheet.h b/apps/cuesheet.h index b6cf239..de51512 100644 --- a/apps/cuesheet.h +++ b/apps/cuesheet.h @@ -25,7 +25,7 @@ #include <stdbool.h> #include "screens.h" #include "file.h" -#include "id3.h" +#include "metadata.h" #define MAX_NAME 80 /* Max length of information strings */ #define MAX_TRACKS 99 /* Max number of tracks in a cuesheet */ diff --git a/apps/gui/gwps.h b/apps/gui/gwps.h index 579a340..6a4849c 100644 --- a/apps/gui/gwps.h +++ b/apps/gui/gwps.h @@ -23,7 +23,7 @@ #include "screen_access.h" #include "statusbar.h" -#include "id3.h" +#include "metadata.h" /* constants used in line_type and as refresh_mode for wps_refresh */ #define WPS_REFRESH_STATIC 1 /* line doesn't change over time */ diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c index d426054..1a264ee 100644 --- a/apps/gui/statusbar.c +++ b/apps/gui/statusbar.c @@ -27,7 +27,7 @@ #include "sound.h" #include "settings.h" #if CONFIG_CODEC == SWCODEC -#include "id3.h" +#include "metadata.h" #endif #include "icons.h" #include "powermgmt.h" diff --git a/apps/id3.h b/apps/id3.h deleted file mode 100644 index da2faf1..0000000 --- a/apps/id3.h +++ /dev/null @@ -1,246 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2002 by Daniel Stenberg - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef ID3_H -#define ID3_H - -#include <stdbool.h> -#include "config.h" -#include "file.h" - -#define ID3V2_BUF_SIZE 300 - -/* Audio file types. */ -/* NOTE: The values of the AFMT_* items are used for the %fc tag in the WPS - - so new entries MUST be added to the end to maintain compatibility. - */ -enum -{ - AFMT_UNKNOWN = 0, /* Unknown file format */ - - /* start formats */ - - AFMT_MPA_L1, /* MPEG Audio layer 1 */ - AFMT_MPA_L2, /* MPEG Audio layer 2 */ - AFMT_MPA_L3, /* MPEG Audio layer 3 */ - -#if CONFIG_CODEC == SWCODEC - AFMT_AIFF, /* Audio Interchange File Format */ - AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ - AFMT_OGG_VORBIS, /* Ogg Vorbis */ - AFMT_FLAC, /* FLAC */ - AFMT_MPC, /* Musepack */ - AFMT_A52, /* A/52 (aka AC3) audio */ - AFMT_WAVPACK, /* WavPack */ - AFMT_ALAC, /* Apple Lossless Audio Codec */ - AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ - AFMT_SHN, /* Shorten */ - AFMT_SID, /* SID File Format */ - AFMT_ADX, /* ADX File Format */ - AFMT_NSF, /* NESM (NES Sound Format) */ - AFMT_SPEEX, /* Ogg Speex speech */ - AFMT_SPC, /* SPC700 save state */ - AFMT_APE, /* Monkey's Audio (APE) */ - AFMT_WMA, /* WMAV1/V2 in ASF */ - AFMT_MOD, /* Amiga MOD File Format */ - AFMT_SAP, /* Amiga 8Bit SAP Format */ -#endif - - /* add new formats at any index above this line to have a sensible order - - specified array index inits are used */ - /* format arrays defined in id3.c */ - - AFMT_NUM_CODECS, - -#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) - /* masks to decompose parts */ - CODEC_AFMT_MASK = 0x0fff, - CODEC_TYPE_MASK = 0x7000, - - /* switch for specifying codec type when requesting a filename */ - CODEC_TYPE_DECODER = (0 << 12), /* default */ - CODEC_TYPE_ENCODER = (1 << 12), -#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ -}; - -#if CONFIG_CODEC == SWCODEC -#define CODEC_EXTENSION "codec" - -#ifdef HAVE_RECORDING -#define ENCODER_SUFFIX "_enc" -enum rec_format_indexes -{ - __REC_FORMAT_START_INDEX = -1, - - /* start formats */ - - REC_FORMAT_PCM_WAV, - REC_FORMAT_AIFF, - REC_FORMAT_WAVPACK, - REC_FORMAT_MPA_L3, - - /* add new formats at any index above this line to have a sensible order - - specified array index inits are used - REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range - REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes - */ - - REC_NUM_FORMATS, - - REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV, - REC_FORMAT_CFG_NUM_BITS = 2 -}; - -#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3" - -/* get REC_FORMAT_* corresponding AFMT_* */ -extern const int rec_format_afmt[REC_NUM_FORMATS]; -/* get AFMT_* corresponding REC_FORMAT_* */ -extern const int afmt_rec_format[AFMT_NUM_CODECS]; - -#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ - { label, root_fname, enc_root_fname, ext_list } -#else /* !HAVE_RECORDING */ -#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ - { label, root_fname, ext_list } -#endif /* HAVE_RECORDING */ -#else /* !SWCODEC */ - -#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ - { label, ext_list } -#endif /* CONFIG_CODEC == SWCODEC */ - -/* record describing the audio format */ -struct afmt_entry -{ - char label[8]; /* format label */ -#if CONFIG_CODEC == SWCODEC - char *codec_root_fn; /* root codec filename (sans _enc and .codec) */ -#ifdef HAVE_RECORDING - char *codec_enc_root_fn; /* filename of encoder codec */ -#endif -#endif - char *ext_list; /* double NULL terminated extension - list for type with the first as - the default for recording */ -}; - -/* database of labels and codecs. add formats per above enum */ -extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; - -struct mp3entry { - char path[MAX_PATH]; - char* title; - char* artist; - char* album; - char* genre_string; - char* disc_string; - char* track_string; - char* year_string; - char* composer; - char* comment; - char* albumartist; - char* grouping; - int discnum; - int tracknum; - int version; - int layer; - int year; - unsigned char id3version; - unsigned int codectype; - unsigned int bitrate; - unsigned long frequency; - unsigned long id3v2len; - unsigned long id3v1len; - unsigned long first_frame_offset; /* Byte offset to first real MP3 frame. - Used for skipping leading garbage to - avoid gaps between tracks. */ - unsigned long vbr_header_pos; - unsigned long filesize; /* without headers; in bytes */ - unsigned long length; /* song length in ms */ - unsigned long elapsed; /* ms played */ - - int lead_trim; /* Number of samples to skip at the beginning */ - int tail_trim; /* Number of samples to remove from the end */ - - /* Added for Vorbis */ - unsigned long samples; /* number of samples in track */ - - /* MP3 stream specific info */ - unsigned long frame_count; /* number of frames in the file (if VBR) */ - - /* Used for A52/AC3 */ - unsigned long bytesperframe; /* number of bytes per frame (if CBR) */ - - /* Xing VBR fields */ - bool vbr; - bool has_toc; /* True if there is a VBR header in the file */ - unsigned char toc[100]; /* table of contents */ - - /* these following two fields are used for local buffering */ - char id3v2buf[ID3V2_BUF_SIZE]; - char id3v1buf[4][92]; - - /* resume related */ - unsigned long offset; /* bytes played */ - int index; /* playlist index */ - - /* runtime database fields */ - long tagcache_idx; /* 0=invalid, otherwise idx+1 */ - int rating; - int score; - long playcount; - long lastplayed; - long playtime; - - /* replaygain support */ - -#if CONFIG_CODEC == SWCODEC - char* track_gain_string; - char* album_gain_string; - long track_gain; /* 7.24 signed fixed point. 0 for no gain. */ - long album_gain; - long track_peak; /* 7.24 signed fixed point. 0 for no peak. */ - long album_peak; -#endif - - /* Cuesheet support */ - int cuesheet_type; /* 0: none, 1: external, 2: embedded */ - - /* Musicbrainz Track ID */ - char* mb_track_id; -}; - -enum { - ID3_VER_1_0 = 1, - ID3_VER_1_1, - ID3_VER_2_2, - ID3_VER_2_3, - ID3_VER_2_4 -}; - -bool get_mp3_metadata(int fd, struct mp3entry *entry, const char *filename); -bool mp3info(struct mp3entry *entry, const char *filename); -char* id3_get_num_genre(unsigned int genre_num); -int getid3v2len(int fd); -void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig); -void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig); - -#endif diff --git a/apps/menus/recording_menu.c b/apps/menus/recording_menu.c index 53cebfe..3b5a25e 100644 --- a/apps/menus/recording_menu.c +++ b/apps/menus/recording_menu.c @@ -55,7 +55,7 @@ #endif #include "splash.h" #if CONFIG_CODEC == SWCODEC -#include "id3.h" +#include "metadata.h" #include "dsp.h" #include "menus/eq_menu.h" #ifdef HAVE_RECORDING diff --git a/apps/metadata.c b/apps/metadata.c index 17c89f1..8df046a 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -24,23 +24,126 @@ #include <ctype.h> #include <inttypes.h> -#include "system.h" #include "playback.h" #include "debug.h" #include "logf.h" #include "cuesheet.h" #include "metadata.h" +#include "metadata/metadata_parsers.h" + #if CONFIG_CODEC == SWCODEC /* For trailing tag stripping */ #include "buffering.h" #include "metadata/metadata_common.h" -#include "metadata/metadata_parsers.h" #endif /* CONFIG_CODEC == SWCODEC */ +const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = +{ + /* Unknown file format */ + [AFMT_UNKNOWN] = + AFMT_ENTRY("???", NULL, NULL, NULL ), + + /* MPEG Audio layer 1 */ + [AFMT_MPA_L1] = + AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ), + /* MPEG Audio layer 2 */ + [AFMT_MPA_L2] = + AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ), + /* MPEG Audio layer 3 */ + [AFMT_MPA_L3] = + AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ), + +#if CONFIG_CODEC == SWCODEC + /* Audio Interchange File Format */ + [AFMT_AIFF] = + AFMT_ENTRY("AIFF", "aiff", "aiff_enc", "aiff\0aif\0"), + /* Uncompressed PCM in a WAV file */ + [AFMT_PCM_WAV] = + AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ), + /* Ogg Vorbis */ + [AFMT_OGG_VORBIS] = + AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ), + /* FLAC */ + [AFMT_FLAC] = + AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ), + /* Musepack */ + [AFMT_MPC] = + AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ), + /* A/52 (aka AC3) audio */ + [AFMT_A52] = + AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ), + /* WavPack */ + [AFMT_WAVPACK] = + AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ), + /* Apple Lossless Audio Codec */ + [AFMT_ALAC] = + AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0m4b\0" ), + /* Advanced Audio Coding in M4A container */ + [AFMT_AAC] = + AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ), + /* Shorten */ + [AFMT_SHN] = + AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ), + /* SID File Format */ + [AFMT_SID] = + AFMT_ENTRY("SID", "sid", NULL, "sid\0" ), + /* ADX File Format */ + [AFMT_ADX] = + AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ), + /* NESM (NES Sound Format) */ + [AFMT_NSF] = + AFMT_ENTRY("NSF", "nsf", NULL, "nsf\0nsfe\0" ), + /* Speex File Format */ + [AFMT_SPEEX] = + AFMT_ENTRY("Speex","speex", NULL, "spx\0" ), + /* SPC700 Save State */ + [AFMT_SPC] = + AFMT_ENTRY("SPC", "spc", NULL, "spc\0" ), + /* APE (Monkey's Audio) */ + [AFMT_APE] = + AFMT_ENTRY("APE", "ape", NULL, "ape\0mac\0" ), + /* WMA (WMAV1/V2 in ASF) */ + [AFMT_WMA] = + AFMT_ENTRY("WMA", "wma", NULL, "wma\0wmv\0asf\0" ), + /* Amiga MOD File */ + [AFMT_MOD] = + AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ), + /* Amiga SAP File */ + [AFMT_SAP] = + AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ), +#endif +}; + +#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) +/* get REC_FORMAT_* corresponding AFMT_* */ +const int rec_format_afmt[REC_NUM_FORMATS] = +{ + /* give AFMT_UNKNOWN by default */ + [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN, + /* add new entries below this line */ + [REC_FORMAT_AIFF] = AFMT_AIFF, + [REC_FORMAT_MPA_L3] = AFMT_MPA_L3, + [REC_FORMAT_WAVPACK] = AFMT_WAVPACK, + [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV, +}; + +/* get AFMT_* corresponding REC_FORMAT_* */ +const int afmt_rec_format[AFMT_NUM_CODECS] = +{ + /* give -1 by default */ + [0 ... AFMT_NUM_CODECS-1] = -1, + /* add new entries below this line */ + [AFMT_AIFF] = REC_FORMAT_AIFF, + [AFMT_MPA_L3] = REC_FORMAT_MPA_L3, + [AFMT_WAVPACK] = REC_FORMAT_WAVPACK, + [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV, +}; +#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ + /* Simple file type probing by looking at the filename extension. */ unsigned int probe_file_format(const char *filename) @@ -78,6 +181,23 @@ unsigned int probe_file_format(const char *filename) return AFMT_UNKNOWN; } +/* Note, that this returns false for successful, true for error! */ +bool mp3info(struct mp3entry *entry, const char *filename) +{ + int fd; + bool result; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return true; + + result = !get_metadata(entry, fd, filename); + + close(fd); + + return result; +} + /* Get metadata for track - return false if parsing showed problems with the * file that would prevent playback. */ @@ -314,3 +434,50 @@ void strip_tags(int handle_id) bufcuttail(handle_id, len); } #endif /* CONFIG_CODEC == SWCODEC */ + +void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig) +{ + long offset; + if (orig > dest) + offset = - ((size_t)orig - (size_t)dest); + else + offset = (size_t)dest - (size_t)orig; + + if (entry->title) + entry->title += offset; + if (entry->artist) + entry->artist += offset; + if (entry->album) + entry->album += offset; + if (entry->genre_string && !id3_is_genre_string(entry->genre_string)) + /* Don't adjust that if it points to an entry of the "genres" array */ + entry->genre_string += offset; + if (entry->track_string) + entry->track_string += offset; + if (entry->disc_string) + entry->disc_string += offset; + if (entry->year_string) + entry->year_string += offset; + if (entry->composer) + entry->composer += offset; + if (entry->comment) + entry->comment += offset; + if (entry->albumartist) + entry->albumartist += offset; + if (entry->grouping) + entry->grouping += offset; +#if CONFIG_CODEC == SWCODEC + if (entry->track_gain_string) + entry->track_gain_string += offset; + if (entry->album_gain_string) + entry->album_gain_string += offset; +#endif + if (entry->mb_track_id) + entry->mb_track_id += offset; +} + +void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig) +{ + memcpy(dest, orig, sizeof(struct mp3entry)); + adjust_mp3entry(dest, dest, orig); +} diff --git a/apps/metadata.h b/apps/metadata.h index c496f40..b190986 100644 --- a/apps/metadata.h +++ b/apps/metadata.h @@ -23,11 +23,228 @@ #define _METADATA_H #include <stdbool.h> +#include "file.h" #include "config.h" -#include "id3.h" + + +/* Audio file types. */ +/* NOTE: The values of the AFMT_* items are used for the %fc tag in the WPS + - so new entries MUST be added to the end to maintain compatibility. + */ +enum +{ + AFMT_UNKNOWN = 0, /* Unknown file format */ + + /* start formats */ + + AFMT_MPA_L1, /* MPEG Audio layer 1 */ + AFMT_MPA_L2, /* MPEG Audio layer 2 */ + AFMT_MPA_L3, /* MPEG Audio layer 3 */ + +#if CONFIG_CODEC == SWCODEC + AFMT_AIFF, /* Audio Interchange File Format */ + AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */ + AFMT_OGG_VORBIS, /* Ogg Vorbis */ + AFMT_FLAC, /* FLAC */ + AFMT_MPC, /* Musepack */ + AFMT_A52, /* A/52 (aka AC3) audio */ + AFMT_WAVPACK, /* WavPack */ + AFMT_ALAC, /* Apple Lossless Audio Codec */ + AFMT_AAC, /* Advanced Audio Coding (AAC) in M4A container */ + AFMT_SHN, /* Shorten */ + AFMT_SID, /* SID File Format */ + AFMT_ADX, /* ADX File Format */ + AFMT_NSF, /* NESM (NES Sound Format) */ + AFMT_SPEEX, /* Ogg Speex speech */ + AFMT_SPC, /* SPC700 save state */ + AFMT_APE, /* Monkey's Audio (APE) */ + AFMT_WMA, /* WMAV1/V2 in ASF */ + AFMT_MOD, /* Amiga MOD File Format */ + AFMT_SAP, /* Amiga 8Bit SAP Format */ +#endif + + /* add new formats at any index above this line to have a sensible order - + specified array index inits are used */ + /* format arrays defined in id3.c */ + + AFMT_NUM_CODECS, + +#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) + /* masks to decompose parts */ + CODEC_AFMT_MASK = 0x0fff, + CODEC_TYPE_MASK = 0x7000, + + /* switch for specifying codec type when requesting a filename */ + CODEC_TYPE_DECODER = (0 << 12), /* default */ + CODEC_TYPE_ENCODER = (1 << 12), +#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ +}; + +#if CONFIG_CODEC == SWCODEC +#define CODEC_EXTENSION "codec" + +#ifdef HAVE_RECORDING +#define ENCODER_SUFFIX "_enc" +enum rec_format_indexes +{ + __REC_FORMAT_START_INDEX = -1, + + /* start formats */ + + REC_FORMAT_PCM_WAV, + REC_FORMAT_AIFF, + REC_FORMAT_WAVPACK, + REC_FORMAT_MPA_L3, + + /* add new formats at any index above this line to have a sensible order - + specified array index inits are used + REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range + REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes + */ + + REC_NUM_FORMATS, + + REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV, + REC_FORMAT_CFG_NUM_BITS = 2 +}; + +#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3" + +/* get REC_FORMAT_* corresponding AFMT_* */ +extern const int rec_format_afmt[REC_NUM_FORMATS]; +/* get AFMT_* corresponding REC_FORMAT_* */ +extern const int afmt_rec_format[AFMT_NUM_CODECS]; + +#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ + { label, root_fname, enc_root_fname, ext_list } +#else /* !HAVE_RECORDING */ +#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ + { label, root_fname, ext_list } +#endif /* HAVE_RECORDING */ + +#else /* !SWCODEC */ + +#define AFMT_ENTRY(label, root_fname, enc_root_fname, ext_list) \ + { label, ext_list } +#endif /* CONFIG_CODEC == SWCODEC */ + +/** Database of audio formats **/ +/* record describing the audio format */ +struct afmt_entry +{ + char label[8]; /* format label */ +#if CONFIG_CODEC == SWCODEC + char *codec_root_fn; /* root codec filename (sans _enc and .codec) */ +#ifdef HAVE_RECORDING + char *codec_enc_root_fn; /* filename of encoder codec */ +#endif +#endif + char *ext_list; /* double NULL terminated extension + list for type with the first as + the default for recording */ +}; + +/* database of labels and codecs. add formats per above enum */ +extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS]; + +#define ID3V2_BUF_SIZE 300 + +enum { + ID3_VER_1_0 = 1, + ID3_VER_1_1, + ID3_VER_2_2, + ID3_VER_2_3, + ID3_VER_2_4 +}; + +struct mp3entry { + char path[MAX_PATH]; + char* title; + char* artist; + char* album; + char* genre_string; + char* disc_string; + char* track_string; + char* year_string; + char* composer; + char* comment; + char* albumartist; + char* grouping; + int discnum; + int tracknum; + int version; + int layer; + int year; + unsigned char id3version; + unsigned int codectype; + unsigned int bitrate; + unsigned long frequency; + unsigned long id3v2len; + unsigned long id3v1len; + unsigned long first_frame_offset; /* Byte offset to first real MP3 frame. + Used for skipping leading garbage to + avoid gaps between tracks. */ + unsigned long vbr_header_pos; + unsigned long filesize; /* without headers; in bytes */ + unsigned long length; /* song length in ms */ + unsigned long elapsed; /* ms played */ + + int lead_trim; /* Number of samples to skip at the beginning */ + int tail_trim; /* Number of samples to remove from the end */ + + /* Added for Vorbis */ + unsigned long samples; /* number of samples in track */ + + /* MP3 stream specific info */ + unsigned long frame_count; /* number of frames in the file (if VBR) */ + + /* Used for A52/AC3 */ + unsigned long bytesperframe; /* number of bytes per frame (if CBR) */ + + /* Xing VBR fields */ + bool vbr; + bool has_toc; /* True if there is a VBR header in the file */ + unsigned char toc[100]; /* table of contents */ + + /* these following two fields are used for local buffering */ + char id3v2buf[ID3V2_BUF_SIZE]; + char id3v1buf[4][92]; + + /* resume related */ + unsigned long offset; /* bytes played */ + int index; /* playlist index */ + + /* runtime database fields */ + long tagcache_idx; /* 0=invalid, otherwise idx+1 */ + int rating; + int score; + long playcount; + long lastplayed; + long playtime; + + /* replaygain support */ + +#if CONFIG_CODEC == SWCODEC + char* track_gain_string; + char* album_gain_string; + long track_gain; /* 7.24 signed fixed point. 0 for no gain. */ + long album_gain; + long track_peak; /* 7.24 signed fixed point. 0 for no peak. */ + long album_peak; +#endif + + /* Cuesheet support */ + int cuesheet_type; /* 0: none, 1: external, 2: embedded */ + + /* Musicbrainz Track ID */ + char* mb_track_id; +}; unsigned int probe_file_format(const char *filename); bool get_metadata(struct mp3entry* id3, int fd, const char* trackname); +bool mp3info(struct mp3entry *entry, const char *filename); +void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig); +void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig); #if CONFIG_CODEC == SWCODEC void strip_tags(int handle_id); #endif diff --git a/apps/metadata/a52.c b/apps/metadata/a52.c index bcfd3c7..c35b32d 100644 --- a/apps/metadata/a52.c +++ b/apps/metadata/a52.c @@ -19,7 +19,7 @@ * ****************************************************************************/ -#include "id3.h" +#include "metadata.h" #include "logf.h" #include "metadata_parsers.h" diff --git a/apps/metadata/adx.c b/apps/metadata/adx.c index c5da0de..a903a6d 100644 --- a/apps/metadata/adx.c +++ b/apps/metadata/adx.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "debug.h" diff --git a/apps/metadata/aiff.c b/apps/metadata/aiff.c index 74e2465..cb18e92 100644 --- a/apps/metadata/aiff.c +++ b/apps/metadata/aiff.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" diff --git a/apps/metadata/ape.c b/apps/metadata/ape.c index 7e9100a..dcb3597 100644 --- a/apps/metadata/ape.c +++ b/apps/metadata/ape.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "structec.h" diff --git a/apps/metadata/asap.c b/apps/metadata/asap.c index 9bd615a..128a18d 100644 --- a/apps/metadata/asap.c +++ b/apps/metadata/asap.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "rbunicode.h" diff --git a/apps/metadata/asf.c b/apps/metadata/asf.c index 255a0bc..611cc2a 100644 --- a/apps/metadata/asf.c +++ b/apps/metadata/asf.c @@ -25,7 +25,7 @@ #include <ctype.h> #include <inttypes.h> -#include "id3.h" +#include "metadata.h" #include "replaygain.h" #include "debug.h" #include "rbunicode.h" diff --git a/apps/metadata/flac.c b/apps/metadata/flac.c index 286d356..a50649e 100644 --- a/apps/metadata/flac.c +++ b/apps/metadata/flac.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "logf.h" diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c index e4df874..94ff212 100644 --- a/apps/metadata/metadata_common.c +++ b/apps/metadata/metadata_common.c @@ -25,8 +25,9 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" +#include "metadata_parsers.h" #include "replaygain.h" /* 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 3d9a075..f57690a 100644 --- a/apps/metadata/metadata_common.h +++ b/apps/metadata/metadata_common.h @@ -18,7 +18,7 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "id3.h" +#include "metadata.h" #ifdef ROCKBOX_BIG_ENDIAN #define IS_BIG_ENDIAN 1 diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h index 00ad112..1521f13 100644 --- a/apps/metadata/metadata_parsers.h +++ b/apps/metadata/metadata_parsers.h @@ -18,7 +18,11 @@ * KIND, either express or implied. * ****************************************************************************/ -#include "id3.h" + +char* id3_get_num_genre(unsigned int genre_num); +bool id3_is_genre_string(const char *string); +int getid3v2len(int fd); +bool get_mp3_metadata(int fd, struct mp3entry* id3, const char *filename); bool get_adx_metadata(int fd, struct mp3entry* id3); bool get_aiff_metadata(int fd, struct mp3entry* id3); diff --git a/apps/metadata/mod.c b/apps/metadata/mod.c index 38adeea..e100904 100644 --- a/apps/metadata/mod.c +++ b/apps/metadata/mod.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "rbunicode.h" diff --git a/apps/metadata/monkeys.c b/apps/metadata/monkeys.c index d59e7ee..1cacff1 100644 --- a/apps/metadata/monkeys.c +++ b/apps/metadata/monkeys.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" diff --git a/apps/id3.c b/apps/metadata/mp3.c index c1541e3..8c85c89 100644 --- a/apps/id3.c +++ b/apps/metadata/mp3.c @@ -39,117 +39,11 @@ #include "file.h" #include "logf.h" -#include "id3.h" #include "mp3data.h" #include "system.h" #include "replaygain.h" #include "rbunicode.h" -/** Database of audio formats **/ -const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = -{ - /* Unknown file format */ - [AFMT_UNKNOWN] = - AFMT_ENTRY("???", NULL, NULL, NULL ), - - /* MPEG Audio layer 1 */ - [AFMT_MPA_L1] = - AFMT_ENTRY("MP1", "mpa", NULL, "mp1\0" ), - /* MPEG Audio layer 2 */ - [AFMT_MPA_L2] = - AFMT_ENTRY("MP2", "mpa", NULL, "mpa\0mp2\0" ), - /* MPEG Audio layer 3 */ - [AFMT_MPA_L3] = - AFMT_ENTRY("MP3", "mpa", "mp3_enc", "mp3\0" ), - -#if CONFIG_CODEC == SWCODEC - /* Audio Interchange File Format */ - [AFMT_AIFF] = - AFMT_ENTRY("AIFF", "aiff", "aiff_enc", "aiff\0aif\0"), - /* Uncompressed PCM in a WAV file */ - [AFMT_PCM_WAV] = - AFMT_ENTRY("WAV", "wav", "wav_enc", "wav\0" ), - /* Ogg Vorbis */ - [AFMT_OGG_VORBIS] = - AFMT_ENTRY("Ogg", "vorbis", NULL, "ogg\0" ), - /* FLAC */ - [AFMT_FLAC] = - AFMT_ENTRY("FLAC", "flac", NULL, "flac\0" ), - /* Musepack */ - [AFMT_MPC] = - AFMT_ENTRY("MPC", "mpc", NULL, "mpc\0" ), - /* A/52 (aka AC3) audio */ - [AFMT_A52] = - AFMT_ENTRY("AC3", "a52", NULL, "a52\0ac3\0" ), - /* WavPack */ - [AFMT_WAVPACK] = - AFMT_ENTRY("WV", "wavpack", "wavpack_enc", "wv\0" ), - /* Apple Lossless Audio Codec */ - [AFMT_ALAC] = - AFMT_ENTRY("ALAC", "alac", NULL, "m4a\0m4b\0" ), - /* Advanced Audio Coding in M4A container */ - [AFMT_AAC] = - AFMT_ENTRY("AAC", "aac", NULL, "mp4\0" ), - /* Shorten */ - [AFMT_SHN] = - AFMT_ENTRY("SHN", "shorten", NULL, "shn\0" ), - /* SID File Format */ - [AFMT_SID] = - AFMT_ENTRY("SID", "sid", NULL, "sid\0" ), - /* ADX File Format */ - [AFMT_ADX] = - AFMT_ENTRY("ADX", "adx", NULL, "adx\0" ), - /* NESM (NES Sound Format) */ - [AFMT_NSF] = - AFMT_ENTRY("NSF", "nsf", NULL, "nsf\0nsfe\0" ), - /* Speex File Format */ - [AFMT_SPEEX] = - AFMT_ENTRY("Speex","speex", NULL, "spx\0" ), - /* SPC700 Save State */ - [AFMT_SPC] = - AFMT_ENTRY("SPC", "spc", NULL, "spc\0" ), - /* APE (Monkey's Audio) */ - [AFMT_APE] = - AFMT_ENTRY("APE", "ape", NULL, "ape\0mac\0" ), - /* WMA (WMAV1/V2 in ASF) */ - [AFMT_WMA] = - AFMT_ENTRY("WMA", "wma", NULL, "wma\0wmv\0asf\0" ), - /* Amiga MOD File */ - [AFMT_MOD] = - AFMT_ENTRY("MOD", "mod", NULL, "mod\0" ), - /* Amiga SAP File */ - [AFMT_SAP] = - AFMT_ENTRY("SAP", "asap", NULL, "sap\0" ), -#endif -}; - -#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) -/* get REC_FORMAT_* corresponding AFMT_* */ -const int rec_format_afmt[REC_NUM_FORMATS] = -{ - /* give AFMT_UNKNOWN by default */ - [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN, - /* add new entries below this line */ - [REC_FORMAT_AIFF] = AFMT_AIFF, - [REC_FORMAT_MPA_L3] = AFMT_MPA_L3, - [REC_FORMAT_WAVPACK] = AFMT_WAVPACK, - [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV, -}; - -/* get AFMT_* corresponding REC_FORMAT_* */ -const int afmt_rec_format[AFMT_NUM_CODECS] = -{ - /* give -1 by default */ - [0 ... AFMT_NUM_CODECS-1] = -1, - /* add new entries below this line */ - [AFMT_AIFF] = REC_FORMAT_AIFF, - [AFMT_MPA_L3] = REC_FORMAT_MPA_L3, - [AFMT_WAVPACK] = REC_FORMAT_WAVPACK, - [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV, -}; -#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ -/****/ - static unsigned long unsync(unsigned long b0, unsigned long b1, unsigned long b2, @@ -200,7 +94,7 @@ char* id3_get_num_genre(unsigned int genre_num) } /* True if the string is from the "genres" array */ -static bool id3_is_genre_string(const char *string) +bool id3_is_genre_string(const char *string) { return ( string >= genres[0] && string <= genres[sizeof(genres)/sizeof(char*) - 1] ); @@ -1233,70 +1127,6 @@ bool get_mp3_metadata(int fd, struct mp3entry *entry, const char *filename) return true; } -/* Note, that this returns false for successful, true for error! */ -bool mp3info(struct mp3entry *entry, const char *filename) -{ - int fd; - bool result; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return true; - - result = !get_mp3_metadata(fd, entry, filename); - - close(fd); - - return result; -} - -void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig) -{ - long offset; - if (orig > dest) - offset = - ((size_t)orig - (size_t)dest); - else - offset = (size_t)dest - (size_t)orig; - - if (entry->title) - entry->title += offset; - if (entry->artist) - entry->artist += offset; - if (entry->album) - entry->album += offset; - if (entry->genre_string && !id3_is_genre_string(entry->genre_string)) - /* Don't adjust that if it points to an entry of the "genres" array */ - entry->genre_string += offset; - if (entry->track_string) - entry->track_string += offset; - if (entry->disc_string) - entry->disc_string += offset; - if (entry->year_string) - entry->year_string += offset; - if (entry->composer) - entry->composer += offset; - if (entry->comment) - entry->comment += offset; - if (entry->albumartist) - entry->albumartist += offset; - if (entry->grouping) - entry->grouping += offset; -#if CONFIG_CODEC == SWCODEC - if (entry->track_gain_string) - entry->track_gain_string += offset; - if (entry->album_gain_string) - entry->album_gain_string += offset; -#endif - if (entry->mb_track_id) - entry->mb_track_id += offset; -} - -void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig) -{ - memcpy(dest, orig, sizeof(struct mp3entry)); - adjust_mp3entry(dest, dest, orig); -} - #ifdef DEBUG_STANDALONE char *secs2str(int ms) diff --git a/apps/metadata/mp4.c b/apps/metadata/mp4.c index 493bc48..803f82f 100644 --- a/apps/metadata/mp4.c +++ b/apps/metadata/mp4.c @@ -26,7 +26,7 @@ #include "system.h" #include "errno.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "logf.h" diff --git a/apps/metadata/mpc.c b/apps/metadata/mpc.c index dd83515..5ab1241 100644 --- a/apps/metadata/mpc.c +++ b/apps/metadata/mpc.c @@ -22,7 +22,7 @@ #include <string.h> #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "logf.h" diff --git a/apps/metadata/ogg.c b/apps/metadata/ogg.c index edb55f5..cd4c85f 100644 --- a/apps/metadata/ogg.c +++ b/apps/metadata/ogg.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "logf.h" diff --git a/apps/metadata/sid.c b/apps/metadata/sid.c index 8741ce6..bab7233 100644 --- a/apps/metadata/sid.c +++ b/apps/metadata/sid.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "rbunicode.h" diff --git a/apps/metadata/spc.c b/apps/metadata/spc.c index 094fcce..786c678 100644 --- a/apps/metadata/spc.c +++ b/apps/metadata/spc.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "debug.h" diff --git a/apps/metadata/vorbis.c b/apps/metadata/vorbis.c index 19b7915..cfaa715 100644 --- a/apps/metadata/vorbis.c +++ b/apps/metadata/vorbis.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "structec.h" diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c index 229d615..cf676f8 100644 --- a/apps/metadata/wave.c +++ b/apps/metadata/wave.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" diff --git a/apps/metadata/wavpack.c b/apps/metadata/wavpack.c index c695203..a5a342b 100644 --- a/apps/metadata/wavpack.c +++ b/apps/metadata/wavpack.c @@ -25,7 +25,7 @@ #include <inttypes.h> #include "system.h" -#include "id3.h" +#include "metadata.h" #include "metadata_common.h" #include "metadata_parsers.h" #include "logf.h" diff --git a/apps/mp3data.c b/apps/mp3data.c new file mode 100644 index 0000000..80870cd --- /dev/null +++ b/apps/mp3data.c @@ -0,0 +1,782 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Daniel Stenberg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * Parts of this code has been stolen from the Ample project and was written + * by David Härdeman. It has since been extended and enhanced pretty much by + * all sorts of friendly Rockbox people. + * + * A nice reference for MPEG header info: + * http://rockbox.haxx.se/docs/mpeghdr.html + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <limits.h> +#include "debug.h" +#include "logf.h" +#include "mp3data.h" +#include "file.h" +#include "buffer.h" + +// #define DEBUG_VERBOSE + +#define SYNC_MASK (0x7ffL << 21) +#define VERSION_MASK (3L << 19) +#define LAYER_MASK (3L << 17) +#define PROTECTION_MASK (1L << 16) +#define BITRATE_MASK (0xfL << 12) +#define SAMPLERATE_MASK (3L << 10) +#define PADDING_MASK (1L << 9) +#define PRIVATE_MASK (1L << 8) +#define CHANNELMODE_MASK (3L << 6) +#define MODE_EXT_MASK (3L << 4) +#define COPYRIGHT_MASK (1L << 3) +#define ORIGINAL_MASK (1L << 2) +#define EMPHASIS_MASK 3L + +/* MPEG Version table, sorted by version index */ +static const signed char version_table[4] = { + MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1 +}; + +/* Bitrate table for mpeg audio, indexed by row index and birate index */ +static const short bitrates[5][16] = { + {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */ + {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */ + {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */ + {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */ + {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */ +}; + +/* Bitrate pointer table, indexed by version and layer */ +static const short *bitrate_table[3][3] = +{ + {bitrates[0], bitrates[1], bitrates[2]}, + {bitrates[3], bitrates[4], bitrates[4]}, + {bitrates[3], bitrates[4], bitrates[4]} +}; + +/* Sampling frequency table, indexed by version and frequency index */ +static const unsigned short freq_table[3][3] = +{ + {44100, 48000, 32000}, /* MPEG Version 1 */ + {22050, 24000, 16000}, /* MPEG version 2 */ + {11025, 12000, 8000}, /* MPEG version 2.5 */ +}; + +unsigned long bytes2int(unsigned long b0, + unsigned long b1, + unsigned long b2, + unsigned long b3) +{ + return (((long)(b0 & 0xFF) << (3*8)) | + ((long)(b1 & 0xFF) << (2*8)) | + ((long)(b2 & 0xFF) << (1*8)) | + ((long)(b3 & 0xFF) << (0*8))); +} + +/* check if 'head' is a valid mp3 frame header */ +static bool is_mp3frameheader(unsigned long head) +{ + if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */ + return false; + if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */ + return false; + if (!(head & LAYER_MASK)) /* no layer? */ + return false; +#if CONFIG_CODEC != SWCODEC + /* The MAS can't decode layer 1, so treat layer 1 data as invalid */ + if ((head & LAYER_MASK) == LAYER_MASK) + return false; +#endif + if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */ + return false; + if (!(head & BITRATE_MASK)) /* no bitrate? */ + return false; + if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */ + return false; + + return true; +} + +static bool mp3headerinfo(struct mp3info *info, unsigned long header) +{ + int bitindex, freqindex; + + /* MPEG Audio Version */ + if ((header & VERSION_MASK) >> 19 >= sizeof(version_table)) + return false; + + info->version = version_table[(header & VERSION_MASK) >> 19]; + if (info->version < 0) + return false; + + /* Layer */ + info->layer = 3 - ((header & LAYER_MASK) >> 17); + if (info->layer == 3) + return false; + + info->protection = (header & PROTECTION_MASK) ? true : false; + + /* Bitrate */ + bitindex = (header & BITRATE_MASK) >> 12; + info->bitrate = bitrate_table[info->version][info->layer][bitindex]; + if(info->bitrate == 0) + return false; + + /* Sampling frequency */ + freqindex = (header & SAMPLERATE_MASK) >> 10; + if (freqindex == 3) + return false; + info->frequency = freq_table[info->version][freqindex]; + + info->padding = (header & PADDING_MASK) ? 1 : 0; + + /* Calculate number of bytes, calculation depends on layer */ + if (info->layer == 0) { + info->frame_samples = 384; + info->frame_size = (12000 * info->bitrate / info->frequency + + info->padding) * 4; + } + else { + if ((info->version > MPEG_VERSION1) && (info->layer == 2)) + info->frame_samples = 576; + else + info->frame_samples = 1152; + info->frame_size = (1000/8) * info->frame_samples * info->bitrate + / info->frequency + info->padding; + } + + /* Frametime fraction denominator */ + if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */ + info->ft_den = 1; /* integer number of milliseconds */ + } + else { /* 44.1/22.05/11.025 kHz */ + if (info->layer == 0) /* layer 1 */ + info->ft_den = 147; + else /* layer 2+3 */ + info->ft_den = 49; + } + /* Frametime fraction numerator */ + info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency; + + info->channel_mode = (header & CHANNELMODE_MASK) >> 6; + info->mode_extension = (header & MODE_EXT_MASK) >> 4; + info->emphasis = header & EMPHASIS_MASK; + +#ifdef DEBUG_VERBOSE + DEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, " + "chmode %d, mode_ext %d, emph %d, bytes: %d time: %d/%d\n", + header, info->version, info->layer+1, info->bitrate, + info->frequency, info->channel_mode, info->mode_extension, + info->emphasis, info->frame_size, info->ft_num, info->ft_den); +#endif + return true; +} + +static unsigned long __find_next_frame(int fd, long *offset, long max_offset, + unsigned long last_header, + int(*getfunc)(int fd, unsigned char *c)) +{ + unsigned long header=0; + unsigned char tmp; + int i; + + long pos = 0; + + /* We remember the last header we found, to use as a template to see if + the header we find has the same frequency, layer etc */ + last_header &= 0xffff0c00; + + /* Fill up header with first 24 bits */ + for(i = 0; i < 3; i++) { + header <<= 8; + if(!getfunc(fd, &tmp)) + return 0; + header |= tmp; + pos++; + } + + do { + header <<= 8; + if(!getfunc(fd, &tmp)) + return 0; + header |= tmp; + pos++; + if(max_offset > 0 && pos > max_offset) + return 0; + } while(!is_mp3frameheader(header) || + (last_header?((header & 0xffff0c00) != last_header):false)); + + *offset = pos - 4; + +#if defined(DEBUG) + if(*offset) + DEBUGF("Warning: skipping %ld bytes of garbage\n", *offset); +#endif + + return header; +} + +static int fileread(int fd, unsigned char *c) +{ + return read(fd, c, 1); +} + +unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header) +{ + return __find_next_frame(fd, offset, max_offset, last_header, fileread); +} + +#ifndef __PCTOOL__ +static int fnf_read_index; +static int fnf_buf_len; + +static int buf_getbyte(int fd, unsigned char *c) +{ + if(fnf_read_index < fnf_buf_len) + { + *c = audiobuf[fnf_read_index++]; + return 1; + } + else + { + fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf); + if(fnf_buf_len < 0) + return -1; + + fnf_read_index = 0; + + if(fnf_buf_len > 0) + { + *c = audiobuf[fnf_read_index++]; + return 1; + } + else + return 0; + } + return 0; +} + +static int buf_seek(int fd, int len) +{ + fnf_read_index += len; + if(fnf_read_index > fnf_buf_len) + { + len = fnf_read_index - fnf_buf_len; + + fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf); + if(fnf_buf_len < 0) + return -1; + + fnf_read_index = 0; + fnf_read_index += len; + } + + if(fnf_read_index > fnf_buf_len) + { + return -1; + } + else + return 0; +} + +static void buf_init(void) +{ + fnf_buf_len = 0; + fnf_read_index = 0; +} + +static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset, + unsigned long last_header) +{ + return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte); +} + +static int audiobuflen; +static int mem_pos; +static int mem_cnt; +static int mem_maxlen; + +static int mem_getbyte(int dummy, unsigned char *c) +{ + dummy = dummy; + + *c = audiobuf[mem_pos++]; + if(mem_pos >= audiobuflen) + mem_pos = 0; + + if(mem_cnt++ >= mem_maxlen) + return 0; + else + return 1; +} + +unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, + unsigned long last_header) +{ + audiobuflen = audiobufend - audiobuf; + mem_pos = startpos; + mem_cnt = 0; + mem_maxlen = max_offset; + + return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte); +} +#endif + +int get_mp3file_info(int fd, struct mp3info *info) +{ + unsigned char frame[1800]; + unsigned char *vbrheader; + unsigned long header; + long bytecount; + int num_offsets; + int frames_per_entry; + int i; + long offset; + int j; + long tmp; + + header = find_next_frame(fd, &bytecount, 0x20000, 0); + /* Quit if we haven't found a valid header within 128K */ + if(header == 0) + return -1; + + memset(info, 0, sizeof(struct mp3info)); +#if CONFIG_CODEC==SWCODEC + /* These two are needed for proper LAME gapless MP3 playback */ + info->enc_delay = -1; + info->enc_padding = -1; +#endif + if(!mp3headerinfo(info, header)) + return -2; + + /* OK, we have found a frame. Let's see if it has a Xing header */ + if (info->frame_size-4 >= (int)sizeof(frame)) + { +#if defined(DEBUG) + DEBUGF("Error: Invalid id3 header, frame_size: %d\n", info->frame_size); +#endif + return -8; + } + + if(read(fd, frame, info->frame_size-4) < 0) + return -3; + + /* calculate position of VBR header */ + if ( info->version == MPEG_VERSION1 ) { + if (info->channel_mode == 3) /* mono */ + vbrheader = frame + 17; + else + vbrheader = frame + 32; + } + else { + if (info->channel_mode == 3) /* mono */ + vbrheader = frame + 9; + else + vbrheader = frame + 17; + } + + if (!memcmp(vbrheader, "Xing", 4) + || !memcmp(vbrheader, "Info", 4)) + { + int i = 8; /* Where to start parsing info */ + + /* DEBUGF("Xing/Info header\n"); */ + + /* Remember where in the file the Xing header is */ + info->vbr_header_pos = lseek(fd, 0, SEEK_CUR) - info->frame_size; + + /* We want to skip the Xing frame when playing the stream */ + bytecount += info->frame_size; + + /* Now get the next frame to find out the real info about + the mp3 stream */ + header = find_next_frame(fd, &tmp, 0x20000, 0); + if(header == 0) + return -4; + + if(!mp3headerinfo(info, header)) + return -5; + + /* Is it a VBR file? */ + info->is_vbr = info->is_xing_vbr = !memcmp(vbrheader, "Xing", 4); + + if (vbrheader[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */ + { + info->frame_count = bytes2int(vbrheader[i], vbrheader[i+1], + vbrheader[i+2], vbrheader[i+3]); + if (info->frame_count <= ULONG_MAX / info->ft_num) + info->file_time = info->frame_count * info->ft_num / info->ft_den; + else + info->file_time = info->frame_count / info->ft_den * info->ft_num; + i += 4; + } + + if (vbrheader[7] & VBR_BYTES_FLAG) /* Is byte count there? */ + { + info->byte_count = bytes2int(vbrheader[i], vbrheader[i+1], + vbrheader[i+2], vbrheader[i+3]); + i += 4; + } + + if (info->file_time && info->byte_count) + { + if (info->byte_count <= (ULONG_MAX/8)) + info->bitrate = info->byte_count * 8 / info->file_time; + else + info->bitrate = info->byte_count / (info->file_time >> 3); + } + else + info->bitrate = 0; + + if (vbrheader[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */ + { + info->has_toc = true; + memcpy( info->toc, vbrheader+i, 100 ); + i += 100; + } + if (vbrheader[7] & VBR_QUALITY_FLAG) + { + /* We don't care about this, but need to skip it */ + i += 4; + } +#if CONFIG_CODEC==SWCODEC + i += 21; + info->enc_delay = (vbrheader[i] << 4) | (vbrheader[i + 1] >> 4); + info->enc_padding = ((vbrheader[i + 1] & 0x0f) << 8) | vbrheader[i + 2]; + /* TODO: This sanity checking is rather silly, seeing as how the LAME + header contains a CRC field that can be used to verify integrity. */ + if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 && + info->enc_padding >= 0 && info->enc_padding <= 2*1152)) + { + /* Invalid data */ + info->enc_delay = -1; + info->enc_padding = -1; + } +#endif + } + + if (!memcmp(vbrheader, "VBRI", 4)) + { + DEBUGF("VBRI header\n"); + + /* We want to skip the VBRI frame when playing the stream */ + bytecount += info->frame_size; + + /* Now get the next frame to find out the real info about + the mp3 stream */ + header = find_next_frame(fd, &tmp, 0x20000, 0); + if(header == 0) + return -6; + + bytecount += tmp; + + if(!mp3headerinfo(info, header)) + return -7; + + DEBUGF("%04x: %04x %04x ", 0, (short)(header >> 16), + (short)(header & 0xffff)); + for(i = 4;i < (int)sizeof(frame)-4;i+=2) { + if(i % 16 == 0) { + DEBUGF("\n%04x: ", i-4); + } + DEBUGF("%04x ", (frame[i-4] << 8) | frame[i-4+1]); + } + + DEBUGF("\n"); + + /* Yes, it is a FhG VBR file */ + info->is_vbr = true; + info->is_vbri_vbr = true; + info->has_toc = false; /* We don't parse the TOC (yet) */ + + info->byte_count = bytes2int(vbrheader[10], vbrheader[11], + vbrheader[12], vbrheader[13]); + info->frame_count = bytes2int(vbrheader[14], vbrheader[15], + vbrheader[16], vbrheader[17]); + if (info->frame_count <= ULONG_MAX / info->ft_num) + info->file_time = info->frame_count * info->ft_num / info->ft_den; + else + info->file_time = info->frame_count / info->ft_den * info->ft_num; + + if (info->byte_count <= (ULONG_MAX/8)) + info->bitrate = info->byte_count * 8 / info->file_time; + else + info->bitrate = info->byte_count / (info->file_time >> 3); + + /* We don't parse the TOC, since we don't yet know how to (FIXME) */ + num_offsets = bytes2int(0, 0, vbrheader[18], vbrheader[19]); + frames_per_entry = bytes2int(0, 0, vbrheader[24], vbrheader[25]); + DEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n", + info->bitrate, info->frame_size, info->frame_size); + DEBUGF("Frame count: %lx\n", info->frame_count); + DEBUGF("Byte count: %lx\n", info->byte_count); + DEBUGF("Offsets: %d\n", num_offsets); + DEBUGF("Frames/entry: %d\n", frames_per_entry); + + offset = 0; + + for(i = 0;i < num_offsets;i++) + { + j = bytes2int(0, 0, vbrheader[26+i*2], vbrheader[27+i*2]); + offset += j; + DEBUGF("%03d: %lx (%x)\n", i, offset - bytecount, j); + } + } + + return bytecount; +} + +#ifndef __PCTOOL__ +static void long2bytes(unsigned char *buf, long val) +{ + buf[0] = (val >> 24) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[3] = val & 0xff; +} + +int count_mp3_frames(int fd, int startpos, int filesize, + void (*progressfunc)(int)) +{ + unsigned long header = 0; + struct mp3info info; + int num_frames; + long bytes; + int cnt; + long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */ + int progress_cnt = 0; + bool is_vbr = false; + int last_bitrate = 0; + int header_template = 0; + + if(lseek(fd, startpos, SEEK_SET) < 0) + return -1; + + buf_init(); + + /* Find out the total number of frames */ + num_frames = 0; + cnt = 0; + + while((header = buf_find_next_frame(fd, &bytes, -1, header_template))) { + mp3headerinfo(&info, header); + + if(!header_template) + header_template = header; + + /* See if this really is a VBR file */ + if(last_bitrate && info.bitrate != last_bitrate) + { + is_vbr = true; + } + last_bitrate = info.bitrate; + + buf_seek(fd, info.frame_size-4); + num_frames++; + if(progressfunc) + { + cnt += bytes + info.frame_size; + if(cnt > progress_chunk) + { + progress_cnt++; + progressfunc(progress_cnt); + cnt = 0; + } + } + } + DEBUGF("Total number of frames: %d\n", num_frames); + + if(is_vbr) + return num_frames; + else + { + DEBUGF("Not a VBR file\n"); + return 0; + } +} + +static const char cooltext[] = "Rockbox - rocks your box"; + +/* buf needs to be the audio buffer with TOC generation enabled, + and at least MAX_XING_HEADER_SIZE bytes otherwise */ +int create_xing_header(int fd, long startpos, long filesize, + unsigned char *buf, unsigned long num_frames, + unsigned long rec_time, unsigned long header_template, + void (*progressfunc)(int), bool generate_toc) +{ + struct mp3info info; + unsigned char toc[100]; + unsigned long header = 0; + unsigned long xing_header_template = header_template; + unsigned long filepos; + long pos, last_pos; + long j; + long bytes; + int i; + int index; + + DEBUGF("create_xing_header()\n"); + + if(generate_toc) + { + lseek(fd, startpos, SEEK_SET); + buf_init(); + + /* Generate filepos table */ + last_pos = 0; + filepos = 0; + header = 0; + for(i = 0;i < 100;i++) { + /* Calculate the absolute frame number for this seek point */ + pos = i * num_frames / 100; + + /* Advance from the last seek point to this one */ + for(j = 0;j < pos - last_pos;j++) + { + header = buf_find_next_frame(fd, &bytes, -1, header_template); + filepos += bytes; + mp3headerinfo(&info, header); + buf_seek(fd, info.frame_size-4); + filepos += info.frame_size; + + if(!header_template) + header_template = header; + } + + /* Save a header for later use if header_template is empty. + We only save one header, and we want to save one in the + middle of the stream, just in case the first and the last + headers are corrupt. */ + if(!xing_header_template && i == 1) + xing_header_template = header; + + if(progressfunc) + { + progressfunc(50 + i/2); + } + + /* Fill in the TOC entry */ + /* each toc is a single byte indicating how many 256ths of the + * way through the file, is that percent of the way through the + * song. the easy method, filepos*256/filesize, chokes when + * the upper 8 bits of the file position are nonzero + * (i.e. files over 16mb in size). + */ + if (filepos > (ULONG_MAX/256)) + { + /* instead of multiplying filepos by 256, we divide + * filesize by 256. + */ + toc[i] = filepos / (filesize >> 8); + } + else + { + toc[i] = filepos * 256 / filesize; + } + + DEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n", + i, pos, pos-last_pos, filepos, toc[i]); + + last_pos = pos; + } + } + + /* Use the template header and create a new one. + We ignore the Protection bit even if the rest of the stream is + protected. */ + header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK); + header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */ + + if (!mp3headerinfo(&info, header)) + return 0; /* invalid header */ + + if (num_frames == 0 && rec_time) { + /* estimate the number of frames based on the recording time */ + if (rec_time <= ULONG_MAX / info.ft_den) + num_frames = rec_time * info.ft_den / info.ft_num; + else + num_frames = rec_time / info.ft_num * info.ft_den; + } + + /* Clear the frame */ + memset(buf, 0, MAX_XING_HEADER_SIZE); + + /* Write the header to the buffer */ + long2bytes(buf, header); + + /* Calculate position of VBR header */ + if (info.version == MPEG_VERSION1) { + if (info.channel_mode == 3) /* mono */ + index = 21; + else + index = 36; + } + else { + if (info.channel_mode == 3) /* mono */ + index = 13; + else + index = 21; + } + + /* Create the Xing data */ + memcpy(&buf[index], "Xing", 4); + long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0) + | (filesize ? VBR_BYTES_FLAG : 0) + | (generate_toc ? VBR_TOC_FLAG : 0)); + index += 8; + if(num_frames) + { + long2bytes(&buf[index], num_frames); + index += 4; + } + + if(filesize) + { + long2bytes(&buf[index], filesize - startpos); + index += 4; + } + + /* Copy the TOC */ + memcpy(buf + index, toc, 100); + + /* And some extra cool info */ + memcpy(buf + index + 100, cooltext, sizeof(cooltext)); + +#ifdef DEBUG + for(i = 0;i < info.frame_size;i++) + { + if(i && !(i % 16)) + DEBUGF("\n"); + + DEBUGF("%02x ", buf[i]); + } +#endif + + return info.frame_size; +} + +#endif diff --git a/apps/mp3data.h b/apps/mp3data.h new file mode 100644 index 0000000..2a6a27a --- /dev/null +++ b/apps/mp3data.h @@ -0,0 +1,83 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _MP3DATA_H_ +#define _MP3DATA_H_ + +#define MPEG_VERSION1 0 +#define MPEG_VERSION2 1 +#define MPEG_VERSION2_5 2 + +struct mp3info { + /* Standard MP3 frame header fields */ + int version; + int layer; + bool protection; + int bitrate; + long frequency; + int padding; + int channel_mode; + int mode_extension; + int emphasis; + int frame_size; /* Frame size in bytes */ + int frame_samples; /* Samples per frame */ + int ft_num; /* Numerator of frametime in milliseconds */ + int ft_den; /* Denominator of frametime in milliseconds */ + + bool is_vbr; /* True if the file is VBR */ + bool has_toc; /* True if there is a VBR header in the file */ + bool is_xing_vbr; /* True if the VBR header is of Xing type */ + bool is_vbri_vbr; /* True if the VBR header is of VBRI type */ + unsigned char toc[100]; + unsigned long frame_count; /* Number of frames in the file (if VBR) */ + unsigned long byte_count; /* File size in bytes */ + unsigned long file_time; /* Length of the whole file in milliseconds */ + unsigned long vbr_header_pos; + int enc_delay; /* Encoder delay, fetched from LAME header */ + int enc_padding; /* Padded samples added to last frame. LAME header */ +}; + +/* Xing header information */ +#define VBR_FRAMES_FLAG 0x01 +#define VBR_BYTES_FLAG 0x02 +#define VBR_TOC_FLAG 0x04 +#define VBR_QUALITY_FLAG 0x08 + +#define MAX_XING_HEADER_SIZE 576 + +unsigned long find_next_frame(int fd, long *offset, long max_offset, + unsigned long last_header); +unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, + unsigned long last_header); +int get_mp3file_info(int fd, struct mp3info *info); +int count_mp3_frames(int fd, int startpos, int filesize, + void (*progressfunc)(int)); +int create_xing_header(int fd, long startpos, long filesize, + unsigned char *buf, unsigned long num_frames, + unsigned long rec_time, unsigned long header_template, + void (*progressfunc)(int), bool generate_toc); + +extern unsigned long bytes2int(unsigned long b0, + unsigned long b1, + unsigned long b2, + unsigned long b3); + +#endif diff --git a/apps/mpeg.c b/apps/mpeg.c index b570f41..6056b68 100644 --- a/apps/mpeg.c +++ b/apps/mpeg.c @@ -26,7 +26,7 @@ #include "debug.h" #include "panic.h" -#include "id3.h" +#include "metadata.h" #include "mpeg.h" #include "audio.h" #include "ata.h" diff --git a/apps/mpeg.h b/apps/mpeg.h index ce2cff0..f5ce613 100644 --- a/apps/mpeg.h +++ b/apps/mpeg.h @@ -22,7 +22,7 @@ #define _MPEG_H_ #include <stdbool.h> -#include "id3.h" +#include "metadata.h" #define MPEG_SWAP_CHUNKSIZE 0x2000 #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we diff --git a/apps/onplay.c b/apps/onplay.c index fae86cf..1735fdb 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -37,7 +37,7 @@ #include "kernel.h" #include "keyboard.h" #include "mp3data.h" -#include "id3.h" +#include "metadata.h" #include "screens.h" #include "tree.h" #include "buffer.h" diff --git a/apps/playlist.h b/apps/playlist.h index 345417a..df3bd62 100644 --- a/apps/playlist.h +++ b/apps/playlist.h @@ -25,7 +25,7 @@ #include <stdbool.h> #include "file.h" #include "kernel.h" -#include "id3.h" +#include "metadata.h" #define PLAYLIST_ATTR_QUEUED 0x01 #define PLAYLIST_ATTR_INSERTED 0x02 diff --git a/apps/plugin.h b/apps/plugin.h index 20724f8..1029431 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -52,7 +52,7 @@ void* plugin_get_buffer(size_t *buffer_size); #include "usb.h" #include "font.h" #include "lcd.h" -#include "id3.h" +#include "metadata.h" #include "sound.h" #include "mpeg.h" #include "audio.h" diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c index 29a1ed3..30a4e0c 100644 --- a/apps/recorder/albumart.c +++ b/apps/recorder/albumart.c @@ -23,7 +23,7 @@ #include "sprintf.h" #include "system.h" #include "albumart.h" -#include "id3.h" +#include "metadata.h" #include "gwps.h" #include "buffering.h" #include "dircache.h" diff --git a/apps/recorder/albumart.h b/apps/recorder/albumart.h index e7033c1..52e7c74 100644 --- a/apps/recorder/albumart.h +++ b/apps/recorder/albumart.h @@ -25,7 +25,7 @@ #ifdef HAVE_ALBUMART #include <stdbool.h> -#include "id3.h" +#include "metadata.h" #include "gwps.h" /* 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 c4f18e8..0b48c12 100644 --- a/apps/recorder/icons.c +++ b/apps/recorder/icons.c @@ -28,7 +28,7 @@ #include "settings.h" -#include "id3.h" +#include "metadata.h" #include "icons.h" const unsigned char bitmap_icons_5x8[][5] = diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h index dca5f29..767e0f2 100644 --- a/apps/recorder/icons.h +++ b/apps/recorder/icons.h @@ -24,6 +24,7 @@ #ifndef PLUGIN #include <lcd.h> +#include "metadata.h" #ifdef HAVE_LCD_BITMAP @@ -88,7 +89,7 @@ enum Glyphs_4x8 { extern const unsigned char bitmap_glyphs_4x8[Glyph_4x8Last][4]; #define BM_MPA_L3_M_WIDTH 6 -#ifdef ID3_H + /* This enum is redundant but sort of in keeping with the style */ enum rec_format_18x8 { Format_18x8_AIFF = REC_FORMAT_AIFF, @@ -98,7 +99,7 @@ enum rec_format_18x8 { Format_18x8Last = REC_NUM_FORMATS }; extern const unsigned char bitmap_formats_18x8[Format_18x8Last][18]; -#endif /* ID3_H */ + #endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ extern const unsigned char bitmap_icons_5x8[Icon5x8Last][5]; diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c index b1ea535..da4e9b7 100644 --- a/apps/recorder/pcm_record.c +++ b/apps/recorder/pcm_record.c @@ -30,7 +30,7 @@ #include "general.h" #include "audio.h" #include "sound.h" -#include "id3.h" +#include "metadata.h" #ifdef HAVE_SPDIF_IN #include "spdif.h" #endif diff --git a/apps/replaygain.c b/apps/replaygain.c index e160a1b..e0bfc8e 100644 --- a/apps/replaygain.c +++ b/apps/replaygain.c @@ -27,7 +27,7 @@ #include <stdlib.h> #include <string.h> #include <system.h> -#include "id3.h" +#include "metadata.h" #include "debug.h" #include "replaygain.h" diff --git a/apps/replaygain.h b/apps/replaygain.h index dbc079b..02ca2e0 100644 --- a/apps/replaygain.h +++ b/apps/replaygain.h @@ -22,7 +22,7 @@ #ifndef _REPLAYGAIN_H #define _REPLAYGAIN_H -#include "id3.h" +#include "metadata.h" long get_replaygain_int(long int_gain); long parse_replaygain(const char* key, const char* value, diff --git a/apps/screens.c b/apps/screens.c index 33c54ab..32edae2 100644 --- a/apps/screens.c +++ b/apps/screens.c @@ -46,7 +46,7 @@ #include "action.h" #include "talk.h" #include "misc.h" -#include "id3.h" +#include "metadata.h" #include "screens.h" #include "debug.h" #include "led.h" diff --git a/apps/scrobbler.c b/apps/scrobbler.c index 3b35e0d..2c6bdf4 100644 --- a/apps/scrobbler.c +++ b/apps/scrobbler.c @@ -27,7 +27,7 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging #include "sprintf.h" #include "playback.h" #include "logf.h" -#include "id3.h" +#include "metadata.h" #include "kernel.h" #include "audio.h" #include "buffer.h" diff --git a/apps/tagcache.c b/apps/tagcache.c index ffad383..19469cd 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -69,7 +69,7 @@ #include "string.h" #include "usb.h" #include "metadata.h" -#include "id3.h" +#include "metadata.h" #include "tagcache.h" #include "buffer.h" #include "crc32.h" diff --git a/apps/tagcache.h b/apps/tagcache.h index e49b65f..c69e28f 100644 --- a/apps/tagcache.h +++ b/apps/tagcache.h @@ -22,7 +22,7 @@ #ifndef _TAGCACHE_H #define _TAGCACHE_H -#include "id3.h" +#include "metadata.h" /** Note: When adding new tags, make sure to update index_entry_ec in diff --git a/apps/talk.c b/apps/talk.c index 1b2b1e7..2da4cd5 100644 --- a/apps/talk.c +++ b/apps/talk.c @@ -36,7 +36,7 @@ #include "audio.h" #include "lang.h" #include "talk.h" -#include "id3.h" +#include "metadata.h" #include "logf.h" #include "bitswap.h" #include "structec.h" |