summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES54
-rw-r--r--apps/compressor.c363
-rw-r--r--apps/compressor.h29
-rw-r--r--apps/dsp.c1573
-rw-r--r--apps/dsp.h125
-rw-r--r--apps/dsp_arm.S561
-rw-r--r--apps/dsp_arm_v6.S127
-rw-r--r--apps/dsp_asm.h86
-rw-r--r--apps/dsp_cf.S611
-rw-r--r--apps/eq.c268
-rw-r--r--apps/eq.h50
-rw-r--r--apps/eq_arm.S89
-rw-r--r--apps/eq_cf.S91
-rw-r--r--apps/eqs/Acoustic.cfg17
-rw-r--r--apps/eqs/Bass.cfg17
-rw-r--r--apps/eqs/Classical.cfg17
-rw-r--r--apps/eqs/Default.cfg17
-rw-r--r--apps/eqs/Disco.cfg17
-rw-r--r--apps/eqs/Electronic.cfg17
-rw-r--r--apps/eqs/Hip-Hop.cfg17
-rw-r--r--apps/eqs/Jazz.cfg17
-rw-r--r--apps/eqs/Lounge.cfg17
-rw-r--r--apps/eqs/Pop.cfg17
-rw-r--r--apps/eqs/R&B.cfg17
-rw-r--r--apps/eqs/Rock.cfg17
-rw-r--r--apps/eqs/Vocal.cfg17
-rw-r--r--apps/fracmul.h2
-rw-r--r--apps/metadata.c641
-rw-r--r--apps/metadata.h353
-rw-r--r--apps/metadata/a52.c103
-rw-r--r--apps/metadata/adx.c124
-rw-r--r--apps/metadata/aiff.c108
-rw-r--r--apps/metadata/ape.c182
-rw-r--r--apps/metadata/asap.c254
-rw-r--r--apps/metadata/asf.c591
-rw-r--r--apps/metadata/au.c105
-rw-r--r--apps/metadata/ay.c148
-rw-r--r--apps/metadata/flac.c127
-rw-r--r--apps/metadata/gbs.c65
-rw-r--r--apps/metadata/hes.c39
-rw-r--r--apps/metadata/id3tags.c1199
-rw-r--r--apps/metadata/kss.c53
-rw-r--r--apps/metadata/metadata_common.c374
-rw-r--r--apps/metadata/metadata_common.h69
-rw-r--r--apps/metadata/metadata_parsers.h59
-rw-r--r--apps/metadata/mod.c103
-rw-r--r--apps/metadata/monkeys.c97
-rw-r--r--apps/metadata/mp3.c193
-rw-r--r--apps/metadata/mp4.c842
-rw-r--r--apps/metadata/mpc.c220
-rw-r--r--apps/metadata/nsf.c278
-rw-r--r--apps/metadata/ogg.c215
-rw-r--r--apps/metadata/oma.c189
-rw-r--r--apps/metadata/rm.c464
-rw-r--r--apps/metadata/sgc.c67
-rw-r--r--apps/metadata/sid.c89
-rw-r--r--apps/metadata/smaf.c470
-rw-r--r--apps/metadata/spc.c130
-rw-r--r--apps/metadata/tta.c123
-rw-r--r--apps/metadata/vgm.c195
-rw-r--r--apps/metadata/vorbis.c381
-rw-r--r--apps/metadata/vox.c49
-rw-r--r--apps/metadata/wave.c432
-rw-r--r--apps/metadata/wavpack.c160
-rw-r--r--apps/mp3data.c849
-rw-r--r--apps/mp3data.h89
-rw-r--r--apps/plugins/lrcplayer.c1
-rw-r--r--apps/replaygain.c222
-rw-r--r--apps/replaygain.h34
-rw-r--r--apps/tdspeed.c450
-rw-r--r--apps/tdspeed.h49
71 files changed, 1 insertions, 15234 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index e1990217ca..45eb0768a3 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -26,7 +26,6 @@ menus/audiohw_eq_menu.c
26menus/eq_menu.c 26menus/eq_menu.c
27buffering.c 27buffering.c
28voice_thread.c 28voice_thread.c
29replaygain.c
30#else /* !SWCODEC */ 29#else /* !SWCODEC */
31mpeg.c 30mpeg.c
32#endif 31#endif
@@ -42,7 +41,6 @@ menus/sound_menu.c
42menus/time_menu.c 41menus/time_menu.c
43#endif 42#endif
44misc.c 43misc.c
45mp3data.c
46onplay.c 44onplay.c
47playlist.c 45playlist.c
48playlist_catalog.c 46playlist_catalog.c
@@ -168,29 +166,13 @@ pcmbuf.c
168codec_thread.c 166codec_thread.c
169playback.c 167playback.c
170codecs.c 168codecs.c
171dsp.c
172compressor.c
173#ifndef HAVE_HARDWARE_BEEP 169#ifndef HAVE_HARDWARE_BEEP
174beep.c 170beep.c
175#endif 171#endif
176#ifdef HAVE_PITCHSCREEN
177tdspeed.c
178#endif
179#ifdef HAVE_RECORDING 172#ifdef HAVE_RECORDING
180enc_config.c 173enc_config.c
181recorder/pcm_record.c 174recorder/pcm_record.c
182#endif 175#endif
183eq.c
184#if defined(CPU_COLDFIRE)
185dsp_cf.S
186eq_cf.S
187#elif defined(CPU_ARM)
188dsp_arm.S
189#if ARM_ARCH >= 6
190dsp_arm_v6.S
191#endif
192eq_arm.S
193#endif
194#endif 176#endif
195#ifdef USB_ENABLE_HID 177#ifdef USB_ENABLE_HID
196usb_keymaps.c 178usb_keymaps.c
@@ -198,42 +180,6 @@ usb_keymaps.c
198#ifndef USB_NONE 180#ifndef USB_NONE
199gui/usb_screen.c 181gui/usb_screen.c
200#endif 182#endif
201metadata.c
202metadata/id3tags.c
203metadata/mp3.c
204#if CONFIG_CODEC == SWCODEC
205metadata/metadata_common.c
206metadata/aiff.c
207metadata/ape.c
208metadata/asf.c
209metadata/adx.c
210metadata/flac.c
211metadata/monkeys.c
212metadata/mp4.c
213metadata/mpc.c
214metadata/ogg.c
215metadata/sid.c
216metadata/mod.c
217metadata/spc.c
218metadata/vorbis.c
219metadata/wave.c
220metadata/wavpack.c
221metadata/a52.c
222metadata/asap.c
223metadata/rm.c
224metadata/nsf.c
225metadata/oma.c
226metadata/smaf.c
227metadata/au.c
228metadata/vox.c
229metadata/tta.c
230metadata/ay.c
231metadata/gbs.c
232metadata/hes.c
233metadata/sgc.c
234metadata/vgm.c
235metadata/kss.c
236#endif
237#ifdef HAVE_TAGCACHE 183#ifdef HAVE_TAGCACHE
238tagcache.c 184tagcache.c
239#endif 185#endif
diff --git a/apps/compressor.c b/apps/compressor.c
deleted file mode 100644
index 3a8d52e4da..0000000000
--- a/apps/compressor.c
+++ /dev/null
@@ -1,363 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Jeffrey Goode
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "fixedpoint.h"
23#include "fracmul.h"
24#include "settings.h"
25#include "dsp.h"
26#include "compressor.h"
27
28/* Define LOGF_ENABLE to enable logf output in this file */
29/*#define LOGF_ENABLE*/
30#include "logf.h"
31
32static int32_t comp_rel_slope IBSS_ATTR; /* S7.24 format */
33static int32_t comp_makeup_gain IBSS_ATTR; /* S7.24 format */
34static int32_t comp_curve[66] IBSS_ATTR; /* S7.24 format */
35static int32_t release_gain IBSS_ATTR; /* S7.24 format */
36
37#define UNITY (1L << 24) /* unity gain in S7.24 format */
38
39/** COMPRESSOR UPDATE
40 * Called via the menu system to configure the compressor process */
41bool compressor_update(void)
42{
43 static int curr_set[5];
44 int new_set[5] = {
45 global_settings.compressor_threshold,
46 global_settings.compressor_makeup_gain,
47 global_settings.compressor_ratio,
48 global_settings.compressor_knee,
49 global_settings.compressor_release_time};
50
51 /* make menu values useful */
52 int threshold = new_set[0];
53 bool auto_gain = (new_set[1] == 1);
54 const int comp_ratios[] = {2, 4, 6, 10, 0};
55 int ratio = comp_ratios[new_set[2]];
56 bool soft_knee = (new_set[3] == 1);
57 int release = new_set[4] * NATIVE_FREQUENCY / 1000;
58
59 bool changed = false;
60 bool active = (threshold < 0);
61
62 for (int i = 0; i < 5; i++)
63 {
64 if (curr_set[i] != new_set[i])
65 {
66 changed = true;
67 curr_set[i] = new_set[i];
68
69#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
70 switch (i)
71 {
72 case 0:
73 logf(" Compressor Threshold: %d dB\tEnabled: %s",
74 threshold, active ? "Yes" : "No");
75 break;
76 case 1:
77 logf(" Compressor Makeup Gain: %s",
78 auto_gain ? "Auto" : "Off");
79 break;
80 case 2:
81 if (ratio)
82 { logf(" Compressor Ratio: %d:1", ratio); }
83 else
84 { logf(" Compressor Ratio: Limit"); }
85 break;
86 case 3:
87 logf(" Compressor Knee: %s", soft_knee?"Soft":"Hard");
88 break;
89 case 4:
90 logf(" Compressor Release: %d", release);
91 break;
92 }
93#endif
94 }
95 }
96
97 if (changed && active)
98 {
99 /* configure variables for compressor operation */
100 static const int32_t db[] = {
101 /* positive db equivalents in S15.16 format */
102 0x000000, 0x241FA4, 0x1E1A5E, 0x1A94C8,
103 0x181518, 0x1624EA, 0x148F82, 0x1338BD,
104 0x120FD2, 0x1109EB, 0x101FA4, 0x0F4BB6,
105 0x0E8A3C, 0x0DD840, 0x0D3377, 0x0C9A0E,
106 0x0C0A8C, 0x0B83BE, 0x0B04A5, 0x0A8C6C,
107 0x0A1A5E, 0x09ADE1, 0x094670, 0x08E398,
108 0x0884F6, 0x082A30, 0x07D2FA, 0x077F0F,
109 0x072E31, 0x06E02A, 0x0694C8, 0x064BDF,
110 0x060546, 0x05C0DA, 0x057E78, 0x053E03,
111 0x04FF5F, 0x04C273, 0x048726, 0x044D64,
112 0x041518, 0x03DE30, 0x03A89B, 0x037448,
113 0x03412A, 0x030F32, 0x02DE52, 0x02AE80,
114 0x027FB0, 0x0251D6, 0x0224EA, 0x01F8E2,
115 0x01CDB4, 0x01A359, 0x0179C9, 0x0150FC,
116 0x0128EB, 0x010190, 0x00DAE4, 0x00B4E1,
117 0x008F82, 0x006AC1, 0x004699, 0x002305};
118
119 struct curve_point
120 {
121 int32_t db; /* S15.16 format */
122 int32_t offset; /* S15.16 format */
123 } db_curve[5];
124
125 /** Set up the shape of the compression curve first as decibel
126 values */
127 /* db_curve[0] = bottom of knee
128 [1] = threshold
129 [2] = top of knee
130 [3] = 0 db input
131 [4] = ~+12db input (2 bits clipping overhead) */
132
133 db_curve[1].db = threshold << 16;
134 if (soft_knee)
135 {
136 /* bottom of knee is 3dB below the threshold for soft knee*/
137 db_curve[0].db = db_curve[1].db - (3 << 16);
138 /* top of knee is 3dB above the threshold for soft knee */
139 db_curve[2].db = db_curve[1].db + (3 << 16);
140 if (ratio)
141 /* offset = -3db * (ratio - 1) / ratio */
142 db_curve[2].offset = (int32_t)((long long)(-3 << 16)
143 * (ratio - 1) / ratio);
144 else
145 /* offset = -3db for hard limit */
146 db_curve[2].offset = (-3 << 16);
147 }
148 else
149 {
150 /* bottom of knee is at the threshold for hard knee */
151 db_curve[0].db = threshold << 16;
152 /* top of knee is at the threshold for hard knee */
153 db_curve[2].db = threshold << 16;
154 db_curve[2].offset = 0;
155 }
156
157 /* Calculate 0db and ~+12db offsets */
158 db_curve[4].db = 0xC0A8C; /* db of 2 bits clipping */
159 if (ratio)
160 {
161 /* offset = threshold * (ratio - 1) / ratio */
162 db_curve[3].offset = (int32_t)((long long)(threshold << 16)
163 * (ratio - 1) / ratio);
164 db_curve[4].offset = (int32_t)((long long)-db_curve[4].db
165 * (ratio - 1) / ratio) + db_curve[3].offset;
166 }
167 else
168 {
169 /* offset = threshold for hard limit */
170 db_curve[3].offset = (threshold << 16);
171 db_curve[4].offset = -db_curve[4].db + db_curve[3].offset;
172 }
173
174 /** Now set up the comp_curve table with compression offsets in the
175 form of gain factors in S7.24 format */
176 /* comp_curve[0] is 0 (-infinity db) input */
177 comp_curve[0] = UNITY;
178 /* comp_curve[1 to 63] are intermediate compression values
179 corresponding to the 6 MSB of the input values of a non-clipped
180 signal */
181 for (int i = 1; i < 64; i++)
182 {
183 /* db constants are stored as positive numbers;
184 make them negative here */
185 int32_t this_db = -db[i];
186
187 /* no compression below the knee */
188 if (this_db <= db_curve[0].db)
189 comp_curve[i] = UNITY;
190
191 /* if soft knee and below top of knee,
192 interpolate along soft knee slope */
193 else if (soft_knee && (this_db <= db_curve[2].db))
194 comp_curve[i] = fp_factor(fp_mul(
195 ((this_db - db_curve[0].db) / 6),
196 db_curve[2].offset, 16), 16) << 8;
197
198 /* interpolate along ratio slope above the knee */
199 else
200 comp_curve[i] = fp_factor(fp_mul(
201 fp_div((db_curve[1].db - this_db), db_curve[1].db, 16),
202 db_curve[3].offset, 16), 16) << 8;
203 }
204 /* comp_curve[64] is the compression level of a maximum level,
205 non-clipped signal */
206 comp_curve[64] = fp_factor(db_curve[3].offset, 16) << 8;
207
208 /* comp_curve[65] is the compression level of a maximum level,
209 clipped signal */
210 comp_curve[65] = fp_factor(db_curve[4].offset, 16) << 8;
211
212#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
213 logf("\n *** Compression Offsets ***");
214 /* some settings for display only, not used in calculations */
215 db_curve[0].offset = 0;
216 db_curve[1].offset = 0;
217 db_curve[3].db = 0;
218
219 for (int i = 0; i <= 4; i++)
220 {
221 logf("Curve[%d]: db: % 6.2f\toffset: % 6.2f", i,
222 (float)db_curve[i].db / (1 << 16),
223 (float)db_curve[i].offset / (1 << 16));
224 }
225
226 logf("\nGain factors:");
227 for (int i = 1; i <= 65; i++)
228 {
229 debugf("%02d: %.6f ", i, (float)comp_curve[i] / UNITY);
230 if (i % 4 == 0) debugf("\n");
231 }
232 debugf("\n");
233#endif
234
235 /* if using auto peak, then makeup gain is max offset -
236 .1dB headroom */
237 comp_makeup_gain = auto_gain ?
238 fp_factor(-(db_curve[3].offset) - 0x199A, 16) << 8 : UNITY;
239 logf("Makeup gain:\t%.6f", (float)comp_makeup_gain / UNITY);
240
241 /* calculate per-sample gain change a rate of 10db over release time
242 */
243 comp_rel_slope = 0xAF0BB2 / release;
244 logf("Release slope:\t%.6f", (float)comp_rel_slope / UNITY);
245
246 release_gain = UNITY;
247 }
248
249 return active;
250}
251
252/** GET COMPRESSION GAIN
253 * Returns the required gain factor in S7.24 format in order to compress the
254 * sample in accordance with the compression curve. Always 1 or less.
255 */
256static inline int32_t get_compression_gain(struct dsp_data *data,
257 int32_t sample)
258{
259 const int frac_bits_offset = data->frac_bits - 15;
260
261 /* sample must be positive */
262 if (sample < 0)
263 sample = -(sample + 1);
264
265 /* shift sample into 15 frac bit range */
266 if (frac_bits_offset > 0)
267 sample >>= frac_bits_offset;
268 if (frac_bits_offset < 0)
269 sample <<= -frac_bits_offset;
270
271 /* normal case: sample isn't clipped */
272 if (sample < (1 << 15))
273 {
274 /* index is 6 MSB, rem is 9 LSB */
275 int index = sample >> 9;
276 int32_t rem = (sample & 0x1FF) << 22;
277
278 /* interpolate from the compression curve:
279 higher gain - ((rem / (1 << 31)) * (higher gain - lower gain)) */
280 return comp_curve[index] - (FRACMUL(rem,
281 (comp_curve[index] - comp_curve[index + 1])));
282 }
283 /* sample is somewhat clipped, up to 2 bits of overhead */
284 if (sample < (1 << 17))
285 {
286 /* straight interpolation:
287 higher gain - ((clipped portion of sample * 4/3
288 / (1 << 31)) * (higher gain - lower gain)) */
289 return comp_curve[64] - (FRACMUL(((sample - (1 << 15)) / 3) << 16,
290 (comp_curve[64] - comp_curve[65])));
291 }
292
293 /* sample is too clipped, return invalid value */
294 return -1;
295}
296
297/** COMPRESSOR PROCESS
298 * Changes the gain of the samples according to the compressor curve
299 */
300void compressor_process(int count, struct dsp_data *data, int32_t *buf[])
301{
302 const int num_chan = data->num_channels;
303 int32_t *in_buf[2] = {buf[0], buf[1]};
304
305 while (count-- > 0)
306 {
307 int ch;
308 /* use lowest (most compressed) gain factor of the output buffer
309 sample pair for both samples (mono is also handled correctly here)
310 */
311 int32_t sample_gain = UNITY;
312 for (ch = 0; ch < num_chan; ch++)
313 {
314 int32_t this_gain = get_compression_gain(data, *in_buf[ch]);
315 if (this_gain < sample_gain)
316 sample_gain = this_gain;
317 }
318
319 /* perform release slope; skip if no compression and no release slope
320 */
321 if ((sample_gain != UNITY) || (release_gain != UNITY))
322 {
323 /* if larger offset than previous slope, start new release slope
324 */
325 if ((sample_gain <= release_gain) && (sample_gain > 0))
326 {
327 release_gain = sample_gain;
328 }
329 else
330 /* keep sloping towards unity gain (and ignore invalid value) */
331 {
332 release_gain += comp_rel_slope;
333 if (release_gain > UNITY)
334 {
335 release_gain = UNITY;
336 }
337 }
338 }
339
340 /* total gain factor is the product of release gain and makeup gain,
341 but avoid computation if possible */
342 int32_t total_gain = ((release_gain == UNITY) ? comp_makeup_gain :
343 (comp_makeup_gain == UNITY) ? release_gain :
344 FRACMUL_SHL(release_gain, comp_makeup_gain, 7));
345
346 /* Implement the compressor: apply total gain factor (if any) to the
347 output buffer sample pair/mono sample */
348 if (total_gain != UNITY)
349 {
350 for (ch = 0; ch < num_chan; ch++)
351 {
352 *in_buf[ch] = FRACMUL_SHL(total_gain, *in_buf[ch], 7);
353 }
354 }
355 in_buf[0]++;
356 in_buf[1]++;
357 }
358}
359
360void compressor_reset(void)
361{
362 release_gain = UNITY;
363}
diff --git a/apps/compressor.h b/apps/compressor.h
deleted file mode 100644
index 6154372e05..0000000000
--- a/apps/compressor.h
+++ /dev/null
@@ -1,29 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Jeffrey Goode
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 COMPRESSOR_H
23#define COMPRESSOR_H
24
25void compressor_process(int count, struct dsp_data *data, int32_t *buf[]);
26bool compressor_update(void);
27void compressor_reset(void);
28
29#endif /* COMPRESSOR_H */
diff --git a/apps/dsp.c b/apps/dsp.c
deleted file mode 100644
index 4da555747b..0000000000
--- a/apps/dsp.c
+++ /dev/null
@@ -1,1573 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Miika Pekkarinen
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
22#include "system.h"
23#include <sound.h>
24#include "dsp.h"
25#include "dsp-util.h"
26#include "eq.h"
27#include "compressor.h"
28#include "kernel.h"
29#include "settings.h"
30#include "replaygain.h"
31#include "tdspeed.h"
32#include "core_alloc.h"
33#include "fixedpoint.h"
34#include "fracmul.h"
35
36/* Define LOGF_ENABLE to enable logf output in this file */
37/*#define LOGF_ENABLE*/
38#include "logf.h"
39
40/* 16-bit samples are scaled based on these constants. The shift should be
41 * no more than 15.
42 */
43#define WORD_SHIFT 12
44#define WORD_FRACBITS 27
45
46#define NATIVE_DEPTH 16
47#define SMALL_SAMPLE_BUF_COUNT 128 /* Per channel */
48#define DEFAULT_GAIN 0x01000000
49
50/* enums to index conversion properly with stereo mode and other settings */
51enum
52{
53 SAMPLE_INPUT_LE_NATIVE_I_STEREO = STEREO_INTERLEAVED,
54 SAMPLE_INPUT_LE_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED,
55 SAMPLE_INPUT_LE_NATIVE_MONO = STEREO_MONO,
56 SAMPLE_INPUT_GT_NATIVE_I_STEREO = STEREO_INTERLEAVED + STEREO_NUM_MODES,
57 SAMPLE_INPUT_GT_NATIVE_NI_STEREO = STEREO_NONINTERLEAVED + STEREO_NUM_MODES,
58 SAMPLE_INPUT_GT_NATIVE_MONO = STEREO_MONO + STEREO_NUM_MODES,
59 SAMPLE_INPUT_GT_NATIVE_1ST_INDEX = STEREO_NUM_MODES
60};
61
62enum
63{
64 SAMPLE_OUTPUT_MONO = 0,
65 SAMPLE_OUTPUT_STEREO,
66 SAMPLE_OUTPUT_DITHERED_MONO,
67 SAMPLE_OUTPUT_DITHERED_STEREO
68};
69
70/* No asm...yet */
71struct dither_data
72{
73 long error[3]; /* 00h */
74 long random; /* 0ch */
75 /* 10h */
76};
77
78struct crossfeed_data
79{
80 int32_t gain; /* 00h - Direct path gain */
81 int32_t coefs[3]; /* 04h - Coefficients for the shelving filter */
82 int32_t history[4]; /* 10h - Format is x[n - 1], y[n - 1] for both channels */
83 int32_t delay[13][2]; /* 20h */
84 int32_t *index; /* 88h - Current pointer into the delay line */
85 /* 8ch */
86};
87
88/* Current setup is one lowshelf filters three peaking filters and one
89 * highshelf filter. Varying the number of shelving filters make no sense,
90 * but adding peaking filters is possible.
91 */
92struct eq_state
93{
94 char enabled[5]; /* 00h - Flags for active filters */
95 struct eqfilter filters[5]; /* 08h - packing is 4? */
96 /* 10ch */
97};
98
99/* Include header with defines which functions are implemented in assembly
100 code for the target */
101#include <dsp_asm.h>
102
103/* Typedefs keep things much neater in this case */
104typedef void (*sample_input_fn_type)(int count, const char *src[],
105 int32_t *dst[]);
106typedef int (*resample_fn_type)(int count, struct dsp_data *data,
107 const int32_t *src[], int32_t *dst[]);
108typedef void (*sample_output_fn_type)(int count, struct dsp_data *data,
109 const int32_t *src[], int16_t *dst);
110
111/* Single-DSP channel processing in place */
112typedef void (*channels_process_fn_type)(int count, int32_t *buf[]);
113/* DSP local channel processing in place */
114typedef void (*channels_process_dsp_fn_type)(int count, struct dsp_data *data,
115 int32_t *buf[]);
116
117/*
118 ***************************************************************************/
119
120struct dsp_config
121{
122 struct dsp_data data; /* Config members for use in external routines */
123 long codec_frequency; /* Sample rate of data coming from the codec */
124 long frequency; /* Effective sample rate after pitch shift (if any) */
125 int sample_depth;
126 int sample_bytes;
127 int stereo_mode;
128 int32_t tdspeed_percent; /* Speed% * PITCH_SPEED_PRECISION */
129#ifdef HAVE_PITCHSCREEN
130 bool tdspeed_active; /* Timestretch is in use */
131#endif
132#ifdef HAVE_SW_TONE_CONTROLS
133 /* Filter struct for software bass/treble controls */
134 struct eqfilter tone_filter;
135#endif
136 /* Functions that change depending upon settings - NULL if stage is
137 disabled */
138 sample_input_fn_type input_samples;
139 resample_fn_type resample;
140 sample_output_fn_type output_samples;
141 /* These will be NULL for the voice codec and is more economical that
142 way */
143 channels_process_dsp_fn_type apply_gain;
144 channels_process_fn_type apply_crossfeed;
145 channels_process_fn_type eq_process;
146 channels_process_fn_type channels_process;
147 channels_process_dsp_fn_type compressor_process;
148};
149
150/* General DSP config */
151static struct dsp_config dsp_conf[2] IBSS_ATTR; /* 0=A, 1=V */
152/* Dithering */
153static struct dither_data dither_data[2] IBSS_ATTR; /* 0=left, 1=right */
154static long dither_mask IBSS_ATTR;
155static long dither_bias IBSS_ATTR;
156/* Crossfeed */
157struct crossfeed_data crossfeed_data IDATA_ATTR = /* A */
158{
159 .index = (int32_t *)crossfeed_data.delay
160};
161
162/* Equalizer */
163static struct eq_state eq_data; /* A */
164
165/* Software tone controls */
166#ifdef HAVE_SW_TONE_CONTROLS
167static int prescale; /* A/V */
168static int bass; /* A/V */
169static int treble; /* A/V */
170#endif
171
172/* Settings applicable to audio codec only */
173#ifdef HAVE_PITCHSCREEN
174static int32_t pitch_ratio = PITCH_SPEED_100;
175static int big_sample_locks;
176#endif
177static int channels_mode;
178 long dsp_sw_gain;
179 long dsp_sw_cross;
180static bool dither_enabled;
181static long eq_precut;
182static long track_gain;
183static bool new_gain;
184static long album_gain;
185static long track_peak;
186static long album_peak;
187static long replaygain;
188static bool crossfeed_enabled;
189
190#define AUDIO_DSP (dsp_conf[CODEC_IDX_AUDIO])
191#define VOICE_DSP (dsp_conf[CODEC_IDX_VOICE])
192
193/* The internal format is 32-bit samples, non-interleaved, stereo. This
194 * format is similar to the raw output from several codecs, so the amount
195 * of copying needed is minimized for that case.
196 */
197
198#define RESAMPLE_RATIO 4 /* Enough for 11,025 Hz -> 44,100 Hz */
199#define SMALL_RESAMPLE_BUF_COUNT (SMALL_SAMPLE_BUF_COUNT * RESAMPLE_RATIO)
200#define BIG_SAMPLE_BUF_COUNT SMALL_RESAMPLE_BUF_COUNT
201#define BIG_RESAMPLE_BUF_COUNT (BIG_SAMPLE_BUF_COUNT * RESAMPLE_RATIO)
202
203static int32_t small_sample_buf[2][SMALL_SAMPLE_BUF_COUNT] IBSS_ATTR;
204static int32_t small_resample_buf[2][SMALL_RESAMPLE_BUF_COUNT] IBSS_ATTR;
205
206#ifdef HAVE_PITCHSCREEN
207static int32_t (* big_sample_buf)[BIG_SAMPLE_BUF_COUNT] = NULL;
208static int32_t (* big_resample_buf)[BIG_RESAMPLE_BUF_COUNT] = NULL;
209#endif
210
211static int sample_buf_count = SMALL_SAMPLE_BUF_COUNT;
212static int32_t *sample_buf[2] = { small_sample_buf[0], small_sample_buf[1] };
213static int resample_buf_count = SMALL_RESAMPLE_BUF_COUNT;
214static int32_t *resample_buf[2] = { small_resample_buf[0], small_resample_buf[1] };
215
216#ifdef HAVE_PITCHSCREEN
217int32_t sound_get_pitch(void)
218{
219 return pitch_ratio;
220}
221
222void sound_set_pitch(int32_t percent)
223{
224 pitch_ratio = percent;
225 dsp_configure(&AUDIO_DSP, DSP_SWITCH_FREQUENCY,
226 AUDIO_DSP.codec_frequency);
227}
228
229static void tdspeed_set_pointers( bool time_stretch_active )
230{
231 if( time_stretch_active )
232 {
233 sample_buf_count = BIG_SAMPLE_BUF_COUNT;
234 resample_buf_count = BIG_RESAMPLE_BUF_COUNT;
235 sample_buf[0] = big_sample_buf[0];
236 sample_buf[1] = big_sample_buf[1];
237 resample_buf[0] = big_resample_buf[0];
238 resample_buf[1] = big_resample_buf[1];
239 }
240 else
241 {
242 sample_buf_count = SMALL_SAMPLE_BUF_COUNT;
243 resample_buf_count = SMALL_RESAMPLE_BUF_COUNT;
244 sample_buf[0] = small_sample_buf[0];
245 sample_buf[1] = small_sample_buf[1];
246 resample_buf[0] = small_resample_buf[0];
247 resample_buf[1] = small_resample_buf[1];
248 }
249}
250
251static void tdspeed_setup(struct dsp_config *dspc)
252{
253 /* Assume timestretch will not be used */
254 dspc->tdspeed_active = false;
255
256 tdspeed_set_pointers( false );
257
258 if (!dsp_timestretch_available())
259 return; /* Timestretch not enabled or buffer not allocated */
260
261 if (dspc->tdspeed_percent == 0)
262 dspc->tdspeed_percent = PITCH_SPEED_100;
263
264 if (!tdspeed_config(
265 dspc->codec_frequency == 0 ? NATIVE_FREQUENCY : dspc->codec_frequency,
266 dspc->stereo_mode != STEREO_MONO,
267 dspc->tdspeed_percent))
268 return; /* Timestretch not possible or needed with these parameters */
269
270 /* Timestretch is to be used */
271 dspc->tdspeed_active = true;
272
273 tdspeed_set_pointers( true );
274}
275
276
277static int move_callback(int handle, void* current, void* new)
278{
279 (void)handle;(void)current;
280
281 if ( big_sample_locks > 0 )
282 return BUFLIB_CB_CANNOT_MOVE;
283
284 big_sample_buf = new;
285
286 /* no allocation without timestretch enabled */
287 tdspeed_set_pointers( true );
288 return BUFLIB_CB_OK;
289}
290
291static void lock_sample_buf( bool lock )
292{
293 if ( lock )
294 big_sample_locks++;
295 else
296 big_sample_locks--;
297}
298
299static struct buflib_callbacks ops = {
300 .move_callback = move_callback,
301 .shrink_callback = NULL,
302};
303
304
305void dsp_timestretch_enable(bool enabled)
306{
307 /* Hook to set up timestretch buffer on first call to settings_apply() */
308 static int handle = -1;
309 if (enabled)
310 {
311 if (big_sample_buf)
312 return; /* already allocated and enabled */
313
314 /* Set up timestretch buffers */
315 big_sample_buf = &small_resample_buf[0];
316 handle = core_alloc_ex("resample buf",
317 2 * BIG_RESAMPLE_BUF_COUNT * sizeof(int32_t),
318 &ops);
319 big_sample_locks = 0;
320 enabled = handle >= 0;
321
322 if (enabled)
323 {
324 /* success, now setup tdspeed */
325 big_resample_buf = core_get_data(handle);
326
327 tdspeed_init();
328 tdspeed_setup(&AUDIO_DSP);
329 }
330 }
331
332 if (!enabled)
333 {
334 dsp_set_timestretch(PITCH_SPEED_100);
335 tdspeed_finish();
336
337 if (handle >= 0)
338 core_free(handle);
339
340 handle = -1;
341 big_sample_buf = NULL;
342 }
343}
344
345void dsp_set_timestretch(int32_t percent)
346{
347 AUDIO_DSP.tdspeed_percent = percent;
348 tdspeed_setup(&AUDIO_DSP);
349}
350
351int32_t dsp_get_timestretch()
352{
353 return AUDIO_DSP.tdspeed_percent;
354}
355
356bool dsp_timestretch_available()
357{
358 return (global_settings.timestretch_enabled && big_sample_buf);
359}
360#endif /* HAVE_PITCHSCREEN */
361
362/* Convert count samples to the internal format, if needed. Updates src
363 * to point past the samples "consumed" and dst is set to point to the
364 * samples to consume. Note that for mono, dst[0] equals dst[1], as there
365 * is no point in processing the same data twice.
366 */
367
368/* convert count 16-bit mono to 32-bit mono */
369static void sample_input_lte_native_mono(
370 int count, const char *src[], int32_t *dst[])
371{
372 const int16_t *s = (int16_t *) src[0];
373 const int16_t * const send = s + count;
374 int32_t *d = dst[0] = dst[1] = sample_buf[0];
375 int scale = WORD_SHIFT;
376
377 while (s < send)
378 {
379 *d++ = *s++ << scale;
380 }
381
382 src[0] = (char *)s;
383}
384
385/* convert count 16-bit interleaved stereo to 32-bit noninterleaved */
386static void sample_input_lte_native_i_stereo(
387 int count, const char *src[], int32_t *dst[])
388{
389 const int32_t *s = (int32_t *) src[0];
390 const int32_t * const send = s + count;
391 int32_t *dl = dst[0] = sample_buf[0];
392 int32_t *dr = dst[1] = sample_buf[1];
393 int scale = WORD_SHIFT;
394
395 while (s < send)
396 {
397 int32_t slr = *s++;
398#ifdef ROCKBOX_LITTLE_ENDIAN
399 *dl++ = (slr >> 16) << scale;
400 *dr++ = (int32_t)(int16_t)slr << scale;
401#else /* ROCKBOX_BIG_ENDIAN */
402 *dl++ = (int32_t)(int16_t)slr << scale;
403 *dr++ = (slr >> 16) << scale;
404#endif
405 }
406
407 src[0] = (char *)s;
408}
409
410/* convert count 16-bit noninterleaved stereo to 32-bit noninterleaved */
411static void sample_input_lte_native_ni_stereo(
412 int count, const char *src[], int32_t *dst[])
413{
414 const int16_t *sl = (int16_t *) src[0];
415 const int16_t *sr = (int16_t *) src[1];
416 const int16_t * const slend = sl + count;
417 int32_t *dl = dst[0] = sample_buf[0];
418 int32_t *dr = dst[1] = sample_buf[1];
419 int scale = WORD_SHIFT;
420
421 while (sl < slend)
422 {
423 *dl++ = *sl++ << scale;
424 *dr++ = *sr++ << scale;
425 }
426
427 src[0] = (char *)sl;
428 src[1] = (char *)sr;
429}
430
431/* convert count 32-bit mono to 32-bit mono */
432static void sample_input_gt_native_mono(
433 int count, const char *src[], int32_t *dst[])
434{
435 dst[0] = dst[1] = (int32_t *)src[0];
436 src[0] = (char *)(dst[0] + count);
437}
438
439/* convert count 32-bit interleaved stereo to 32-bit noninterleaved stereo */
440static void sample_input_gt_native_i_stereo(
441 int count, const char *src[], int32_t *dst[])
442{
443 const int32_t *s = (int32_t *)src[0];
444 const int32_t * const send = s + 2*count;
445 int32_t *dl = dst[0] = sample_buf[0];
446 int32_t *dr = dst[1] = sample_buf[1];
447
448 while (s < send)
449 {
450 *dl++ = *s++;
451 *dr++ = *s++;
452 }
453
454 src[0] = (char *)send;
455}
456
457/* convert 32 bit-noninterleaved stereo to 32-bit noninterleaved stereo */
458static void sample_input_gt_native_ni_stereo(
459 int count, const char *src[], int32_t *dst[])
460{
461 dst[0] = (int32_t *)src[0];
462 dst[1] = (int32_t *)src[1];
463 src[0] = (char *)(dst[0] + count);
464 src[1] = (char *)(dst[1] + count);
465}
466
467/**
468 * sample_input_new_format()
469 *
470 * set the to-native sample conversion function based on dsp sample parameters
471 *
472 * !DSPPARAMSYNC
473 * needs syncing with changes to the following dsp parameters:
474 * * dsp->stereo_mode (A/V)
475 * * dsp->sample_depth (A/V)
476 */
477static void sample_input_new_format(struct dsp_config *dsp)
478{
479 static const sample_input_fn_type sample_input_functions[] =
480 {
481 [SAMPLE_INPUT_LE_NATIVE_I_STEREO] = sample_input_lte_native_i_stereo,
482 [SAMPLE_INPUT_LE_NATIVE_NI_STEREO] = sample_input_lte_native_ni_stereo,
483 [SAMPLE_INPUT_LE_NATIVE_MONO] = sample_input_lte_native_mono,
484 [SAMPLE_INPUT_GT_NATIVE_I_STEREO] = sample_input_gt_native_i_stereo,
485 [SAMPLE_INPUT_GT_NATIVE_NI_STEREO] = sample_input_gt_native_ni_stereo,
486 [SAMPLE_INPUT_GT_NATIVE_MONO] = sample_input_gt_native_mono,
487 };
488
489 int convert = dsp->stereo_mode;
490
491 if (dsp->sample_depth > NATIVE_DEPTH)
492 convert += SAMPLE_INPUT_GT_NATIVE_1ST_INDEX;
493
494 dsp->input_samples = sample_input_functions[convert];
495}
496
497
498#ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO
499/* write mono internal format to output format */
500static void sample_output_mono(int count, struct dsp_data *data,
501 const int32_t *src[], int16_t *dst)
502{
503 const int32_t *s0 = src[0];
504 const int scale = data->output_scale;
505 const int dc_bias = 1 << (scale - 1);
506
507 while (count-- > 0)
508 {
509 int32_t lr = clip_sample_16((*s0++ + dc_bias) >> scale);
510 *dst++ = lr;
511 *dst++ = lr;
512 }
513}
514#endif /* DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO */
515
516/* write stereo internal format to output format */
517#ifndef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO
518static void sample_output_stereo(int count, struct dsp_data *data,
519 const int32_t *src[], int16_t *dst)
520{
521 const int32_t *s0 = src[0];
522 const int32_t *s1 = src[1];
523 const int scale = data->output_scale;
524 const int dc_bias = 1 << (scale - 1);
525
526 while (count-- > 0)
527 {
528 *dst++ = clip_sample_16((*s0++ + dc_bias) >> scale);
529 *dst++ = clip_sample_16((*s1++ + dc_bias) >> scale);
530 }
531}
532#endif /* DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO */
533
534/**
535 * The "dither" code to convert the 24-bit samples produced by libmad was
536 * taken from the coolplayer project - coolplayer.sourceforge.net
537 *
538 * This function handles mono and stereo outputs.
539 */
540static void sample_output_dithered(int count, struct dsp_data *data,
541 const int32_t *src[], int16_t *dst)
542{
543 const int32_t mask = dither_mask;
544 const int32_t bias = dither_bias;
545 const int scale = data->output_scale;
546 const int32_t min = data->clip_min;
547 const int32_t max = data->clip_max;
548 const int32_t range = max - min;
549 int ch;
550 int16_t *d;
551
552 for (ch = 0; ch < data->num_channels; ch++)
553 {
554 struct dither_data * const dither = &dither_data[ch];
555 const int32_t *s = src[ch];
556 int i;
557
558 for (i = 0, d = &dst[ch]; i < count; i++, s++, d += 2)
559 {
560 int32_t output, sample;
561 int32_t random;
562
563 /* Noise shape and bias (for correct rounding later) */
564 sample = *s;
565 sample += dither->error[0] - dither->error[1] + dither->error[2];
566 dither->error[2] = dither->error[1];
567 dither->error[1] = dither->error[0]/2;
568
569 output = sample + bias;
570
571 /* Dither, highpass triangle PDF */
572 random = dither->random*0x0019660dL + 0x3c6ef35fL;
573 output += (random & mask) - (dither->random & mask);
574 dither->random = random;
575
576 /* Round sample to output range */
577 output &= ~mask;
578
579 /* Error feedback */
580 dither->error[0] = sample - output;
581
582 /* Clip */
583 if ((uint32_t)(output - min) > (uint32_t)range)
584 {
585 int32_t c = min;
586 if (output > min)
587 c += range;
588 output = c;
589 }
590
591 /* Quantize and store */
592 *d = output >> scale;
593 }
594 }
595
596 if (data->num_channels == 2)
597 return;
598
599 /* Have to duplicate left samples into the right channel since
600 pcm buffer and hardware is interleaved stereo */
601 d = &dst[0];
602
603 while (count-- > 0)
604 {
605 int16_t s = *d++;
606 *d++ = s;
607 }
608}
609
610/**
611 * sample_output_new_format()
612 *
613 * set the from-native to ouput sample conversion routine
614 *
615 * !DSPPARAMSYNC
616 * needs syncing with changes to the following dsp parameters:
617 * * dsp->stereo_mode (A/V)
618 * * dither_enabled (A)
619 */
620static void sample_output_new_format(struct dsp_config *dsp)
621{
622 static const sample_output_fn_type sample_output_functions[] =
623 {
624 sample_output_mono,
625 sample_output_stereo,
626 sample_output_dithered,
627 sample_output_dithered
628 };
629
630 int out = dsp->data.num_channels - 1;
631
632 if (dsp == &AUDIO_DSP && dither_enabled)
633 out += 2;
634
635 dsp->output_samples = sample_output_functions[out];
636}
637
638/**
639 * Linear interpolation resampling that introduces a one sample delay because
640 * of our inability to look into the future at the end of a frame.
641 */
642#ifndef DSP_HAVE_ASM_RESAMPLING
643static int dsp_downsample(int count, struct dsp_data *data,
644 const int32_t *src[], int32_t *dst[])
645{
646 int ch = data->num_channels - 1;
647 uint32_t delta = data->resample_data.delta;
648 uint32_t phase, pos;
649 int32_t *d;
650
651 /* Rolled channel loop actually showed slightly faster. */
652 do
653 {
654 /* Just initialize things and not worry too much about the relatively
655 * uncommon case of not being able to spit out a sample for the frame.
656 */
657 const int32_t *s = src[ch];
658 int32_t last = data->resample_data.last_sample[ch];
659
660 data->resample_data.last_sample[ch] = s[count - 1];
661 d = dst[ch];
662 phase = data->resample_data.phase;
663 pos = phase >> 16;
664
665 /* Do we need last sample of previous frame for interpolation? */
666 if (pos > 0)
667 last = s[pos - 1];
668
669 while (pos < (uint32_t)count)
670 {
671 *d++ = last + FRACMUL((phase & 0xffff) << 15, s[pos] - last);
672 phase += delta;
673 pos = phase >> 16;
674 last = s[pos - 1];
675 }
676 }
677 while (--ch >= 0);
678
679 /* Wrap phase accumulator back to start of next frame. */
680 data->resample_data.phase = phase - (count << 16);
681 return d - dst[0];
682}
683
684static int dsp_upsample(int count, struct dsp_data *data,
685 const int32_t *src[], int32_t *dst[])
686{
687 int ch = data->num_channels - 1;
688 uint32_t delta = data->resample_data.delta;
689 uint32_t phase, pos;
690 int32_t *d;
691
692 /* Rolled channel loop actually showed slightly faster. */
693 do
694 {
695 /* Should always be able to output a sample for a ratio up to RESAMPLE_RATIO */
696 const int32_t *s = src[ch];
697 int32_t last = data->resample_data.last_sample[ch];
698
699 data->resample_data.last_sample[ch] = s[count - 1];
700 d = dst[ch];
701 phase = data->resample_data.phase;
702 pos = phase >> 16;
703
704 while (pos == 0)
705 {
706 *d++ = last + FRACMUL((phase & 0xffff) << 15, s[0] - last);
707 phase += delta;
708 pos = phase >> 16;
709 }
710
711 while (pos < (uint32_t)count)
712 {
713 last = s[pos - 1];
714 *d++ = last + FRACMUL((phase & 0xffff) << 15, s[pos] - last);
715 phase += delta;
716 pos = phase >> 16;
717 }
718 }
719 while (--ch >= 0);
720
721 /* Wrap phase accumulator back to start of next frame. */
722 data->resample_data.phase = phase & 0xffff;
723 return d - dst[0];
724}
725#endif /* DSP_HAVE_ASM_RESAMPLING */
726
727static void resampler_new_delta(struct dsp_config *dsp)
728{
729 dsp->data.resample_data.delta = (unsigned long)
730 dsp->frequency * 65536LL / NATIVE_FREQUENCY;
731
732 if (dsp->frequency == NATIVE_FREQUENCY)
733 {
734 /* NOTE: If fully glitch-free transistions from no resampling to
735 resampling are desired, last_sample history should be maintained
736 even when not resampling. */
737 dsp->resample = NULL;
738 dsp->data.resample_data.phase = 0;
739 dsp->data.resample_data.last_sample[0] = 0;
740 dsp->data.resample_data.last_sample[1] = 0;
741 }
742 else if (dsp->frequency < NATIVE_FREQUENCY)
743 dsp->resample = dsp_upsample;
744 else
745 dsp->resample = dsp_downsample;
746}
747
748/* Resample count stereo samples. Updates the src array, if resampling is
749 * done, to refer to the resampled data. Returns number of stereo samples
750 * for further processing.
751 */
752static inline int resample(struct dsp_config *dsp, int count, int32_t *src[])
753{
754 int32_t *dst[2] =
755 {
756 resample_buf[0],
757 resample_buf[1]
758 };
759 lock_sample_buf( true );
760 count = dsp->resample(count, &dsp->data, (const int32_t **)src, dst);
761
762 src[0] = dst[0];
763 src[1] = dst[dsp->data.num_channels - 1];
764 lock_sample_buf( false );
765 return count;
766}
767
768static void dither_init(struct dsp_config *dsp)
769{
770 memset(dither_data, 0, sizeof (dither_data));
771 dither_bias = (1L << (dsp->data.frac_bits - NATIVE_DEPTH));
772 dither_mask = (1L << (dsp->data.frac_bits + 1 - NATIVE_DEPTH)) - 1;
773}
774
775void dsp_dither_enable(bool enable)
776{
777 struct dsp_config *dsp = &AUDIO_DSP;
778 dither_enabled = enable;
779 sample_output_new_format(dsp);
780}
781
782/* Applies crossfeed to the stereo signal in src.
783 * Crossfeed is a process where listening over speakers is simulated. This
784 * is good for old hard panned stereo records, which might be quite fatiguing
785 * to listen to on headphones with no crossfeed.
786 */
787#ifndef DSP_HAVE_ASM_CROSSFEED
788static void apply_crossfeed(int count, int32_t *buf[])
789{
790 int32_t *hist_l = &crossfeed_data.history[0];
791 int32_t *hist_r = &crossfeed_data.history[2];
792 int32_t *delay = &crossfeed_data.delay[0][0];
793 int32_t *coefs = &crossfeed_data.coefs[0];
794 int32_t gain = crossfeed_data.gain;
795 int32_t *di = crossfeed_data.index;
796
797 int32_t acc;
798 int32_t left, right;
799 int i;
800
801 for (i = 0; i < count; i++)
802 {
803 left = buf[0][i];
804 right = buf[1][i];
805
806 /* Filter delayed sample from left speaker */
807 acc = FRACMUL(*di, coefs[0]);
808 acc += FRACMUL(hist_l[0], coefs[1]);
809 acc += FRACMUL(hist_l[1], coefs[2]);
810 /* Save filter history for left speaker */
811 hist_l[1] = acc;
812 hist_l[0] = *di;
813 *di++ = left;
814 /* Filter delayed sample from right speaker */
815 acc = FRACMUL(*di, coefs[0]);
816 acc += FRACMUL(hist_r[0], coefs[1]);
817 acc += FRACMUL(hist_r[1], coefs[2]);
818 /* Save filter history for right speaker */
819 hist_r[1] = acc;
820 hist_r[0] = *di;
821 *di++ = right;
822 /* Now add the attenuated direct sound and write to outputs */
823 buf[0][i] = FRACMUL(left, gain) + hist_r[1];
824 buf[1][i] = FRACMUL(right, gain) + hist_l[1];
825
826 /* Wrap delay line index if bigger than delay line size */
827 if (di >= delay + 13*2)
828 di = delay;
829 }
830 /* Write back local copies of data we've modified */
831 crossfeed_data.index = di;
832}
833#endif /* DSP_HAVE_ASM_CROSSFEED */
834
835/**
836 * dsp_set_crossfeed(bool enable)
837 *
838 * !DSPPARAMSYNC
839 * needs syncing with changes to the following dsp parameters:
840 * * dsp->stereo_mode (A)
841 */
842void dsp_set_crossfeed(bool enable)
843{
844 crossfeed_enabled = enable;
845 AUDIO_DSP.apply_crossfeed = (enable && AUDIO_DSP.data.num_channels > 1)
846 ? apply_crossfeed : NULL;
847}
848
849void dsp_set_crossfeed_direct_gain(int gain)
850{
851 crossfeed_data.gain = get_replaygain_int(gain * 10) << 7;
852 /* If gain is negative, the calculation overflowed and we need to clamp */
853 if (crossfeed_data.gain < 0)
854 crossfeed_data.gain = 0x7fffffff;
855}
856
857/* Both gains should be below 0 dB */
858void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff)
859{
860 int32_t *c = crossfeed_data.coefs;
861 long scaler = get_replaygain_int(lf_gain * 10) << 7;
862
863 cutoff = 0xffffffff/NATIVE_FREQUENCY*cutoff;
864 hf_gain -= lf_gain;
865 /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB
866 * point instead of shelf midpoint. This is for compatibility with the old
867 * crossfeed shelf filter and should be removed if crossfeed settings are
868 * ever made incompatible for any other good reason.
869 */
870 cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24);
871 filter_shelf_coefs(cutoff, hf_gain, false, c);
872 /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains
873 * over 1 and can do this safely
874 */
875 c[0] = FRACMUL_SHL(c[0], scaler, 4);
876 c[1] = FRACMUL_SHL(c[1], scaler, 4);
877 c[2] <<= 4;
878}
879
880/* Apply a constant gain to the samples (e.g., for ReplayGain).
881 * Note that this must be called before the resampler.
882 */
883#ifndef DSP_HAVE_ASM_APPLY_GAIN
884static void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[])
885{
886 const int32_t gain = data->gain;
887 int ch;
888
889 for (ch = 0; ch < data->num_channels; ch++)
890 {
891 int32_t *d = buf[ch];
892 int i;
893
894 for (i = 0; i < count; i++)
895 d[i] = FRACMUL_SHL(d[i], gain, 8);
896 }
897}
898#endif /* DSP_HAVE_ASM_APPLY_GAIN */
899
900/* Combine all gains to a global gain. */
901static void set_gain(struct dsp_config *dsp)
902{
903 /* gains are in S7.24 format */
904 dsp->data.gain = DEFAULT_GAIN;
905
906 /* Replay gain not relevant to voice */
907 if (dsp == &AUDIO_DSP && replaygain)
908 {
909 dsp->data.gain = replaygain;
910 }
911
912 if (dsp->eq_process && eq_precut)
913 {
914 dsp->data.gain = fp_mul(dsp->data.gain, eq_precut, 24);
915 }
916
917#ifdef HAVE_SW_VOLUME_CONTROL
918 if (global_settings.volume < SW_VOLUME_MAX ||
919 global_settings.volume > SW_VOLUME_MIN)
920 {
921 int vol_gain = get_replaygain_int(global_settings.volume * 100);
922 dsp->data.gain = (long) (((int64_t) dsp->data.gain * vol_gain) >> 24);
923 }
924#endif
925
926 if (dsp->data.gain == DEFAULT_GAIN)
927 {
928 dsp->data.gain = 0;
929 }
930 else
931 {
932 dsp->data.gain >>= 1; /* convert gain to S8.23 format */
933 }
934
935 dsp->apply_gain = dsp->data.gain != 0 ? dsp_apply_gain : NULL;
936}
937
938/**
939 * Update the amount to cut the audio before applying the equalizer.
940 *
941 * @param precut to apply in decibels (multiplied by 10)
942 */
943void dsp_set_eq_precut(int precut)
944{
945 eq_precut = get_replaygain_int(precut * -10);
946 set_gain(&AUDIO_DSP);
947}
948
949/**
950 * Synchronize the equalizer filter coefficients with the global settings.
951 *
952 * @param band the equalizer band to synchronize
953 */
954void dsp_set_eq_coefs(int band)
955{
956 /* Adjust setting pointer to the band we actually want to change */
957 struct eq_band_setting *setting = &global_settings.eq_band_settings[band];
958
959 /* Convert user settings to format required by coef generator functions */
960 unsigned long cutoff = 0xffffffff / NATIVE_FREQUENCY * setting->cutoff;
961 unsigned long q = setting->q;
962 int gain = setting->gain;
963
964 if (q == 0)
965 q = 1;
966
967 /* NOTE: The coef functions assume the EMAC unit is in fractional mode,
968 which it should be, since we're executed from the main thread. */
969
970 /* Assume a band is disabled if the gain is zero */
971 if (gain == 0)
972 {
973 eq_data.enabled[band] = 0;
974 }
975 else
976 {
977 if (band == 0)
978 eq_ls_coefs(cutoff, q, gain, eq_data.filters[band].coefs);
979 else if (band == 4)
980 eq_hs_coefs(cutoff, q, gain, eq_data.filters[band].coefs);
981 else
982 eq_pk_coefs(cutoff, q, gain, eq_data.filters[band].coefs);
983
984 eq_data.enabled[band] = 1;
985 }
986}
987
988/* Apply EQ filters to those bands that have got it switched on. */
989static void eq_process(int count, int32_t *buf[])
990{
991 static const int shifts[] =
992 {
993 EQ_SHELF_SHIFT, /* low shelf */
994 EQ_PEAK_SHIFT, /* peaking */
995 EQ_PEAK_SHIFT, /* peaking */
996 EQ_PEAK_SHIFT, /* peaking */
997 EQ_SHELF_SHIFT, /* high shelf */
998 };
999 unsigned int channels = AUDIO_DSP.data.num_channels;
1000 int i;
1001
1002 /* filter configuration currently is 1 low shelf filter, 3 band peaking
1003 filters and 1 high shelf filter, in that order. we need to know this
1004 so we can choose the correct shift factor.
1005 */
1006 for (i = 0; i < 5; i++)
1007 {
1008 if (!eq_data.enabled[i])
1009 continue;
1010 eq_filter(buf, &eq_data.filters[i], count, channels, shifts[i]);
1011 }
1012}
1013
1014/**
1015 * Use to enable the equalizer.
1016 *
1017 * @param enable true to enable the equalizer
1018 */
1019void dsp_set_eq(bool enable)
1020{
1021 AUDIO_DSP.eq_process = enable ? eq_process : NULL;
1022 set_gain(&AUDIO_DSP);
1023}
1024
1025static void dsp_set_stereo_width(int value)
1026{
1027 long width, straight, cross;
1028
1029 width = value * 0x7fffff / 100;
1030
1031 if (value <= 100)
1032 {
1033 straight = (0x7fffff + width) / 2;
1034 cross = straight - width;
1035 }
1036 else
1037 {
1038 /* straight = (1 + width) / (2 * width) */
1039 straight = ((int64_t)(0x7fffff + width) << 22) / width;
1040 cross = straight - 0x7fffff;
1041 }
1042
1043 dsp_sw_gain = straight << 8;
1044 dsp_sw_cross = cross << 8;
1045}
1046
1047/**
1048 * Implements the different channel configurations and stereo width.
1049 */
1050
1051/* SOUND_CHAN_STEREO mode is a noop so has no function - just outline one for
1052 * completeness. */
1053#if 0
1054static void channels_process_sound_chan_stereo(int count, int32_t *buf[])
1055{
1056 /* The channels are each just themselves */
1057 (void)count; (void)buf;
1058}
1059#endif
1060
1061#ifndef DSP_HAVE_ASM_SOUND_CHAN_MONO
1062static void channels_process_sound_chan_mono(int count, int32_t *buf[])
1063{
1064 int32_t *sl = buf[0], *sr = buf[1];
1065
1066 while (count-- > 0)
1067 {
1068 int32_t lr = *sl/2 + *sr/2;
1069 *sl++ = lr;
1070 *sr++ = lr;
1071 }
1072}
1073#endif /* DSP_HAVE_ASM_SOUND_CHAN_MONO */
1074
1075#ifndef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
1076static void channels_process_sound_chan_custom(int count, int32_t *buf[])
1077{
1078 const int32_t gain = dsp_sw_gain;
1079 const int32_t cross = dsp_sw_cross;
1080 int32_t *sl = buf[0], *sr = buf[1];
1081
1082 while (count-- > 0)
1083 {
1084 int32_t l = *sl;
1085 int32_t r = *sr;
1086 *sl++ = FRACMUL(l, gain) + FRACMUL(r, cross);
1087 *sr++ = FRACMUL(r, gain) + FRACMUL(l, cross);
1088 }
1089}
1090#endif /* DSP_HAVE_ASM_SOUND_CHAN_CUSTOM */
1091
1092static void channels_process_sound_chan_mono_left(int count, int32_t *buf[])
1093{
1094 /* Just copy over the other channel */
1095 memcpy(buf[1], buf[0], count * sizeof (*buf));
1096}
1097
1098static void channels_process_sound_chan_mono_right(int count, int32_t *buf[])
1099{
1100 /* Just copy over the other channel */
1101 memcpy(buf[0], buf[1], count * sizeof (*buf));
1102}
1103
1104#ifndef DSP_HAVE_ASM_SOUND_CHAN_KARAOKE
1105static void channels_process_sound_chan_karaoke(int count, int32_t *buf[])
1106{
1107 int32_t *sl = buf[0], *sr = buf[1];
1108
1109 while (count-- > 0)
1110 {
1111 int32_t ch = *sl/2 - *sr/2;
1112 *sl++ = ch;
1113 *sr++ = -ch;
1114 }
1115}
1116#endif /* DSP_HAVE_ASM_SOUND_CHAN_KARAOKE */
1117
1118static void dsp_set_channel_config(int value)
1119{
1120 static const channels_process_fn_type channels_process_functions[] =
1121 {
1122 /* SOUND_CHAN_STEREO = All-purpose index for no channel processing */
1123 [SOUND_CHAN_STEREO] = NULL,
1124 [SOUND_CHAN_MONO] = channels_process_sound_chan_mono,
1125 [SOUND_CHAN_CUSTOM] = channels_process_sound_chan_custom,
1126 [SOUND_CHAN_MONO_LEFT] = channels_process_sound_chan_mono_left,
1127 [SOUND_CHAN_MONO_RIGHT] = channels_process_sound_chan_mono_right,
1128 [SOUND_CHAN_KARAOKE] = channels_process_sound_chan_karaoke,
1129 };
1130
1131 if ((unsigned)value >= ARRAYLEN(channels_process_functions) ||
1132 AUDIO_DSP.stereo_mode == STEREO_MONO)
1133 {
1134 value = SOUND_CHAN_STEREO;
1135 }
1136
1137 /* This doesn't apply to voice */
1138 channels_mode = value;
1139 AUDIO_DSP.channels_process = channels_process_functions[value];
1140}
1141
1142#if CONFIG_CODEC == SWCODEC
1143
1144#ifdef HAVE_SW_TONE_CONTROLS
1145static void set_tone_controls(void)
1146{
1147 filter_bishelf_coefs(0xffffffff/NATIVE_FREQUENCY*200,
1148 0xffffffff/NATIVE_FREQUENCY*3500,
1149 bass, treble, -prescale,
1150 AUDIO_DSP.tone_filter.coefs);
1151 /* Sync the voice dsp coefficients */
1152 memcpy(&VOICE_DSP.tone_filter.coefs, AUDIO_DSP.tone_filter.coefs,
1153 sizeof (VOICE_DSP.tone_filter.coefs));
1154}
1155#endif
1156
1157/* Hook back from firmware/ part of audio, which can't/shouldn't call apps/
1158 * code directly.
1159 */
1160int dsp_callback(int msg, intptr_t param)
1161{
1162 switch (msg)
1163 {
1164#ifdef HAVE_SW_TONE_CONTROLS
1165 case DSP_CALLBACK_SET_PRESCALE:
1166 prescale = param;
1167 set_tone_controls();
1168 break;
1169 /* prescaler is always set after calling any of these, so we wait with
1170 * calculating coefs until the above case is hit.
1171 */
1172 case DSP_CALLBACK_SET_BASS:
1173 bass = param;
1174 break;
1175 case DSP_CALLBACK_SET_TREBLE:
1176 treble = param;
1177 break;
1178#ifdef HAVE_SW_VOLUME_CONTROL
1179 case DSP_CALLBACK_SET_SW_VOLUME:
1180 set_gain(&AUDIO_DSP);
1181 break;
1182#endif
1183#endif
1184 case DSP_CALLBACK_SET_CHANNEL_CONFIG:
1185 dsp_set_channel_config(param);
1186 break;
1187 case DSP_CALLBACK_SET_STEREO_WIDTH:
1188 dsp_set_stereo_width(param);
1189 break;
1190 default:
1191 break;
1192 }
1193 return 0;
1194}
1195#endif
1196
1197/* Process and convert src audio to dst based on the DSP configuration,
1198 * reading count number of audio samples. dst is assumed to be large
1199 * enough; use dsp_output_count() to get the required number. src is an
1200 * array of pointers; for mono and interleaved stereo, it contains one
1201 * pointer to the start of the audio data and the other is ignored; for
1202 * non-interleaved stereo, it contains two pointers, one for each audio
1203 * channel. Returns number of bytes written to dst.
1204 */
1205int dsp_process(struct dsp_config *dsp, char *dst, const char *src[], int count)
1206{
1207 static int32_t *tmp[2]; /* tdspeed_doit() needs it static */
1208 static long last_yield;
1209 long tick;
1210 int written = 0;
1211
1212#if defined(CPU_COLDFIRE)
1213 /* set emac unit for dsp processing, and save old macsr, we're running in
1214 codec thread context at this point, so can't clobber it */
1215 unsigned long old_macsr = coldfire_get_macsr();
1216 coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
1217#endif
1218
1219 if (new_gain)
1220 dsp_set_replaygain(); /* Gain has changed */
1221
1222 /* Perform at least one yield before starting */
1223 last_yield = current_tick;
1224 yield();
1225
1226 /* Testing function pointers for NULL is preferred since the pointer
1227 will be preloaded to be used for the call if not. */
1228 while (count > 0)
1229 {
1230 int samples = MIN(sample_buf_count, count);
1231 count -= samples;
1232
1233 dsp->input_samples(samples, src, tmp);
1234
1235#ifdef HAVE_PITCHSCREEN
1236 if (dsp->tdspeed_active)
1237 samples = tdspeed_doit(tmp, samples);
1238#endif
1239
1240 int chunk_offset = 0;
1241 while (samples > 0)
1242 {
1243 int32_t *t2[2];
1244 t2[0] = tmp[0]+chunk_offset;
1245 t2[1] = tmp[1]+chunk_offset;
1246
1247 int chunk = MIN(sample_buf_count, samples);
1248 chunk_offset += chunk;
1249 samples -= chunk;
1250
1251 if (dsp->apply_gain)
1252 dsp->apply_gain(chunk, &dsp->data, t2);
1253
1254 if (dsp->resample && (chunk = resample(dsp, chunk, t2)) <= 0)
1255 break; /* I'm pretty sure we're downsampling here */
1256
1257 if (dsp->apply_crossfeed)
1258 dsp->apply_crossfeed(chunk, t2);
1259
1260 if (dsp->eq_process)
1261 dsp->eq_process(chunk, t2);
1262
1263#ifdef HAVE_SW_TONE_CONTROLS
1264 if ((bass | treble) != 0)
1265 eq_filter(t2, &dsp->tone_filter, chunk,
1266 dsp->data.num_channels, FILTER_BISHELF_SHIFT);
1267#endif
1268
1269 if (dsp->channels_process)
1270 dsp->channels_process(chunk, t2);
1271
1272 if (dsp->compressor_process)
1273 dsp->compressor_process(chunk, &dsp->data, t2);
1274
1275 dsp->output_samples(chunk, &dsp->data, (const int32_t **)t2, (int16_t *)dst);
1276
1277 written += chunk;
1278 dst += chunk * sizeof (int16_t) * 2;
1279
1280 /* yield at least once each tick */
1281 tick = current_tick;
1282 if (TIME_AFTER(tick, last_yield))
1283 {
1284 last_yield = tick;
1285 yield();
1286 }
1287 }
1288 }
1289
1290#if defined(CPU_COLDFIRE)
1291 /* set old macsr again */
1292 coldfire_set_macsr(old_macsr);
1293#endif
1294 return written;
1295}
1296
1297/* Given count number of input samples, calculate the maximum number of
1298 * samples of output data that would be generated (the calculation is not
1299 * entirely exact and rounds upwards to be on the safe side; during
1300 * resampling, the number of samples generated depends on the current state
1301 * of the resampler).
1302 */
1303/* dsp_input_size MUST be called afterwards */
1304int dsp_output_count(struct dsp_config *dsp, int count)
1305{
1306#ifdef HAVE_PITCHSCREEN
1307 if (dsp->tdspeed_active)
1308 count = tdspeed_est_output_size();
1309#endif
1310 if (dsp->resample)
1311 {
1312 count = (int)(((unsigned long)count * NATIVE_FREQUENCY
1313 + (dsp->frequency - 1)) / dsp->frequency);
1314 }
1315
1316 /* Now we have the resampled sample count which must not exceed
1317 * resample_buf_count to avoid resample buffer overflow. One
1318 * must call dsp_input_count() to get the correct input sample
1319 * count.
1320 */
1321 if (count > resample_buf_count)
1322 count = resample_buf_count;
1323
1324 return count;
1325}
1326
1327/* Given count output samples, calculate number of input samples
1328 * that would be consumed in order to fill the output buffer.
1329 */
1330int dsp_input_count(struct dsp_config *dsp, int count)
1331{
1332 /* count is now the number of resampled input samples. Convert to
1333 original input samples. */
1334 if (dsp->resample)
1335 {
1336 /* Use the real resampling delta =
1337 * dsp->frequency * 65536 / NATIVE_FREQUENCY, and
1338 * round towards zero to avoid buffer overflows. */
1339 count = (int)(((unsigned long)count *
1340 dsp->data.resample_data.delta) >> 16);
1341 }
1342
1343#ifdef HAVE_PITCHSCREEN
1344 if (dsp->tdspeed_active)
1345 count = tdspeed_est_input_size(count);
1346#endif
1347
1348 return count;
1349}
1350
1351static void dsp_set_gain_var(long *var, long value)
1352{
1353 *var = value;
1354 new_gain = true;
1355}
1356
1357static void dsp_update_functions(struct dsp_config *dsp)
1358{
1359 sample_input_new_format(dsp);
1360 sample_output_new_format(dsp);
1361 if (dsp == &AUDIO_DSP)
1362 dsp_set_crossfeed(crossfeed_enabled);
1363}
1364
1365intptr_t dsp_configure(struct dsp_config *dsp, int setting, intptr_t value)
1366{
1367 switch (setting)
1368 {
1369 case DSP_MYDSP:
1370 switch (value)
1371 {
1372 case CODEC_IDX_AUDIO:
1373 return (intptr_t)&AUDIO_DSP;
1374 case CODEC_IDX_VOICE:
1375 return (intptr_t)&VOICE_DSP;
1376 default:
1377 return (intptr_t)NULL;
1378 }
1379
1380 case DSP_SET_FREQUENCY:
1381 memset(&dsp->data.resample_data, 0, sizeof (dsp->data.resample_data));
1382 /* Fall through!!! */
1383 case DSP_SWITCH_FREQUENCY:
1384 dsp->codec_frequency = (value == 0) ? NATIVE_FREQUENCY : value;
1385 /* Account for playback speed adjustment when setting dsp->frequency
1386 if we're called from the main audio thread. Voice UI thread should
1387 not need this feature.
1388 */
1389#ifdef HAVE_PITCHSCREEN
1390 if (dsp == &AUDIO_DSP)
1391 dsp->frequency = pitch_ratio * dsp->codec_frequency / PITCH_SPEED_100;
1392 else
1393#endif
1394 dsp->frequency = dsp->codec_frequency;
1395
1396 resampler_new_delta(dsp);
1397#ifdef HAVE_PITCHSCREEN
1398 tdspeed_setup(dsp);
1399#endif
1400 break;
1401
1402 case DSP_SET_SAMPLE_DEPTH:
1403 dsp->sample_depth = value;
1404
1405 if (dsp->sample_depth <= NATIVE_DEPTH)
1406 {
1407 dsp->data.frac_bits = WORD_FRACBITS;
1408 dsp->sample_bytes = sizeof (int16_t); /* samples are 16 bits */
1409 dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1);
1410 dsp->data.clip_min = -((1 << WORD_FRACBITS));
1411 }
1412 else
1413 {
1414 dsp->data.frac_bits = value;
1415 dsp->sample_bytes = sizeof (int32_t); /* samples are 32 bits */
1416 dsp->data.clip_max = (1 << value) - 1;
1417 dsp->data.clip_min = -(1 << value);
1418 }
1419
1420 dsp->data.output_scale = dsp->data.frac_bits + 1 - NATIVE_DEPTH;
1421 sample_input_new_format(dsp);
1422 dither_init(dsp);
1423 break;
1424
1425 case DSP_SET_STEREO_MODE:
1426 dsp->stereo_mode = value;
1427 dsp->data.num_channels = value == STEREO_MONO ? 1 : 2;
1428 dsp_update_functions(dsp);
1429#ifdef HAVE_PITCHSCREEN
1430 tdspeed_setup(dsp);
1431#endif
1432 break;
1433
1434 case DSP_RESET:
1435 dsp->stereo_mode = STEREO_NONINTERLEAVED;
1436 dsp->data.num_channels = 2;
1437 dsp->sample_depth = NATIVE_DEPTH;
1438 dsp->data.frac_bits = WORD_FRACBITS;
1439 dsp->sample_bytes = sizeof (int16_t);
1440 dsp->data.output_scale = dsp->data.frac_bits + 1 - NATIVE_DEPTH;
1441 dsp->data.clip_max = ((1 << WORD_FRACBITS) - 1);
1442 dsp->data.clip_min = -((1 << WORD_FRACBITS));
1443 dsp->codec_frequency = dsp->frequency = NATIVE_FREQUENCY;
1444
1445 if (dsp == &AUDIO_DSP)
1446 {
1447 track_gain = 0;
1448 album_gain = 0;
1449 track_peak = 0;
1450 album_peak = 0;
1451 new_gain = true;
1452 }
1453
1454 dsp_update_functions(dsp);
1455 resampler_new_delta(dsp);
1456#ifdef HAVE_PITCHSCREEN
1457 tdspeed_setup(dsp);
1458#endif
1459 if (dsp == &AUDIO_DSP)
1460 compressor_reset();
1461 break;
1462
1463 case DSP_FLUSH:
1464 memset(&dsp->data.resample_data, 0,
1465 sizeof (dsp->data.resample_data));
1466 resampler_new_delta(dsp);
1467 dither_init(dsp);
1468#ifdef HAVE_PITCHSCREEN
1469 tdspeed_setup(dsp);
1470#endif
1471 if (dsp == &AUDIO_DSP)
1472 compressor_reset();
1473 break;
1474
1475 case DSP_SET_TRACK_GAIN:
1476 if (dsp == &AUDIO_DSP)
1477 dsp_set_gain_var(&track_gain, value);
1478 break;
1479
1480 case DSP_SET_ALBUM_GAIN:
1481 if (dsp == &AUDIO_DSP)
1482 dsp_set_gain_var(&album_gain, value);
1483 break;
1484
1485 case DSP_SET_TRACK_PEAK:
1486 if (dsp == &AUDIO_DSP)
1487 dsp_set_gain_var(&track_peak, value);
1488 break;
1489
1490 case DSP_SET_ALBUM_PEAK:
1491 if (dsp == &AUDIO_DSP)
1492 dsp_set_gain_var(&album_peak, value);
1493 break;
1494
1495 default:
1496 return 0;
1497 }
1498
1499 return 1;
1500}
1501
1502int get_replaygain_mode(bool have_track_gain, bool have_album_gain)
1503{
1504 int type;
1505
1506 bool track = ((global_settings.replaygain_type == REPLAYGAIN_TRACK)
1507 || ((global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
1508 && global_settings.playlist_shuffle));
1509
1510 type = (!track && have_album_gain) ? REPLAYGAIN_ALBUM
1511 : have_track_gain ? REPLAYGAIN_TRACK : -1;
1512
1513 return type;
1514}
1515
1516void dsp_set_replaygain(void)
1517{
1518 long gain = 0;
1519
1520 new_gain = false;
1521
1522 if ((global_settings.replaygain_type != REPLAYGAIN_OFF) ||
1523 global_settings.replaygain_noclip)
1524 {
1525 bool track_mode = get_replaygain_mode(track_gain != 0,
1526 album_gain != 0) == REPLAYGAIN_TRACK;
1527 long peak = (track_mode || !album_peak) ? track_peak : album_peak;
1528
1529 if (global_settings.replaygain_type != REPLAYGAIN_OFF)
1530 {
1531 gain = (track_mode || !album_gain) ? track_gain : album_gain;
1532
1533 if (global_settings.replaygain_preamp)
1534 {
1535 long preamp = get_replaygain_int(
1536 global_settings.replaygain_preamp * 10);
1537
1538 gain = (long) (((int64_t) gain * preamp) >> 24);
1539 }
1540 }
1541
1542 if (gain == 0)
1543 {
1544 /* So that noclip can work even with no gain information. */
1545 gain = DEFAULT_GAIN;
1546 }
1547
1548 if (global_settings.replaygain_noclip && (peak != 0)
1549 && ((((int64_t) gain * peak) >> 24) >= DEFAULT_GAIN))
1550 {
1551 gain = (((int64_t) DEFAULT_GAIN << 24) / peak);
1552 }
1553
1554 if (gain == DEFAULT_GAIN)
1555 {
1556 /* Nothing to do, disable processing. */
1557 gain = 0;
1558 }
1559 }
1560
1561 /* Store in S7.24 format to simplify calculations. */
1562 replaygain = gain;
1563 set_gain(&AUDIO_DSP);
1564}
1565
1566/** SET COMPRESSOR
1567 * Called by the menu system to configure the compressor process */
1568void dsp_set_compressor(void)
1569{
1570 /* enable/disable the compressor */
1571 AUDIO_DSP.compressor_process = compressor_update() ?
1572 compressor_process : NULL;
1573}
diff --git a/apps/dsp.h b/apps/dsp.h
deleted file mode 100644
index 2a00f649f8..0000000000
--- a/apps/dsp.h
+++ /dev/null
@@ -1,125 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Miika Pekkarinen
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 _DSP_H
23#define _DSP_H
24
25#include <stdlib.h>
26#include <stdbool.h>
27
28#define NATIVE_FREQUENCY 44100
29
30enum
31{
32 STEREO_INTERLEAVED = 0,
33 STEREO_NONINTERLEAVED,
34 STEREO_MONO,
35 STEREO_NUM_MODES,
36};
37
38enum
39{
40 CODEC_IDX_AUDIO = 0,
41 CODEC_IDX_VOICE,
42};
43
44enum
45{
46 DSP_MYDSP = 1,
47 DSP_SET_FREQUENCY,
48 DSP_SWITCH_FREQUENCY,
49 DSP_SET_SAMPLE_DEPTH,
50 DSP_SET_STEREO_MODE,
51 DSP_RESET,
52 DSP_FLUSH,
53 DSP_SET_TRACK_GAIN,
54 DSP_SET_ALBUM_GAIN,
55 DSP_SET_TRACK_PEAK,
56 DSP_SET_ALBUM_PEAK,
57 DSP_CROSSFEED
58};
59
60
61/****************************************************************************
62 * NOTE: Any assembly routines that use these structures must be updated
63 * if current data members are moved or changed.
64 */
65struct resample_data
66{
67 uint32_t delta; /* 00h */
68 uint32_t phase; /* 04h */
69 int32_t last_sample[2]; /* 08h */
70 /* 10h */
71};
72
73/* This is for passing needed data to external dsp routines. If another
74 * dsp parameter needs to be passed, add to the end of the structure
75 * and remove from dsp_config.
76 * If another function type becomes assembly/external and requires dsp
77 * config info, add a pointer paramter of type "struct dsp_data *".
78 * If removing something from other than the end, reserve the spot or
79 * else update every implementation for every target.
80 * Be sure to add the offset of the new member for easy viewing as well. :)
81 * It is the first member of dsp_config and all members can be accessesed
82 * through the main aggregate but this is intended to make a safe haven
83 * for these items whereas the c part can be rearranged at will. dsp_data
84 * could even moved within dsp_config without disurbing the order.
85 */
86struct dsp_data
87{
88 int output_scale; /* 00h */
89 int num_channels; /* 04h */
90 struct resample_data resample_data; /* 08h */
91 int32_t clip_min; /* 18h */
92 int32_t clip_max; /* 1ch */
93 int32_t gain; /* 20h - Note that this is in S8.23 format. */
94 int frac_bits; /* 24h */
95 /* 28h */
96};
97
98struct dsp_config;
99
100int dsp_process(struct dsp_config *dsp, char *dest,
101 const char *src[], int count);
102int dsp_input_count(struct dsp_config *dsp, int count);
103int dsp_output_count(struct dsp_config *dsp, int count);
104intptr_t dsp_configure(struct dsp_config *dsp, int setting,
105 intptr_t value);
106int get_replaygain_mode(bool have_track_gain, bool have_album_gain);
107void dsp_set_replaygain(void);
108void dsp_set_crossfeed(bool enable);
109void dsp_set_crossfeed_direct_gain(int gain);
110void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain,
111 long cutoff);
112void dsp_set_eq(bool enable);
113void dsp_set_eq_precut(int precut);
114void dsp_set_eq_coefs(int band);
115void dsp_dither_enable(bool enable);
116void dsp_timestretch_enable(bool enable);
117bool dsp_timestretch_available(void);
118void sound_set_pitch(int32_t r);
119int32_t sound_get_pitch(void);
120void dsp_set_timestretch(int32_t percent);
121int32_t dsp_get_timestretch(void);
122int dsp_callback(int msg, intptr_t param);
123void dsp_set_compressor(void);
124
125#endif
diff --git a/apps/dsp_arm.S b/apps/dsp_arm.S
deleted file mode 100644
index 7e360749a3..0000000000
--- a/apps/dsp_arm.S
+++ /dev/null
@@ -1,561 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Thom Johansen
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21 #include "config.h"
22
23/****************************************************************************
24 * void channels_process_sound_chan_mono(int count, int32_t *buf[])
25 */
26
27#include "config.h"
28
29 .section .icode, "ax", %progbits
30 .align 2
31 .global channels_process_sound_chan_mono
32 .type channels_process_sound_chan_mono, %function
33channels_process_sound_chan_mono:
34 @ input: r0 = count, r1 = buf
35 stmfd sp!, { r4, lr } @
36 @
37 ldmia r1, { r1, r2 } @ r1 = buf[0], r2 = buf[1]
38 subs r0, r0, #1 @ odd: end at 0; even: end at -1
39 beq .mono_singlesample @ Zero? Only one sample!
40 @
41.monoloop: @
42 ldmia r1, { r3, r4 } @ r3, r4 = Li0, Li1
43 ldmia r2, { r12, r14 } @ r12, r14 = Ri0, Ri1
44 mov r3, r3, asr #1 @ Mo0 = Li0 / 2 + Ri0 / 2
45 mov r4, r4, asr #1 @ Mo1 = Li1 / 2 + Ri1 / 2
46 add r12, r3, r12, asr #1 @
47 add r14, r4, r14, asr #1 @
48 subs r0, r0, #2 @
49 stmia r1!, { r12, r14 } @ store Mo0, Mo1
50 stmia r2!, { r12, r14 } @ store Mo0, Mo1
51 bgt .monoloop @
52 @
53 ldmpc cond=lt, regs=r4 @ if count was even, we're done
54 @
55.mono_singlesample: @
56 ldr r3, [r1] @ r3 = Ls
57 ldr r12, [r2] @ r12 = Rs
58 mov r3, r3, asr #1 @ Mo = Ls / 2 + Rs / 2
59 add r12, r3, r12, asr #1 @
60 str r12, [r1] @ store Mo
61 str r12, [r2] @ store Mo
62 @
63 ldmpc regs=r4 @
64 .size channels_process_sound_chan_mono, \
65 .-channels_process_sound_chan_mono
66
67/****************************************************************************
68 * void channels_process_sound_chan_custom(int count, int32_t *buf[])
69 */
70 .section .icode, "ax", %progbits
71 .align 2
72 .global channels_process_sound_chan_custom
73 .type channels_process_sound_chan_custom, %function
74channels_process_sound_chan_custom:
75 stmfd sp!, { r4-r10, lr }
76
77 ldr r3, =dsp_sw_gain
78 ldr r4, =dsp_sw_cross
79
80 ldmia r1, { r1, r2 } @ r1 = buf[0], r2 = buf[1]
81 ldr r3, [r3] @ r3 = dsp_sw_gain
82 ldr r4, [r4] @ r4 = dsp_sw_cross
83
84 subs r0, r0, #1
85 beq .custom_single_sample @ Zero? Only one sample!
86
87.custom_loop:
88 ldmia r1, { r5, r6 } @ r5 = Li0, r6 = Li1
89 ldmia r2, { r7, r8 } @ r7 = Ri0, r8 = Ri1
90
91 subs r0, r0, #2
92
93 smull r9, r10, r5, r3 @ Lc0 = Li0*gain
94 smull r12, r14, r7, r3 @ Rc0 = Ri0*gain
95 smlal r9, r10, r7, r4 @ Lc0 += Ri0*cross
96 smlal r12, r14, r5, r4 @ Rc0 += Li0*cross
97
98 mov r9, r9, lsr #31 @ Convert to s0.31
99 mov r12, r12, lsr #31
100 orr r5, r9, r10, asl #1
101 orr r7, r12, r14, asl #1
102
103 smull r9, r10, r6, r3 @ Lc1 = Li1*gain
104 smull r12, r14, r8, r3 @ Rc1 = Ri1*gain
105 smlal r9, r10, r8, r4 @ Lc1 += Ri1*cross
106 smlal r12, r14, r6, r4 @ Rc1 += Li1*cross
107
108 mov r9, r9, lsr #31 @ Convert to s0.31
109 mov r12, r12, lsr #31
110 orr r6, r9, r10, asl #1
111 orr r8, r12, r14, asl #1
112
113 stmia r1!, { r5, r6 } @ Store Lc0, Lc1
114 stmia r2!, { r7, r8 } @ Store Rc0, Rc1
115
116 bgt .custom_loop
117
118 ldmpc cond=lt, regs=r4-r10 @ < 0? even count
119
120.custom_single_sample:
121 ldr r5, [r1] @ handle odd sample
122 ldr r7, [r2]
123
124 smull r9, r10, r5, r3 @ Lc0 = Li0*gain
125 smull r12, r14, r7, r3 @ Rc0 = Ri0*gain
126 smlal r9, r10, r7, r4 @ Lc0 += Ri0*cross
127 smlal r12, r14, r5, r4 @ Rc0 += Li0*cross
128
129 mov r9, r9, lsr #31 @ Convert to s0.31
130 mov r12, r12, lsr #31
131 orr r5, r9, r10, asl #1
132 orr r7, r12, r14, asl #1
133
134 str r5, [r1] @ Store Lc0
135 str r7, [r2] @ Store Rc0
136
137 ldmpc regs=r4-r10
138 .size channels_process_sound_chan_custom, \
139 .-channels_process_sound_chan_custom
140
141/****************************************************************************
142 * void channels_process_sound_chan_karaoke(int count, int32_t *buf[])
143 */
144 .section .icode, "ax", %progbits
145 .align 2
146 .global channels_process_sound_chan_karaoke
147 .type channels_process_sound_chan_karaoke, %function
148channels_process_sound_chan_karaoke:
149 @ input: r0 = count, r1 = buf
150 stmfd sp!, { r4, lr } @
151 @
152 ldmia r1, { r1, r2 } @ r1 = buf[0], r2 = buf[1]
153 subs r0, r0, #1 @ odd: end at 0; even: end at -1
154 beq .karaoke_singlesample @ Zero? Only one sample!
155 @
156.karaokeloop: @
157 ldmia r1, { r3, r4 } @ r3, r4 = Li0, Li1
158 ldmia r2, { r12, r14 } @ r12, r14 = Ri0, Ri1
159 mov r3, r3, asr #1 @ Lo0 = Li0 / 2 - Ri0 / 2
160 mov r4, r4, asr #1 @ Lo1 = Li1 / 2 - Ri1 / 2
161 sub r3, r3, r12, asr #1 @
162 sub r4, r4, r14, asr #1 @
163 rsb r12, r3, #0 @ Ro0 = -Lk0 = Rs0 / 2 - Ls0 / 2
164 rsb r14, r4, #0 @ Ro1 = -Lk1 = Ri1 / 2 - Li1 / 2
165 subs r0, r0, #2 @
166 stmia r1!, { r3, r4 } @ store Lo0, Lo1
167 stmia r2!, { r12, r14 } @ store Ro0, Ro1
168 bgt .karaokeloop @
169 @
170 ldmpc cond=lt, regs=r4 @ if count was even, we're done
171 @
172.karaoke_singlesample: @
173 ldr r3, [r1] @ r3 = Li
174 ldr r12, [r2] @ r12 = Ri
175 mov r3, r3, asr #1 @ Lk = Li / 2 - Ri /2
176 sub r3, r3, r12, asr #1 @
177 rsb r12, r3, #0 @ Rk = -Lo = Ri / 2 - Li / 2
178 str r3, [r1] @ store Lo
179 str r12, [r2] @ store Ro
180 @
181 ldmpc regs=r4 @
182 .size channels_process_sound_chan_karaoke, \
183 .-channels_process_sound_chan_karaoke
184
185#if ARM_ARCH < 6
186/****************************************************************************
187 * void sample_output_mono(int count, struct dsp_data *data,
188 * const int32_t *src[], int16_t *dst)
189 */
190 .section .icode, "ax", %progbits
191 .align 2
192 .global sample_output_mono
193 .type sample_output_mono, %function
194sample_output_mono:
195 @ input: r0 = count, r1 = data, r2 = src, r3 = dst
196 stmfd sp!, { r4-r6, lr }
197
198 ldr r1, [r1] @ lr = data->output_scale
199 ldr r2, [r2] @ r2 = src[0]
200
201 mov r4, #1
202 mov r4, r4, lsl r1 @ r4 = 1 << (scale-1)
203 mov r4, r4, lsr #1
204 mvn r14, #0x8000 @ r14 = 0xffff7fff, needed for
205 @ clipping and masking
206 subs r0, r0, #1 @
207 beq .som_singlesample @ Zero? Only one sample!
208
209.somloop:
210 ldmia r2!, { r5, r6 }
211 add r5, r5, r4 @ r6 = (r6 + 1<<(scale-1)) >> scale
212 mov r5, r5, asr r1
213 mov r12, r5, asr #15
214 teq r12, r12, asr #31
215 eorne r5, r14, r5, asr #31 @ Clip (-32768...+32767)
216 add r6, r6, r4
217 mov r6, r6, asr r1 @ r7 = (r7 + 1<<(scale-1)) >> scale
218 mov r12, r6, asr #15
219 teq r12, r12, asr #31
220 eorne r6, r14, r6, asr #31 @ Clip (-32768...+32767)
221
222 and r5, r5, r14, lsr #16
223 and r6, r6, r14, lsr #16
224 orr r5, r5, r5, lsl #16 @ pack first 2 halfwords into 1 word
225 orr r6, r6, r6, lsl #16 @ pack last 2 halfwords into 1 word
226 stmia r3!, { r5, r6 }
227
228 subs r0, r0, #2
229 bgt .somloop
230
231 ldmpc cond=lt, regs=r4-r6 @ even 'count'? return
232
233.som_singlesample:
234 ldr r5, [r2] @ do odd sample
235 add r5, r5, r4
236 mov r5, r5, asr r1
237 mov r12, r5, asr #15
238 teq r12, r12, asr #31
239 eorne r5, r14, r5, asr #31
240
241 and r5, r5, r14, lsr #16 @ pack 2 halfwords into 1 word
242 orr r5, r5, r5, lsl #16
243 str r5, [r3]
244
245 ldmpc regs=r4-r6
246 .size sample_output_mono, .-sample_output_mono
247
248/****************************************************************************
249 * void sample_output_stereo(int count, struct dsp_data *data,
250 * const int32_t *src[], int16_t *dst)
251 */
252 .section .icode, "ax", %progbits
253 .align 2
254 .global sample_output_stereo
255 .type sample_output_stereo, %function
256sample_output_stereo:
257 @ input: r0 = count, r1 = data, r2 = src, r3 = dst
258 stmfd sp!, { r4-r9, lr }
259
260 ldr r1, [r1] @ r1 = data->output_scale
261 ldmia r2, { r2, r5 } @ r2 = src[0], r5 = src[1]
262
263 mov r4, #1
264 mov r4, r4, lsl r1 @ r4 = 1 << (scale-1)
265 mov r4, r4, lsr #1 @
266
267 mvn r14, #0x8000 @ r14 = 0xffff7fff, needed for
268 @ clipping and masking
269 subs r0, r0, #1 @
270 beq .sos_singlesample @ Zero? Only one sample!
271
272.sosloop:
273 ldmia r2!, { r6, r7 } @ 2 left
274 ldmia r5!, { r8, r9 } @ 2 right
275
276 add r6, r6, r4 @ r6 = (r6 + 1<<(scale-1)) >> scale
277 mov r6, r6, asr r1
278 mov r12, r6, asr #15
279 teq r12, r12, asr #31
280 eorne r6, r14, r6, asr #31 @ Clip (-32768...+32767)
281 add r7, r7, r4
282 mov r7, r7, asr r1 @ r7 = (r7 + 1<<(scale-1)) >> scale
283 mov r12, r7, asr #15
284 teq r12, r12, asr #31
285 eorne r7, r14, r7, asr #31 @ Clip (-32768...+32767)
286
287 add r8, r8, r4 @ r8 = (r8 + 1<<(scale-1)) >> scale
288 mov r8, r8, asr r1
289 mov r12, r8, asr #15
290 teq r12, r12, asr #31
291 eorne r8, r14, r8, asr #31 @ Clip (-32768...+32767)
292 add r9, r9, r4 @ r9 = (r9 + 1<<(scale-1)) >> scale
293 mov r9, r9, asr r1
294 mov r12, r9, asr #15
295 teq r12, r12, asr #31
296 eorne r9, r14, r9, asr #31 @ Clip (-32768...+32767)
297
298 and r6, r6, r14, lsr #16 @ pack first 2 halfwords into 1 word
299 orr r8, r6, r8, asl #16
300 and r7, r7, r14, lsr #16 @ pack last 2 halfwords into 1 word
301 orr r9, r7, r9, asl #16
302
303 stmia r3!, { r8, r9 }
304
305 subs r0, r0, #2
306 bgt .sosloop
307
308 ldmpc cond=lt, regs=r4-r9 @ even 'count'? return
309
310.sos_singlesample:
311 ldr r6, [r2] @ left odd sample
312 ldr r8, [r5] @ right odd sample
313
314 add r6, r6, r4 @ r6 = (r7 + 1<<(scale-1)) >> scale
315 mov r6, r6, asr r1
316 mov r12, r6, asr #15
317 teq r12, r12, asr #31
318 eorne r6, r14, r6, asr #31 @ Clip (-32768...+32767)
319 add r8, r8, r4 @ r8 = (r8 + 1<<(scale-1)) >> scale
320 mov r8, r8, asr r1
321 mov r12, r8, asr #15
322 teq r12, r12, asr #31
323 eorne r8, r14, r8, asr #31 @ Clip (-32768...+32767)
324
325 and r6, r6, r14, lsr #16 @ pack 2 halfwords into 1 word
326 orr r8, r6, r8, asl #16
327
328 str r8, [r3]
329
330 ldmpc regs=r4-r9
331 .size sample_output_stereo, .-sample_output_stereo
332#endif /* ARM_ARCH < 6 */
333
334/****************************************************************************
335 * void apply_crossfeed(int count, int32_t* src[])
336 */
337 .section .text
338 .global apply_crossfeed
339apply_crossfeed:
340 @ unfortunately, we ended up in a bit of a register squeeze here, and need
341 @ to keep the count on the stack :/
342 stmdb sp!, { r4-r11, lr } @ stack modified regs
343 ldmia r1, { r2-r3 } @ r2 = src[0], r3 = src[1]
344
345 ldr r1, =crossfeed_data
346 ldmia r1!, { r4-r11 } @ load direct gain and filter data
347 mov r12, r0 @ better to ldm delay + count later
348 add r0, r1, #13*4*2 @ calculate end of delay
349 stmdb sp!, { r0, r12 } @ stack end of delay adr and count
350 ldr r0, [r1, #13*4*2] @ fetch current delay line address
351
352 /* Register usage in loop:
353 * r0 = &delay[index][0], r1 = accumulator high, r2 = src[0], r3 = src[1],
354 * r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs),
355 * r8-r11 = filter history, r12 = temp, r14 = accumulator low
356 */
357.cfloop:
358 smull r14, r1, r6, r8 @ acc = b1*dr[n - 1]
359 smlal r14, r1, r7, r9 @ acc += a1*y_l[n - 1]
360 ldr r8, [r0, #4] @ r8 = dr[n]
361 smlal r14, r1, r5, r8 @ acc += b0*dr[n]
362 mov r9, r1, lsl #1 @ fix format for filter history
363 ldr r12, [r2] @ load left input
364 smlal r14, r1, r4, r12 @ acc += gain*x_l[n]
365 mov r1, r1, lsl #1 @ fix format
366 str r1, [r2], #4 @ save result
367
368 smull r14, r1, r6, r10 @ acc = b1*dl[n - 1]
369 smlal r14, r1, r7, r11 @ acc += a1*y_r[n - 1]
370 ldr r10, [r0] @ r10 = dl[n]
371 str r12, [r0], #4 @ save left input to delay line
372 smlal r14, r1, r5, r10 @ acc += b0*dl[n]
373 mov r11, r1, lsl #1 @ fix format for filter history
374 ldr r12, [r3] @ load right input
375 smlal r14, r1, r4, r12 @ acc += gain*x_r[n]
376 str r12, [r0], #4 @ save right input to delay line
377 mov r1, r1, lsl #1 @ fix format
378 ldmia sp, { r12, r14 } @ fetch delay line end addr and count from stack
379 str r1, [r3], #4 @ save result
380
381 cmp r0, r12 @ need to wrap to start of delay?
382 subeq r0, r0, #13*4*2 @ wrap back delay line ptr to start
383
384 subs r14, r14, #1 @ are we finished?
385 strne r14, [sp, #4] @ nope, save count back to stack
386 bne .cfloop
387
388 @ save data back to struct
389 ldr r12, =crossfeed_data + 4*4
390 stmia r12, { r8-r11 } @ save filter history
391 str r0, [r12, #30*4] @ save delay line index
392 add sp, sp, #8 @ remove temp variables from stack
393 ldmpc regs=r4-r11
394 .size apply_crossfeed, .-apply_crossfeed
395
396/****************************************************************************
397 * int dsp_downsample(int count, struct dsp_data *data,
398 * in32_t *src[], int32_t *dst[])
399 */
400 .section .text
401 .global dsp_downsample
402dsp_downsample:
403 stmdb sp!, { r4-r11, lr } @ stack modified regs
404 ldmib r1, { r5-r6 } @ r5 = num_channels,r6 = resample_data.delta
405 sub r5, r5, #1 @ pre-decrement num_channels for use
406 add r4, r1, #12 @ r4 = &resample_data.phase
407 mov r12, #0xff
408 orr r12, r12, #0xff00 @ r12 = 0xffff
409.dschannel_loop:
410 ldr r1, [r4] @ r1 = resample_data.phase
411 ldr r7, [r2, r5, lsl #2] @ r7 = s = src[ch - 1]
412 ldr r8, [r3, r5, lsl #2] @ r8 = d = dst[ch - 1]
413 add r9, r4, #4 @ r9 = &last_sample[0]
414 ldr r10, [r9, r5, lsl #2] @ r10 = last_sample[ch - 1]
415 sub r11, r0, #1
416 ldr r14, [r7, r11, lsl #2] @ load last sample in s[] ...
417 str r14, [r9, r5, lsl #2] @ and write as next frame's last_sample
418 movs r9, r1, lsr #16 @ r9 = pos = phase >> 16
419 ldreq r11, [r7] @ if pos = 0, load src[0] and jump into loop
420 beq .dsuse_last_start
421 cmp r9, r0 @ if pos >= count, we're already done
422 bge .dsloop_skip
423
424 @ Register usage in loop:
425 @ r0 = count, r1 = phase, r4 = &resample_data.phase, r5 = cur_channel,
426 @ r6 = delta, r7 = s, r8 = d, r9 = pos, r10 = s[pos - 1], r11 = s[pos]
427.dsloop:
428 add r9, r7, r9, lsl #2 @ r9 = &s[pos]
429 ldmda r9, { r10, r11 } @ r10 = s[pos - 1], r11 = s[pos]
430.dsuse_last_start:
431 sub r11, r11, r10 @ r11 = diff = s[pos] - s[pos - 1]
432 @ keep frac in lower bits to take advantage of multiplier early termination
433 and r9, r1, r12 @ frac = phase & 0xffff
434 smull r9, r14, r11, r9
435 add r1, r1, r6 @ phase += delta
436 add r10, r10, r9, lsr #16 @ r10 = out = s[pos - 1] + frac*diff
437 add r10, r10, r14, lsl #16
438 str r10, [r8], #4 @ *d++ = out
439 mov r9, r1, lsr #16 @ pos = phase >> 16
440 cmp r9, r0 @ pos < count?
441 blt .dsloop @ yup, do more samples
442.dsloop_skip:
443 subs r5, r5, #1
444 bpl .dschannel_loop @ if (--ch) >= 0, do another channel
445 sub r1, r1, r0, lsl #16 @ wrap phase back to start
446 str r1, [r4] @ store back
447 ldr r1, [r3] @ r1 = &dst[0]
448 sub r8, r8, r1 @ dst - &dst[0]
449 mov r0, r8, lsr #2 @ convert bytes->samples
450 ldmpc regs=r4-r11 @ ... and we're out
451 .size dsp_downsample, .-dsp_downsample
452
453/****************************************************************************
454 * int dsp_upsample(int count, struct dsp_data *dsp,
455 * in32_t *src[], int32_t *dst[])
456 */
457 .section .text
458 .global dsp_upsample
459dsp_upsample:
460 stmfd sp!, { r4-r11, lr } @ stack modified regs
461 ldmib r1, { r5-r6 } @ r5 = num_channels,r6 = resample_data.delta
462 sub r5, r5, #1 @ pre-decrement num_channels for use
463 add r4, r1, #12 @ r4 = &resample_data.phase
464 mov r6, r6, lsl #16 @ we'll use carry to detect pos increments
465 stmfd sp!, { r0, r4 } @ stack count and &resample_data.phase
466.uschannel_loop:
467 ldr r12, [r4] @ r12 = resample_data.phase
468 ldr r7, [r2, r5, lsl #2] @ r7 = s = src[ch - 1]
469 ldr r8, [r3, r5, lsl #2] @ r8 = d = dst[ch - 1]
470 add r9, r4, #4 @ r9 = &last_sample[0]
471 mov r1, r12, lsl #16 @ we'll use carry to detect pos increments
472 sub r11, r0, #1
473 ldr r14, [r7, r11, lsl #2] @ load last sample in s[] ...
474 ldr r10, [r9, r5, lsl #2] @ r10 = last_sample[ch - 1]
475 str r14, [r9, r5, lsl #2] @ and write as next frame's last_sample
476 movs r14, r12, lsr #16 @ pos = resample_data.phase >> 16
477 beq .usstart_0 @ pos = 0
478 cmp r14, r0 @ if pos >= count, we're already done
479 bge .usloop_skip
480 add r7, r7, r14, lsl #2 @ r7 = &s[pos]
481 ldr r10, [r7, #-4] @ r11 = s[pos - 1]
482 b .usstart_0
483
484 @ Register usage in loop:
485 @ r0 = count, r1 = phase, r4 = &resample_data.phase, r5 = cur_channel,
486 @ r6 = delta, r7 = s, r8 = d, r9 = diff, r10 = s[pos - 1], r11 = s[pos]
487.usloop_1:
488 mov r10, r11 @ r10 = previous sample
489.usstart_0:
490 ldr r11, [r7], #4 @ r11 = next sample
491 mov r4, r1, lsr #16 @ r4 = frac = phase >> 16
492 sub r9, r11, r10 @ r9 = diff = s[pos] - s[pos - 1]
493.usloop_0:
494 smull r12, r14, r4, r9
495 adds r1, r1, r6 @ phase += delta << 16
496 mov r4, r1, lsr #16 @ r4 = frac = phase >> 16
497 add r14, r10, r14, lsl #16
498 add r14, r14, r12, lsr #16 @ r14 = out = s[pos - 1] + frac*diff
499 str r14, [r8], #4 @ *d++ = out
500 bcc .usloop_0 @ if carry is set, pos is incremented
501 subs r0, r0, #1 @ if count > 0, do another sample
502 bgt .usloop_1
503.usloop_skip:
504 subs r5, r5, #1
505 ldmfd sp, { r0, r4 } @ reload count and &resample_data.phase
506 bpl .uschannel_loop @ if (--ch) >= 0, do another channel
507 mov r1, r1, lsr #16 @ wrap phase back to start of next frame
508 ldr r2, [r3] @ r1 = &dst[0]
509 str r1, [r4] @ store phase
510 sub r8, r8, r2 @ dst - &dst[0]
511 mov r0, r8, lsr #2 @ convert bytes->samples
512 add sp, sp, #8 @ adjust stack for temp variables
513 ldmpc regs=r4-r11 @ ... and we're out
514 .size dsp_upsample, .-dsp_upsample
515
516/****************************************************************************
517 * void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[])
518 */
519 .section .icode, "ax", %progbits
520 .align 2
521 .global dsp_apply_gain
522 .type dsp_apply_gain, %function
523dsp_apply_gain:
524 @ input: r0 = count, r1 = data, r2 = buf[]
525 stmfd sp!, { r4-r8, lr }
526
527 ldr r3, [r1, #4] @ r3 = data->num_channels
528 ldr r4, [r1, #32] @ r5 = data->gain
529
530.dag_outerloop:
531 ldr r1, [r2], #4 @ r1 = buf[0] and increment index of buf[]
532 subs r12, r0, #1 @ r12 = r0 = count - 1
533 beq .dag_singlesample @ Zero? Only one sample!
534
535.dag_innerloop:
536 ldmia r1, { r5, r6 } @ load r5, r6 from r1
537 smull r7, r8, r5, r4 @ r7 = FRACMUL_SHL(r5, r4, 8)
538 smull r14, r5, r6, r4 @ r14 = FRACMUL_SHL(r6, r4, 8)
539 subs r12, r12, #2
540 mov r7, r7, lsr #23
541 mov r14, r14, lsr #23
542 orr r7, r7, r8, asl #9
543 orr r14, r14, r5, asl #9
544 stmia r1!, { r7, r14 } @ save r7, r14 to [r1] and increment r1
545 bgt .dag_innerloop @ end of inner loop
546
547 blt .dag_evencount @ < 0? even count
548
549.dag_singlesample:
550 ldr r5, [r1] @ handle odd sample
551 smull r7, r8, r5, r4 @ r7 = FRACMUL_SHL(r5, r4, 8)
552 mov r7, r7, lsr #23
553 orr r7, r7, r8, asl #9
554 str r7, [r1]
555
556.dag_evencount:
557 subs r3, r3, #1
558 bgt .dag_outerloop @ end of outer loop
559
560 ldmpc regs=r4-r8
561 .size dsp_apply_gain, .-dsp_apply_gain
diff --git a/apps/dsp_arm_v6.S b/apps/dsp_arm_v6.S
deleted file mode 100644
index 39949498ea..0000000000
--- a/apps/dsp_arm_v6.S
+++ /dev/null
@@ -1,127 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Michael Sevakis
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 * void sample_output_mono(int count, struct dsp_data *data,
24 * const int32_t *src[], int16_t *dst)
25 */
26 .section .text, "ax", %progbits
27 .align 2
28 .global sample_output_mono
29 .type sample_output_mono, %function
30sample_output_mono:
31 @ input: r0 = count, r1 = data, r2 = src, r3 = dst
32 stmfd sp!, { r4, lr } @
33 @
34 ldr r1, [r1] @ r1 = data->output_scale
35 ldr r2, [r2] @ r2 = src[0]
36 @
37 mov r4, #1 @ r4 = 1 << (scale - 1)
38 mov r4, r4, lsl r1 @
39 subs r0, r0, #1 @ odd: end at 0; even: end at -1
40 mov r4, r4, lsr #1 @
41 beq 2f @ Zero? Only one sample!
42 @
431: @
44 ldmia r2!, { r12, r14 } @ load Mi0, Mi1
45 qadd r12, r12, r4 @ round, scale, saturate and
46 qadd r14, r14, r4 @ pack Mi0 to So0, Mi1 to So1
47 mov r12, r12, asr r1 @
48 mov r14, r14, asr r1 @
49 ssat r12, #16, r12 @
50 ssat r14, #16, r14 @
51 pkhbt r12, r12, r12, asl #16 @
52 pkhbt r14, r14, r14, asl #16 @
53 subs r0, r0, #2 @
54 stmia r3!, { r12, r14 } @ store So0, So1
55 bgt 1b @
56 @
57 ldmltfd sp!, { r4, pc } @ if count was even, we're done
58 @
592: @
60 ldr r12, [r2] @ round, scale, saturate
61 qadd r12, r12, r4 @ and pack Mi to So
62 mov r12, r12, asr r1 @
63 ssat r12, #16, r12 @
64 pkhbt r12, r12, r12, asl #16 @
65 str r12, [r3] @ store So
66 @
67 ldmfd sp!, { r4, pc } @
68 .size sample_output_mono, .-sample_output_mono
69
70/****************************************************************************
71 * void sample_output_stereo(int count, struct dsp_data *data,
72 * const int32_t *src[], int16_t *dst)
73 */
74 .section .text, "ax", %progbits
75 .align 2
76 .global sample_output_stereo
77 .type sample_output_stereo, %function
78sample_output_stereo:
79 @ input: r0 = count, r1 = data, r2 = src, r3 = dst
80 stmfd sp!, { r4-r7, lr } @
81 @
82 ldr r1, [r1] @ r1 = data->output_scale
83 ldmia r2, { r2, r4 } @ r2 = src[0], r4 = src[1]
84 @
85 mov r5, #1 @ r5 = 1 << (scale - 1)
86 mov r5, r5, lsl r1 @
87 subs r0, r0, #1 @ odd: end at 0; even: end at -1
88 mov r5, r5, lsr #1 @
89 beq 2f @ Zero? Only one sample!
90 @
911: @
92 ldmia r2!, { r6, r7 } @ r6, r7 = Li0, Li1
93 ldmia r4!, { r12, r14 } @ r12, r14 = Ri0, Ri1
94 qadd r6, r6, r5 @ round, scale, saturate and pack
95 qadd r7, r7, r5 @ Li0+Ri0 to So0, Li1+Ri1 to So1
96 qadd r12, r12, r5 @
97 qadd r14, r14, r5 @
98 mov r6, r6, asr r1 @
99 mov r7, r7, asr r1 @
100 mov r12, r12, asr r1 @
101 mov r14, r14, asr r1 @
102 ssat r6, #16, r6 @
103 ssat r12, #16, r12 @
104 ssat r7, #16, r7 @
105 ssat r14, #16, r14 @
106 pkhbt r6, r6, r12, asl #16 @
107 pkhbt r7, r7, r14, asl #16 @
108 subs r0, r0, #2 @
109 stmia r3!, { r6, r7 } @ store So0, So1
110 bgt 1b @
111 @
112 ldmltfd sp!, { r4-r7, pc } @ if count was even, we're done
113 @
1142: @
115 ldr r6, [r2] @ r6 = Li
116 ldr r12, [r4] @ r12 = Ri
117 qadd r6, r6, r5 @ round, scale, saturate
118 qadd r12, r12, r5 @ and pack Li+Ri to So
119 mov r6, r6, asr r1 @
120 mov r12, r12, asr r1 @
121 ssat r6, #16, r6 @
122 ssat r12, #16, r12 @
123 pkhbt r6, r6, r12, asl #16 @
124 str r6, [r3] @ store So
125 @
126 ldmfd sp!, { r4-r7, pc } @
127 .size sample_output_stereo, .-sample_output_stereo
diff --git a/apps/dsp_asm.h b/apps/dsp_asm.h
deleted file mode 100644
index 7bf18370a3..0000000000
--- a/apps/dsp_asm.h
+++ /dev/null
@@ -1,86 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Thom Johansen
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <config.h>
23
24#ifndef _DSP_ASM_H
25#define _DSP_ASM_H
26
27/* Set the appropriate #defines based on CPU or whatever matters */
28#if defined(CPU_ARM)
29#define DSP_HAVE_ASM_APPLY_GAIN
30#define DSP_HAVE_ASM_RESAMPLING
31#define DSP_HAVE_ASM_CROSSFEED
32#define DSP_HAVE_ASM_SOUND_CHAN_MONO
33#define DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
34#define DSP_HAVE_ASM_SOUND_CHAN_KARAOKE
35#define DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO
36#define DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO
37#elif defined (CPU_COLDFIRE)
38#define DSP_HAVE_ASM_APPLY_GAIN
39#define DSP_HAVE_ASM_RESAMPLING
40#define DSP_HAVE_ASM_CROSSFEED
41#define DSP_HAVE_ASM_SOUND_CHAN_MONO
42#define DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
43#define DSP_HAVE_ASM_SOUND_CHAN_KARAOKE
44#define DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO
45#define DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO
46#endif /* CPU_COLDFIRE */
47
48/* Declare prototypes based upon what's #defined above */
49#ifdef DSP_HAVE_ASM_CROSSFEED
50void apply_crossfeed(int count, int32_t *buf[]);
51#endif
52
53#ifdef DSP_HAVE_ASM_APPLY_GAIN
54void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[]);
55#endif /* DSP_HAVE_ASM_APPLY_GAIN* */
56
57#ifdef DSP_HAVE_ASM_RESAMPLING
58int dsp_upsample(int count, struct dsp_data *data,
59 const int32_t *src[], int32_t *dst[]);
60int dsp_downsample(int count, struct dsp_data *data,
61 const int32_t *src[], int32_t *dst[]);
62#endif /* DSP_HAVE_ASM_RESAMPLING */
63
64#ifdef DSP_HAVE_ASM_SOUND_CHAN_MONO
65void channels_process_sound_chan_mono(int count, int32_t *buf[]);
66#endif
67
68#ifdef DSP_HAVE_ASM_SOUND_CHAN_CUSTOM
69void channels_process_sound_chan_custom(int count, int32_t *buf[]);
70#endif
71
72#ifdef DSP_HAVE_ASM_SOUND_CHAN_KARAOKE
73void channels_process_sound_chan_karaoke(int count, int32_t *buf[]);
74#endif
75
76#ifdef DSP_HAVE_ASM_SAMPLE_OUTPUT_STEREO
77void sample_output_stereo(int count, struct dsp_data *data,
78 const int32_t *src[], int16_t *dst);
79#endif
80
81#ifdef DSP_HAVE_ASM_SAMPLE_OUTPUT_MONO
82void sample_output_mono(int count, struct dsp_data *data,
83 const int32_t *src[], int16_t *dst);
84#endif
85
86#endif /* _DSP_ASM_H */
diff --git a/apps/dsp_cf.S b/apps/dsp_cf.S
deleted file mode 100644
index cda811a7d5..0000000000
--- a/apps/dsp_cf.S
+++ /dev/null
@@ -1,611 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Thom Johansen
11 * Portions Copyright (C) 2007 Michael Sevakis
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23/****************************************************************************
24 * void dsp_apply_gain(int count, struct dsp_data *data, int32_t *buf[])
25 */
26 .section .text
27 .align 2
28 .global dsp_apply_gain
29dsp_apply_gain:
30 lea.l -20(%sp), %sp | save registers
31 movem.l %d2-%d4/%a2-%a3, (%sp) |
32 movem.l 28(%sp), %a0-%a1 | %a0 = data,
33 | %a1 = buf
34 move.l 4(%a0), %d1 | %d1 = data->num_channels
35 move.l 32(%a0), %a0 | %a0 = data->gain (in s8.23)
3610: | channel loop |
37 move.l 24(%sp), %d0 | %d0 = count
38 move.l -4(%a1, %d1.l*4), %a2 | %a2 = s = buf[ch-1]
39 move.l %a2, %a3 | %a3 = d = s
40 move.l (%a2)+, %d2 | %d2 = *s++,
41 mac.l %a0, %d2, (%a2)+, %d2, %acc0 | %acc0 = S(n)*gain, load S(n+1)
42 subq.l #1, %d0 | --count > 0 ? : effectively n++
43 ble.b 30f | loop done | no? finish up
4420: | loop |
45 move.l %accext01, %d4 | fetch S(n-1)[7:0]
46 movclr.l %acc0, %d3 | fetch S(n-1)[40:8] in %d5[31:0]
47 asl.l #8, %d3 | *s++ = (S(n-1)[40:8] << 8) | S(n-1)[7:0]
48 mac.l %a0, %d2, (%a2)+, %d2, %acc0 | %acc0 = S(n)*gain, load S(n+1)
49 move.b %d4, %d3 |
50 move.l %d3, (%a3)+ |
51 subq.l #1, %d0 | --count > 0 ? : effectively n++
52 bgt.b 20b | loop | yes? do more samples
5330: | loop done |
54 move.l %accext01, %d4 | fetch S(n-1)[7:0]
55 movclr.l %acc0, %d3 | fetch S(n-1)[40:8] in %d5[31:0]
56 asl.l #8, %d3 | *s = (S(n-1)[40:8] << 8) | S(n-1)[7:0]
57 move.b %d4, %d3 |
58 move.l %d3, (%a3) |
59 subq.l #1, %d1 | next channel
60 bgt.b 10b | channel loop |
61 movem.l (%sp), %d2-%d4/%a2-%a3 | restore registers
62 lea.l 20(%sp), %sp | cleanup stack
63 rts |
64 .size dsp_apply_gain,.-dsp_apply_gain
65
66/****************************************************************************
67 * void apply_crossfeed(int count, int32_t *buf[])
68 */
69 .section .text
70 .align 2
71 .global apply_crossfeed
72apply_crossfeed:
73 lea.l -44(%sp), %sp |
74 movem.l %d2-%d7/%a2-%a6, (%sp) | save all regs
75 movem.l 48(%sp), %d7/%a4 | %d7 = count, %a4 = src
76 movem.l (%a4), %a4-%a5 | %a4 = src[0], %a5 = src[1]
77 lea.l crossfeed_data, %a1 | %a1 = &crossfeed_data
78 move.l (%a1)+, %d6 | %d6 = direct gain
79 movem.l 12(%a1), %d0-%d3 | fetch filter history samples
80 move.l 132(%a1), %a0 | fetch delay line address
81 movem.l (%a1), %a1-%a3 | load filter coefs
82 lea.l crossfeed_data+136, %a6 | %a6 = delay line wrap limit
83 bra.b 20f | loop start | go to loop start point
84 /* Register usage in loop:
85 * %a0 = delay_p, %a1..%a3 = b0, b1, a1 (filter coefs),
86 * %a4 = buf[0], %a5 = buf[1],
87 * %a6 = delay line pointer wrap limit,
88 * %d0..%d3 = history
89 * %d4..%d5 = temp.
90 * %d6 = direct gain,
91 * %d7 = count
92 */
9310: | loop |
94 movclr.l %acc0, %d4 | write outputs
95 move.l %d4, (%a4)+ | .
96 movclr.l %acc1, %d5 | .
97 move.l %d5, (%a5)+ | .
9820: | loop start |
99 mac.l %a2, %d0, (%a0)+, %d0, %acc0 | %acc0 = b1*dl[n - 1], %d0 = dl[n]
100 mac.l %a1, %d0 , %acc0 | %acc0 += b0*dl[n]
101 mac.l %a3, %d1, (%a5), %d5, %acc0 | %acc0 += a1*y_r[n - 1], load R
102 mac.l %a2, %d2, (%a0)+, %d2, %acc1 | %acc1 = b1*dr[n - 1], %d2 = dr[n]
103 mac.l %a1, %d2 , %acc1 | %acc1 += b0*dr[n]
104 mac.l %a3, %d3, (%a4), %d4, %acc1 | %acc1 += a1*y_l[n - 1], load L
105 movem.l %d4-%d5, -8(%a0) | save left & right inputs to delay line
106 move.l %acc0, %d3 | get filtered delayed left sample (y_l[n])
107 move.l %acc1, %d1 | get filtered delayed right sample (y_r[n])
108 mac.l %d6, %d4, %acc0 | %acc0 += gain*x_l[n]
109 mac.l %d6, %d5, %acc1 | %acc1 += gain*x_r[n]
110 cmp.l %a6, %a0 | wrap %a0 if passed end
111 bhs.b 30f | wrap buffer |
112 .word 0x51fb | tpf.l | trap the buffer wrap
11330: | wrap buffer | ...fwd taken branches more costly
114 lea.l -104(%a0), %a0 | wrap it up
115 subq.l #1, %d7 | --count > 0 ?
116 bgt.b 10b | loop | yes? do more
117 movclr.l %acc0, %d4 | write last outputs
118 move.l %d4, (%a4) | .
119 movclr.l %acc1, %d5 | .
120 move.l %d5, (%a5) | .
121 lea.l crossfeed_data+16, %a1 | save data back to struct
122 movem.l %d0-%d3, (%a1) | ...history
123 move.l %a0, 120(%a1) | ...delay_p
124 movem.l (%sp), %d2-%d7/%a2-%a6 | restore all regs
125 lea.l 44(%sp), %sp |
126 rts |
127 .size apply_crossfeed,.-apply_crossfeed
128
129/****************************************************************************
130 * int dsp_downsample(int count, struct dsp_data *data,
131 * in32_t *src[], int32_t *dst[])
132 */
133 .section .text
134 .align 2
135 .global dsp_downsample
136dsp_downsample:
137 lea.l -40(%sp), %sp | save non-clobberables
138 movem.l %d2-%d7/%a2-%a5, (%sp) |
139 movem.l 44(%sp), %d2/%a0-%a2 | %d2 = count
140 | %a0 = data
141 | %a1 = src
142 | %a2 = dst
143 movem.l 4(%a0), %d3-%d4 | %d3 = ch = data->num_channels
144 | %d4 = delta = data->resample_data.delta
145 moveq.l #16, %d7 | %d7 = shift
14610: | channel loop |
147 move.l 12(%a0), %d5 | %d5 = phase = data->resample_data.phase
148 move.l -4(%a1, %d3.l*4), %a3 | %a3 = s = src[ch-1]
149 move.l -4(%a2, %d3.l*4), %a4 | %a4 = d = dst[ch-1]
150 lea.l 12(%a0, %d3.l*4), %a5 | %a5 = &data->resample_data.ast_sample[ch-1]
151 move.l (%a5), %d0 | %d0 = last = data->resample_data.last_sample[ch-1]
152 move.l -4(%a3, %d2.l*4), (%a5) | data->resample_data.last_sample[ch-1] = s[count-1]
153 move.l %d5, %d6 | %d6 = pos = phase >> 16
154 lsr.l %d7, %d6 |
155 cmp.l %d2, %d6 | past end of samples?
156 bge.b 40f | skip resample loop| yes? skip loop
157 tst.l %d6 | need last sample of prev. frame?
158 bne.b 20f | resample loop | no? start main loop
159 move.l (%a3, %d6.l*4), %d1 | %d1 = s[pos]
160 bra.b 30f | resample start last | start with last (last in %d0)
16120: | resample loop |
162 lea.l -4(%a3, %d6.l*4), %a5 | load s[pos-1] and s[pos]
163 movem.l (%a5), %d0-%d1 |
16430: | resample start last |
165 sub.l %d0, %d1 | %d1 = diff = s[pos] - s[pos-1]
166 move.l %d0, %acc0 | %acc0 = previous sample
167 move.l %d5, %d0 | frac = (phase << 16) >> 1
168 lsl.l %d7, %d0 |
169 lsr.l #1, %d0 |
170 mac.l %d0, %d1, %acc0 | %acc0 += frac * diff
171 add.l %d4, %d5 | phase += delta
172 move.l %d5, %d6 | pos = phase >> 16
173 lsr.l %d7, %d6 |
174 movclr.l %acc0, %d0 |
175 move.l %d0, (%a4)+ | *d++ = %d0
176 cmp.l %d2, %d6 | pos < count?
177 blt.b 20b | resample loop | yes? continue resampling
17840: | skip resample loop |
179 subq.l #1, %d3 | ch > 0?
180 bgt.b 10b | channel loop | yes? process next channel
181 lsl.l %d7, %d2 | wrap phase to start of next frame
182 sub.l %d2, %d5 | data->resample_data.phase =
183 move.l %d5, 12(%a0) | ... phase - (count << 16)
184 move.l %a4, %d0 | return d - d[0]
185 sub.l (%a2), %d0 |
186 asr.l #2, %d0 | convert bytes->samples
187 movem.l (%sp), %d2-%d7/%a2-%a5 | restore non-clobberables
188 lea.l 40(%sp), %sp | cleanup stack
189 rts | buh-bye
190 .size dsp_downsample,.-dsp_downsample
191
192/****************************************************************************
193 * int dsp_upsample(int count, struct dsp_data *dsp,
194 * const int32_t *src[], int32_t *dst[])
195 */
196 .section .text
197 .align 2
198 .global dsp_upsample
199dsp_upsample:
200 lea.l -40(%sp), %sp | save non-clobberables
201 movem.l %d2-%d7/%a2-%a5, (%sp) |
202 movem.l 44(%sp), %d2/%a0-%a2 | %d2 = count
203 | %a0 = data
204 | %a1 = src
205 | %a2 = dst
206 movem.l 4(%a0), %d3-%d4 | %d3 = ch = channels
207 | %d4 = delta = data->resample_data.delta
208 swap %d4 | swap delta to high word to use...
209 | ...carries to increment position
21010: | channel loop |
211 move.l 12(%a0), %d5 | %d5 = phase = data->resample_data.phase
212 move.l -4(%a1, %d3.l*4), %a3 | %a3 = s = src[ch-1]
213 lea.l 12(%a0, %d3.l*4), %a4 | %a4 = &data->resample_data.last_sample[ch-1]
214 lea.l -4(%a3, %d2.l*4), %a5 | %a5 = src_end = &src[count-1]
215 move.l (%a4), %d0 | %d0 = last = data->resample_data.last_sample[ch-1]
216 move.l (%a5), (%a4) | data->resample_data.last_sample[ch-1] = s[count-1]
217 move.l -4(%a2, %d3.l*4), %a4 | %a4 = d = dst[ch-1]
218 move.l (%a3)+, %d1 | fetch first sample - might throw this...
219 | ...away later but we'll be preincremented
220 move.l %d1, %d6 | save sample value
221 sub.l %d0, %d1 | %d1 = diff = s[0] - last
222 swap %d5 | swap phase to high word to use
223 | carries to increment position
224 move.l %d5, %d7 | %d7 = pos = phase >> 16
225 clr.w %d5 |
226 eor.l %d5, %d7 | pos == 0?
227 beq.b 40f | loop start | yes? start loop
228 cmp.l %d2, %d7 | past end of samples?
229 bge.b 50f | skip resample loop| yes? go to next channel and collect info
230 lea.l (%a3, %d7.l*4), %a3 | %a3 = s = &s[pos+1]
231 movem.l -8(%a3), %d0-%d1 | %d0 = s[pos-1], %d1 = s[pos]
232 move.l %d1, %d6 | save sample value
233 sub.l %d0, %d1 | %d1 = diff = s[pos] - s[pos-1]
234 bra.b 40f | loop start |
23520: | next sample loop |
236 move.l %d6, %d0 | move previous sample to %d0
237 move.l (%a3)+, %d1 | fetch next sample
238 move.l %d1, %d6 | save sample value
239 sub.l %d0, %d1 | %d1 = diff = s[pos] - s[pos-1]
24030: | same sample loop |
241 movclr.l %acc0, %d7 | %d7 = result
242 move.l %d7, (%a4)+ | *d++ = %d7
24340: | loop start |
244 lsr.l #1, %d5 | make phase into frac
245 move.l %d0, %acc0 | %acc0 = s[pos-1]
246 mac.l %d1, %d5, %acc0 | %acc0 = diff * frac
247 lsl.l #1, %d5 | restore frac to phase
248 add.l %d4, %d5 | phase += delta
249 bcc.b 30b | same sample loop | load next values?
250 cmp.l %a5, %a3 | src <= src_end?
251 bls.b 20b | next sample loop | yes? continue resampling
252 movclr.l %acc0, %d7 | %d7 = result
253 move.l %d7, (%a4)+ | *d++ = %d7
25450: | skip resample loop |
255 subq.l #1, %d3 | ch > 0?
256 bgt.b 10b | channel loop | yes? process next channel
257 swap %d5 | wrap phase to start of next frame
258 move.l %d5, 12(%a0) | ...and save in data->resample_data.phase
259 move.l %a4, %d0 | return d - d[0]
260 sub.l (%a2), %d0 |
261 movem.l (%sp), %d2-%d7/%a2-%a5 | restore non-clobberables
262 asr.l #2, %d0 | convert bytes->samples
263 lea.l 40(%sp), %sp | cleanup stack
264 rts | buh-bye
265 .size dsp_upsample,.-dsp_upsample
266
267/****************************************************************************
268 * void channels_process_sound_chan_mono(int count, int32_t *buf[])
269 *
270 * Mix left and right channels 50/50 into a center channel.
271 */
272 .section .text
273 .align 2
274 .global channels_process_sound_chan_mono
275channels_process_sound_chan_mono:
276 movem.l 4(%sp), %d0/%a0 | %d0 = count, %a0 = buf
277 lea.l -20(%sp), %sp | save registers
278 movem.l %d2-%d4/%a2-%a3, (%sp) |
279 movem.l (%a0), %a0-%a1 | get channel pointers
280 move.l %a0, %a2 | use separate dst pointers since read
281 move.l %a1, %a3 | pointers run one ahead of write
282 move.l #0x40000000, %d3 | %d3 = 0.5
283 move.l (%a0)+, %d1 | prime the input registers
284 move.l (%a1)+, %d2 |
285 mac.l %d1, %d3, (%a0)+, %d1, %acc0 |
286 mac.l %d2, %d3, (%a1)+, %d2, %acc0 |
287 subq.l #1, %d0 |
288 ble.s 20f | loop done |
28910: | loop |
290 movclr.l %acc0, %d4 | L = R = l/2 + r/2
291 mac.l %d1, %d3, (%a0)+, %d1, %acc0 |
292 mac.l %d2, %d3, (%a1)+, %d2, %acc0 |
293 move.l %d4, (%a2)+ | output to original buffer
294 move.l %d4, (%a3)+ |
295 subq.l #1, %d0 |
296 bgt.s 10b | loop |
29720: | loop done |
298 movclr.l %acc0, %d4 | output last sample
299 move.l %d4, (%a2) |
300 move.l %d4, (%a3) |
301 movem.l (%sp), %d2-%d4/%a2-%a3 | restore registers
302 lea.l 20(%sp), %sp | cleanup
303 rts |
304 .size channels_process_sound_chan_mono, \
305 .-channels_process_sound_chan_mono
306
307/****************************************************************************
308 * void channels_process_sound_chan_custom(int count, int32_t *buf[])
309 *
310 * Apply stereo width (narrowing/expanding) effect.
311 */
312 .section .text
313 .align 2
314 .global channels_process_sound_chan_custom
315channels_process_sound_chan_custom:
316 movem.l 4(%sp), %d0/%a0 | %d0 = count, %a0 = buf
317 lea.l -28(%sp), %sp | save registers
318 movem.l %d2-%d6/%a2-%a3, (%sp) |
319 movem.l (%a0), %a0-%a1 | get channel pointers
320 move.l %a0, %a2 | use separate dst pointers since read
321 move.l %a1, %a3 | pointers run one ahead of write
322 move.l dsp_sw_gain, %d3 | load straight (mid) gain
323 move.l dsp_sw_cross, %d4 | load cross (side) gain
324 move.l (%a0)+, %d1 | prime the input registers
325 move.l (%a1)+, %d2 |
326 mac.l %d1, %d3 , %acc0 | L = l*gain + r*cross
327 mac.l %d1, %d4, (%a0)+, %d1, %acc1 | R = r*gain + l*cross
328 mac.l %d2, %d4 , %acc0 |
329 mac.l %d2, %d3, (%a1)+, %d2, %acc1 |
330 subq.l #1, %d0 |
331 ble.b 20f | loop done |
33210: | loop |
333 movclr.l %acc0, %d5 |
334 movclr.l %acc1, %d6 |
335 mac.l %d1, %d3 , %acc0 | L = l*gain + r*cross
336 mac.l %d1, %d4, (%a0)+, %d1, %acc1 | R = r*gain + l*cross
337 mac.l %d2, %d4 , %acc0 |
338 mac.l %d2, %d3, (%a1)+, %d2, %acc1 |
339 move.l %d5, (%a2)+ |
340 move.l %d6, (%a3)+ |
341 subq.l #1, %d0 |
342 bgt.s 10b | loop |
34320: | loop done |
344 movclr.l %acc0, %d5 | output last sample
345 movclr.l %acc1, %d6 |
346 move.l %d5, (%a2) |
347 move.l %d6, (%a3) |
348 movem.l (%sp), %d2-%d6/%a2-%a3 | restore registers
349 lea.l 28(%sp), %sp | cleanup
350 rts |
351 .size channels_process_sound_chan_custom, \
352 .-channels_process_sound_chan_custom
353
354/****************************************************************************
355 * void channels_process_sound_chan_karaoke(int count, int32_t *buf[])
356 *
357 * Separate channels into side channels.
358 */
359 .section .text
360 .align 2
361 .global channels_process_sound_chan_karaoke
362channels_process_sound_chan_karaoke:
363 movem.l 4(%sp), %d0/%a0 | %d0 = count, %a0 = buf
364 lea.l -20(%sp), %sp | save registers
365 movem.l %d2-%d4/%a2-%a3, (%sp) |
366 movem.l (%a0), %a0-%a1 | get channel src pointers
367 move.l %a0, %a2 | use separate dst pointers since read
368 move.l %a1, %a3 | pointers run one ahead of write
369 move.l #0x40000000, %d3 | %d3 = 0.5
370 move.l (%a0)+, %d1 | prime the input registers
371 move.l (%a1)+, %d2 |
372 mac.l %d1, %d3, (%a0)+, %d1, %acc0 | L = l/2 - r/2
373 msac.l %d2, %d3, (%a1)+, %d2, %acc0 |
374 subq.l #1, %d0 |
375 ble.b 20f | loop done |
37610: | loop |
377 movclr.l %acc0, %d4 |
378 mac.l %d1, %d3, (%a0)+, %d1, %acc0 | L = l/2 - r/2
379 msac.l %d2, %d3, (%a1)+, %d2, %acc0 |
380 move.l %d4, (%a2)+ |
381 neg.l %d4 | R = -L = -(l/2 - r/2) = r/2 - l/2
382 move.l %d4, (%a3)+ |
383 subq.l #1, %d0 |
384 bgt.s 10b | loop |
38520: | loop done |
386 movclr.l %acc0, %d4 | output last sample
387 move.l %d4, (%a2) |
388 neg.l %d4 | R = -L = -(l/2 - r/2) = r/2 - l/2
389 move.l %d4, (%a3) |
390 movem.l (%sp), %d2-%d4/%a2-%a3 | restore registers
391 lea.l 20(%sp), %sp | cleanup
392 rts |
393 .size channels_process_sound_chan_karaoke, \
394 .-channels_process_sound_chan_karaoke
395
396/****************************************************************************
397 * void sample_output_stereo(int count, struct dsp_data *data,
398 * const int32_t *src[], int16_t *dst)
399 *
400 * Framework based on the ubiquitous Rockbox line transfer logic for
401 * Coldfire CPUs.
402 *
403 * Does emac clamping and scaling (which proved faster than the usual
404 * checks and branches - even single test clamping) and writes using
405 * line burst transfers. Also better than writing a single L-R pair per
406 * loop but a good deal more code.
407 *
408 * Attemping bursting during reads is rather futile since the source and
409 * destination alignments rarely agree and too much complication will
410 * slow us up. The parallel loads seem to do a bit better at least until
411 * a pcm buffer can always give line aligned chunk and then aligning the
412 * dest can then imply the source is aligned if the source buffers are.
413 * For now longword alignment is assumed of both the source and dest.
414 *
415 */
416 .section .text
417 .align 2
418 .global sample_output_stereo
419sample_output_stereo:
420 lea.l -48(%sp), %sp | save registers
421 move.l %macsr, %d1 | do it now as at many lines will
422 movem.l %d1-%d7/%a2-%a6, (%sp) | be the far more common condition
423 move.l #0x80, %macsr | put emac unit in signed int mode
424 movem.l 52(%sp), %a0-%a2/%a4 |
425 lea.l (%a4, %a0.l*4), %a0 | %a0 = end address
426 move.l (%a1), %d1 | %a1 = multiplier: (1 << (16 - scale))
427 sub.l #16, %d1 |
428 neg.l %d1 |
429 moveq.l #1, %d0 |
430 asl.l %d1, %d0 |
431 move.l %d0, %a1 |
432 move.l #0x8000, %a6 | %a6 = rounding term
433 movem.l (%a2), %a2-%a3 | get L/R channel pointers
434 moveq.l #28, %d0 | %d0 = second line bound
435 add.l %a4, %d0 |
436 and.l #0xfffffff0, %d0 |
437 cmp.l %a0, %d0 | at least a full line?
438 bhi.w 40f | long loop 1 start | no? do as trailing longwords
439 sub.l #16, %d0 | %d1 = first line bound
440 cmp.l %a4, %d0 | any leading longwords?
441 bls.b 20f | line loop start | no? start line loop
44210: | long loop 0 |
443 move.l (%a2)+, %d1 | read longword from L and R
444 move.l %a6, %acc0 |
445 move.l %acc0, %acc1 |
446 mac.l %d1, %a1, (%a3)+, %d2, %acc0 | shift L to high word
447 mac.l %d2, %a1, %acc1 | shift R to high word
448 movclr.l %acc0, %d1 | get possibly saturated results
449 movclr.l %acc1, %d2 |
450 swap %d2 | move R to low word
451 move.w %d2, %d1 | interleave MS 16 bits of each
452 move.l %d1, (%a4)+ | ...and write both
453 cmp.l %a4, %d0 |
454 bhi.b 10b | long loop 0 |
45520: | line loop start |
456 lea.l -12(%a0), %a5 | %a5 = at or just before last line bound
45730: | line loop |
458 move.l (%a3)+, %d4 | get next 4 R samples and scale
459 move.l %a6, %acc0 |
460 move.l %acc0, %acc1 |
461 move.l %acc1, %acc2 |
462 move.l %acc2, %acc3 |
463 mac.l %d4, %a1, (%a3)+, %d5, %acc0 | with saturation
464 mac.l %d5, %a1, (%a3)+, %d6, %acc1 |
465 mac.l %d6, %a1, (%a3)+, %d7, %acc2 |
466 mac.l %d7, %a1, (%a2)+, %d0, %acc3 |
467 lea.l 16(%a4), %a4 | increment dest here, mitigate stalls
468 movclr.l %acc0, %d4 | obtain R results
469 movclr.l %acc1, %d5 |
470 movclr.l %acc2, %d6 |
471 movclr.l %acc3, %d7 |
472 move.l %a6, %acc0 |
473 move.l %acc0, %acc1 |
474 move.l %acc1, %acc2 |
475 move.l %acc2, %acc3 |
476 mac.l %d0, %a1, (%a2)+, %d1, %acc0 | get next 4 L samples and scale
477 mac.l %d1, %a1, (%a2)+, %d2, %acc1 | with saturation
478 mac.l %d2, %a1, (%a2)+, %d3, %acc2 |
479 mac.l %d3, %a1 , %acc3 |
480 swap %d4 | a) interleave most significant...
481 swap %d5 |
482 swap %d6 |
483 swap %d7 |
484 movclr.l %acc0, %d0 | obtain L results
485 movclr.l %acc1, %d1 |
486 movclr.l %acc2, %d2 |
487 movclr.l %acc3, %d3 |
488 move.w %d4, %d0 | a) ... 16 bits of L and R
489 move.w %d5, %d1 |
490 move.w %d6, %d2 |
491 move.w %d7, %d3 |
492 movem.l %d0-%d3, -16(%a4) | write four stereo samples
493 cmp.l %a4, %a5 |
494 bhi.b 30b | line loop |
49540: | long loop 1 start |
496 cmp.l %a4, %a0 | any longwords left?
497 bls.b 60f | output end | no? stop
49850: | long loop 1 |
499 move.l (%a2)+, %d1 | handle trailing longwords
500 move.l %a6, %acc0 |
501 move.l %acc0, %acc1 |
502 mac.l %d1, %a1, (%a3)+, %d2, %acc0 | the same way as leading ones
503 mac.l %d2, %a1, %acc1 |
504 movclr.l %acc0, %d1 |
505 movclr.l %acc1, %d2 |
506 swap %d2 |
507 move.w %d2, %d1 |
508 move.l %d1, (%a4)+ |
509 cmp.l %a4, %a0 |
510 bhi.b 50b | long loop 1
51160: | output end |
512 movem.l (%sp), %d1-%d7/%a2-%a6 | restore registers
513 move.l %d1, %macsr |
514 lea.l 48(%sp), %sp | cleanup
515 rts |
516 .size sample_output_stereo, .-sample_output_stereo
517
518/****************************************************************************
519 * void sample_output_mono(int count, struct dsp_data *data,
520 * const int32_t *src[], int16_t *dst)
521 *
522 * Same treatment as sample_output_stereo but for one channel.
523 */
524 .section .text
525 .align 2
526 .global sample_output_mono
527sample_output_mono:
528 lea.l -32(%sp), %sp | save registers
529 move.l %macsr, %d1 | do it now as at many lines will
530 movem.l %d1-%d5/%a2-%a4, (%sp) | be the far more common condition
531 move.l #0x80, %macsr | put emac unit in signed int mode
532 movem.l 36(%sp), %a0-%a3 |
533 lea.l (%a3, %a0.l*4), %a0 | %a0 = end address
534 move.l (%a1), %d1 | %d5 = multiplier: (1 << (16 - scale))
535 sub.l #16, %d1 |
536 neg.l %d1 |
537 moveq.l #1, %d5 |
538 asl.l %d1, %d5 |
539 move.l #0x8000, %a4 | %a4 = rounding term
540 movem.l (%a2), %a2 | get source channel pointer
541 moveq.l #28, %d0 | %d0 = second line bound
542 add.l %a3, %d0 |
543 and.l #0xfffffff0, %d0 |
544 cmp.l %a0, %d0 | at least a full line?
545 bhi.w 40f | long loop 1 start | no? do as trailing longwords
546 sub.l #16, %d0 | %d1 = first line bound
547 cmp.l %a3, %d0 | any leading longwords?
548 bls.b 20f | line loop start | no? start line loop
54910: | long loop 0 |
550 move.l (%a2)+, %d1 | read longword from L and R
551 move.l %a4, %acc0 |
552 mac.l %d1, %d5, %acc0 | shift L to high word
553 movclr.l %acc0, %d1 | get possibly saturated results
554 move.l %d1, %d2 |
555 swap %d2 | move R to low word
556 move.w %d2, %d1 | duplicate single channel into
557 move.l %d1, (%a3)+ | L and R
558 cmp.l %a3, %d0 |
559 bhi.b 10b | long loop 0 |
56020: | line loop start |
561 lea.l -12(%a0), %a1 | %a1 = at or just before last line bound
56230: | line loop |
563 move.l (%a2)+, %d0 | get next 4 L samples and scale
564 move.l %a4, %acc0 |
565 move.l %acc0, %acc1 |
566 move.l %acc1, %acc2 |
567 move.l %acc2, %acc3 |
568 mac.l %d0, %d5, (%a2)+, %d1, %acc0 | with saturation
569 mac.l %d1, %d5, (%a2)+, %d2, %acc1 |
570 mac.l %d2, %d5, (%a2)+, %d3, %acc2 |
571 mac.l %d3, %d5 , %acc3 |
572 lea.l 16(%a3), %a3 | increment dest here, mitigate stalls
573 movclr.l %acc0, %d0 | obtain results
574 movclr.l %acc1, %d1 |
575 movclr.l %acc2, %d2 |
576 movclr.l %acc3, %d3 |
577 move.l %d0, %d4 | duplicate single channel
578 swap %d4 | into L and R
579 move.w %d4, %d0 |
580 move.l %d1, %d4 |
581 swap %d4 |
582 move.w %d4, %d1 |
583 move.l %d2, %d4 |
584 swap %d4 |
585 move.w %d4, %d2 |
586 move.l %d3, %d4 |
587 swap %d4 |
588 move.w %d4, %d3 |
589 movem.l %d0-%d3, -16(%a3) | write four stereo samples
590 cmp.l %a3, %a1 |
591 bhi.b 30b | line loop |
59240: | long loop 1 start |
593 cmp.l %a3, %a0 | any longwords left?
594 bls.b 60f | output end | no? stop
59550: | loop loop 1 |
596 move.l (%a2)+, %d1 | handle trailing longwords
597 move.l %a4, %acc0 |
598 mac.l %d1, %d5, %acc0 | the same way as leading ones
599 movclr.l %acc0, %d1 |
600 move.l %d1, %d2 |
601 swap %d2 |
602 move.w %d2, %d1 |
603 move.l %d1, (%a3)+ |
604 cmp.l %a3, %a0 |
605 bhi.b 50b | long loop 1 |
60660: | output end |
607 movem.l (%sp), %d1-%d5/%a2-%a4 | restore registers
608 move.l %d1, %macsr |
609 lea.l 32(%sp), %sp | cleanup
610 rts |
611 .size sample_output_mono, .-sample_output_mono
diff --git a/apps/eq.c b/apps/eq.c
deleted file mode 100644
index 122a46a4c5..0000000000
--- a/apps/eq.c
+++ /dev/null
@@ -1,268 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Thom Johansen
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <inttypes.h>
23#include "config.h"
24#include "fixedpoint.h"
25#include "fracmul.h"
26#include "eq.h"
27#include "replaygain.h"
28
29/**
30 * Calculate first order shelving filter. Filter is not directly usable by the
31 * eq_filter() function.
32 * @param cutoff shelf midpoint frequency. See eq_pk_coefs for format.
33 * @param A decibel value multiplied by ten, describing gain/attenuation of
34 * shelf. Max value is 24 dB.
35 * @param low true for low-shelf filter, false for high-shelf filter.
36 * @param c pointer to coefficient storage. Coefficients are s4.27 format.
37 */
38void filter_shelf_coefs(unsigned long cutoff, long A, bool low, int32_t *c)
39{
40 long sin, cos;
41 int32_t b0, b1, a0, a1; /* s3.28 */
42 const long g = get_replaygain_int(A*5) << 4; /* 10^(db/40), s3.28 */
43
44 sin = fp_sincos(cutoff/2, &cos);
45 if (low) {
46 const int32_t sin_div_g = fp_div(sin, g, 25);
47 const int32_t sin_g = FRACMUL(sin, g);
48 cos >>= 3;
49 b0 = sin_g + cos; /* 0.25 .. 4.10 */
50 b1 = sin_g - cos; /* -1 .. 3.98 */
51 a0 = sin_div_g + cos; /* 0.25 .. 4.10 */
52 a1 = sin_div_g - cos; /* -1 .. 3.98 */
53 } else {
54 const int32_t cos_div_g = fp_div(cos, g, 25);
55 const int32_t cos_g = FRACMUL(cos, g);
56 sin >>= 3;
57 b0 = sin + cos_g; /* 0.25 .. 4.10 */
58 b1 = sin - cos_g; /* -3.98 .. 1 */
59 a0 = sin + cos_div_g; /* 0.25 .. 4.10 */
60 a1 = sin - cos_div_g; /* -3.98 .. 1 */
61 }
62
63 const int32_t rcp_a0 = fp_div(1, a0, 57); /* 0.24 .. 3.98, s2.29 */
64 *c++ = FRACMUL_SHL(b0, rcp_a0, 1); /* 0.063 .. 15.85 */
65 *c++ = FRACMUL_SHL(b1, rcp_a0, 1); /* -15.85 .. 15.85 */
66 *c++ = -FRACMUL_SHL(a1, rcp_a0, 1); /* -1 .. 1 */
67}
68
69#ifdef HAVE_SW_TONE_CONTROLS
70/**
71 * Calculate second order section filter consisting of one low-shelf and one
72 * high-shelf section.
73 * @param cutoff_low low-shelf midpoint frequency. See eq_pk_coefs for format.
74 * @param cutoff_high high-shelf midpoint frequency.
75 * @param A_low decibel value multiplied by ten, describing gain/attenuation of
76 * low-shelf part. Max value is 24 dB.
77 * @param A_high decibel value multiplied by ten, describing gain/attenuation of
78 * high-shelf part. Max value is 24 dB.
79 * @param A decibel value multiplied by ten, describing additional overall gain.
80 * @param c pointer to coefficient storage. Coefficients are s4.27 format.
81 */
82void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high,
83 long A_low, long A_high, long A, int32_t *c)
84{
85 const long g = get_replaygain_int(A*10) << 7; /* 10^(db/20), s0.31 */
86 int32_t c_ls[3], c_hs[3];
87
88 filter_shelf_coefs(cutoff_low, A_low, true, c_ls);
89 filter_shelf_coefs(cutoff_high, A_high, false, c_hs);
90 c_ls[0] = FRACMUL(g, c_ls[0]);
91 c_ls[1] = FRACMUL(g, c_ls[1]);
92
93 /* now we cascade the two first order filters to one second order filter
94 * which can be used by eq_filter(). these resulting coefficients have a
95 * really wide numerical range, so we use a fixed point format which will
96 * work for the selected cutoff frequencies (in dsp.c) only.
97 */
98 const int32_t b0 = c_ls[0], b1 = c_ls[1], b2 = c_hs[0], b3 = c_hs[1];
99 const int32_t a0 = c_ls[2], a1 = c_hs[2];
100 *c++ = FRACMUL_SHL(b0, b2, 4);
101 *c++ = FRACMUL_SHL(b0, b3, 4) + FRACMUL_SHL(b1, b2, 4);
102 *c++ = FRACMUL_SHL(b1, b3, 4);
103 *c++ = a0 + a1;
104 *c++ = -FRACMUL_SHL(a0, a1, 4);
105}
106#endif
107
108/* Coef calculation taken from Audio-EQ-Cookbook.txt by Robert Bristow-Johnson.
109 * Slightly faster calculation can be done by deriving forms which use tan()
110 * instead of cos() and sin(), but the latter are far easier to use when doing
111 * fixed point math, and performance is not a big point in the calculation part.
112 * All the 'a' filter coefficients are negated so we can use only additions
113 * in the filtering equation.
114 */
115
116/**
117 * Calculate second order section peaking filter coefficients.
118 * @param cutoff a value from 0 to 0x80000000, where 0 represents 0 Hz and
119 * 0x80000000 represents the Nyquist frequency (samplerate/2).
120 * @param Q Q factor value multiplied by ten. Lower bound is artificially set
121 * at 0.5.
122 * @param db decibel value multiplied by ten, describing gain/attenuation at
123 * peak freq. Max value is 24 dB.
124 * @param c pointer to coefficient storage. Coefficients are s3.28 format.
125 */
126void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c)
127{
128 long cs;
129 const long one = 1 << 28; /* s3.28 */
130 const long A = get_replaygain_int(db*5) << 5; /* 10^(db/40), s2.29 */
131 const long alpha = fp_sincos(cutoff, &cs)/(2*Q)*10 >> 1; /* s1.30 */
132 int32_t a0, a1, a2; /* these are all s3.28 format */
133 int32_t b0, b1, b2;
134 const long alphadivA = fp_div(alpha, A, 27);
135 const long alphaA = FRACMUL(alpha, A);
136
137 /* possible numerical ranges are in comments by each coef */
138 b0 = one + alphaA; /* [1 .. 5] */
139 b1 = a1 = -2*(cs >> 3); /* [-2 .. 2] */
140 b2 = one - alphaA; /* [-3 .. 1] */
141 a0 = one + alphadivA; /* [1 .. 5] */
142 a2 = one - alphadivA; /* [-3 .. 1] */
143
144 /* range of this is roughly [0.2 .. 1], but we'll never hit 1 completely */
145 const long rcp_a0 = fp_div(1, a0, 59); /* s0.31 */
146 *c++ = FRACMUL(b0, rcp_a0); /* [0.25 .. 4] */
147 *c++ = FRACMUL(b1, rcp_a0); /* [-2 .. 2] */
148 *c++ = FRACMUL(b2, rcp_a0); /* [-2.4 .. 1] */
149 *c++ = FRACMUL(-a1, rcp_a0); /* [-2 .. 2] */
150 *c++ = FRACMUL(-a2, rcp_a0); /* [-0.6 .. 1] */
151}
152
153/**
154 * Calculate coefficients for lowshelf filter. Parameters are as for
155 * eq_pk_coefs, but the coefficient format is s5.26 fixed point.
156 */
157void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c)
158{
159 long cs;
160 const long one = 1 << 25; /* s6.25 */
161 const long sqrtA = get_replaygain_int(db*5/2) << 2; /* 10^(db/80), s5.26 */
162 const long A = FRACMUL_SHL(sqrtA, sqrtA, 8); /* s2.29 */
163 const long alpha = fp_sincos(cutoff, &cs)/(2*Q)*10 >> 1; /* s1.30 */
164 const long ap1 = (A >> 4) + one;
165 const long am1 = (A >> 4) - one;
166 const long ap1_cs = FRACMUL(ap1, cs);
167 const long am1_cs = FRACMUL(am1, cs);
168 const long twosqrtalpha = 2*FRACMUL(sqrtA, alpha);
169 int32_t a0, a1, a2; /* these are all s6.25 format */
170 int32_t b0, b1, b2;
171
172 /* [0.1 .. 40] */
173 b0 = FRACMUL_SHL(A, ap1 - am1_cs + twosqrtalpha, 2);
174 /* [-16 .. 63.4] */
175 b1 = FRACMUL_SHL(A, am1 - ap1_cs, 3);
176 /* [0 .. 31.7] */
177 b2 = FRACMUL_SHL(A, ap1 - am1_cs - twosqrtalpha, 2);
178 /* [0.5 .. 10] */
179 a0 = ap1 + am1_cs + twosqrtalpha;
180 /* [-16 .. 4] */
181 a1 = -2*(am1 + ap1_cs);
182 /* [0 .. 8] */
183 a2 = ap1 + am1_cs - twosqrtalpha;
184
185 /* [0.1 .. 1.99] */
186 const long rcp_a0 = fp_div(1, a0, 55); /* s1.30 */
187 *c++ = FRACMUL_SHL(b0, rcp_a0, 2); /* [0.06 .. 15.9] */
188 *c++ = FRACMUL_SHL(b1, rcp_a0, 2); /* [-2 .. 31.7] */
189 *c++ = FRACMUL_SHL(b2, rcp_a0, 2); /* [0 .. 15.9] */
190 *c++ = FRACMUL_SHL(-a1, rcp_a0, 2); /* [-2 .. 2] */
191 *c++ = FRACMUL_SHL(-a2, rcp_a0, 2); /* [0 .. 1] */
192}
193
194/**
195 * Calculate coefficients for highshelf filter. Parameters are as for
196 * eq_pk_coefs, but the coefficient format is s5.26 fixed point.
197 */
198void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c)
199{
200 long cs;
201 const long one = 1 << 25; /* s6.25 */
202 const long sqrtA = get_replaygain_int(db*5/2) << 2; /* 10^(db/80), s5.26 */
203 const long A = FRACMUL_SHL(sqrtA, sqrtA, 8); /* s2.29 */
204 const long alpha = fp_sincos(cutoff, &cs)/(2*Q)*10 >> 1; /* s1.30 */
205 const long ap1 = (A >> 4) + one;
206 const long am1 = (A >> 4) - one;
207 const long ap1_cs = FRACMUL(ap1, cs);
208 const long am1_cs = FRACMUL(am1, cs);
209 const long twosqrtalpha = 2*FRACMUL(sqrtA, alpha);
210 int32_t a0, a1, a2; /* these are all s6.25 format */
211 int32_t b0, b1, b2;
212
213 /* [0.1 .. 40] */
214 b0 = FRACMUL_SHL(A, ap1 + am1_cs + twosqrtalpha, 2);
215 /* [-63.5 .. 16] */
216 b1 = -FRACMUL_SHL(A, am1 + ap1_cs, 3);
217 /* [0 .. 32] */
218 b2 = FRACMUL_SHL(A, ap1 + am1_cs - twosqrtalpha, 2);
219 /* [0.5 .. 10] */
220 a0 = ap1 - am1_cs + twosqrtalpha;
221 /* [-4 .. 16] */
222 a1 = 2*(am1 - ap1_cs);
223 /* [0 .. 8] */
224 a2 = ap1 - am1_cs - twosqrtalpha;
225
226 /* [0.1 .. 1.99] */
227 const long rcp_a0 = fp_div(1, a0, 55); /* s1.30 */
228 *c++ = FRACMUL_SHL(b0, rcp_a0, 2); /* [0 .. 16] */
229 *c++ = FRACMUL_SHL(b1, rcp_a0, 2); /* [-31.7 .. 2] */
230 *c++ = FRACMUL_SHL(b2, rcp_a0, 2); /* [0 .. 16] */
231 *c++ = FRACMUL_SHL(-a1, rcp_a0, 2); /* [-2 .. 2] */
232 *c++ = FRACMUL_SHL(-a2, rcp_a0, 2); /* [0 .. 1] */
233}
234
235/* We realise the filters as a second order direct form 1 structure. Direct
236 * form 1 was chosen because of better numerical properties for fixed point
237 * implementations.
238 */
239
240#if (!defined(CPU_COLDFIRE) && !defined(CPU_ARM))
241void eq_filter(int32_t **x, struct eqfilter *f, unsigned num,
242 unsigned channels, unsigned shift)
243{
244 unsigned c, i;
245 long long acc;
246
247 /* Direct form 1 filtering code.
248 y[n] = b0*x[i] + b1*x[i - 1] + b2*x[i - 2] + a1*y[i - 1] + a2*y[i - 2],
249 where y[] is output and x[] is input.
250 */
251
252 for (c = 0; c < channels; c++) {
253 for (i = 0; i < num; i++) {
254 acc = (long long) x[c][i] * f->coefs[0];
255 acc += (long long) f->history[c][0] * f->coefs[1];
256 acc += (long long) f->history[c][1] * f->coefs[2];
257 acc += (long long) f->history[c][2] * f->coefs[3];
258 acc += (long long) f->history[c][3] * f->coefs[4];
259 f->history[c][1] = f->history[c][0];
260 f->history[c][0] = x[c][i];
261 f->history[c][3] = f->history[c][2];
262 x[c][i] = (acc << shift) >> 32;
263 f->history[c][2] = x[c][i];
264 }
265 }
266}
267#endif
268
diff --git a/apps/eq.h b/apps/eq.h
deleted file mode 100644
index a44e9153ac..0000000000
--- a/apps/eq.h
+++ /dev/null
@@ -1,50 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Thom Johansen
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 _EQ_H
23#define _EQ_H
24
25#include <inttypes.h>
26#include <stdbool.h>
27
28/* These depend on the fixed point formats used by the different filter types
29 and need to be changed when they change.
30 */
31#define FILTER_BISHELF_SHIFT 5
32#define EQ_PEAK_SHIFT 4
33#define EQ_SHELF_SHIFT 6
34
35struct eqfilter {
36 int32_t coefs[5]; /* Order is b0, b1, b2, a1, a2 */
37 int32_t history[2][4];
38};
39
40void filter_shelf_coefs(unsigned long cutoff, long A, bool low, int32_t *c);
41void filter_bishelf_coefs(unsigned long cutoff_low, unsigned long cutoff_high,
42 long A_low, long A_high, long A, int32_t *c);
43void eq_pk_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
44void eq_ls_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
45void eq_hs_coefs(unsigned long cutoff, unsigned long Q, long db, int32_t *c);
46void eq_filter(int32_t **x, struct eqfilter *f, unsigned num,
47 unsigned channels, unsigned shift);
48
49#endif
50
diff --git a/apps/eq_arm.S b/apps/eq_arm.S
deleted file mode 100644
index b0e1771e89..0000000000
--- a/apps/eq_arm.S
+++ /dev/null
@@ -1,89 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Thom Johansen
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "config.h"
23
24/* uncomment this to make filtering calculate lower bits after shifting.
25 * without this, "shift" of the lower bits will be lost here.
26 */
27/* #define HIGH_PRECISION */
28
29/*
30 * void eq_filter(int32_t **x, struct eqfilter *f, unsigned num,
31 * unsigned channels, unsigned shift)
32 */
33#if CONFIG_CPU == PP5002
34 .section .icode,"ax",%progbits
35#else
36 .text
37#endif
38 .global eq_filter
39eq_filter:
40 ldr r12, [sp] @ get shift parameter
41 stmdb sp!, { r0-r11, lr } @ save all params and clobbered regs
42 ldmia r1!, { r4-r8 } @ load coefs
43 mov r10, r1 @ loop prelude expects filter struct addr in r10
44
45.filterloop:
46 ldr r9, [sp] @ get pointer to this channels data
47 add r0, r9, #4
48 str r0, [sp] @ save back pointer to next channels data
49 ldr r9, [r9] @ r9 = x[]
50 ldr r14, [sp, #8] @ r14 = numsamples
51 ldmia r10, { r0-r3 } @ load history, r10 should be filter struct addr
52 str r10, [sp, #4] @ save it for loop end
53
54 /* r0-r3 = history, r4-r8 = coefs, r9 = x[], r10..r11 = accumulator,
55 * r12 = shift amount, r14 = number of samples.
56 */
57.loop:
58 /* Direct form 1 filtering code.
59 * y[n] = b0*x[i] + b1*x[i - 1] + b2*x[i - 2] + a1*y[i - 1] + a2*y[i - 2],
60 * where y[] is output and x[] is input. This is performed out of order to
61 * reuse registers, we're pretty short on regs.
62 */
63 smull r10, r11, r6, r1 @ acc = b2*x[i - 2]
64 mov r1, r0 @ fix input history
65 smlal r10, r11, r5, r0 @ acc += b1*x[i - 1]
66 ldr r0, [r9] @ load input and fix history in same operation
67 smlal r10, r11, r7, r2 @ acc += a1*y[i - 1]
68 smlal r10, r11, r8, r3 @ acc += a2*y[i - 2]
69 smlal r10, r11, r4, r0 @ acc += b0*x[i] /* avoid stall on arm9*/
70 mov r3, r2 @ fix output history
71 mov r2, r11, asl r12 @ get upper part of result and shift left
72#ifdef HIGH_PRECISION
73 rsb r11, r12, #32 @ get shift amount for lower part
74 orr r2, r2, r10, lsr r11 @ then mix in correctly shifted lower part
75#endif
76 str r2, [r9], #4 @ save result
77 subs r14, r14, #1 @ are we done with this channel?
78 bne .loop
79
80 ldr r10, [sp, #4] @ load filter struct pointer
81 stmia r10!, { r0-r3 } @ save back history
82 ldr r11, [sp, #12] @ load number of channels
83 subs r11, r11, #1 @ all channels processed?
84 strne r11, [sp, #12]
85 bne .filterloop
86
87 add sp, sp, #16 @ compensate for temp storage
88 ldmpc regs=r4-r11
89
diff --git a/apps/eq_cf.S b/apps/eq_cf.S
deleted file mode 100644
index 30a28b9d99..0000000000
--- a/apps/eq_cf.S
+++ /dev/null
@@ -1,91 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Thom Johansen
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/* uncomment this to make filtering calculate lower bits after shifting.
23 * without this, "shift" - 1 of the lower bits will be lost here.
24 */
25/* #define HIGH_PRECISION */
26
27/*
28 * void eq_filter(int32_t **x, struct eqfilter *f, unsigned num,
29 * unsigned channels, unsigned shift)
30 */
31 .text
32 .global eq_filter
33eq_filter:
34 lea.l (-11*4, %sp), %sp
35 movem.l %d2-%d7/%a2-%a6, (%sp) | save clobbered regs
36 move.l (11*4+8, %sp), %a5 | fetch filter structure address
37 move.l (11*4+20, %sp), %d7 | load shift count
38 subq.l #1, %d7 | EMAC gives us one free shift
39#ifdef HIGH_PRECISION
40 moveq.l #8, %d6
41 sub.l %d7, %d6 | shift for lower part of accumulator
42#endif
43 movem.l (%a5), %a0-%a4 | load coefs
44 lea.l (5*4, %a5), %a5 | point to filter history
45
46.filterloop:
47 move.l (11*4+4, %sp), %a6 | load input channel pointer
48 addq.l #4, (11*4+4, %sp) | point x to next channel
49 move.l (%a6), %a6
50 move.l (11*4+12, %sp), %d5 | number of samples
51 movem.l (%a5), %d0-%d3 | load filter history
52
53 /* d0-d3 = history, d4 = temp, d5 = sample count, d6 = lower shift amount,
54 * d7 = upper shift amount, a0-a4 = coefs, a5 = history pointer, a6 = x[]
55 */
56.loop:
57 /* Direct form 1 filtering code. We assume DSP has put EMAC in frac mode.
58 * y[n] = b0*x[i] + b1*x[i - 1] + b2*x[i - 2] + a1*y[i - 1] + a2*y[i - 2],
59 * where y[] is output and x[] is input. This is performed out of order
60 * to do parallel load of input value.
61 */
62 mac.l %a2, %d1, %acc0 | acc = b2*x[i - 2]
63 move.l %d0, %d1 | fix input history
64 mac.l %a1, %d0, (%a6), %d0, %acc0 | acc += b1*x[i - 1], x[i] -> d0
65 mac.l %a0, %d0, %acc0 | acc += b0*x[i]
66 mac.l %a3, %d2, %acc0 | acc += a1*y[i - 1]
67 mac.l %a4, %d3, %acc0 | acc += a2*y[i - 2]
68 move.l %d2, %d3 | fix output history
69#ifdef HIGH_PRECISION
70 move.l %accext01, %d2 | fetch lower part of accumulator
71 move.b %d2, %d4 | clear upper three bytes
72 lsr.l %d6, %d4 | shift lower bits
73#endif
74 movclr.l %acc0, %d2 | fetch upper part of result
75 asl.l %d7, %d2 | restore fixed point format
76#ifdef HIGH_PRECISION
77 or.l %d2, %d4 | combine lower and upper parts
78#endif
79 move.l %d2, (%a6)+ | save result
80 subq.l #1, %d5 | are we done with this channel?
81 jne .loop
82
83 movem.l %d0-%d3, (%a5) | save history back to struct
84 lea.l (4*4, %a5), %a5 | point to next channel's history
85 subq.l #1, (11*4+16, %sp) | have we processed both channels?
86 jne .filterloop
87
88 movem.l (%sp), %d2-%d7/%a2-%a6
89 lea.l (11*4, %sp), %sp
90 rts
91
diff --git a/apps/eqs/Acoustic.cfg b/apps/eqs/Acoustic.cfg
deleted file mode 100644
index 34b5ed8a2b..0000000000
--- a/apps/eqs/Acoustic.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 45
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 45
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 10
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 15
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 30
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 20
diff --git a/apps/eqs/Bass.cfg b/apps/eqs/Bass.cfg
deleted file mode 100644
index 2742459081..0000000000
--- a/apps/eqs/Bass.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 50
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 50
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 35
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 15
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 5
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: -5
diff --git a/apps/eqs/Classical.cfg b/apps/eqs/Classical.cfg
deleted file mode 100644
index bf2f9f9566..0000000000
--- a/apps/eqs/Classical.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 50
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 50
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 40
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: -20
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 10
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 20
diff --git a/apps/eqs/Default.cfg b/apps/eqs/Default.cfg
deleted file mode 100644
index d6f345fa9e..0000000000
--- a/apps/eqs/Default.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: off
2eq precut: 0
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 0
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 0
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 0
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 0
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 0
diff --git a/apps/eqs/Disco.cfg b/apps/eqs/Disco.cfg
deleted file mode 100644
index f894f26da1..0000000000
--- a/apps/eqs/Disco.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 45
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 30
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 10
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 45
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 25
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 10
diff --git a/apps/eqs/Electronic.cfg b/apps/eqs/Electronic.cfg
deleted file mode 100644
index e70c911272..0000000000
--- a/apps/eqs/Electronic.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 55
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 45
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 5
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 25
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 15
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 55
diff --git a/apps/eqs/Hip-Hop.cfg b/apps/eqs/Hip-Hop.cfg
deleted file mode 100644
index 2d38425dc4..0000000000
--- a/apps/eqs/Hip-Hop.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 65
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 65
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 25
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: -10
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 15
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 35
diff --git a/apps/eqs/Jazz.cfg b/apps/eqs/Jazz.cfg
deleted file mode 100644
index f576f9fcc1..0000000000
--- a/apps/eqs/Jazz.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 60
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 40
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 15
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: -25
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 5
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 60
diff --git a/apps/eqs/Lounge.cfg b/apps/eqs/Lounge.cfg
deleted file mode 100644
index 39ae23a7e7..0000000000
--- a/apps/eqs/Lounge.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 20
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: -25
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 5
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 20
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: -15
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 15
diff --git a/apps/eqs/Pop.cfg b/apps/eqs/Pop.cfg
deleted file mode 100644
index 1d8cefe173..0000000000
--- a/apps/eqs/Pop.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 50
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: -10
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 5
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 50
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 15
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: -10
diff --git a/apps/eqs/R&B.cfg b/apps/eqs/R&B.cfg
deleted file mode 100644
index a460b587f5..0000000000
--- a/apps/eqs/R&B.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 45
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 35
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 45
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 5
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 25
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 30
diff --git a/apps/eqs/Rock.cfg b/apps/eqs/Rock.cfg
deleted file mode 100644
index ec4f0356a8..0000000000
--- a/apps/eqs/Rock.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 45
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: 25
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 10
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 0
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 20
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 45
diff --git a/apps/eqs/Vocal.cfg b/apps/eqs/Vocal.cfg
deleted file mode 100644
index 1de754f07c..0000000000
--- a/apps/eqs/Vocal.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
1eq enabled: on
2eq precut: 45
3eq band 0 cutoff: 60
4eq band 0 q: 7
5eq band 0 gain: -45
6eq band 1 cutoff: 200
7eq band 1 q: 10
8eq band 1 gain: 5
9eq band 2 cutoff: 800
10eq band 2 q: 10
11eq band 2 gain: 45
12eq band 3 cutoff: 4000
13eq band 3 q: 10
14eq band 3 gain: 20
15eq band 4 cutoff: 12000
16eq band 4 q: 7
17eq band 4 gain: 0
diff --git a/apps/fracmul.h b/apps/fracmul.h
index 6aaedaf3e6..47b85e59ef 100644
--- a/apps/fracmul.h
+++ b/apps/fracmul.h
@@ -4,7 +4,7 @@
4#include <stdint.h> 4#include <stdint.h>
5#include "gcc_extensions.h" 5#include "gcc_extensions.h"
6 6
7/** FRACTIONAL MULTIPLICATION - TAKEN FROM apps/dsp.h 7/** FRACTIONAL MULTIPLICATION
8 * Multiply two fixed point numbers with 31 fractional bits: 8 * Multiply two fixed point numbers with 31 fractional bits:
9 * FRACMUL(x, y) 9 * FRACMUL(x, y)
10 * 10 *
diff --git a/apps/metadata.c b/apps/metadata.c
deleted file mode 100644
index 2a93c1880c..0000000000
--- a/apps/metadata.c
+++ /dev/null
@@ -1,641 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include "string-extra.h"
25
26#include "debug.h"
27#include "logf.h"
28#include "settings.h"
29#include "cuesheet.h"
30#include "metadata.h"
31
32#include "metadata/metadata_parsers.h"
33
34#if CONFIG_CODEC == SWCODEC
35
36/* For trailing tag stripping and base audio data types */
37#include "buffering.h"
38
39#include "metadata/metadata_common.h"
40
41static bool get_shn_metadata(int fd, struct mp3entry *id3)
42{
43 /* TODO: read the id3v2 header if it exists */
44 id3->vbr = true;
45 id3->filesize = filesize(fd);
46 return skip_id3v2(fd, id3);
47}
48
49static bool get_other_asap_metadata(int fd, struct mp3entry *id3)
50{
51 id3->bitrate = 706;
52 id3->frequency = 44100;
53 id3->vbr = false;
54 id3->filesize = filesize(fd);
55 id3->genre_string = id3_get_num_genre(36);
56 return true;
57}
58#endif /* CONFIG_CODEC == SWCODEC */
59bool write_metadata_log = false;
60
61const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
62{
63 /* Unknown file format */
64 [0 ... AFMT_NUM_CODECS-1] =
65 AFMT_ENTRY("???", NULL, NULL, NULL, "\0" ),
66
67 /* MPEG Audio layer 2 */
68 [AFMT_MPA_L2] =
69 AFMT_ENTRY("MP2", "mpa", NULL, get_mp3_metadata, "mpa\0mp2\0"),
70
71#if CONFIG_CODEC != SWCODEC
72 /* MPEG Audio layer 3 on HWCODEC: .talk clips, no encoder */
73 [AFMT_MPA_L3] =
74 AFMT_ENTRY("MP3", "mpa", NULL, get_mp3_metadata, "mp3\0talk\0"),
75
76#else /* CONFIG_CODEC == SWCODEC */
77 /* MPEG Audio layer 3 on SWCODEC */
78 [AFMT_MPA_L3] =
79 AFMT_ENTRY("MP3", "mpa", "mp3_enc", get_mp3_metadata, "mp3\0"),
80
81 /* MPEG Audio layer 1 */
82 [AFMT_MPA_L1] =
83 AFMT_ENTRY("MP1", "mpa", NULL, get_mp3_metadata, "mp1\0"),
84 /* Audio Interchange File Format */
85 [AFMT_AIFF] =
86 AFMT_ENTRY("AIFF", "aiff", "aiff_enc", get_aiff_metadata, "aiff\0aif\0"),
87 /* Uncompressed PCM in a WAV file OR ATRAC3 stream in WAV file (.at3) */
88 [AFMT_PCM_WAV] =
89 AFMT_ENTRY("WAV", "wav", "wav_enc", get_wave_metadata, "wav\0at3\0"),
90 /* Ogg Vorbis */
91 [AFMT_OGG_VORBIS] =
92 AFMT_ENTRY("Ogg", "vorbis", NULL, get_ogg_metadata, "ogg\0oga\0"),
93 /* FLAC */
94 [AFMT_FLAC] =
95 AFMT_ENTRY("FLAC", "flac", NULL, get_flac_metadata, "flac\0"),
96 /* Musepack SV7 */
97 [AFMT_MPC_SV7] =
98 AFMT_ENTRY("MPCv7", "mpc", NULL, get_musepack_metadata,"mpc\0"),
99 /* A/52 (aka AC3) audio */
100 [AFMT_A52] =
101 AFMT_ENTRY("AC3", "a52", NULL, get_a52_metadata, "a52\0ac3\0"),
102 /* WavPack */
103 [AFMT_WAVPACK] =
104 AFMT_ENTRY("WV","wavpack","wavpack_enc",get_wavpack_metadata,"wv\0"),
105 /* Apple Lossless Audio Codec */
106 [AFMT_MP4_ALAC] =
107 AFMT_ENTRY("ALAC", "alac", NULL, get_mp4_metadata, "m4a\0m4b\0"),
108 /* Advanced Audio Coding in M4A container */
109 [AFMT_MP4_AAC] =
110 AFMT_ENTRY("AAC", "aac", NULL, get_mp4_metadata, "mp4\0"),
111 /* Shorten */
112 [AFMT_SHN] =
113 AFMT_ENTRY("SHN","shorten", NULL, get_shn_metadata, "shn\0"),
114 /* SID File Format */
115 [AFMT_SID] =
116 AFMT_ENTRY("SID", "sid", NULL, get_sid_metadata, "sid\0"),
117 /* ADX File Format */
118 [AFMT_ADX] =
119 AFMT_ENTRY("ADX", "adx", NULL, get_adx_metadata, "adx\0"),
120 /* NESM (NES Sound Format) */
121 [AFMT_NSF] =
122 AFMT_ENTRY("NSF", "nsf", NULL, get_nsf_metadata, "nsf\0nsfe\0"),
123 /* Speex File Format */
124 [AFMT_SPEEX] =
125 AFMT_ENTRY("Speex", "speex",NULL, get_ogg_metadata, "spx\0"),
126 /* SPC700 Save State */
127 [AFMT_SPC] =
128 AFMT_ENTRY("SPC", "spc", NULL, get_spc_metadata, "spc\0"),
129 /* APE (Monkey's Audio) */
130 [AFMT_APE] =
131 AFMT_ENTRY("APE", "ape", NULL, get_monkeys_metadata,"ape\0mac\0"),
132 /* WMA (WMAV1/V2 in ASF) */
133 [AFMT_WMA] =
134 AFMT_ENTRY("WMA", "wma", NULL, get_asf_metadata,"wma\0wmv\0asf\0"),
135 /* WMA Professional in ASF */
136 [AFMT_WMAPRO] =
137 AFMT_ENTRY("WMAPro","wmapro",NULL, NULL, "wma\0wmv\0asf\0"),
138 /* Amiga MOD File */
139 [AFMT_MOD] =
140 AFMT_ENTRY("MOD", "mod", NULL, get_mod_metadata, "mod\0"),
141 /* Atari SAP File */
142 [AFMT_SAP] =
143 AFMT_ENTRY("SAP", "asap", NULL, get_asap_metadata, "sap\0"),
144 /* Cook in RM/RA */
145 [AFMT_RM_COOK] =
146 AFMT_ENTRY("Cook", "cook", NULL, get_rm_metadata,"rm\0ra\0rmvb\0"),
147 /* AAC in RM/RA */
148 [AFMT_RM_AAC] =
149 AFMT_ENTRY("RAAC", "raac", NULL, NULL, "rm\0ra\0rmvb\0"),
150 /* AC3 in RM/RA */
151 [AFMT_RM_AC3] =
152 AFMT_ENTRY("AC3", "a52_rm", NULL, NULL, "rm\0ra\0rmvb\0"),
153 /* ATRAC3 in RM/RA */
154 [AFMT_RM_ATRAC3] =
155 AFMT_ENTRY("ATRAC3","atrac3_rm",NULL, NULL, "rm\0ra\0rmvb\0"),
156 /* Atari CMC File */
157 [AFMT_CMC] =
158 AFMT_ENTRY("CMC", "asap", NULL, get_other_asap_metadata,"cmc\0"),
159 /* Atari CM3 File */
160 [AFMT_CM3] =
161 AFMT_ENTRY("CM3", "asap", NULL, get_other_asap_metadata,"cm3\0"),
162 /* Atari CMR File */
163 [AFMT_CMR] =
164 AFMT_ENTRY("CMR", "asap", NULL, get_other_asap_metadata,"cmr\0"),
165 /* Atari CMS File */
166 [AFMT_CMS] =
167 AFMT_ENTRY("CMS", "asap", NULL, get_other_asap_metadata,"cms\0"),
168 /* Atari DMC File */
169 [AFMT_DMC] =
170 AFMT_ENTRY("DMC", "asap", NULL, get_other_asap_metadata,"dmc\0"),
171 /* Atari DLT File */
172 [AFMT_DLT] =
173 AFMT_ENTRY("DLT", "asap", NULL, get_other_asap_metadata,"dlt\0"),
174 /* Atari MPT File */
175 [AFMT_MPT] =
176 AFMT_ENTRY("MPT", "asap", NULL, get_other_asap_metadata,"mpt\0"),
177 /* Atari MPD File */
178 [AFMT_MPD] =
179 AFMT_ENTRY("MPD", "asap", NULL, get_other_asap_metadata,"mpd\0"),
180 /* Atari RMT File */
181 [AFMT_RMT] =
182 AFMT_ENTRY("RMT", "asap", NULL, get_other_asap_metadata,"rmt\0"),
183 /* Atari TMC File */
184 [AFMT_TMC] =
185 AFMT_ENTRY("TMC", "asap", NULL, get_other_asap_metadata,"tmc\0"),
186 /* Atari TM8 File */
187 [AFMT_TM8] =
188 AFMT_ENTRY("TM8", "asap", NULL, get_other_asap_metadata,"tm8\0"),
189 /* Atari TM2 File */
190 [AFMT_TM2] =
191 AFMT_ENTRY("TM2", "asap", NULL, get_other_asap_metadata,"tm2\0"),
192 /* Atrac3 in Sony OMA Container */
193 [AFMT_OMA_ATRAC3] =
194 AFMT_ENTRY("ATRAC3","atrac3_oma",NULL, get_oma_metadata, "oma\0aa3\0"),
195 /* SMAF (Synthetic music Mobile Application Format) */
196 [AFMT_SMAF] =
197 AFMT_ENTRY("SMAF", "smaf", NULL, get_smaf_metadata, "mmf\0"),
198 /* Sun Audio file */
199 [AFMT_AU] =
200 AFMT_ENTRY("AU", "au", NULL, get_au_metadata, "au\0snd\0"),
201 /* VOX (Dialogic telephony file formats) */
202 [AFMT_VOX] =
203 AFMT_ENTRY("VOX", "vox", NULL, get_vox_metadata, "vox\0"),
204 /* Wave64 */
205 [AFMT_WAVE64] =
206 AFMT_ENTRY("WAVE64","wav64",NULL, get_wave64_metadata,"w64\0"),
207 /* True Audio */
208 [AFMT_TTA] =
209 AFMT_ENTRY("TTA", "tta", NULL, get_tta_metadata, "tta\0"),
210 /* WMA Voice in ASF */
211 [AFMT_WMAVOICE] =
212 AFMT_ENTRY("WMAVoice","wmavoice",NULL, NULL, "wma\0wmv\0"),
213 /* Musepack SV8 */
214 [AFMT_MPC_SV8] =
215 AFMT_ENTRY("MPCv8", "mpc", NULL, get_musepack_metadata,"mpc\0"),
216 /* Advanced Audio Coding High Efficiency in M4A container */
217 [AFMT_MP4_AAC_HE] =
218 AFMT_ENTRY("AAC-HE","aac", NULL, get_mp4_metadata, "mp4\0"),
219 /* AY (ZX Spectrum, Amstrad CPC Sound Format) */
220 [AFMT_AY] =
221 AFMT_ENTRY("AY", "ay", NULL, get_ay_metadata, "ay\0"),
222 /* GBS (Game Boy Sound Format) */
223 [AFMT_GBS] =
224 AFMT_ENTRY("GBS", "gbs", NULL, get_gbs_metadata, "gbs\0"),
225 /* HES (Hudson Entertainment System Sound Format) */
226 [AFMT_HES] =
227 AFMT_ENTRY("HES", "hes", NULL, get_hes_metadata, "hes\0"),
228 /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */
229 [AFMT_SGC] =
230 AFMT_ENTRY("SGC", "sgc", NULL, get_sgc_metadata, "sgc\0"),
231 /* VGM (Video Game Music Format) */
232 [AFMT_VGM] =
233 AFMT_ENTRY("VGM", "vgm", NULL, get_vgm_metadata, "vgm\0vgz\0"),
234 /* KSS (MSX computer KSS Music File) */
235 [AFMT_KSS] =
236 AFMT_ENTRY("KSS", "kss", NULL, get_kss_metadata, "kss\0"),
237#endif
238};
239
240#if CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING)
241/* get REC_FORMAT_* corresponding AFMT_* */
242const int rec_format_afmt[REC_NUM_FORMATS] =
243{
244 /* give AFMT_UNKNOWN by default */
245 [0 ... REC_NUM_FORMATS-1] = AFMT_UNKNOWN,
246 /* add new entries below this line */
247 [REC_FORMAT_AIFF] = AFMT_AIFF,
248 [REC_FORMAT_MPA_L3] = AFMT_MPA_L3,
249 [REC_FORMAT_WAVPACK] = AFMT_WAVPACK,
250 [REC_FORMAT_PCM_WAV] = AFMT_PCM_WAV,
251};
252
253#if 0 /* Currently unused, left for reference and future use */
254/* get AFMT_* corresponding REC_FORMAT_* */
255const int afmt_rec_format[AFMT_NUM_CODECS] =
256{
257 /* give -1 by default */
258 [0 ... AFMT_NUM_CODECS-1] = -1,
259 /* add new entries below this line */
260 [AFMT_AIFF] = REC_FORMAT_AIFF,
261 [AFMT_MPA_L3] = REC_FORMAT_MPA_L3,
262 [AFMT_WAVPACK] = REC_FORMAT_WAVPACK,
263 [AFMT_PCM_WAV] = REC_FORMAT_PCM_WAV,
264};
265#endif
266#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
267
268#if CONFIG_CODEC == SWCODEC
269/* Get the canonical AFMT type */
270int get_audio_base_codec_type(int type)
271{
272 int base_type = type;
273 switch (type) {
274 case AFMT_MPA_L1:
275 case AFMT_MPA_L2:
276 case AFMT_MPA_L3:
277 base_type = AFMT_MPA_L3;
278 break;
279 case AFMT_MPC_SV7:
280 case AFMT_MPC_SV8:
281 base_type = AFMT_MPC_SV7;
282 break;
283 case AFMT_MP4_AAC:
284 case AFMT_MP4_AAC_HE:
285 base_type = AFMT_MP4_AAC;
286 break;
287 case AFMT_SAP:
288 case AFMT_CMC:
289 case AFMT_CM3:
290 case AFMT_CMR:
291 case AFMT_CMS:
292 case AFMT_DMC:
293 case AFMT_DLT:
294 case AFMT_MPT:
295 case AFMT_MPD:
296 case AFMT_RMT:
297 case AFMT_TMC:
298 case AFMT_TM8:
299 case AFMT_TM2:
300 base_type = AFMT_SAP;
301 break;
302 default:
303 break;
304 }
305
306 return base_type;
307}
308
309/* Get the basic audio type */
310enum data_type get_audio_base_data_type(int afmt)
311{
312 if ((unsigned)afmt >= AFMT_NUM_CODECS)
313 return TYPE_UNKNOWN;
314
315 switch (get_audio_base_codec_type(afmt))
316 {
317 case AFMT_NSF:
318 case AFMT_SPC:
319 case AFMT_SID:
320 case AFMT_MOD:
321 case AFMT_SAP:
322 case AFMT_AY:
323 case AFMT_GBS:
324 case AFMT_HES:
325 case AFMT_SGC:
326 case AFMT_VGM:
327 case AFMT_KSS:
328 /* Type must be allocated and loaded in its entirety onto
329 the buffer */
330 return TYPE_ATOMIC_AUDIO;
331
332 default:
333 /* Assume type may be loaded and discarded incrementally */
334 return TYPE_PACKET_AUDIO;
335
336 case AFMT_UNKNOWN:
337 /* Have no idea at all */
338 return TYPE_UNKNOWN;
339 }
340}
341
342/* Is the format allowed to buffer starting at some offset other than 0
343 or first frame only for resume purposes? */
344bool format_buffers_with_offset(int afmt)
345{
346 switch (afmt)
347 {
348 case AFMT_MPA_L1:
349 case AFMT_MPA_L2:
350 case AFMT_MPA_L3:
351 case AFMT_WAVPACK:
352 /* Format may be loaded at the first needed frame */
353 return true;
354 default:
355 /* Format must be loaded from the beginning of the file
356 (does not imply 'atomic', while 'atomic' implies 'no offset') */
357 return false;
358 }
359}
360#endif /* CONFIG_CODEC == SWCODEC */
361
362
363/* Simple file type probing by looking at the filename extension. */
364unsigned int probe_file_format(const char *filename)
365{
366 char *suffix;
367 unsigned int i;
368
369 suffix = strrchr(filename, '.');
370
371 if (suffix == NULL)
372 {
373 return AFMT_UNKNOWN;
374 }
375
376 /* skip '.' */
377 suffix++;
378
379 for (i = 1; i < AFMT_NUM_CODECS; i++)
380 {
381 /* search extension list for type */
382 const char *ext = audio_formats[i].ext_list;
383
384 do
385 {
386 if (strcasecmp(suffix, ext) == 0)
387 {
388 return i;
389 }
390
391 ext += strlen(ext) + 1;
392 }
393 while (*ext != '\0');
394 }
395
396 return AFMT_UNKNOWN;
397}
398
399/* Note, that this returns false for successful, true for error! */
400bool mp3info(struct mp3entry *entry, const char *filename)
401{
402 int fd;
403 bool result;
404
405 fd = open(filename, O_RDONLY);
406 if (fd < 0)
407 return true;
408
409 result = !get_metadata(entry, fd, filename);
410
411 close(fd);
412
413 return result;
414}
415
416/* Get metadata for track - return false if parsing showed problems with the
417 * file that would prevent playback.
418 */
419bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
420{
421 const struct afmt_entry *entry;
422 int logfd = 0;
423 DEBUGF("Read metadata for %s\n", trackname);
424 if (write_metadata_log)
425 {
426 logfd = open("/metadata.log", O_WRONLY | O_APPEND | O_CREAT, 0666);
427 if (logfd >= 0)
428 {
429 write(logfd, trackname, strlen(trackname));
430 write(logfd, "\n", 1);
431 close(logfd);
432 }
433 }
434
435 /* Clear the mp3entry to avoid having bogus pointers appear */
436 wipe_mp3entry(id3);
437
438 /* Take our best guess at the codec type based on file extension */
439 id3->codectype = probe_file_format(trackname);
440
441 /* default values for embedded cuesheets */
442 id3->has_embedded_cuesheet = false;
443 id3->embedded_cuesheet.pos = 0;
444
445 entry = &audio_formats[id3->codectype];
446
447 /* Load codec specific track tag information and confirm the codec type. */
448 if (!entry->parse_func)
449 {
450 DEBUGF("nothing to parse for %s (format %s)", trackname, entry->label);
451 return false;
452 }
453
454 if (!entry->parse_func(fd, id3))
455 {
456 DEBUGF("parsing %s failed (format: %s)", trackname, entry->label);
457 return false;
458 }
459
460 lseek(fd, 0, SEEK_SET);
461 strlcpy(id3->path, trackname, sizeof(id3->path));
462 /* We have successfully read the metadata from the file */
463 return true;
464}
465
466#ifndef __PCTOOL__
467#if CONFIG_CODEC == SWCODEC
468void strip_tags(int handle_id)
469{
470 static const unsigned char tag[] = "TAG";
471 static const unsigned char apetag[] = "APETAGEX";
472 size_t len, version;
473 void *tail;
474
475 if (bufgettail(handle_id, 128, &tail) != 128)
476 return;
477
478 if (memcmp(tail, tag, 3) == 0)
479 {
480 /* Skip id3v1 tag */
481 logf("Cutting off ID3v1 tag");
482 bufcuttail(handle_id, 128);
483 }
484
485 /* Get a new tail, as the old one may have been cut */
486 if (bufgettail(handle_id, 32, &tail) != 32)
487 return;
488
489 /* Check for APE tag (look for the APE tag footer) */
490 if (memcmp(tail, apetag, 8) != 0)
491 return;
492
493 /* Read the version and length from the footer */
494 version = get_long_le(&((unsigned char *)tail)[8]);
495 len = get_long_le(&((unsigned char *)tail)[12]);
496 if (version == 2000)
497 len += 32; /* APEv2 has a 32 byte header */
498
499 /* Skip APE tag */
500 logf("Cutting off APE tag (%ldB)", len);
501 bufcuttail(handle_id, len);
502}
503#endif /* CONFIG_CODEC == SWCODEC */
504#endif /* ! __PCTOOL__ */
505
506#define MOVE_ENTRY(x) if (x) x += offset;
507
508void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig)
509{
510 long offset;
511 if (orig > dest)
512 offset = -((size_t)orig - (size_t)dest);
513 else
514 offset = ((size_t)dest - (size_t)orig);
515
516 MOVE_ENTRY(entry->title)
517 MOVE_ENTRY(entry->artist)
518 MOVE_ENTRY(entry->album)
519
520 if (entry->genre_string > (char*)orig &&
521 entry->genre_string < (char*)orig + sizeof(struct mp3entry))
522 /* Don't adjust that if it points to an entry of the "genres" array */
523 entry->genre_string += offset;
524
525 MOVE_ENTRY(entry->track_string)
526 MOVE_ENTRY(entry->disc_string)
527 MOVE_ENTRY(entry->year_string)
528 MOVE_ENTRY(entry->composer)
529 MOVE_ENTRY(entry->comment)
530 MOVE_ENTRY(entry->albumartist)
531 MOVE_ENTRY(entry->grouping)
532 MOVE_ENTRY(entry->mb_track_id)
533}
534
535void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
536{
537 memcpy(dest, orig, sizeof(struct mp3entry));
538 adjust_mp3entry(dest, dest, orig);
539}
540
541/* A shortcut to simplify the common task of clearing the struct */
542void wipe_mp3entry(struct mp3entry *id3)
543{
544 memset(id3, 0, sizeof (struct mp3entry));
545}
546
547#if CONFIG_CODEC == SWCODEC
548/* Glean what is possible from the filename alone - does not parse metadata */
549void fill_metadata_from_path(struct mp3entry *id3, const char *trackname)
550{
551 char *p;
552
553 /* Clear the mp3entry to avoid having bogus pointers appear */
554 wipe_mp3entry(id3);
555
556 /* Find the filename portion of the path */
557 p = strrchr(trackname, '/');
558 strlcpy(id3->id3v2buf, p ? ++p : id3->path, ID3V2_BUF_SIZE);
559
560 /* Get the format from the extension and trim it off */
561 p = strrchr(id3->id3v2buf, '.');
562 if (p)
563 {
564 /* Might be wrong for container formats - should we bother? */
565 id3->codectype = probe_file_format(p);
566
567 if (id3->codectype != AFMT_UNKNOWN)
568 *p = '\0';
569 }
570
571 /* Set the filename as the title */
572 id3->title = id3->id3v2buf;
573
574 /* Copy the path info */
575 strlcpy(id3->path, trackname, sizeof (id3->path));
576}
577#endif /* CONFIG_CODEC == SWCODEC */
578
579#ifndef __PCTOOL__
580#ifdef HAVE_TAGCACHE
581#if CONFIG_CODEC == SWCODEC
582
583enum { AUTORESUMABLE_UNKNOWN = 0, AUTORESUMABLE_TRUE, AUTORESUMABLE_FALSE };
584
585bool autoresumable(struct mp3entry *id3)
586{
587 char *endp, *path;
588 size_t len;
589 bool is_resumable;
590
591 if (id3->autoresumable) /* result cached? */
592 return id3->autoresumable == AUTORESUMABLE_TRUE;
593
594 is_resumable = false;
595
596 if (id3->path)
597 {
598 for (path = global_settings.autoresume_paths;
599 *path; /* search terms left? */
600 path++)
601 {
602 if (*path == ':') /* Skip empty search patterns */
603 continue;
604
605 /* FIXME: As soon as strcspn or strchrnul are made available in
606 the core, the following can be made more efficient. */
607 endp = strchr(path, ':');
608 if (endp)
609 len = endp - path;
610 else
611 len = strlen(path);
612
613 /* Note: At this point, len is always > 0 */
614
615 if (strncasecmp(id3->path, path, len) == 0)
616 {
617 /* Full directory-name matches only. Trailing '/' in
618 search path OK. */
619 if (id3->path[len] == '/' || id3->path[len - 1] == '/')
620 {
621 is_resumable = true;
622 break;
623 }
624 }
625 path += len - 1;
626 }
627 }
628
629 /* cache result */
630 id3->autoresumable =
631 is_resumable ? AUTORESUMABLE_TRUE : AUTORESUMABLE_FALSE;
632
633 logf("autoresumable: %s is%s resumable",
634 id3->path, is_resumable ? "" : " not");
635
636 return is_resumable;
637}
638
639#endif /* SWCODEC */
640#endif /* HAVE_TAGCACHE */
641#endif /* __PCTOOL__ */
diff --git a/apps/metadata.h b/apps/metadata.h
deleted file mode 100644
index 55e4d76f25..0000000000
--- a/apps/metadata.h
+++ /dev/null
@@ -1,353 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
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 _METADATA_H
23#define _METADATA_H
24
25#include <stdbool.h>
26#include "config.h"
27#include "file.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 AFMT_MPA_L1, /* MPEG Audio layer 1 */
40 AFMT_MPA_L2, /* MPEG Audio layer 2 */
41 AFMT_MPA_L3, /* MPEG Audio layer 3 */
42
43#if CONFIG_CODEC == SWCODEC
44 AFMT_AIFF, /* Audio Interchange File Format */
45 AFMT_PCM_WAV, /* Uncompressed PCM in a WAV file */
46 AFMT_OGG_VORBIS, /* Ogg Vorbis */
47 AFMT_FLAC, /* FLAC */
48 AFMT_MPC_SV7, /* Musepack SV7 */
49 AFMT_A52, /* A/52 (aka AC3) audio */
50 AFMT_WAVPACK, /* WavPack */
51 AFMT_MP4_ALAC, /* Apple Lossless Audio Codec */
52 AFMT_MP4_AAC, /* Advanced Audio Coding (AAC) in M4A container */
53 AFMT_SHN, /* Shorten */
54 AFMT_SID, /* SID File Format */
55 AFMT_ADX, /* ADX File Format */
56 AFMT_NSF, /* NESM (NES Sound Format) */
57 AFMT_SPEEX, /* Ogg Speex speech */
58 AFMT_SPC, /* SPC700 save state */
59 AFMT_APE, /* Monkey's Audio (APE) */
60 AFMT_WMA, /* WMAV1/V2 in ASF */
61 AFMT_WMAPRO, /* WMA Professional in ASF */
62 AFMT_MOD, /* Amiga MOD File Format */
63 AFMT_SAP, /* Atari 8Bit SAP Format */
64 AFMT_RM_COOK, /* Cook in RM/RA */
65 AFMT_RM_AAC, /* AAC in RM/RA */
66 AFMT_RM_AC3, /* AC3 in RM/RA */
67 AFMT_RM_ATRAC3, /* ATRAC3 in RM/RA */
68 AFMT_CMC, /* Atari 8bit cmc format */
69 AFMT_CM3, /* Atari 8bit cm3 format */
70 AFMT_CMR, /* Atari 8bit cmr format */
71 AFMT_CMS, /* Atari 8bit cms format */
72 AFMT_DMC, /* Atari 8bit dmc format */
73 AFMT_DLT, /* Atari 8bit dlt format */
74 AFMT_MPT, /* Atari 8bit mpt format */
75 AFMT_MPD, /* Atari 8bit mpd format */
76 AFMT_RMT, /* Atari 8bit rmt format */
77 AFMT_TMC, /* Atari 8bit tmc format */
78 AFMT_TM8, /* Atari 8bit tm8 format */
79 AFMT_TM2, /* Atari 8bit tm2 format */
80 AFMT_OMA_ATRAC3, /* Atrac3 in Sony OMA container */
81 AFMT_SMAF, /* SMAF */
82 AFMT_AU, /* Sun Audio file */
83 AFMT_VOX, /* VOX */
84 AFMT_WAVE64, /* Wave64 */
85 AFMT_TTA, /* True Audio */
86 AFMT_WMAVOICE, /* WMA Voice in ASF */
87 AFMT_MPC_SV8, /* Musepack SV8 */
88 AFMT_MP4_AAC_HE, /* Advanced Audio Coding (AAC-HE) in M4A container */
89 AFMT_AY, /* AY (ZX Spectrum, Amstrad CPC Sound Format) */
90 AFMT_GBS, /* GBS (Game Boy Sound Format) */
91 AFMT_HES, /* HES (Hudson Entertainment System Sound Format) */
92 AFMT_SGC, /* SGC (Sega Master System, Game Gear, Coleco Vision Sound Format) */
93 AFMT_VGM, /* VGM (Video Game Music Format) */
94 AFMT_KSS, /* KSS (MSX computer KSS Music File) */
95#endif
96
97 /* add new formats at any index above this line to have a sensible order -
98 specified array index inits are used */
99 /* format arrays defined in id3.c */
100
101 AFMT_NUM_CODECS,
102
103#if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING)
104 /* masks to decompose parts */
105 CODEC_AFMT_MASK = 0x0fff,
106 CODEC_TYPE_MASK = 0x7000,
107
108 /* switch for specifying codec type when requesting a filename */
109 CODEC_TYPE_DECODER = (0 << 12), /* default */
110 CODEC_TYPE_ENCODER = (1 << 12),
111#endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */
112};
113
114#if CONFIG_CODEC == SWCODEC
115#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
116#define CODEC_EXTENSION "so"
117#define CODEC_PREFIX "lib"
118#else
119#define CODEC_EXTENSION "codec"
120#define CODEC_PREFIX ""
121#endif
122
123#ifdef HAVE_RECORDING
124enum rec_format_indexes
125{
126 __REC_FORMAT_START_INDEX = -1,
127
128 /* start formats */
129
130 REC_FORMAT_PCM_WAV,
131 REC_FORMAT_AIFF,
132 REC_FORMAT_WAVPACK,
133 REC_FORMAT_MPA_L3,
134
135 /* add new formats at any index above this line to have a sensible order -
136 specified array index inits are used
137 REC_FORMAT_CFG_NUM_BITS should allocate enough bits to hold the range
138 REC_FORMAT_CFG_VALUE_LIST should be in same order as indexes
139 */
140
141 REC_NUM_FORMATS,
142
143 REC_FORMAT_DEFAULT = REC_FORMAT_PCM_WAV,
144 REC_FORMAT_CFG_NUM_BITS = 2
145};
146
147#define REC_FORMAT_CFG_VAL_LIST "wave,aiff,wvpk,mpa3"
148
149/* get REC_FORMAT_* corresponding AFMT_* */
150extern const int rec_format_afmt[REC_NUM_FORMATS];
151/* get AFMT_* corresponding REC_FORMAT_* */
152/* unused: extern const int afmt_rec_format[AFMT_NUM_CODECS]; */
153
154#define AFMT_ENTRY(label, root_fname, enc_root_fname, func, ext_list) \
155 { label, root_fname, enc_root_fname, func, ext_list }
156#else /* !HAVE_RECORDING */
157#define AFMT_ENTRY(label, root_fname, enc_root_fname, func, ext_list) \
158 { label, root_fname, func, ext_list }
159#endif /* HAVE_RECORDING */
160
161#else /* !SWCODEC */
162
163#define AFMT_ENTRY(label, root_fname, enc_root_fname, func, ext_list) \
164 { label, func, ext_list }
165#endif /* CONFIG_CODEC == SWCODEC */
166
167/** Database of audio formats **/
168/* record describing the audio format */
169struct mp3entry;
170struct afmt_entry
171{
172 const char *label; /* format label */
173#if CONFIG_CODEC == SWCODEC
174 const char *codec_root_fn; /* root codec filename (sans _enc and .codec) */
175#ifdef HAVE_RECORDING
176 const char *codec_enc_root_fn; /* filename of encoder codec */
177#endif
178#endif
179 bool (*parse_func)(int fd, struct mp3entry *id3); /* return true on success */
180 const char *ext_list; /* NULL terminated extension
181 list for type with the first as
182 the default for recording */
183};
184
185/* database of labels and codecs. add formats per above enum */
186extern const struct afmt_entry audio_formats[AFMT_NUM_CODECS];
187
188#if MEMORYSIZE > 2
189#define ID3V2_BUF_SIZE 900
190#define ID3V2_MAX_ITEM_SIZE 240
191#else
192#define ID3V2_BUF_SIZE 300
193#define ID3V2_MAX_ITEM_SIZE 90
194#endif
195
196enum {
197 ID3_VER_1_0 = 1,
198 ID3_VER_1_1,
199 ID3_VER_2_2,
200 ID3_VER_2_3,
201 ID3_VER_2_4
202};
203
204#ifdef HAVE_ALBUMART
205enum mp3_aa_type {
206 AA_TYPE_UNSYNC = -1,
207 AA_TYPE_UNKNOWN,
208 AA_TYPE_BMP,
209 AA_TYPE_PNG,
210 AA_TYPE_JPG,
211};
212
213struct mp3_albumart {
214 enum mp3_aa_type type;
215 int size;
216 off_t pos;
217};
218#endif
219
220enum character_encoding {
221 CHAR_ENC_ISO_8859_1 = 1,
222 CHAR_ENC_UTF_8,
223 CHAR_ENC_UTF_16_LE,
224 CHAR_ENC_UTF_16_BE,
225};
226
227/* cache embedded cuesheet details */
228struct embedded_cuesheet {
229 int size;
230 off_t pos;
231 enum character_encoding encoding;
232};
233
234struct mp3entry {
235 char path[MAX_PATH];
236 char* title;
237 char* artist;
238 char* album;
239 char* genre_string;
240 char* disc_string;
241 char* track_string;
242 char* year_string;
243 char* composer;
244 char* comment;
245 char* albumartist;
246 char* grouping;
247 int discnum;
248 int tracknum;
249 int layer;
250 int year;
251 unsigned char id3version;
252 unsigned int codectype;
253 unsigned int bitrate;
254 unsigned long frequency;
255 unsigned long id3v2len;
256 unsigned long id3v1len;
257 unsigned long first_frame_offset; /* Byte offset to first real MP3 frame.
258 Used for skipping leading garbage to
259 avoid gaps between tracks. */
260 unsigned long filesize; /* without headers; in bytes */
261 unsigned long length; /* song length in ms */
262 unsigned long elapsed; /* ms played */
263
264 int lead_trim; /* Number of samples to skip at the beginning */
265 int tail_trim; /* Number of samples to remove from the end */
266
267 /* Added for Vorbis, used by mp4 parser as well. */
268 unsigned long samples; /* number of samples in track */
269
270 /* MP3 stream specific info */
271 unsigned long frame_count; /* number of frames in the file (if VBR) */
272
273 /* Used for A52/AC3 */
274 unsigned long bytesperframe; /* number of bytes per frame (if CBR) */
275
276 /* Xing VBR fields */
277 bool vbr;
278 bool has_toc; /* True if there is a VBR header in the file */
279 unsigned char toc[100]; /* table of contents */
280
281 /* Added for ATRAC3 */
282 unsigned int channels; /* Number of channels in the stream */
283 unsigned int extradata_size; /* Size (in bytes) of the codec's extradata from the container */
284
285 /* Added for AAC HE SBR */
286 bool needs_upsampling_correction; /* flag used by aac codec */
287
288 /* these following two fields are used for local buffering */
289 char id3v2buf[ID3V2_BUF_SIZE];
290 char id3v1buf[4][92];
291
292 /* resume related */
293 unsigned long offset; /* bytes played */
294 int index; /* playlist index */
295
296#ifdef HAVE_TAGCACHE
297 unsigned char autoresumable; /* caches result of autoresumable() */
298
299 /* runtime database fields */
300 long tagcache_idx; /* 0=invalid, otherwise idx+1 */
301 int rating;
302 int score;
303 long playcount;
304 long lastplayed;
305 long playtime;
306#endif
307
308 /* replaygain support */
309#if CONFIG_CODEC == SWCODEC
310 long track_level; /* holds the level in dB * (1<<FP_BITS) */
311 long album_level;
312 long track_gain; /* s19.12 signed fixed point. 0 for no gain. */
313 long album_gain;
314 long track_peak; /* s19.12 signed fixed point. 0 for no peak. */
315 long album_peak;
316#endif
317
318#ifdef HAVE_ALBUMART
319 bool has_embedded_albumart;
320 struct mp3_albumart albumart;
321#endif
322
323 /* Cuesheet support */
324 bool has_embedded_cuesheet;
325 struct embedded_cuesheet embedded_cuesheet;
326 struct cuesheet *cuesheet;
327
328 /* Musicbrainz Track ID */
329 char* mb_track_id;
330};
331
332unsigned int probe_file_format(const char *filename);
333bool get_metadata(struct mp3entry* id3, int fd, const char* trackname);
334bool mp3info(struct mp3entry *entry, const char *filename);
335void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig);
336void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig);
337void wipe_mp3entry(struct mp3entry *id3);
338
339#if CONFIG_CODEC == SWCODEC
340void fill_metadata_from_path(struct mp3entry *id3, const char *trackname);
341int get_audio_base_codec_type(int type);
342void strip_tags(int handle_id);
343enum data_type get_audio_base_data_type(int afmt);
344bool format_buffers_with_offset(int afmt);
345#endif
346
347#ifdef HAVE_TAGCACHE
348bool autoresumable(struct mp3entry *id3);
349#endif
350
351#endif
352
353
diff --git a/apps/metadata/a52.c b/apps/metadata/a52.c
deleted file mode 100644
index a8aad3fa4f..0000000000
--- a/apps/metadata/a52.c
+++ /dev/null
@@ -1,103 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include "metadata.h"
24#include "logf.h"
25
26#include "metadata_parsers.h"
27
28static const unsigned short a52_bitrates[] =
29{
30 32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
31 192, 224, 256, 320, 384, 448, 512, 576, 640
32};
33
34/* Only store frame sizes for 44.1KHz - others are simply multiples
35 of the bitrate */
36static const unsigned short a52_441framesizes[] =
37{
38 69 * 2, 70 * 2, 87 * 2, 88 * 2, 104 * 2, 105 * 2, 121 * 2,
39 122 * 2, 139 * 2, 140 * 2, 174 * 2, 175 * 2, 208 * 2, 209 * 2,
40 243 * 2, 244 * 2, 278 * 2, 279 * 2, 348 * 2, 349 * 2, 417 * 2,
41 418 * 2, 487 * 2, 488 * 2, 557 * 2, 558 * 2, 696 * 2, 697 * 2,
42 835 * 2, 836 * 2, 975 * 2, 976 * 2, 1114 * 2, 1115 * 2, 1253 * 2,
43 1254 * 2, 1393 * 2, 1394 * 2
44};
45
46bool get_a52_metadata(int fd, struct mp3entry *id3)
47{
48 /* Use the trackname part of the id3 structure as a temporary buffer */
49 unsigned char* buf = (unsigned char *)id3->path;
50 unsigned long totalsamples;
51 int i;
52
53 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 5) < 5))
54 {
55 return false;
56 }
57
58 if ((buf[0] != 0x0b) || (buf[1] != 0x77))
59 {
60 logf("not an A52/AC3 file\n");
61 return false;
62 }
63
64 i = buf[4] & 0x3e;
65
66 if (i > 36)
67 {
68 logf("A52: Invalid frmsizecod: %d\n",i);
69 return false;
70 }
71
72 id3->bitrate = a52_bitrates[i >> 1];
73 id3->vbr = false;
74 id3->filesize = filesize(fd);
75
76 switch (buf[4] & 0xc0)
77 {
78 case 0x00:
79 id3->frequency = 48000;
80 id3->bytesperframe=id3->bitrate * 2 * 2;
81 break;
82
83 case 0x40:
84 id3->frequency = 44100;
85 id3->bytesperframe = a52_441framesizes[i];
86 break;
87
88 case 0x80:
89 id3->frequency = 32000;
90 id3->bytesperframe = id3->bitrate * 3 * 2;
91 break;
92
93 default:
94 logf("A52: Invalid samplerate code: 0x%02x\n", buf[4] & 0xc0);
95 return false;
96 break;
97 }
98
99 /* One A52 frame contains 6 blocks, each containing 256 samples */
100 totalsamples = id3->filesize / id3->bytesperframe * 6 * 256;
101 id3->length = totalsamples / id3->frequency * 1000;
102 return true;
103}
diff --git a/apps/metadata/adx.c b/apps/metadata/adx.c
deleted file mode 100644
index 7c341b4835..0000000000
--- a/apps/metadata/adx.c
+++ /dev/null
@@ -1,124 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "debug.h"
32
33bool get_adx_metadata(int fd, struct mp3entry* id3)
34{
35 /* Use the trackname part of the id3 structure as a temporary buffer */
36 unsigned char * buf = (unsigned char *)id3->path;
37 int chanstart, channels;
38 int looping = 0, start_adr = 0, end_adr = 0;
39
40 /* try to get the basic header */
41 if ((lseek(fd, 0, SEEK_SET) < 0)
42 || (read(fd, buf, 0x38) < 0x38))
43 {
44 DEBUGF("lseek or read failed\n");
45 return false;
46 }
47
48 /* ADX starts with 0x80 */
49 if (buf[0] != 0x80) {
50 DEBUGF("get_adx_metadata: wrong first byte %c\n",buf[0]);
51 return false;
52 }
53
54 /* check for a reasonable offset */
55 chanstart = ((buf[2] << 8) | buf[3]) + 4;
56 if (chanstart > 4096) {
57 DEBUGF("get_adx_metadata: bad chanstart %i\n", chanstart);
58 return false;
59 }
60
61 /* check for a workable number of channels */
62 channels = buf[7];
63 if (channels != 1 && channels != 2) {
64 DEBUGF("get_adx_metadata: bad channel count %i\n",channels);
65 return false;
66 }
67
68 id3->frequency = get_long_be(&buf[8]);
69 /* 32 samples per 18 bytes */
70 id3->bitrate = id3->frequency * channels * 18 * 8 / 32 / 1000;
71 id3->length = get_long_be(&buf[12]) / id3->frequency * 1000;
72 id3->vbr = false;
73 id3->filesize = filesize(fd);
74
75 /* get loop info */
76 if (!memcmp(buf+0x10,"\x01\xF4\x03",3)) {
77 /* Soul Calibur 2 style (type 03) */
78 DEBUGF("get_adx_metadata: type 03 found\n");
79 /* check if header is too small for loop data */
80 if (chanstart-6 < 0x2c) looping=0;
81 else {
82 looping = get_long_be(&buf[0x18]);
83 end_adr = get_long_be(&buf[0x28]);
84 start_adr = get_long_be(&buf[0x1c])/32*channels*18+chanstart;
85 }
86 } else if (!memcmp(buf+0x10,"\x01\xF4\x04",3)) {
87 /* Standard (type 04) */
88 DEBUGF("get_adx_metadata: type 04 found\n");
89 /* check if header is too small for loop data */
90 if (chanstart-6 < 0x38) looping=0;
91 else {
92 looping = get_long_be(&buf[0x24]);
93 end_adr = get_long_be(&buf[0x34]);
94 start_adr = get_long_be(&buf[0x28])/32*channels*18+chanstart;
95 }
96 } else {
97 DEBUGF("get_adx_metadata: error, couldn't determine ADX type\n");
98 return false;
99 }
100
101 /* is file using encryption */
102 if (buf[0x13]==0x08) {
103 DEBUGF("get_adx_metadata: error, encrypted ADX not supported\n");
104 return false;
105 }
106
107 if (looping) {
108 /* 2 loops, 10 second fade */
109 id3->length = (start_adr-chanstart + 2*(end_adr-start_adr))
110 *8 / id3->bitrate + 10000;
111 }
112
113 /* try to get the channel header */
114 if ((lseek(fd, chanstart-6, SEEK_SET) < 0)
115 || (read(fd, buf, 6) < 6))
116 {
117 return false;
118 }
119
120 /* check channel header */
121 if (memcmp(buf, "(c)CRI", 6) != 0) return false;
122
123 return true;
124}
diff --git a/apps/metadata/aiff.c b/apps/metadata/aiff.c
deleted file mode 100644
index 654f37cf98..0000000000
--- a/apps/metadata/aiff.c
+++ /dev/null
@@ -1,108 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31
32#include "debug.h"
33
34/* compressionType: AIFC QuickTime IMA ADPCM */
35#define AIFC_FORMAT_QT_IMA_ADPCM "ima4"
36
37bool get_aiff_metadata(int fd, struct mp3entry* id3)
38{
39 unsigned char buf[512];
40 unsigned long numChannels = 0;
41 unsigned long numSampleFrames = 0;
42 unsigned long numbytes = 0;
43 bool is_aifc = false;
44
45 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, &buf[0], 12) < 12) ||
46 (memcmp(&buf[0], "FORM", 4) != 0) || (memcmp(&buf[8], "AIF", 3) != 0) ||
47 (!(is_aifc = (buf[11] == 'C')) && buf[11] != 'F'))
48 {
49 return false;
50 }
51
52 while (read(fd, &buf[0], 8) == 8)
53 {
54 size_t size = get_long_be(&buf[4]); /* chunkSize */
55
56 if (memcmp(&buf[0], "SSND", 4) == 0)
57 {
58 numbytes = size - 8;
59 break; /* assume COMM was already read */
60 }
61
62 /* odd chunk sizes must be padded */
63 size += size & 1;
64
65 if (size > sizeof(buf))
66 {
67 DEBUGF("AIFF \"%4.4s\" chunk too large (%zd > %zd)",
68 (char*) &buf[0], size, sizeof(buf));
69 }
70
71 if (memcmp(&buf[0], "COMM", 4) == 0)
72 {
73 if (size > sizeof(buf) || read(fd, &buf[0], size) != (ssize_t)size)
74 return false;
75
76 numChannels = ((buf[0]<<8)|buf[1]);
77
78 numSampleFrames = get_long_be(&buf[2]);
79
80 /* sampleRate */
81 id3->frequency = get_long_be(&buf[10]);
82 id3->frequency >>= (16+14-buf[9]);
83
84 /* save format infos */
85 id3->bitrate = ((buf[6]<<8)|buf[7]) * numChannels * id3->frequency;
86 id3->bitrate /= 1000;
87
88 if (!is_aifc || memcmp(&buf[18], AIFC_FORMAT_QT_IMA_ADPCM, 4) != 0)
89 id3->length = ((int64_t) numSampleFrames * 1000) / id3->frequency;
90 else
91 {
92 /* QuickTime IMA ADPCM is 1block = 64 data for each channel */
93 id3->length = ((int64_t) numSampleFrames * 64000LL) / id3->frequency;
94 }
95
96 id3->vbr = false; /* AIFF files are CBR */
97 id3->filesize = filesize(fd);
98 }
99 else
100 {
101 /* skip chunk */
102 if (lseek(fd, size, SEEK_CUR) < 0)
103 return false;
104 }
105 }
106
107 return numbytes && numChannels;
108}
diff --git a/apps/metadata/ape.c b/apps/metadata/ape.c
deleted file mode 100644
index 0bd2477431..0000000000
--- a/apps/metadata/ape.c
+++ /dev/null
@@ -1,182 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "structec.h"
32
33#define APETAG_HEADER_LENGTH 32
34#define APETAG_HEADER_FORMAT "8llll8"
35#define APETAG_ITEM_HEADER_FORMAT "ll"
36#define APETAG_ITEM_TYPE_MASK 3
37
38#ifdef HAVE_ALBUMART
39/* The AA header consists of the pseudo filename "Album Cover (Front).ext"
40 * whereas ".ext" is the file extension. For now ".jpg" and ".png" are
41 * supported by this APE metadata parser. Therefore the length is 22. */
42#define APETAG_AA_HEADER_LENGTH 22
43#endif
44
45struct apetag_header
46{
47 char id[8];
48 long version;
49 long length;
50 long item_count;
51 long flags;
52 char reserved[8];
53};
54
55struct apetag_item_header
56{
57 long length;
58 long flags;
59};
60
61/* Read the items in an APEV2 tag. Only looks for a tag at the end of a
62 * file. Returns true if a tag was found and fully read, false otherwise.
63 */
64bool read_ape_tags(int fd, struct mp3entry* id3)
65{
66 struct apetag_header header;
67
68 if ((lseek(fd, -APETAG_HEADER_LENGTH, SEEK_END) < 0)
69 || (ecread(fd, &header, 1, APETAG_HEADER_FORMAT, IS_BIG_ENDIAN)
70 != APETAG_HEADER_LENGTH)
71 || (memcmp(header.id, "APETAGEX", sizeof(header.id))))
72 {
73 return false;
74 }
75
76 if ((header.version == 2000) && (header.item_count > 0)
77 && (header.length > APETAG_HEADER_LENGTH))
78 {
79 char *buf = id3->id3v2buf;
80 unsigned int buf_remaining = sizeof(id3->id3v2buf)
81 + sizeof(id3->id3v1buf);
82 unsigned int tag_remaining = header.length - APETAG_HEADER_LENGTH;
83 int i;
84
85 if (lseek(fd, -header.length, SEEK_END) < 0)
86 {
87 return false;
88 }
89
90 for (i = 0; i < header.item_count; i++)
91 {
92 struct apetag_item_header item;
93 char name[TAG_NAME_LENGTH];
94 char value[TAG_VALUE_LENGTH];
95 long r;
96
97 if (tag_remaining < sizeof(item))
98 {
99 break;
100 }
101
102 if (ecread(fd, &item, 1, APETAG_ITEM_HEADER_FORMAT, IS_BIG_ENDIAN)
103 < (long) sizeof(item))
104 {
105 return false;
106 }
107
108 tag_remaining -= sizeof(item);
109 r = read_string(fd, name, sizeof(name), 0, tag_remaining);
110
111 if (r == -1)
112 {
113 return false;
114 }
115
116 tag_remaining -= r + item.length;
117
118 if ((item.flags & APETAG_ITEM_TYPE_MASK) == 0)
119 {
120 long len;
121
122 if (read_string(fd, value, sizeof(value), -1, item.length)
123 != item.length)
124 {
125 return false;
126 }
127
128 len = parse_tag(name, value, id3, buf, buf_remaining,
129 TAGTYPE_APE);
130 buf += len;
131 buf_remaining -= len;
132 }
133 else
134 {
135#ifdef HAVE_ALBUMART
136 if (strcasecmp(name, "cover art (front)") == 0)
137 {
138 /* Allow to read at least APETAG_AA_HEADER_LENGTH bytes. */
139 r = read_string(fd, name, sizeof(name), 0, APETAG_AA_HEADER_LENGTH);
140 if (r == -1)
141 {
142 return false;
143 }
144
145 /* Gather the album art format from the pseudo file name's ending. */
146 strcpy(name, name + strlen(name) - 4);
147 id3->albumart.type = AA_TYPE_UNKNOWN;
148 if (strcasecmp(name, ".jpg") == 0)
149 {
150 id3->albumart.type = AA_TYPE_JPG;
151 }
152 else if (strcasecmp(name, ".png") == 0)
153 {
154 id3->albumart.type = AA_TYPE_PNG;
155 }
156
157 /* Set the album art size and position. */
158 if (id3->albumart.type != AA_TYPE_UNKNOWN)
159 {
160 id3->albumart.pos = lseek(fd, 0, SEEK_CUR);
161 id3->albumart.size = item.length - r;
162 id3->has_embedded_albumart = true;
163 }
164
165 /* Seek back to this APE items begin. */
166 if (lseek(fd, -r, SEEK_CUR) < 0)
167 {
168 return false;
169 }
170 }
171#endif
172 /* Seek to the next APE item. */
173 if (lseek(fd, item.length, SEEK_CUR) < 0)
174 {
175 return false;
176 }
177 }
178 }
179 }
180
181 return true;
182}
diff --git a/apps/metadata/asap.c b/apps/metadata/asap.c
deleted file mode 100644
index 9e7f227031..0000000000
--- a/apps/metadata/asap.c
+++ /dev/null
@@ -1,254 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 Dominik Wenger
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32#include "debug.h"
33
34#define MAX_SONGS 32
35
36static bool parse_dec(int *retval, const char *p, int minval, int maxval)
37{
38 int r = 0;
39 do {
40 char c = *p;
41 if (c >= '0' && c <= '9')
42 r = 10 * r + c - '0';
43 else
44 return false;
45 if (r > maxval)
46 return false;
47 } while (*++p != '\0');
48 if (r < minval)
49 return false;
50 *retval = r;
51 return true;
52}
53
54static bool parse_text(char *retval, const char *p)
55{
56 int i;
57 if (*p != '"')
58 return false;
59 p++;
60 if (p[0] == '<' && p[1] == '?' && p[2] == '>' && p[3] == '"')
61 return true;
62 i = 0;
63 while (*p != '"') {
64 if (i >= 127)
65 return false;
66 if (*p == '\0')
67 return false;
68 retval[i++] = *p++;
69 }
70 retval[i] = '\0';
71 return true;
72}
73
74static int ASAP_ParseDuration(const char *s)
75{
76 int r;
77 if (*s < '0' || *s > '9')
78 return -1;
79 r = *s++ - '0';
80 if (*s >= '0' && *s <= '9')
81 r = 10 * r + *s++ - '0';
82 if (*s == ':') {
83 s++;
84 if (*s < '0' || *s > '5')
85 return -1;
86 r = 60 * r + (*s++ - '0') * 10;
87 if (*s < '0' || *s > '9')
88 return -1;
89 r += *s++ - '0';
90 }
91 r *= 1000;
92 if (*s != '.')
93 return r;
94 s++;
95 if (*s < '0' || *s > '9')
96 return r;
97 r += 100 * (*s++ - '0');
98 if (*s < '0' || *s > '9')
99 return r;
100 r += 10 * (*s++ - '0');
101 if (*s < '0' || *s > '9')
102 return r;
103 r += *s - '0';
104 return r;
105}
106
107static bool read_asap_string(char* source, char** buf, char** buffer_end, char** dest)
108{
109 if(parse_text(*buf,source) == false)
110 return false;
111
112 /* set dest pointer */
113 *dest = *buf;
114
115 /* move buf ptr */
116 *buf += strlen(*buf)+1;
117
118 /* check size */
119 if(*buf >= *buffer_end)
120 {
121 DEBUGF("Buffer full\n");
122 return false;
123 }
124 return true;
125}
126
127static bool parse_sap_header(int fd, struct mp3entry* id3, int file_len)
128{
129 int module_index = 0;
130 int sap_signature = -1;
131 int duration_index = 0;
132 unsigned char cur_char = 0;
133 int i;
134
135 /* set defaults */
136 int numSongs = 1;
137 int defSong = 0;
138 int durations[MAX_SONGS];
139 for (i = 0; i < MAX_SONGS; i++)
140 durations[i] = -1;
141
142 /* use id3v2 buffer for our strings */
143 char* buffer = id3->id3v2buf;
144 char* buffer_end = id3->id3v2buf + ID3V2_BUF_SIZE;
145
146 /* parse file */
147 while (1)
148 {
149 char line[256];
150 char *p;
151
152 if (module_index + 8 >= file_len)
153 return false;
154 /* read a char */
155 read(fd,&cur_char,1);
156 /* end of header */
157 if (cur_char == 0xff)
158 break;
159
160 i = 0;
161 while (cur_char != 0x0d)
162 {
163 line[i++] = cur_char;
164 module_index++;
165 if (module_index >= file_len || (unsigned)i >= sizeof(line) - 1)
166 return false;
167 /* read a char */
168 read(fd,&cur_char,1);
169 }
170 if (++module_index >= file_len )
171 return false;
172 /* read a char */
173 read(fd,&cur_char,1);
174 if ( cur_char != 0x0a)
175 return false;
176
177 line[i] = '\0';
178 for (p = line; *p != '\0'; p++) {
179 if (*p == ' ') {
180 *p++ = '\0';
181 break;
182 }
183 }
184
185 /* parse tags */
186 if(strcmp(line, "SAP") == 0)
187 sap_signature = 1;
188 if (sap_signature == -1)
189 return false;
190 if (strcmp(line, "AUTHOR") == 0)
191 {
192 if(read_asap_string(p, &buffer, &buffer_end, &id3->artist) == false)
193 return false;
194 }
195 else if(strcmp(line, "NAME") == 0)
196 {
197 if(read_asap_string(p, &buffer, &buffer_end, &id3->title) == false)
198 return false;
199 }
200 else if(strcmp(line, "DATE") == 0)
201 {
202 if(read_asap_string(p, &buffer, &buffer_end, &id3->year_string) == false)
203 return false;
204 }
205 else if (strcmp(line, "SONGS") == 0)
206 {
207 if (parse_dec(&numSongs, p, 1, MAX_SONGS) == false )
208 return false;
209 }
210 else if (strcmp(line, "DEFSONG") == 0)
211 {
212 if (parse_dec(&defSong, p, 0, MAX_SONGS) == false)
213 return false;
214 }
215 else if (strcmp(line, "TIME") == 0)
216 {
217 int durationTemp = ASAP_ParseDuration(p);
218 if (durationTemp < 0 || duration_index >= MAX_SONGS)
219 return false;
220 durations[duration_index++] = durationTemp;
221 }
222 }
223
224 /* set length: */
225 int length = durations[defSong];
226 if (length < 0)
227 length = 180 * 1000;
228 id3->length = length;
229
230 lseek(fd, 0, SEEK_SET);
231 return true;
232}
233
234
235bool get_asap_metadata(int fd, struct mp3entry* id3)
236{
237
238 int filelength = filesize(fd);
239
240 if(parse_sap_header(fd, id3, filelength) == false)
241 {
242 DEBUGF("parse sap header failed.\n");
243 return false;
244 }
245
246 id3->bitrate = 706;
247 id3->frequency = 44100;
248
249 id3->vbr = false;
250 id3->filesize = filelength;
251 id3->genre_string = id3_get_num_genre(36);
252
253 return true;
254}
diff --git a/apps/metadata/asf.c b/apps/metadata/asf.c
deleted file mode 100644
index b815c09769..0000000000
--- a/apps/metadata/asf.c
+++ /dev/null
@@ -1,591 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * $Id$
10 *
11 * Copyright (C) 2007 Dave Chapman
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <ctype.h>
26#include <inttypes.h>
27
28#include "metadata.h"
29#include "replaygain.h"
30#include "debug.h"
31#include "rbunicode.h"
32#include "metadata_common.h"
33#include "metadata_parsers.h"
34#include "system.h"
35#include <codecs/libasf/asf.h>
36
37/* TODO: Just read the GUIDs into a 16-byte array, and use memcmp to compare */
38struct guid_s {
39 uint32_t v1;
40 uint16_t v2;
41 uint16_t v3;
42 uint8_t v4[8];
43};
44typedef struct guid_s guid_t;
45
46struct asf_object_s {
47 guid_t guid;
48 uint64_t size;
49 uint64_t datalen;
50};
51typedef struct asf_object_s asf_object_t;
52
53static const guid_t asf_guid_null =
54{0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
55
56/* top level object guids */
57
58static const guid_t asf_guid_header =
59{0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
60
61static const guid_t asf_guid_data =
62{0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
63
64static const guid_t asf_guid_index =
65{0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
66
67/* header level object guids */
68
69static const guid_t asf_guid_file_properties =
70{0x8cabdca1, 0xa947, 0x11cf, {0x8E, 0xe4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
71
72static const guid_t asf_guid_stream_properties =
73{0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
74
75static const guid_t asf_guid_content_description =
76{0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
77
78static const guid_t asf_guid_extended_content_description =
79{0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
80
81static const guid_t asf_guid_content_encryption =
82{0x2211b3fb, 0xbd23, 0x11d2, {0xb4, 0xb7, 0x00, 0xa0, 0xc9, 0x55, 0xfc, 0x6e}};
83
84static const guid_t asf_guid_extended_content_encryption =
85{0x298ae614, 0x2622, 0x4c17, {0xb9, 0x35, 0xda, 0xe0, 0x7e, 0xe9, 0x28, 0x9c}};
86
87/* stream type guids */
88
89static const guid_t asf_guid_stream_type_audio =
90{0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
91
92static int asf_guid_match(const guid_t *guid1, const guid_t *guid2)
93{
94 if((guid1->v1 != guid2->v1) ||
95 (guid1->v2 != guid2->v2) ||
96 (guid1->v3 != guid2->v3) ||
97 (memcmp(guid1->v4, guid2->v4, 8))) {
98 return 0;
99 }
100
101 return 1;
102}
103
104/* Read the 16 byte GUID from a file */
105static void asf_readGUID(int fd, guid_t* guid)
106{
107 read_uint32le(fd, &guid->v1);
108 read_uint16le(fd, &guid->v2);
109 read_uint16le(fd, &guid->v3);
110 read(fd, guid->v4, 8);
111}
112
113static void asf_read_object_header(asf_object_t *obj, int fd)
114{
115 asf_readGUID(fd, &obj->guid);
116 read_uint64le(fd, &obj->size);
117 obj->datalen = 0;
118}
119
120/* Parse an integer from the extended content object - we always
121 convert to an int, regardless of native format.
122*/
123static int asf_intdecode(int fd, int type, int length)
124{
125 uint16_t tmp16;
126 uint32_t tmp32;
127 uint64_t tmp64;
128
129 if (type == 3) {
130 read_uint32le(fd, &tmp32);
131 lseek(fd,length - 4,SEEK_CUR);
132 return (int)tmp32;
133 } else if (type == 4) {
134 read_uint64le(fd, &tmp64);
135 lseek(fd,length - 8,SEEK_CUR);
136 return (int)tmp64;
137 } else if (type == 5) {
138 read_uint16le(fd, &tmp16);
139 lseek(fd,length - 2,SEEK_CUR);
140 return (int)tmp16;
141 }
142
143 return 0;
144}
145
146/* Decode a LE utf16 string from a disk buffer into a fixed-sized
147 utf8 buffer.
148*/
149
150static void asf_utf16LEdecode(int fd,
151 uint16_t utf16bytes,
152 unsigned char **utf8,
153 int* utf8bytes
154 )
155{
156 unsigned long ucs;
157 int n;
158 unsigned char utf16buf[256];
159 unsigned char* utf16 = utf16buf;
160 unsigned char* newutf8;
161
162 n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes));
163 utf16bytes -= n;
164
165 while (n > 0) {
166 /* Check for a surrogate pair */
167 if (utf16[1] >= 0xD8 && utf16[1] < 0xE0) {
168 if (n < 4) {
169 /* Run out of utf16 bytes, read some more */
170 utf16buf[0] = utf16[0];
171 utf16buf[1] = utf16[1];
172
173 n = read(fd, utf16buf + 2, MIN(sizeof(utf16buf)-2, utf16bytes));
174 utf16 = utf16buf;
175 utf16bytes -= n;
176 n += 2;
177 }
178
179 if (n < 4) {
180 /* Truncated utf16 string, abort */
181 break;
182 }
183 ucs = 0x10000 + ((utf16[0] << 10) | ((utf16[1] - 0xD8) << 18)
184 | utf16[2] | ((utf16[3] - 0xDC) << 8));
185 utf16 += 4;
186 n -= 4;
187 } else {
188 ucs = (utf16[0] | (utf16[1] << 8));
189 utf16 += 2;
190 n -= 2;
191 }
192
193 if (*utf8bytes > 6) {
194 newutf8 = utf8encode(ucs, *utf8);
195 *utf8bytes -= (newutf8 - *utf8);
196 *utf8 += (newutf8 - *utf8);
197 }
198
199 /* We have run out of utf16 bytes, read more if available */
200 if ((n == 0) && (utf16bytes > 0)) {
201 n = read(fd, utf16buf, MIN(sizeof(utf16buf), utf16bytes));
202 utf16 = utf16buf;
203 utf16bytes -= n;
204 }
205 }
206
207 *utf8[0] = 0;
208 --*utf8bytes;
209
210 if (utf16bytes > 0) {
211 /* Skip any remaining bytes */
212 lseek(fd, utf16bytes, SEEK_CUR);
213 }
214 return;
215}
216
217static int asf_parse_header(int fd, struct mp3entry* id3,
218 asf_waveformatex_t* wfx)
219{
220 asf_object_t current;
221 asf_object_t header;
222 uint64_t datalen;
223 int i;
224 int fileprop = 0;
225 uint64_t play_duration;
226 uint16_t flags;
227 uint32_t subobjects;
228 uint8_t utf8buf[512];
229 int id3buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
230 unsigned char* id3buf = (unsigned char*)id3->id3v2buf;
231
232 asf_read_object_header((asf_object_t *) &header, fd);
233
234 //DEBUGF("header.size=%d\n",(int)header.size);
235 if (header.size < 30) {
236 /* invalid size for header object */
237 return ASF_ERROR_OBJECT_SIZE;
238 }
239
240 read_uint32le(fd, &subobjects);
241
242 /* Two reserved bytes - do we need to read them? */
243 lseek(fd, 2, SEEK_CUR);
244
245 //DEBUGF("Read header - size=%d, subobjects=%d\n",(int)header.size, (int)subobjects);
246
247 if (subobjects > 0) {
248 header.datalen = header.size - 30;
249
250 /* TODO: Check that we have datalen bytes left in the file */
251 datalen = header.datalen;
252
253 for (i=0; i<(int)subobjects; i++) {
254 //DEBUGF("Parsing header object %d - datalen=%d\n",i,(int)datalen);
255 if (datalen < 24) {
256 //DEBUGF("not enough data for reading object\n");
257 break;
258 }
259
260 asf_read_object_header(&current, fd);
261
262 if (current.size > datalen || current.size < 24) {
263 //DEBUGF("invalid object size - current.size=%d, datalen=%d\n",(int)current.size,(int)datalen);
264 break;
265 }
266
267 if (asf_guid_match(&current.guid, &asf_guid_file_properties)) {
268 if (current.size < 104)
269 return ASF_ERROR_OBJECT_SIZE;
270
271 if (fileprop) {
272 /* multiple file properties objects not allowed */
273 return ASF_ERROR_INVALID_OBJECT;
274 }
275
276 fileprop = 1;
277
278 /* Get the number of logical packets - uint16_t at offset 31
279 * (Big endian byte order) */
280 lseek(fd, 31, SEEK_CUR);
281 read_uint16be(fd, &wfx->numpackets);
282
283 /* Now get the play duration - uint64_t at offset 40 */
284 lseek(fd, 7, SEEK_CUR);
285 read_uint64le(fd, &play_duration);
286 id3->length = play_duration / 10000;
287
288 //DEBUGF("****** length = %lums\n", id3->length);
289
290 /* Read the packet size - uint32_t at offset 68 */
291 lseek(fd, 20, SEEK_CUR);
292 read_uint32le(fd, &wfx->packet_size);
293
294 /* Skip bytes remaining in object */
295 lseek(fd, current.size - 24 - 72, SEEK_CUR);
296 } else if (asf_guid_match(&current.guid, &asf_guid_stream_properties)) {
297 guid_t guid;
298 uint32_t propdatalen;
299
300 if (current.size < 78)
301 return ASF_ERROR_OBJECT_SIZE;
302
303#if 0
304 asf_byteio_getGUID(&guid, current->data);
305 datalen = asf_byteio_getDWLE(current->data + 40);
306 flags = asf_byteio_getWLE(current->data + 48);
307#endif
308
309 asf_readGUID(fd, &guid);
310
311 lseek(fd, 24, SEEK_CUR);
312 read_uint32le(fd, &propdatalen);
313 lseek(fd, 4, SEEK_CUR);
314 read_uint16le(fd, &flags);
315
316 if (!asf_guid_match(&guid, &asf_guid_stream_type_audio)) {
317 //DEBUGF("Found stream properties for non audio stream, skipping\n");
318 lseek(fd,current.size - 24 - 50,SEEK_CUR);
319 } else if (wfx->audiostream == -1) {
320 lseek(fd, 4, SEEK_CUR);
321 //DEBUGF("Found stream properties for audio stream %d\n",flags&0x7f);
322
323 if (propdatalen < 18) {
324 return ASF_ERROR_INVALID_LENGTH;
325 }
326
327#if 0
328 if (asf_byteio_getWLE(data + 16) > datalen - 16) {
329 return ASF_ERROR_INVALID_LENGTH;
330 }
331#endif
332 read_uint16le(fd, &wfx->codec_id);
333 read_uint16le(fd, &wfx->channels);
334 read_uint32le(fd, &wfx->rate);
335 read_uint32le(fd, &wfx->bitrate);
336 wfx->bitrate *= 8;
337 read_uint16le(fd, &wfx->blockalign);
338 read_uint16le(fd, &wfx->bitspersample);
339 read_uint16le(fd, &wfx->datalen);
340
341 /* Round bitrate to the nearest kbit */
342 id3->bitrate = (wfx->bitrate + 500) / 1000;
343 id3->frequency = wfx->rate;
344
345 if (wfx->codec_id == ASF_CODEC_ID_WMAV1) {
346 read(fd, wfx->data, 4);
347 lseek(fd,current.size - 24 - 72 - 4,SEEK_CUR);
348 wfx->audiostream = flags&0x7f;
349 } else if (wfx->codec_id == ASF_CODEC_ID_WMAV2) {
350 read(fd, wfx->data, 6);
351 lseek(fd,current.size - 24 - 72 - 6,SEEK_CUR);
352 wfx->audiostream = flags&0x7f;
353 } else if (wfx->codec_id == ASF_CODEC_ID_WMAPRO) {
354 /* wma pro decoder needs the extra-data */
355 read(fd, wfx->data, wfx->datalen);
356 lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
357 wfx->audiostream = flags&0x7f;
358 /* Correct codectype to redirect playback to the proper .codec */
359 id3->codectype = AFMT_WMAPRO;
360 } else if (wfx->codec_id == ASF_CODEC_ID_WMAVOICE) {
361 read(fd, wfx->data, wfx->datalen);
362 lseek(fd,current.size - 24 - 72 - wfx->datalen,SEEK_CUR);
363 wfx->audiostream = flags&0x7f;
364 id3->codectype = AFMT_WMAVOICE;
365 } else {
366 DEBUGF("Unsupported WMA codec (Lossless, Voice, etc)\n");
367 lseek(fd,current.size - 24 - 72,SEEK_CUR);
368 }
369
370 }
371 } else if (asf_guid_match(&current.guid, &asf_guid_content_description)) {
372 /* Object contains five 16-bit string lengths, followed by the five strings:
373 title, artist, copyright, description, rating
374 */
375 uint16_t strlength[5];
376 int i;
377
378 //DEBUGF("Found GUID_CONTENT_DESCRIPTION - size=%d\n",(int)(current.size - 24));
379
380 /* Read the 5 string lengths - number of bytes included trailing zero */
381 for (i=0; i<5; i++) {
382 read_uint16le(fd, &strlength[i]);
383 //DEBUGF("strlength = %u\n",strlength[i]);
384 }
385
386 if (strlength[0] > 0) { /* 0 - Title */
387 id3->title = id3buf;
388 asf_utf16LEdecode(fd, strlength[0], &id3buf, &id3buf_remaining);
389 }
390
391 if (strlength[1] > 0) { /* 1 - Artist */
392 id3->artist = id3buf;
393 asf_utf16LEdecode(fd, strlength[1], &id3buf, &id3buf_remaining);
394 }
395
396 lseek(fd, strlength[2], SEEK_CUR); /* 2 - copyright */
397
398 if (strlength[3] > 0) { /* 3 - description */
399 id3->comment = id3buf;
400 asf_utf16LEdecode(fd, strlength[3], &id3buf, &id3buf_remaining);
401 }
402
403 lseek(fd, strlength[4], SEEK_CUR); /* 4 - rating */
404 } else if (asf_guid_match(&current.guid, &asf_guid_extended_content_description)) {
405 uint16_t count;
406 int i;
407 int bytesleft = current.size - 24;
408 //DEBUGF("Found GUID_EXTENDED_CONTENT_DESCRIPTION\n");
409
410 read_uint16le(fd, &count);
411 bytesleft -= 2;
412 //DEBUGF("extended metadata count = %u\n",count);
413
414 for (i=0; i < count; i++) {
415 uint16_t length, type;
416 unsigned char* utf8 = utf8buf;
417 int utf8length = 512;
418
419 read_uint16le(fd, &length);
420 asf_utf16LEdecode(fd, length, &utf8, &utf8length);
421 bytesleft -= 2 + length;
422
423 read_uint16le(fd, &type);
424 read_uint16le(fd, &length);
425
426 if (!strcmp("WM/TrackNumber",utf8buf)) {
427 if (type == 0) {
428 id3->track_string = id3buf;
429 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
430 id3->tracknum = atoi(id3->track_string);
431 } else if ((type >=2) && (type <= 5)) {
432 id3->tracknum = asf_intdecode(fd, type, length);
433 } else {
434 lseek(fd, length, SEEK_CUR);
435 }
436 } else if ((!strcmp("WM/Genre", utf8buf)) && (type == 0)) {
437 id3->genre_string = id3buf;
438 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
439 } else if ((!strcmp("WM/AlbumTitle", utf8buf)) && (type == 0)) {
440 id3->album = id3buf;
441 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
442 } else if ((!strcmp("WM/AlbumArtist", utf8buf)) && (type == 0)) {
443 id3->albumartist = id3buf;
444 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
445 } else if ((!strcmp("WM/Composer", utf8buf)) && (type == 0)) {
446 id3->composer = id3buf;
447 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
448 } else if (!strcmp("WM/Year", utf8buf)) {
449 if (type == 0) {
450 id3->year_string = id3buf;
451 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
452 id3->year = atoi(id3->year_string);
453 } else if ((type >=2) && (type <= 5)) {
454 id3->year = asf_intdecode(fd, type, length);
455 } else {
456 lseek(fd, length, SEEK_CUR);
457 }
458 } else if (!strncmp("replaygain_", utf8buf, 11)) {
459 char *value = id3buf;
460 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
461 parse_replaygain(utf8buf, value, id3);
462 } else if (!strcmp("MusicBrainz/Track Id", utf8buf)) {
463 id3->mb_track_id = id3buf;
464 asf_utf16LEdecode(fd, length, &id3buf, &id3buf_remaining);
465#ifdef HAVE_ALBUMART
466 } else if (!strcmp("WM/Picture", utf8buf)) {
467 uint32_t datalength, strlength;
468 /* Expected is either "01 00 xx xx 03 yy yy yy yy" or
469 * "03 yy yy yy yy". xx is the size of the WM/Picture
470 * container in bytes. yy equals the raw data length of
471 * the embedded image. */
472 lseek(fd, -4, SEEK_CUR);
473 read(fd, &type, 1);
474 if (type == 1) {
475 lseek(fd, 3, SEEK_CUR);
476 read(fd, &type, 1);
477 /* In case the parsing will fail in the next step we
478 * might at least be able to skip the whole section. */
479 datalength = length - 1;
480 }
481 if (type == 3) {
482 /* Read the raw data length of the embedded image. */
483 read_uint32le(fd, &datalength);
484
485 /* Reset utf8 buffer */
486 utf8 = utf8buf;
487 utf8length = 512;
488
489 /* Gather the album art format, this string has a
490 * double zero-termination. */
491 asf_utf16LEdecode(fd, 32, &utf8, &utf8length);
492 strlength = (strlen(utf8buf) + 2) * 2;
493 lseek(fd, strlength-32, SEEK_CUR);
494 if (!strcmp("image/jpeg", utf8buf)) {
495 id3->albumart.type = AA_TYPE_JPG;
496 } else if (!strcmp("image/png", utf8buf)) {
497 id3->albumart.type = AA_TYPE_PNG;
498 } else {
499 id3->albumart.type = AA_TYPE_UNKNOWN;
500 }
501
502 /* Set the album art size and position. */
503 if (id3->albumart.type != AA_TYPE_UNKNOWN) {
504 id3->albumart.pos = lseek(fd, 0, SEEK_CUR);
505 id3->albumart.size = datalength;
506 id3->has_embedded_albumart = true;
507 }
508 }
509
510 lseek(fd, datalength, SEEK_CUR);
511#endif
512 } else {
513 lseek(fd, length, SEEK_CUR);
514 }
515 bytesleft -= 4 + length;
516 }
517
518 lseek(fd, bytesleft, SEEK_CUR);
519 } else if (asf_guid_match(&current.guid, &asf_guid_content_encryption)
520 || asf_guid_match(&current.guid, &asf_guid_extended_content_encryption)) {
521 //DEBUGF("File is encrypted\n");
522 return ASF_ERROR_ENCRYPTED;
523 } else {
524 //DEBUGF("Skipping %d bytes of object\n",(int)(current.size - 24));
525 lseek(fd,current.size - 24,SEEK_CUR);
526 }
527
528 //DEBUGF("Parsed object - size = %d\n",(int)current.size);
529 datalen -= current.size;
530 }
531
532 if (i != (int)subobjects || datalen != 0) {
533 //DEBUGF("header data doesn't match given subobject count\n");
534 return ASF_ERROR_INVALID_VALUE;
535 }
536
537 //DEBUGF("%d subobjects read successfully\n", i);
538 }
539
540#if 0
541 tmp = asf_parse_header_validate(file, &header);
542 if (tmp < 0) {
543 /* header read ok but doesn't validate correctly */
544 return tmp;
545 }
546#endif
547
548 //DEBUGF("header validated correctly\n");
549
550 return 0;
551}
552
553bool get_asf_metadata(int fd, struct mp3entry* id3)
554{
555 int res;
556 asf_object_t obj;
557 asf_waveformatex_t wfx;
558
559 wfx.audiostream = -1;
560
561 res = asf_parse_header(fd, id3, &wfx);
562
563 if (res < 0) {
564 DEBUGF("ASF: parsing error - %d\n",res);
565 return false;
566 }
567
568 if (wfx.audiostream == -1) {
569 DEBUGF("ASF: No WMA streams found\n");
570 return false;
571 }
572
573 asf_read_object_header(&obj, fd);
574
575 if (!asf_guid_match(&obj.guid, &asf_guid_data)) {
576 DEBUGF("ASF: No data object found\n");
577 return false;
578 }
579
580 /* Store the current file position - no need to parse the header
581 again in the codec. The +26 skips the rest of the data object
582 header.
583 */
584 id3->first_frame_offset = lseek(fd, 0, SEEK_CUR) + 26;
585 id3->filesize = filesize(fd);
586 /* We copy the wfx struct to the MP3 TOC field in the id3 struct so
587 the codec doesn't need to parse the header object again */
588 memcpy(id3->toc, &wfx, sizeof(wfx));
589
590 return true;
591}
diff --git a/apps/metadata/au.c b/apps/metadata/au.c
deleted file mode 100644
index 94e7453644..0000000000
--- a/apps/metadata/au.c
+++ /dev/null
@@ -1,105 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24
25#include "system.h"
26#include "metadata.h"
27#include "metadata_common.h"
28#include "metadata_parsers.h"
29#include "logf.h"
30
31static const unsigned char bitspersamples[9] = {
32 0, /* encoding */
33 8, /* 1: G.711 MULAW */
34 8, /* 2: Linear PCM 8bit */
35 16, /* 3: Linear PCM 16bit */
36 24, /* 4: Linear PCM 24bit */
37 32, /* 5: Linear PCM 32bit */
38 32, /* 6: IEEE float 32bit */
39 64, /* 7: IEEE float 64bit */
40 /* encoding 8 - 26 unsupported. */
41 8, /* 27: G.711 ALAW */
42};
43
44static inline unsigned char get_au_bitspersample(unsigned int encoding)
45{
46 if (encoding < 8)
47 return bitspersamples[encoding];
48 else if (encoding == 27)
49 return bitspersamples[8];
50
51 return 0;
52}
53
54bool get_au_metadata(int fd, struct mp3entry* id3)
55{
56 /* temporary buffer */
57 unsigned char* buf = (unsigned char *)id3->path;
58 unsigned long numbytes = 0;
59 int offset;
60
61 id3->vbr = false; /* All Sun audio files are CBR */
62 id3->filesize = filesize(fd);
63 id3->length = 0;
64
65 lseek(fd, 0, SEEK_SET);
66 if ((read(fd, buf, 24) < 24) || (memcmp(buf, ".snd", 4) != 0))
67 {
68 /*
69 * no header
70 *
71 * frequency: 8000 Hz
72 * bits per sample: 8 bit
73 * channel: mono
74 */
75 numbytes = id3->filesize;
76 id3->frequency = 8000;
77 id3->bitrate = 8;
78 }
79 else
80 {
81 /* parse header */
82
83 /* data offset */
84 offset = get_long_be(buf + 4);
85 if (offset < 24)
86 {
87 DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset);
88 return false;
89 }
90 /* data size */
91 numbytes = get_long_be(buf + 8);
92 if (numbytes == (uint32_t)0xffffffff)
93 numbytes = id3->filesize - offset;
94
95 id3->frequency = get_long_be(buf + 16);
96 id3->bitrate = get_au_bitspersample(get_long_be(buf + 12)) * get_long_be(buf + 20)
97 * id3->frequency / 1000;
98 }
99
100 /* Calculate track length [ms] */
101 if (id3->bitrate)
102 id3->length = (numbytes << 3) / id3->bitrate;
103
104 return true;
105}
diff --git a/apps/metadata/ay.c b/apps/metadata/ay.c
deleted file mode 100644
index 5d00264b3d..0000000000
--- a/apps/metadata/ay.c
+++ /dev/null
@@ -1,148 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Taken from blargg's Game_Music_Emu library */
14
15typedef unsigned char byte;
16
17/* AY file header */
18enum { header_size = 0x14 };
19struct header_t
20{
21 byte tag[8];
22 byte vers;
23 byte player;
24 byte unused[2];
25 byte author[2];
26 byte comment[2];
27 byte max_track;
28 byte first_track;
29 byte track_info[2];
30};
31
32struct file_t {
33 struct header_t const* header;
34 byte const* tracks;
35 byte const* end; /* end of file data */
36};
37
38static int get_be16( const void *a )
39{
40 return get_short_be( (void*) a );
41}
42
43/* Given pointer to 2-byte offset of data, returns pointer to data, or NULL if
44 * offset is 0 or there is less than min_size bytes of data available. */
45static byte const* get_data( struct file_t const* file, byte const ptr [], int min_size )
46{
47 int offset = (int16_t) get_be16( ptr );
48 int pos = ptr - (byte const*) file->header;
49 int size = file->end - (byte const*) file->header;
50 int limit = size - min_size;
51 if ( limit < 0 || !offset || (unsigned) (pos + offset) > (unsigned) limit )
52 return NULL;
53 return ptr + offset;
54}
55
56static const char *parse_header( byte const in [], int size, struct file_t* out )
57{
58 if ( size < header_size )
59 return "wrong file type";
60
61 out->header = (struct header_t const*) in;
62 out->end = in + size;
63 struct header_t const* h = (struct header_t const*) in;
64 if ( memcmp( h->tag, "ZXAYEMUL", 8 ) )
65 return "wrong file type";
66
67 out->tracks = get_data( out, h->track_info, (h->max_track + 1) * 4 );
68 if ( !out->tracks )
69 return "missing track data";
70
71 return 0;
72}
73
74static void copy_ay_fields( struct file_t const* file, struct mp3entry* id3, int track )
75{
76 int track_count = file->header->max_track + 1;
77
78 /* calculate track length based on number of subtracks */
79 if (track_count > 1) {
80 id3->length = file->header->max_track * 1000;
81 } else {
82 byte const* track_info = get_data( file, file->tracks + track * 4 + 2, 6 );
83 if (track_info)
84 id3->length = get_be16( track_info + 4 ) * (1000 / 50); /* frames to msec */
85 else id3->length = 120 * 1000;
86 }
87
88 if ( id3->length <= 0 )
89 id3->length = 120 * 1000; /* 2 minutes */
90
91 /* If meta info was found in the m3u skip next step */
92 if (id3->title && id3->title[0]) return;
93
94 /* If file has more than one track will
95 use file name as title */
96 char * tmp;
97 if (track_count <= 1) {
98 tmp = (char *) get_data( file, file->tracks + track * 4, 1 );
99 if ( tmp ) id3->title = tmp;
100 }
101
102 /* Author */
103 tmp = (char *) get_data( file, file->header->author, 1 );
104 if (tmp) id3->artist = tmp;
105
106 /* Comment */
107 tmp = (char *) get_data( file, file->header->comment, 1 );
108 if (tmp) id3->comment = tmp;
109}
110
111static bool parse_ay_header(int fd, struct mp3entry *id3)
112{
113 /* Use the trackname part of the id3 structure as a temporary buffer */
114 unsigned char* buf = (unsigned char *)id3->id3v2buf;
115 struct file_t file;
116 int read_bytes;
117
118 lseek(fd, 0, SEEK_SET);
119 if ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) < header_size)
120 return false;
121
122 buf [ID3V2_BUF_SIZE] = '\0';
123 if ( parse_header( buf, read_bytes, &file ) )
124 return false;
125
126 copy_ay_fields( &file, id3, 0 );
127 return true;
128}
129
130bool get_ay_metadata(int fd, struct mp3entry* id3)
131{
132 char ay_type[8];
133 if ((lseek(fd, 0, SEEK_SET) < 0) ||
134 read(fd, ay_type, 8) < 8)
135 return false;
136
137 id3->vbr = false;
138 id3->filesize = filesize(fd);
139
140 id3->bitrate = 706;
141 id3->frequency = 44100;
142
143 /* Make sure this is a ZX Ay file */
144 if (memcmp( ay_type, "ZXAYEMUL", 8 ) != 0)
145 return false;
146
147 return parse_ay_header(fd, id3);
148}
diff --git a/apps/metadata/flac.c b/apps/metadata/flac.c
deleted file mode 100644
index 29937173fd..0000000000
--- a/apps/metadata/flac.c
+++ /dev/null
@@ -1,127 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33bool get_flac_metadata(int fd, struct mp3entry* id3)
34{
35 /* A simple parser to read vital metadata from a FLAC file - length,
36 * frequency, bitrate etc. This code should either be moved to a
37 * seperate file, or discarded in favour of the libFLAC code.
38 * The FLAC stream specification can be found at
39 * http://flac.sourceforge.net/format.html#stream
40 */
41
42 /* Use the trackname part of the id3 structure as a temporary buffer */
43 unsigned char* buf = (unsigned char *)id3->path;
44 bool last_metadata = false;
45 bool rc = false;
46
47 if (!skip_id3v2(fd, id3) || (read(fd, buf, 4) < 4))
48 {
49 return rc;
50 }
51
52 if (memcmp(buf, "fLaC", 4) != 0)
53 {
54 return rc;
55 }
56
57 while (!last_metadata)
58 {
59 unsigned long i;
60 int type;
61
62 if (read(fd, buf, 4) < 0)
63 {
64 return rc;
65 }
66
67 last_metadata = buf[0] & 0x80;
68 type = buf[0] & 0x7f;
69 /* The length of the block */
70 i = (buf[1] << 16) | (buf[2] << 8) | buf[3];
71
72 if (type == 0) /* 0 is the STREAMINFO block */
73 {
74 unsigned long totalsamples;
75
76 if (i >= sizeof(id3->path) || read(fd, buf, i) < 0)
77 {
78 return rc;
79 }
80
81 id3->vbr = true; /* All FLAC files are VBR */
82 id3->filesize = filesize(fd);
83 id3->frequency = (buf[10] << 12) | (buf[11] << 4)
84 | ((buf[12] & 0xf0) >> 4);
85 rc = true; /* Got vital metadata */
86
87 /* totalsamples is a 36-bit field, but we assume <= 32 bits are used */
88 totalsamples = get_long_be(&buf[14]);
89
90 if(totalsamples > 0)
91 {
92 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */
93 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
94 id3->bitrate = (id3->filesize * 8) / id3->length;
95 }
96 else if (totalsamples == 0)
97 {
98 id3->length = 0;
99 id3->bitrate = 0;
100 }
101 else
102 {
103 logf("flac length invalid!");
104 return false;
105 }
106
107 }
108 else if (type == 4) /* 4 is the VORBIS_COMMENT block */
109 {
110 /* The next i bytes of the file contain the VORBIS COMMENTS. */
111 if (read_vorbis_tags(fd, id3, i) == 0)
112 {
113 return rc;
114 }
115 }
116 else if (!last_metadata)
117 {
118 /* Skip to next metadata block */
119 if (lseek(fd, i, SEEK_CUR) < 0)
120 {
121 return rc;
122 }
123 }
124 }
125
126 return true;
127}
diff --git a/apps/metadata/gbs.c b/apps/metadata/gbs.c
deleted file mode 100644
index 68f2b2a393..0000000000
--- a/apps/metadata/gbs.c
+++ /dev/null
@@ -1,65 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13static bool parse_gbs_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17 lseek(fd, 0, SEEK_SET);
18 if (read(fd, buf, 112) < 112)
19 return false;
20
21 /* Calculate track length with number of subtracks */
22 id3->length = buf[4] * 1000;
23
24 /* If meta info was found in the m3u skip next step */
25 if (id3->title && id3->title[0]) return true;
26
27 char *p = id3->id3v2buf;
28
29 /* Some metadata entries have 32 bytes length */
30 /* Game */
31 memcpy(p, &buf[16], 32); *(p + 33) = '\0';
32 id3->title = p;
33 p += strlen(p)+1;
34
35 /* Artist */
36 memcpy(p, &buf[48], 32); *(p + 33) = '\0';
37 id3->artist = p;
38 p += strlen(p)+1;
39
40 /* Copyright */
41 memcpy(p, &buf[80], 32); *(p + 33) = '\0';
42 id3->album = p;
43
44 return true;
45}
46
47bool get_gbs_metadata(int fd, struct mp3entry* id3)
48{
49 char gbs_type[3];
50 if ((lseek(fd, 0, SEEK_SET) < 0) ||
51 (read(fd, gbs_type, 3) < 3))
52 return false;
53
54 id3->vbr = false;
55 id3->filesize = filesize(fd);
56 /* we only render 16 bits, 44.1KHz, Stereo */
57 id3->bitrate = 706;
58 id3->frequency = 44100;
59
60 /* Check for GBS magic */
61 if (memcmp( gbs_type, "GBS", 3 ) != 0)
62 return false;
63
64 return parse_gbs_header(fd, id3);
65}
diff --git a/apps/metadata/hes.c b/apps/metadata/hes.c
deleted file mode 100644
index 6d99d523cb..0000000000
--- a/apps/metadata/hes.c
+++ /dev/null
@@ -1,39 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12#include "plugin.h"
13
14bool get_hes_metadata(int fd, struct mp3entry* id3)
15{
16 /* Use the id3v2 buffer part of the id3 structure as a temporary buffer */
17 unsigned char* buf = (unsigned char *)id3->id3v2buf;
18 int read_bytes;
19
20 if ((lseek(fd, 0, SEEK_SET) < 0)
21 || ((read_bytes = read(fd, buf, 4)) < 4))
22 return false;
23
24 /* Verify this is a HES file */
25 if (memcmp(buf,"HESM",4) != 0)
26 return false;
27
28 id3->vbr = false;
29 id3->filesize = filesize(fd);
30 /* we only render 16 bits, 44.1KHz, Stereo */
31 id3->bitrate = 706;
32 id3->frequency = 44100;
33
34 /* Set default track count (length)*/
35 id3->length = 255 * 1000;
36
37 return true;
38}
39
diff --git a/apps/metadata/id3tags.c b/apps/metadata/id3tags.c
deleted file mode 100644
index 2dd1c662ed..0000000000
--- a/apps/metadata/id3tags.c
+++ /dev/null
@@ -1,1199 +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/*
22 * Parts of this code has been stolen from the Ample project and was written
23 * by David H�deman. It has since been extended and enhanced pretty much by
24 * all sorts of friendly Rockbox people.
25 *
26 */
27
28 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <errno.h>
35#include <stdbool.h>
36#include <stddef.h>
37#include <ctype.h>
38#include "string-extra.h"
39#include "config.h"
40#include "file.h"
41#include "logf.h"
42#include "system.h"
43#include "replaygain.h"
44#include "rbunicode.h"
45
46#include "metadata.h"
47#include "mp3data.h"
48#if CONFIG_CODEC == SWCODEC
49#include "metadata_common.h"
50#endif
51#include "metadata_parsers.h"
52#include "misc.h"
53
54static unsigned long unsync(unsigned long b0,
55 unsigned long b1,
56 unsigned long b2,
57 unsigned long b3)
58{
59 return (((long)(b0 & 0x7F) << (3*7)) |
60 ((long)(b1 & 0x7F) << (2*7)) |
61 ((long)(b2 & 0x7F) << (1*7)) |
62 ((long)(b3 & 0x7F) << (0*7)));
63}
64
65static const char* const genres[] = {
66 "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge",
67 "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B",
68 "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
69 "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop",
70 "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
71 "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock",
72 "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
73 "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial",
74 "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
75 "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
76 "Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
77 "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz",
78 "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock",
79
80 /* winamp extensions */
81 "Folk", "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob",
82 "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock",
83 "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock",
84 "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
85 "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
86 "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
87 "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
88 "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
89 "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie",
90 "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap",
91 "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian",
92 "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "Jpop",
93 "Synthpop"
94};
95
96#if CONFIG_CODEC != SWCODEC
97static
98#endif
99char* id3_get_num_genre(unsigned int genre_num)
100{
101 if (genre_num < ARRAYLEN(genres))
102 return (char*)genres[genre_num];
103 return NULL;
104}
105
106/*
107 HOW TO ADD ADDITIONAL ID3 VERSION 2 TAGS
108 Code and comments by Thomas Paul Diffenbach
109
110 To add another ID3v2 Tag, do the following:
111 1. add a char* named for the tag to struct mp3entry in id3.h,
112 (I (tpd) prefer to use char* rather than ints, even for what seems like
113 numerical values, for cases where a number won't do, e.g.,
114 YEAR: "circa 1765", "1790/1977" (composed/performed), "28 Feb 1969"
115 TRACK: "1/12", "1 of 12", GENRE: "Freeform genre name"
116 Text is more flexible, and as the main use of id3 data is to
117 display it, converting it to an int just means reconverting to
118 display it, at a runtime cost.)
119
120 2. If any special processing beyond copying the tag value from the Id3
121 block to the struct mp3entry is rrequired (such as converting to an
122 int), write a function to perform this special processing.
123
124 This function's prototype must match that of
125 typedef tagPostProcessFunc, that is it must be:
126 int func( struct mp3entry*, char* tag, int bufferpos )
127 the first argument is a pointer to the current mp3entry structure the
128 second argument is a pointer to the null terminated string value of the
129 tag found the third argument is the offset of the next free byte in the
130 mp3entry's buffer your function should return the corrected offset; if
131 you don't lengthen or shorten the tag string, you can return the third
132 argument unchanged.
133
134 Unless you have a good reason no to, make the function static.
135 TO JUST COPY THE TAG NO SPECIAL PROCESSING FUNCTION IS NEEDED.
136
137 3. add one or more entries to the tagList array, using the format:
138 char* ID3 Tag symbolic name -- see the ID3 specification for these,
139 sizeof() that name minus 1,
140 offsetof( struct mp3entry, variable_name_in_struct_mp3entry ),
141 pointer to your special processing function or NULL
142 if you need no special processing
143 flag indicating if this tag is binary or textual
144 Many ID3 symbolic names come in more than one form. You can add both
145 forms, each referencing the same variable in struct mp3entry.
146 If both forms are present, the last found will be used.
147 Note that the offset can be zero, in which case no entry will be set
148 in the mp3entry struct; the frame is still read into the buffer and
149 the special processing function is called (several times, if there
150 are several frames with the same name).
151
152 4. Alternately, use the TAG_LIST_ENTRY macro with
153 ID3 tag symbolic name,
154 variable in struct mp3entry,
155 special processing function address
156
157 5. Add code to wps-display.c function get_tag to assign a printf-like
158 format specifier for the tag */
159
160/* Structure for ID3 Tag extraction information */
161struct tag_resolver {
162 const char* tag;
163 int tag_length;
164 size_t offset;
165 int (*ppFunc)(struct mp3entry*, char* tag, int bufferpos);
166 bool binary;
167};
168
169static bool global_ff_found;
170
171static int unsynchronize(char* tag, int len, bool *ff_found)
172{
173 int i;
174 unsigned char c;
175 unsigned char *rp, *wp;
176
177 wp = rp = (unsigned char *)tag;
178
179 rp = (unsigned char *)tag;
180 for(i = 0;i < len;i++) {
181 /* Read the next byte and write it back, but don't increment the
182 write pointer */
183 c = *rp++;
184 *wp = c;
185 if(*ff_found) {
186 /* Increment the write pointer if it isn't an unsynch pattern */
187 if(c != 0)
188 wp++;
189 *ff_found = false;
190 } else {
191 if(c == 0xff)
192 *ff_found = true;
193 wp++;
194 }
195 }
196 return (long)wp - (long)tag;
197}
198
199static int unsynchronize_frame(char* tag, int len)
200{
201 bool ff_found = false;
202
203 return unsynchronize(tag, len, &ff_found);
204}
205
206static int read_unsynched(int fd, void *buf, int len)
207{
208 int i;
209 int rc;
210 int remaining = len;
211 char *wp;
212 char *rp;
213
214 wp = buf;
215
216 while(remaining) {
217 rp = wp;
218 rc = read(fd, rp, remaining);
219 if(rc <= 0)
220 return rc;
221
222 i = unsynchronize(wp, remaining, &global_ff_found);
223 remaining -= i;
224 wp += i;
225 }
226
227 return len;
228}
229
230static int skip_unsynched(int fd, int len)
231{
232 int rc;
233 int remaining = len;
234 int rlen;
235 char buf[32];
236
237 while(remaining) {
238 rlen = MIN(sizeof(buf), (unsigned int)remaining);
239 rc = read(fd, buf, rlen);
240 if(rc <= 0)
241 return rc;
242
243 remaining -= unsynchronize(buf, rlen, &global_ff_found);
244 }
245
246 return len;
247}
248
249/* parse numeric value from string */
250static int parsetracknum( struct mp3entry* entry, char* tag, int bufferpos )
251{
252 entry->tracknum = atoi( tag );
253 return bufferpos;
254}
255
256/* parse numeric value from string */
257static int parsediscnum( struct mp3entry* entry, char* tag, int bufferpos )
258{
259 entry->discnum = atoi( tag );
260 return bufferpos;
261}
262
263/* parse numeric value from string */
264static int parseyearnum( struct mp3entry* entry, char* tag, int bufferpos )
265{
266 entry->year = atoi( tag );
267 return bufferpos;
268}
269
270/* parse numeric genre from string, version 2.2 and 2.3 */
271static int parsegenre( struct mp3entry* entry, char* tag, int bufferpos )
272{
273 /* Use bufferpos to hold current position in entry->id3v2buf. */
274 bufferpos = tag - entry->id3v2buf;
275
276 if(entry->id3version >= ID3_VER_2_4) {
277 /* In version 2.4 and up, there are no parentheses, and the genre frame
278 is a list of strings, either numbers or text. */
279
280 /* Is it a number? */
281 if(isdigit(tag[0])) {
282 entry->genre_string = id3_get_num_genre(atoi( tag ));
283 return bufferpos;
284 } else {
285 entry->genre_string = tag;
286 return bufferpos + strlen(tag) + 1;
287 }
288 } else {
289 if( tag[0] == '(' && tag[1] != '(' ) {
290 entry->genre_string = id3_get_num_genre(atoi( tag + 1 ));
291 return bufferpos;
292 }
293 else {
294 entry->genre_string = tag;
295 return bufferpos + strlen(tag) + 1;
296 }
297 }
298}
299
300#ifdef HAVE_ALBUMART
301/* parse embed albumart */
302static int parsealbumart( struct mp3entry* entry, char* tag, int bufferpos )
303{
304 entry->has_embedded_albumart = false;
305
306 /* we currently don't support unsynchronizing albumart */
307 if (entry->albumart.type == AA_TYPE_UNSYNC)
308 return bufferpos;
309
310 entry->albumart.type = AA_TYPE_UNKNOWN;
311
312 char *start = tag;
313 /* skip text encoding */
314 tag += 1;
315
316 if (memcmp(tag, "image/", 6) == 0)
317 {
318 /* ID3 v2.3+ */
319 tag += 6;
320 if (strcmp(tag, "jpeg") == 0)
321 {
322 entry->albumart.type = AA_TYPE_JPG;
323 tag += 5;
324 }
325 else if (strcmp(tag, "png") == 0)
326 {
327 entry->albumart.type = AA_TYPE_PNG;
328 tag += 4;
329 }
330 }
331 else
332 {
333 /* ID3 v2.2 */
334 if (memcmp(tag, "JPG", 3) == 0)
335 entry->albumart.type = AA_TYPE_JPG;
336 else if (memcmp(tag, "PNG", 3) == 0)
337 entry->albumart.type = AA_TYPE_PNG;
338 tag += 3;
339 }
340
341 if (entry->albumart.type != AA_TYPE_UNKNOWN)
342 {
343 /* skip picture type */
344 tag += 1;
345 /* skip description */
346 tag = strchr(tag, '\0') + 1;
347 /* fixup offset&size for image data */
348 entry->albumart.pos += tag - start;
349 entry->albumart.size -= tag - start;
350 entry->has_embedded_albumart = true;
351 }
352 /* return bufferpos as we didn't store anything in id3v2buf */
353 return bufferpos;
354}
355#endif
356
357/* parse user defined text, looking for album artist and replaygain
358 * information.
359 */
360static int parseuser( struct mp3entry* entry, char* tag, int bufferpos )
361{
362 char* value = NULL;
363 int desc_len = strlen(tag);
364 int length = 0;
365
366 if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos) {
367 /* At least part of the value was read, so we can safely try to
368 * parse it */
369 value = tag + desc_len + 1;
370
371 if (!strcasecmp(tag, "ALBUM ARTIST")) {
372 length = strlen(value) + 1;
373 strlcpy(tag, value, length);
374 entry->albumartist = tag;
375#if CONFIG_CODEC == SWCODEC
376 } else {
377 /* Call parse_replaygain(). */
378 parse_replaygain(tag, value, entry);
379#endif
380 }
381 }
382
383 return tag - entry->id3v2buf + length;
384}
385
386#if CONFIG_CODEC == SWCODEC
387/* parse RVA2 binary data and convert to replaygain information. */
388static int parserva2( struct mp3entry* entry, char* tag, int bufferpos)
389{
390 int desc_len = strlen(tag);
391 int start_pos = tag - entry->id3v2buf;
392 int end_pos = start_pos + desc_len + 5;
393 unsigned char* value = tag + desc_len + 1;
394
395 /* Only parse RVA2 replaygain tags if tag version == 2.4 and channel
396 * type is master volume.
397 */
398 if (entry->id3version == ID3_VER_2_4 && end_pos < bufferpos
399 && *value++ == 1) {
400 long gain = 0;
401 long peak = 0;
402 long peakbits;
403 long peakbytes;
404 bool album = false;
405
406 /* The RVA2 specification is unclear on some things (id string and
407 * peak volume), but this matches how Quod Libet use them.
408 */
409
410 gain = (int16_t) ((value[0] << 8) | value[1]);
411 value += 2;
412 peakbits = *value++;
413 peakbytes = (peakbits + 7) / 8;
414
415 /* Only use the topmost 24 bits for peak volume */
416 if (peakbytes > 3) {
417 peakbytes = 3;
418 }
419
420 /* Make sure the peak bits were read */
421 if (end_pos + peakbytes < bufferpos) {
422 long shift = ((8 - (peakbits & 7)) & 7) + (3 - peakbytes) * 8;
423
424 for ( ; peakbytes; peakbytes--) {
425 peak <<= 8;
426 peak += *value++;
427 }
428
429 peak <<= shift;
430
431 if (peakbits > 24) {
432 peak += *value >> (8 - shift);
433 }
434 }
435
436 if (strcasecmp(tag, "album") == 0) {
437 album = true;
438 } else if (strcasecmp(tag, "track") != 0) {
439 /* Only accept non-track values if we don't have any previous
440 * value.
441 */
442 if (entry->track_gain != 0) {
443 return start_pos;
444 }
445 }
446
447 parse_replaygain_int(album, gain, peak * 2, entry);
448 }
449
450 return start_pos;
451}
452#endif
453
454static int parsembtid( struct mp3entry* entry, char* tag, int bufferpos )
455{
456 char* value = NULL;
457 int desc_len = strlen(tag);
458 /*DEBUGF("MBID len: %d\n", desc_len);*/
459 /* Musicbrainz track IDs are always 36 chars long */
460 const size_t mbtid_len = 36;
461
462 if ((tag - entry->id3v2buf + desc_len + 2) < bufferpos)
463 {
464 value = tag + desc_len + 1;
465
466 if (strcasecmp(tag, "http://musicbrainz.org") == 0)
467 {
468 if (mbtid_len == strlen(value))
469 {
470 entry->mb_track_id = value;
471 return bufferpos + mbtid_len + 1;
472 }
473 }
474 }
475
476 return bufferpos;
477}
478
479static const struct tag_resolver taglist[] = {
480 { "TPE1", 4, offsetof(struct mp3entry, artist), NULL, false },
481 { "TP1", 3, offsetof(struct mp3entry, artist), NULL, false },
482 { "TIT2", 4, offsetof(struct mp3entry, title), NULL, false },
483 { "TT2", 3, offsetof(struct mp3entry, title), NULL, false },
484 { "TALB", 4, offsetof(struct mp3entry, album), NULL, false },
485 { "TAL", 3, offsetof(struct mp3entry, album), NULL, false },
486 { "TRK", 3, offsetof(struct mp3entry, track_string), &parsetracknum, false },
487 { "TPOS", 4, offsetof(struct mp3entry, disc_string), &parsediscnum, false },
488 { "TPA", 3, offsetof(struct mp3entry, disc_string), &parsediscnum, false },
489 { "TRCK", 4, offsetof(struct mp3entry, track_string), &parsetracknum, false },
490 { "TDRC", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false },
491 { "TYER", 4, offsetof(struct mp3entry, year_string), &parseyearnum, false },
492 { "TYE", 3, offsetof(struct mp3entry, year_string), &parseyearnum, false },
493 { "TCOM", 4, offsetof(struct mp3entry, composer), NULL, false },
494 { "TCM", 3, offsetof(struct mp3entry, composer), NULL, false },
495 { "TPE2", 4, offsetof(struct mp3entry, albumartist), NULL, false },
496 { "TP2", 3, offsetof(struct mp3entry, albumartist), NULL, false },
497 { "TIT1", 4, offsetof(struct mp3entry, grouping), NULL, false },
498 { "TT1", 3, offsetof(struct mp3entry, grouping), NULL, false },
499 { "COMM", 4, offsetof(struct mp3entry, comment), NULL, false },
500 { "COM", 3, offsetof(struct mp3entry, comment), NULL, false },
501 { "TCON", 4, offsetof(struct mp3entry, genre_string), &parsegenre, false },
502 { "TCO", 3, offsetof(struct mp3entry, genre_string), &parsegenre, false },
503#ifdef HAVE_ALBUMART
504 { "APIC", 4, 0, &parsealbumart, true },
505 { "PIC", 3, 0, &parsealbumart, true },
506#endif
507 { "TXXX", 4, 0, &parseuser, false },
508#if CONFIG_CODEC == SWCODEC
509 { "RVA2", 4, 0, &parserva2, true },
510#endif
511 { "UFID", 4, 0, &parsembtid, false },
512};
513
514#define TAGLIST_SIZE ((int)ARRAYLEN(taglist))
515
516/* Get the length of an ID3 string in the given encoding. Returns the length
517 * in bytes, including end nil, or -1 if the encoding is unknown.
518 */
519static int unicode_len(char encoding, const void* string)
520{
521 int len = 0;
522
523 if (encoding == 0x01 || encoding == 0x02) {
524 char first;
525 const char *s = string;
526 /* string might be unaligned, so using short* can crash on ARM and SH1 */
527 do {
528 first = *s++;
529 } while ((first | *s++) != 0);
530
531 len = s - (const char*) string;
532 } else {
533 len = strlen((char*) string) + 1;
534 }
535
536 return len;
537}
538
539/* Checks to see if the passed in string is a 16-bit wide Unicode v2
540 string. If it is, we convert it to a UTF-8 string. If it's not unicode,
541 we convert from the default codepage */
542static int unicode_munge(char* string, char* utf8buf, int *len) {
543 long tmp;
544 bool le = false;
545 int i = 0;
546 unsigned char *str = (unsigned char *)string;
547 int templen = 0;
548 unsigned char* utf8 = (unsigned char *)utf8buf;
549
550 switch (str[0]) {
551 case 0x00: /* Type 0x00 is ordinary ISO 8859-1 */
552 str++;
553 (*len)--;
554 utf8 = iso_decode(str, utf8, -1, *len);
555 *utf8 = 0;
556 *len = (unsigned long)utf8 - (unsigned long)utf8buf;
557 break;
558
559 case 0x01: /* Unicode with or without BOM */
560 case 0x02:
561 (*len)--;
562 str++;
563
564 /* Handle frames with more than one string
565 (needed for TXXX frames).*/
566 do {
567 tmp = bytes2int(0, 0, str[0], str[1]);
568
569 /* Now check if there is a BOM
570 (zero-width non-breaking space, 0xfeff)
571 and if it is in little or big endian format */
572 if(tmp == 0xfffe) { /* Little endian? */
573 le = true;
574 str += 2;
575 (*len)-=2;
576 } else if(tmp == 0xfeff) { /* Big endian? */
577 str += 2;
578 (*len)-=2;
579 } else
580 /* If there is no BOM (which is a specification violation),
581 let's try to guess it. If one of the bytes is 0x00, it is
582 probably the most significant one. */
583 if(str[1] == 0)
584 le = true;
585
586 while ((i < *len) && (str[0] || str[1])) {
587 if(le)
588 utf8 = utf16LEdecode(str, utf8, 1);
589 else
590 utf8 = utf16BEdecode(str, utf8, 1);
591
592 str+=2;
593 i += 2;
594 }
595
596 *utf8++ = 0; /* Terminate the string */
597 templen += (strlen(&utf8buf[templen]) + 1);
598 str += 2;
599 i+=2;
600 } while(i < *len);
601 *len = templen - 1;
602 break;
603
604 case 0x03: /* UTF-8 encoded string */
605 for(i=0; i < *len; i++)
606 utf8[i] = str[i+1];
607 (*len)--;
608 break;
609
610 default: /* Plain old string */
611 utf8 = iso_decode(str, utf8, -1, *len);
612 *utf8 = 0;
613 *len = (unsigned long)utf8 - (unsigned long)utf8buf;
614 break;
615 }
616 return 0;
617}
618
619/*
620 * Sets the title of an MP3 entry based on its ID3v1 tag.
621 *
622 * Arguments: file - the MP3 file to scen for a ID3v1 tag
623 * entry - the entry to set the title in
624 *
625 * Returns: true if a title was found and created, else false
626 */
627bool setid3v1title(int fd, struct mp3entry *entry)
628{
629 unsigned char buffer[128];
630 static const char offsets[] = {3, 33, 63, 97, 93, 125, 127};
631 int i, j;
632 unsigned char* utf8;
633
634 if (-1 == lseek(fd, -128, SEEK_END))
635 return false;
636
637 if (read(fd, buffer, sizeof buffer) != sizeof buffer)
638 return false;
639
640 if (strncmp((char *)buffer, "TAG", 3))
641 return false;
642
643 entry->id3v1len = 128;
644 entry->id3version = ID3_VER_1_0;
645
646 for (i=0; i < (int)sizeof offsets; i++) {
647 unsigned char* ptr = (unsigned char *)buffer + offsets[i];
648
649 switch(i) {
650 case 0:
651 case 1:
652 case 2:
653 /* kill trailing space in strings */
654 for (j=29; j && (ptr[j]==0 || ptr[j]==' '); j--)
655 ptr[j] = 0;
656 /* convert string to utf8 */
657 utf8 = (unsigned char *)entry->id3v1buf[i];
658 utf8 = iso_decode(ptr, utf8, -1, 30);
659 /* make sure string is terminated */
660 *utf8 = 0;
661 break;
662
663 case 3:
664 /* kill trailing space in strings */
665 for (j=27; j && (ptr[j]==0 || ptr[j]==' '); j--)
666 ptr[j] = 0;
667 /* convert string to utf8 */
668 utf8 = (unsigned char *)entry->id3v1buf[3];
669 utf8 = iso_decode(ptr, utf8, -1, 28);
670 /* make sure string is terminated */
671 *utf8 = 0;
672 break;
673
674 case 4:
675 ptr[4] = 0;
676 entry->year = atoi((char *)ptr);
677 break;
678
679 case 5:
680 /* id3v1.1 uses last two bytes of comment field for track
681 number: first must be 0 and second is track num */
682 if (!ptr[0] && ptr[1]) {
683 entry->tracknum = ptr[1];
684 entry->id3version = ID3_VER_1_1;
685 }
686 break;
687
688 case 6:
689 /* genre */
690 entry->genre_string = id3_get_num_genre(ptr[0]);
691 break;
692 }
693 }
694
695 entry->title = entry->id3v1buf[0];
696 entry->artist = entry->id3v1buf[1];
697 entry->album = entry->id3v1buf[2];
698 entry->comment = entry->id3v1buf[3];
699
700 return true;
701}
702
703
704/*
705 * Sets the title of an MP3 entry based on its ID3v2 tag.
706 *
707 * Arguments: file - the MP3 file to scan for a ID3v2 tag
708 * entry - the entry to set the title in
709 *
710 * Returns: true if a title was found and created, else false
711 */
712void setid3v2title(int fd, struct mp3entry *entry)
713{
714 int minframesize;
715 int size;
716 long bufferpos = 0, totframelen, framelen;
717 char header[10];
718 char tmp[4];
719 unsigned char version;
720 char *buffer = entry->id3v2buf;
721 int bytesread = 0;
722 int buffersize = sizeof(entry->id3v2buf);
723 unsigned char global_flags;
724 int flags;
725 bool global_unsynch = false;
726 bool unsynch = false;
727 int i, j;
728 int rc;
729#if CONFIG_CODEC == SWCODEC
730 bool itunes_gapless = false;
731#endif
732
733 global_ff_found = false;
734
735 /* Bail out if the tag is shorter than 10 bytes */
736 if(entry->id3v2len < 10)
737 return;
738
739 /* Read the ID3 tag version from the header */
740 lseek(fd, 0, SEEK_SET);
741 if(10 != read(fd, header, 10))
742 return;
743
744 /* Get the total ID3 tag size */
745 size = entry->id3v2len - 10;
746
747 version = header[3];
748 switch ( version ) {
749 case 2:
750 version = ID3_VER_2_2;
751 minframesize = 8;
752 break;
753
754 case 3:
755 version = ID3_VER_2_3;
756 minframesize = 12;
757 break;
758
759 case 4:
760 version = ID3_VER_2_4;
761 minframesize = 12;
762 break;
763
764 default:
765 /* unsupported id3 version */
766 return;
767 }
768 entry->id3version = version;
769 entry->tracknum = entry->year = entry->discnum = 0;
770 entry->title = entry->artist = entry->album = NULL; /* FIXME incomplete */
771
772 global_flags = header[5];
773
774 /* Skip the extended header if it is present */
775 if(global_flags & 0x40) {
776 if(version == ID3_VER_2_3) {
777 if(10 != read(fd, header, 10))
778 return;
779 /* The 2.3 extended header size doesn't include the header size
780 field itself. Also, it is not unsynched. */
781 framelen =
782 bytes2int(header[0], header[1], header[2], header[3]) + 4;
783
784 /* Skip the rest of the header */
785 lseek(fd, framelen - 10, SEEK_CUR);
786 }
787
788 if(version >= ID3_VER_2_4) {
789 if(4 != read(fd, header, 4))
790 return;
791
792 /* The 2.4 extended header size does include the entire header,
793 so here we can just skip it. This header is unsynched. */
794 framelen = unsync(header[0], header[1],
795 header[2], header[3]);
796
797 lseek(fd, framelen - 4, SEEK_CUR);
798 }
799 }
800
801 /* Is unsynchronization applied? */
802 if(global_flags & 0x80) {
803 global_unsynch = true;
804 }
805
806 /*
807 * We must have at least minframesize bytes left for the
808 * remaining frames to be interesting
809 */
810 while (size >= minframesize && bufferpos < buffersize - 1) {
811 flags = 0;
812
813 /* Read frame header and check length */
814 if(version >= ID3_VER_2_3) {
815 if(global_unsynch && version <= ID3_VER_2_3)
816 rc = read_unsynched(fd, header, 10);
817 else
818 rc = read(fd, header, 10);
819 if(rc != 10)
820 return;
821 /* Adjust for the 10 bytes we read */
822 size -= 10;
823
824 flags = bytes2int(0, 0, header[8], header[9]);
825
826 if (version >= ID3_VER_2_4) {
827 framelen = unsync(header[4], header[5],
828 header[6], header[7]);
829 } else {
830 /* version .3 files don't use synchsafe ints for
831 * size */
832 framelen = bytes2int(header[4], header[5],
833 header[6], header[7]);
834 }
835 } else {
836 if(6 != read(fd, header, 6))
837 return;
838 /* Adjust for the 6 bytes we read */
839 size -= 6;
840
841 framelen = bytes2int(0, header[3], header[4], header[5]);
842 }
843
844 logf("framelen = %ld, flags = 0x%04x", framelen, flags);
845 if(framelen == 0){
846 if (header[0] == 0 && header[1] == 0 && header[2] == 0)
847 return;
848 else
849 continue;
850 }
851
852 unsynch = false;
853
854 if(flags)
855 {
856 if (version >= ID3_VER_2_4) {
857 if(flags & 0x0040) { /* Grouping identity */
858 lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
859 framelen--;
860 }
861 } else {
862 if(flags & 0x0020) { /* Grouping identity */
863 lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
864 framelen--;
865 }
866 }
867
868 if(flags & 0x000c) /* Compression or encryption */
869 {
870 /* Skip it */
871 size -= framelen;
872 lseek(fd, framelen, SEEK_CUR);
873 continue;
874 }
875
876 if(flags & 0x0002) /* Unsynchronization */
877 unsynch = true;
878
879 if (version >= ID3_VER_2_4) {
880 if(flags & 0x0001) { /* Data length indicator */
881 if(4 != read(fd, tmp, 4))
882 return;
883
884 /* We don't need the data length */
885 framelen -= 4;
886 }
887 }
888 }
889
890 if (framelen == 0)
891 continue;
892
893 if (framelen < 0)
894 return;
895
896 /* Keep track of the remaining frame size */
897 totframelen = framelen;
898
899 /* If the frame is larger than the remaining buffer space we try
900 to read as much as would fit in the buffer */
901 if(framelen >= buffersize - bufferpos)
902 framelen = buffersize - bufferpos - 1;
903
904 /* Limit the maximum length of an id3 data item to ID3V2_MAX_ITEM_SIZE
905 bytes. This reduces the chance that the available buffer is filled
906 by single metadata items like large comments. */
907 if (ID3V2_MAX_ITEM_SIZE < framelen)
908 framelen = ID3V2_MAX_ITEM_SIZE;
909
910 logf("id3v2 frame: %.4s", header);
911
912 /* Check for certain frame headers
913
914 'size' is the amount of frame bytes remaining. We decrement it by
915 the amount of bytes we read. If we fail to read as many bytes as
916 we expect, we assume that we can't read from this file, and bail
917 out.
918
919 For each frame. we will iterate over the list of supported tags,
920 and read the tag into entry's buffer. All tags will be kept as
921 strings, for cases where a number won't do, e.g., YEAR: "circa
922 1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK:
923 "1/12", "1 of 12", GENRE: "Freeform genre name" Text is more
924 flexible, and as the main use of id3 data is to display it,
925 converting it to an int just means reconverting to display it, at a
926 runtime cost.
927
928 For tags that the current code does convert to ints, a post
929 processing function will be called via a pointer to function. */
930
931 for (i=0; i<TAGLIST_SIZE; i++) {
932 const struct tag_resolver* tr = &taglist[i];
933 char** ptag = tr->offset ? (char**) (((char*)entry) + tr->offset)
934 : NULL;
935 char* tag;
936
937 /* Only ID3_VER_2_2 uses frames with three-character names. */
938 if (((version == ID3_VER_2_2) && (tr->tag_length != 3))
939 || ((version > ID3_VER_2_2) && (tr->tag_length != 4))) {
940 continue;
941 }
942
943 if( !memcmp( header, tr->tag, tr->tag_length ) ) {
944
945 /* found a tag matching one in tagList, and not yet filled */
946 tag = buffer + bufferpos;
947
948 if(global_unsynch && version <= ID3_VER_2_3)
949 bytesread = read_unsynched(fd, tag, framelen);
950 else
951 bytesread = read(fd, tag, framelen);
952
953 if( bytesread != framelen )
954 return;
955
956 size -= bytesread;
957
958 if(unsynch || (global_unsynch && version >= ID3_VER_2_4))
959 bytesread = unsynchronize_frame(tag, bytesread);
960
961 /* the COMM frame has a 3 char field to hold an ISO-639-1
962 * language string and an optional short description;
963 * remove them so unicode_munge can work correctly
964 */
965
966 if((tr->tag_length == 4 && !memcmp( header, "COMM", 4)) ||
967 (tr->tag_length == 3 && !memcmp( header, "COM", 3))) {
968 int offset;
969 if(bytesread >= 8 && !strncmp(tag+4, "iTun", 4)) {
970#if CONFIG_CODEC == SWCODEC
971 /* check for iTunes gapless information */
972 if(bytesread >= 12 && !strncmp(tag+4, "iTunSMPB", 8))
973 itunes_gapless = true;
974 else
975#endif
976 /* ignore other with iTunes tags */
977 break;
978 }
979
980 offset = 3 + unicode_len(*tag, tag + 4);
981 if(bytesread > offset) {
982 bytesread -= offset;
983 memmove(tag + 1, tag + 1 + offset, bytesread - 1);
984 }
985 }
986
987 /* Attempt to parse Unicode string only if the tag contents
988 aren't binary */
989 if(!tr->binary) {
990 /* UTF-8 could potentially be 3 times larger */
991 /* so we need to create a new buffer */
992 char utf8buf[(3 * bytesread) + 1];
993
994 unicode_munge( tag, utf8buf, &bytesread );
995
996 if(bytesread >= buffersize - bufferpos)
997 bytesread = buffersize - bufferpos - 1;
998
999 if ( /* Is it an embedded cuesheet? */
1000 (tr->tag_length == 4 && !memcmp(header, "TXXX", 4)) &&
1001 (bytesread >= 14 && !strncmp(utf8buf, "CUESHEET", 8))
1002 ) {
1003 unsigned char char_enc = 0;
1004 /* [enc type]+"CUESHEET\0" = 10 */
1005 unsigned char cuesheet_offset = 10;
1006 switch (tag[0]) {
1007 case 0x00:
1008 char_enc = CHAR_ENC_ISO_8859_1;
1009 break;
1010 case 0x01:
1011 tag++;
1012 if (!memcmp(tag,
1013 BOM_UTF_16_BE, BOM_UTF_16_SIZE)) {
1014 char_enc = CHAR_ENC_UTF_16_BE;
1015 } else if (!memcmp(tag,
1016 BOM_UTF_16_LE, BOM_UTF_16_SIZE)) {
1017 char_enc = CHAR_ENC_UTF_16_LE;
1018 }
1019 /* \1 + BOM(2) + C0U0E0S0H0E0E0T000 = 21 */
1020 cuesheet_offset = 21;
1021 break;
1022 case 0x02:
1023 char_enc = CHAR_ENC_UTF_16_BE;
1024 /* \2 + 0C0U0E0S0H0E0E0T00 = 19 */
1025 cuesheet_offset = 19;
1026 break;
1027 case 0x03:
1028 char_enc = CHAR_ENC_UTF_8;
1029 break;
1030 }
1031 if (char_enc > 0) {
1032 entry->has_embedded_cuesheet = true;
1033 entry->embedded_cuesheet.pos = lseek(fd, 0, SEEK_CUR)
1034 - framelen + cuesheet_offset;
1035 entry->embedded_cuesheet.size = totframelen
1036 - cuesheet_offset;
1037 entry->embedded_cuesheet.encoding = char_enc;
1038 }
1039 break;
1040 }
1041
1042 for (j = 0; j < bytesread; j++)
1043 tag[j] = utf8buf[j];
1044
1045 /* remove trailing spaces */
1046 while ( bytesread > 0 && isspace(tag[bytesread-1]))
1047 bytesread--;
1048 }
1049
1050 if(bytesread == 0)
1051 /* Skip empty frames */
1052 break;
1053
1054 tag[bytesread] = 0;
1055 bufferpos += bytesread + 1;
1056
1057#if CONFIG_CODEC == SWCODEC
1058 /* parse the tag if it contains iTunes gapless info */
1059 if (itunes_gapless)
1060 {
1061 itunes_gapless = false;
1062 entry->lead_trim = get_itunes_int32(tag, 1);
1063 entry->tail_trim = get_itunes_int32(tag, 2);
1064 }
1065#endif
1066
1067 /* Note that parser functions sometimes set *ptag to NULL, so
1068 * the "!*ptag" check here doesn't always have the desired
1069 * effect. Should the parser functions (parsegenre in
1070 * particular) be updated to handle the case of being called
1071 * multiple times, or should the "*ptag" check be removed?
1072 */
1073 if (ptag && !*ptag)
1074 *ptag = tag;
1075
1076#ifdef HAVE_ALBUMART
1077 /* albumart */
1078 if ((!entry->has_embedded_albumart) &&
1079 ((tr->tag_length == 4 && !memcmp( header, "APIC", 4)) ||
1080 (tr->tag_length == 3 && !memcmp( header, "PIC" , 3))))
1081 {
1082 if (unsynch || (global_unsynch && version <= ID3_VER_2_3))
1083 entry->albumart.type = AA_TYPE_UNSYNC;
1084 else
1085 {
1086 entry->albumart.pos = lseek(fd, 0, SEEK_CUR) - framelen;
1087 entry->albumart.size = totframelen;
1088 entry->albumart.type = AA_TYPE_UNKNOWN;
1089 }
1090 }
1091#endif
1092 if( tr->ppFunc )
1093 bufferpos = tr->ppFunc(entry, tag, bufferpos);
1094 break;
1095 }
1096 }
1097
1098 if( i == TAGLIST_SIZE ) {
1099 /* no tag in tagList was found, or it was a repeat.
1100 skip it using the total size */
1101
1102 if(global_unsynch && version <= ID3_VER_2_3) {
1103 size -= skip_unsynched(fd, totframelen);
1104 } else {
1105 size -= totframelen;
1106 if( lseek(fd, totframelen, SEEK_CUR) == -1 )
1107 return;
1108 }
1109 } else {
1110 /* Seek to the next frame */
1111 if(framelen < totframelen)
1112 lseek(fd, totframelen - framelen, SEEK_CUR);
1113 }
1114 }
1115}
1116
1117/*
1118 * Calculates the size of the ID3v2 tag.
1119 *
1120 * Arguments: file - the file to search for a tag.
1121 *
1122 * Returns: the size of the tag or 0 if none was found
1123 */
1124int getid3v2len(int fd)
1125{
1126 char buf[6];
1127 int offset;
1128
1129 /* Make sure file has a ID3 tag */
1130 if((-1 == lseek(fd, 0, SEEK_SET)) ||
1131 (read(fd, buf, 6) != 6) ||
1132 (strncmp(buf, "ID3", strlen("ID3")) != 0))
1133 offset = 0;
1134
1135 /* Now check what the ID3v2 size field says */
1136 else
1137 if(read(fd, buf, 4) != 4)
1138 offset = 0;
1139 else
1140 offset = unsync(buf[0], buf[1], buf[2], buf[3]) + 10;
1141
1142 logf("ID3V2 Length: 0x%x", offset);
1143 return offset;
1144}
1145
1146#ifdef DEBUG_STANDALONE
1147
1148char *secs2str(int ms)
1149{
1150 static char buffer[32];
1151 int secs = ms/1000;
1152 ms %= 1000;
1153 snprintf(buffer, sizeof(buffer), "%d:%02d.%d", secs/60, secs%60, ms/100);
1154 return buffer;
1155}
1156
1157int main(int argc, char **argv)
1158{
1159 int i;
1160 for(i=1; i<argc; i++) {
1161 struct mp3entry mp3;
1162 mp3.album = "Bogus";
1163 if(mp3info(&mp3, argv[i], false)) {
1164 printf("Failed to get %s\n", argv[i]);
1165 return 0;
1166 }
1167
1168 printf("****** File: %s\n"
1169 " Title: %s\n"
1170 " Artist: %s\n"
1171 " Album: %s\n"
1172 " Genre: %s (%d) \n"
1173 " Composer: %s\n"
1174 " Year: %s (%d)\n"
1175 " Track: %s (%d)\n"
1176 " Length: %s / %d s\n"
1177 " Bitrate: %d\n"
1178 " Frequency: %d\n",
1179 argv[i],
1180 mp3.title?mp3.title:"<blank>",
1181 mp3.artist?mp3.artist:"<blank>",
1182 mp3.album?mp3.album:"<blank>",
1183 mp3.genre_string?mp3.genre_string:"<blank>",
1184 mp3.genre,
1185 mp3.composer?mp3.composer:"<blank>",
1186 mp3.year_string?mp3.year_string:"<blank>",
1187 mp3.year,
1188 mp3.track_string?mp3.track_string:"<blank>",
1189 mp3.tracknum,
1190 secs2str(mp3.length),
1191 mp3.length/1000,
1192 mp3.bitrate,
1193 mp3.frequency);
1194 }
1195
1196 return 0;
1197}
1198
1199#endif
diff --git a/apps/metadata/kss.c b/apps/metadata/kss.c
deleted file mode 100644
index 2ae0cf50b0..0000000000
--- a/apps/metadata/kss.c
+++ /dev/null
@@ -1,53 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13static bool parse_kss_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17
18 lseek(fd, 0, SEEK_SET);
19 if (read(fd, buf, 0x20) < 0x20)
20 return false;
21
22 /* calculate track length with number of tracks */
23 id3->length = 0;
24 if (buf[14] == 0x10) {
25 id3->length = (get_short_le((void *)(buf + 26)) + 1) * 1000;
26 }
27
28 if (id3->length <= 0)
29 id3->length = 255 * 1000; /* 255 tracks */
30
31 return true;
32}
33
34
35bool get_kss_metadata(int fd, struct mp3entry* id3)
36{
37 uint32_t kss_type;
38 if ((lseek(fd, 0, SEEK_SET) < 0) ||
39 read_uint32be(fd, &kss_type) != (int)sizeof(kss_type))
40 return false;
41
42 id3->vbr = false;
43 id3->filesize = filesize(fd);
44 /* we only render 16 bits, 44.1KHz, Stereo */
45 id3->bitrate = 706;
46 id3->frequency = 44100;
47
48 /* Make sure this is an SGC file */
49 if (kss_type != FOURCC('K','S','C','C') && kss_type != FOURCC('K','S','S','X'))
50 return false;
51
52 return parse_kss_header(fd, id3);
53}
diff --git a/apps/metadata/metadata_common.c b/apps/metadata/metadata_common.c
deleted file mode 100644
index e861644025..0000000000
--- a/apps/metadata/metadata_common.c
+++ /dev/null
@@ -1,374 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include "string-extra.h"
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "replaygain.h"
32
33/* Read a string from the file. Read up to size bytes, or, if eos != -1,
34 * until the eos character is found (eos is not stored in buf, unless it is
35 * nil). Writes up to buf_size chars to buf, always terminating with a nil.
36 * Returns number of chars read or -1 on read error.
37 */
38long read_string(int fd, char* buf, long buf_size, int eos, long size)
39{
40 long read_bytes = 0;
41 char c;
42
43 while (size != 0)
44 {
45 if (read(fd, &c, 1) != 1)
46 {
47 read_bytes = -1;
48 break;
49 }
50
51 read_bytes++;
52 size--;
53
54 if ((eos != -1) && (eos == (unsigned char) c))
55 {
56 break;
57 }
58
59 if (buf_size > 1)
60 {
61 *buf++ = c;
62 buf_size--;
63 }
64 }
65
66 *buf = 0;
67 return read_bytes;
68}
69/* Read an unsigned 8-bit integer from a file. */
70int read_uint8(int fd, uint8_t* buf)
71{
72 size_t n;
73
74 n = read(fd, (char*) buf, 1);
75 return n;
76}
77
78#ifdef ROCKBOX_LITTLE_ENDIAN
79/* Read an unsigned 16-bit integer from a big-endian file. */
80int read_uint16be(int fd, uint16_t* buf)
81{
82 size_t n;
83
84 n = read(fd, (char*) buf, 2);
85 *buf = betoh16(*buf);
86 return n;
87}
88/* Read an unsigned 32-bit integer from a big-endian file. */
89int read_uint32be(int fd, uint32_t* buf)
90{
91 size_t n;
92
93 n = read(fd, (char*) buf, 4);
94 *buf = betoh32(*buf);
95 return n;
96}
97/* Read an unsigned 64-bit integer from a big-endian file. */
98int read_uint64be(int fd, uint64_t* buf)
99{
100 size_t n;
101 uint8_t data[8];
102 int i;
103
104 n = read(fd, data, 8);
105
106 for (i=0, *buf=0; i<=7; i++) {
107 *buf <<= 8;
108 *buf |= data[i];
109 }
110 return n;
111}
112#else
113/* Read unsigned integers from a little-endian file. */
114int read_uint16le(int fd, uint16_t* buf)
115{
116 size_t n;
117
118 n = read(fd, (char*) buf, 2);
119 *buf = letoh16(*buf);
120 return n;
121}
122int read_uint32le(int fd, uint32_t* buf)
123{
124 size_t n;
125
126 n = read(fd, (char*) buf, 4);
127 *buf = letoh32(*buf);
128 return n;
129}
130int read_uint64le(int fd, uint64_t* buf)
131{
132 size_t n;
133 uint8_t data[8];
134 int i;
135
136 n = read(fd, data, 8);
137
138 for (i=7, *buf=0; i>=0; i--) {
139 *buf <<= 8;
140 *buf |= data[i];
141 }
142
143 return n;
144}
145#endif
146
147/* Read an unaligned 64-bit little endian unsigned integer from buffer. */
148uint64_t get_uint64_le(void* buf)
149{
150 unsigned char* p = (unsigned char*) buf;
151
152 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24) | ((uint64_t)p[4] << 32) |
153 ((uint64_t)p[5] << 40) | ((uint64_t)p[6] << 48) | ((uint64_t)p[7] << 56);
154}
155
156/* Read an unaligned 32-bit little endian long from buffer. */
157uint32_t get_long_le(void* buf)
158{
159 unsigned char* p = (unsigned char*) buf;
160
161 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
162}
163
164/* Read an unaligned 16-bit little endian short from buffer. */
165uint16_t get_short_le(void* buf)
166{
167 unsigned char* p = (unsigned char*) buf;
168
169 return p[0] | (p[1] << 8);
170}
171
172/* Read an unaligned 32-bit big endian long from buffer. */
173uint32_t get_long_be(void* buf)
174{
175 unsigned char* p = (unsigned char*) buf;
176
177 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
178}
179
180/* Read an unaligned 16-bit little endian short from buffer. */
181uint16_t get_short_be(void* buf)
182{
183 unsigned char* p = (unsigned char*) buf;
184
185 return (p[0] << 8) | p[1];
186}
187
188/* Read an unaligned 32-bit little endian long from buffer. */
189int32_t get_slong(void* buf)
190{
191 unsigned char* p = (unsigned char*) buf;
192
193 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
194}
195
196uint32_t get_itunes_int32(char* value, int count)
197{
198 static const char hexdigits[] = "0123456789ABCDEF";
199 const char* c;
200 int r = 0;
201
202 while (count-- > 0)
203 {
204 while (isspace(*value))
205 {
206 value++;
207 }
208
209 while (*value && !isspace(*value))
210 {
211 value++;
212 }
213 }
214
215 while (isspace(*value))
216 {
217 value++;
218 }
219
220 while (*value && ((c = strchr(hexdigits, toupper(*value))) != NULL))
221 {
222 r = (r << 4) | (c - hexdigits);
223 value++;
224 }
225
226 return r;
227}
228
229/* Skip an ID3v2 tag if it can be found. We assume the tag is located at the
230 * start of the file, which should be true in all cases where we need to skip it.
231 * Returns true if successfully skipped or not skipped, and false if
232 * something went wrong while skipping.
233 */
234bool skip_id3v2(int fd, struct mp3entry *id3)
235{
236 char buf[4];
237
238 read(fd, buf, 4);
239 if (memcmp(buf, "ID3", 3) == 0)
240 {
241 /* We have found an ID3v2 tag at the start of the file - find its
242 length and then skip it. */
243 if ((id3->first_frame_offset = getid3v2len(fd)) == 0)
244 return false;
245
246 if ((lseek(fd, id3->first_frame_offset, SEEK_SET) < 0))
247 return false;
248
249 return true;
250 } else {
251 lseek(fd, 0, SEEK_SET);
252 id3->first_frame_offset = 0;
253 return true;
254 }
255}
256
257/* Parse the tag (the name-value pair) and fill id3 and buffer accordingly.
258 * String values to keep are written to buf. Returns number of bytes written
259 * to buf (including end nil).
260 */
261long parse_tag(const char* name, char* value, struct mp3entry* id3,
262 char* buf, long buf_remaining, enum tagtype type)
263{
264 long len = 0;
265 char** p;
266
267 if ((((strcasecmp(name, "track") == 0) && (type == TAGTYPE_APE)))
268 || ((strcasecmp(name, "tracknumber") == 0) && (type == TAGTYPE_VORBIS)))
269 {
270 id3->tracknum = atoi(value);
271 p = &(id3->track_string);
272 }
273 else if (strcasecmp(name, "discnumber") == 0 || strcasecmp(name, "disc") == 0)
274 {
275 id3->discnum = atoi(value);
276 p = &(id3->disc_string);
277 }
278 else if (((strcasecmp(name, "year") == 0) && (type == TAGTYPE_APE))
279 || ((strcasecmp(name, "date") == 0) && (type == TAGTYPE_VORBIS)))
280 {
281 /* Date's can be in any format in Vorbis. However most of them
282 * are in ISO8601 format so if we try and parse the first part
283 * of the tag as a number, we should get the year. If we get crap,
284 * then act like we never parsed it.
285 */
286 id3->year = atoi(value);
287 if (id3->year < 1900)
288 { /* yeah, not likely */
289 id3->year = 0;
290 }
291 p = &(id3->year_string);
292 }
293 else if (strcasecmp(name, "title") == 0)
294 {
295 p = &(id3->title);
296 }
297 else if (strcasecmp(name, "artist") == 0)
298 {
299 p = &(id3->artist);
300 }
301 else if (strcasecmp(name, "album") == 0)
302 {
303 p = &(id3->album);
304 }
305 else if (strcasecmp(name, "genre") == 0)
306 {
307 p = &(id3->genre_string);
308 }
309 else if (strcasecmp(name, "composer") == 0)
310 {
311 p = &(id3->composer);
312 }
313 else if (strcasecmp(name, "comment") == 0)
314 {
315 p = &(id3->comment);
316 }
317 else if (strcasecmp(name, "albumartist") == 0)
318 {
319 p = &(id3->albumartist);
320 }
321 else if (strcasecmp(name, "album artist") == 0)
322 {
323 p = &(id3->albumartist);
324 }
325 else if (strcasecmp(name, "ensemble") == 0)
326 {
327 p = &(id3->albumartist);
328 }
329 else if (strcasecmp(name, "grouping") == 0)
330 {
331 p = &(id3->grouping);
332 }
333 else if (strcasecmp(name, "content group") == 0)
334 {
335 p = &(id3->grouping);
336 }
337 else if (strcasecmp(name, "contentgroup") == 0)
338 {
339 p = &(id3->grouping);
340 }
341 else if (strcasecmp(name, "musicbrainz_trackid") == 0
342 || strcasecmp(name, "http://musicbrainz.org") == 0 )
343 {
344 p = &(id3->mb_track_id);
345 }
346 else
347 {
348 parse_replaygain(name, value, id3);
349 p = NULL;
350 }
351
352 /* Do not overwrite already available metadata. Especially when reading
353 * tags with e.g. multiple genres / artists. This way only the first
354 * of multiple entries is used, all following are dropped. */
355 if (p!=NULL && *p==NULL)
356 {
357 len = strlen(value);
358 len = MIN(len, buf_remaining - 1);
359 len = MIN(len, ID3V2_MAX_ITEM_SIZE); /* Limit max. item size. */
360
361 if (len > 0)
362 {
363 len++;
364 strlcpy(buf, value, len);
365 *p = buf;
366 }
367 else
368 {
369 len = 0;
370 }
371 }
372
373 return len;
374}
diff --git a/apps/metadata/metadata_common.h b/apps/metadata/metadata_common.h
deleted file mode 100644
index db91729de4..0000000000
--- a/apps/metadata/metadata_common.h
+++ /dev/null
@@ -1,69 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <inttypes.h>
22#include "metadata.h"
23
24#ifdef ROCKBOX_BIG_ENDIAN
25#define IS_BIG_ENDIAN 1
26#else
27#define IS_BIG_ENDIAN 0
28#endif
29
30#define TAG_NAME_LENGTH 32
31#define TAG_VALUE_LENGTH 128
32
33#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d))
34
35enum tagtype { TAGTYPE_APE = 1, TAGTYPE_VORBIS };
36
37bool read_ape_tags(int fd, struct mp3entry* id3);
38long read_vorbis_tags(int fd, struct mp3entry *id3,
39 long tag_remaining);
40
41bool skip_id3v2(int fd, struct mp3entry *id3);
42long read_string(int fd, char* buf, long buf_size, int eos, long size);
43
44int read_uint8(int fd, uint8_t* buf);
45#ifdef ROCKBOX_BIG_ENDIAN
46#define read_uint16be(fd,buf) read((fd), (buf), 2)
47#define read_uint32be(fd,buf) read((fd), (buf), 4)
48#define read_uint64be(fd,buf) read((fd), (buf), 8)
49int read_uint16le(int fd, uint16_t* buf);
50int read_uint32le(int fd, uint32_t* buf);
51int read_uint64le(int fd, uint64_t* buf);
52#else
53int read_uint16be(int fd, uint16_t* buf);
54int read_uint32be(int fd, uint32_t* buf);
55int read_uint64be(int fd, uint64_t* buf);
56#define read_uint16le(fd,buf) read((fd), (buf), 2)
57#define read_uint32le(fd,buf) read((fd), (buf), 4)
58#define read_uint64le(fd,buf) read((fd), (buf), 8)
59#endif
60
61uint64_t get_uint64_le(void* buf);
62uint32_t get_long_le(void* buf);
63uint16_t get_short_le(void* buf);
64uint32_t get_long_be(void* buf);
65uint16_t get_short_be(void* buf);
66int32_t get_slong(void* buf);
67uint32_t get_itunes_int32(char* value, int count);
68long parse_tag(const char* name, char* value, struct mp3entry* id3,
69 char* buf, long buf_remaining, enum tagtype type);
diff --git a/apps/metadata/metadata_parsers.h b/apps/metadata/metadata_parsers.h
deleted file mode 100644
index 304e393538..0000000000
--- a/apps/metadata/metadata_parsers.h
+++ /dev/null
@@ -1,59 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
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#if CONFIG_CODEC == SWCODEC
23char* id3_get_num_genre(unsigned int genre_num);
24#endif
25int getid3v2len(int fd);
26bool setid3v1title(int fd, struct mp3entry *entry);
27void setid3v2title(int fd, struct mp3entry *entry);
28bool get_mp3_metadata(int fd, struct mp3entry* id3);
29#if CONFIG_CODEC == SWCODEC
30bool get_adx_metadata(int fd, struct mp3entry* id3);
31bool get_aiff_metadata(int fd, struct mp3entry* id3);
32bool get_flac_metadata(int fd, struct mp3entry* id3);
33bool get_mp4_metadata(int fd, struct mp3entry* id3);
34bool get_monkeys_metadata(int fd, struct mp3entry* id3);
35bool get_musepack_metadata(int fd, struct mp3entry *id3);
36bool get_sid_metadata(int fd, struct mp3entry* id3);
37bool get_mod_metadata(int fd, struct mp3entry* id3);
38bool get_spc_metadata(int fd, struct mp3entry* id3);
39bool get_ogg_metadata(int fd, struct mp3entry* id3);
40bool get_wave_metadata(int fd, struct mp3entry* id3);
41bool get_wavpack_metadata(int fd, struct mp3entry* id3);
42bool get_a52_metadata(int fd, struct mp3entry* id3);
43bool get_asf_metadata(int fd, struct mp3entry* id3);
44bool get_asap_metadata(int fd, struct mp3entry* id3);
45bool get_rm_metadata(int fd, struct mp3entry* id3);
46bool get_nsf_metadata(int fd, struct mp3entry* id3);
47bool get_oma_metadata(int fd, struct mp3entry* id3);
48bool get_smaf_metadata(int fd, struct mp3entry* id3);
49bool get_au_metadata(int fd, struct mp3entry* id3);
50bool get_vox_metadata(int fd, struct mp3entry* id3);
51bool get_wave64_metadata(int fd, struct mp3entry* id3);
52bool get_tta_metadata(int fd, struct mp3entry* id3);
53bool get_ay_metadata(int fd, struct mp3entry* id3);
54bool get_gbs_metadata(int fd, struct mp3entry* id3);
55bool get_hes_metadata(int fd, struct mp3entry* id3);
56bool get_sgc_metadata(int fd, struct mp3entry* id3);
57bool get_vgm_metadata(int fd, struct mp3entry* id3);
58bool get_kss_metadata(int fd, struct mp3entry* id3);
59#endif /* CONFIG_CODEC == SWCODEC */
diff --git a/apps/metadata/mod.c b/apps/metadata/mod.c
deleted file mode 100644
index de76823e91..0000000000
--- a/apps/metadata/mod.c
+++ /dev/null
@@ -1,103 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include <inttypes.h>
25
26#include "system.h"
27#include "metadata.h"
28#include <string-extra.h>
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32
33#define MODULEHEADERSIZE 0x438
34
35bool get_mod_metadata(int fd, struct mp3entry* id3)
36{
37 /* Use the trackname part of the id3 structure as a temporary buffer */
38 unsigned char *buf = id3->id3v2buf;
39 unsigned char id[4];
40 bool is_mod_file = false;
41
42 /* Seek to file begin */
43 if (lseek(fd, 0, SEEK_SET) < 0)
44 return false;
45 /* Use id3v2buf as buffer for the track name */
46 if (read(fd, buf, sizeof(id3->id3v2buf)) < (ssize_t)sizeof(id3->id3v2buf))
47 return false;
48 /* Seek to MOD ID position */
49 if (lseek(fd, MODULEHEADERSIZE, SEEK_SET) < 0)
50 return false;
51 /* Read MOD ID */
52 if (read(fd, id, sizeof(id)) < (ssize_t)sizeof(id))
53 return false;
54
55 /* Mod type checking based on MikMod */
56 /* Protracker and variants */
57 if ((!memcmp(id, "M.K.", 4)) || (!memcmp(id, "M!K!", 4))) {
58 is_mod_file = true;
59 }
60
61 /* Star Tracker */
62 if (((!memcmp(id, "FLT", 3)) || (!memcmp(id, "EXO", 3))) &&
63 (isdigit(id[3]))) {
64 char numchn = id[3] - '0';
65 if (numchn == 4 || numchn == 8)
66 is_mod_file = true;
67 }
68
69 /* Oktalyzer (Amiga) */
70 if (!memcmp(id, "OKTA", 4)) {
71 is_mod_file = true;
72 }
73
74 /* Oktalyser (Atari) */
75 if (!memcmp(id, "CD81", 4)) {
76 is_mod_file = true;
77 }
78
79 /* Fasttracker */
80 if ((!memcmp(id + 1, "CHN", 3)) && (isdigit(id[0]))) {
81 is_mod_file = true;
82 }
83 /* Fasttracker or Taketracker */
84 if (((!memcmp(id + 2, "CH", 2)) || (!memcmp(id + 2, "CN", 2)))
85 && (isdigit(id[0])) && (isdigit(id[1]))) {
86 is_mod_file = true;
87 }
88
89 /* Don't try to play if we can't find a known mod type
90 * (there are mod files which have nothing to do with music) */
91 if (!is_mod_file)
92 return false;
93
94 id3->title = id3->id3v2buf; /* Point title to previous read ID3 buffer. */
95 id3->bitrate = filesize(fd)/1024; /* size in kb */
96 id3->frequency = 44100;
97 id3->length = 120*1000;
98 id3->vbr = false;
99 id3->filesize = filesize(fd);
100
101 return true;
102}
103
diff --git a/apps/metadata/monkeys.c b/apps/metadata/monkeys.c
deleted file mode 100644
index 4aff1412aa..0000000000
--- a/apps/metadata/monkeys.c
+++ /dev/null
@@ -1,97 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31
32bool get_monkeys_metadata(int fd, struct mp3entry* id3)
33{
34 /* Use the trackname part of the id3 structure as a temporary buffer */
35 unsigned char* buf = (unsigned char *)id3->path;
36 unsigned char* header;
37 bool rc = false;
38 uint32_t descriptorlength;
39 uint32_t totalsamples;
40 uint32_t blocksperframe, finalframeblocks, totalframes;
41 int fileversion;
42
43 lseek(fd, 0, SEEK_SET);
44
45 if (read(fd, buf, 4) < 4)
46 {
47 return rc;
48 }
49
50 if (memcmp(buf, "MAC ", 4) != 0)
51 {
52 return rc;
53 }
54
55 read(fd, buf + 4, MAX_PATH - 4);
56
57 fileversion = get_short_le(buf+4);
58 if (fileversion < 3970)
59 {
60 /* Not supported */
61 return false;
62 }
63
64 if (fileversion >= 3980)
65 {
66 descriptorlength = get_long_le(buf+8);
67
68 header = buf + descriptorlength;
69
70 blocksperframe = get_long_le(header+4);
71 finalframeblocks = get_long_le(header+8);
72 totalframes = get_long_le(header+12);
73 id3->frequency = get_long_le(header+20);
74 }
75 else
76 {
77 /* v3.95 and later files all have a fixed framesize */
78 blocksperframe = 73728 * 4;
79
80 finalframeblocks = get_long_le(buf+28);
81 totalframes = get_long_le(buf+24);
82 id3->frequency = get_long_le(buf+12);
83 }
84
85 id3->vbr = true; /* All APE files are VBR */
86 id3->filesize = filesize(fd);
87
88 totalsamples = finalframeblocks;
89 if (totalframes > 1)
90 totalsamples += blocksperframe * (totalframes-1);
91
92 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
93 id3->bitrate = (id3->filesize * 8) / id3->length;
94
95 read_ape_tags(fd, id3);
96 return true;
97}
diff --git a/apps/metadata/mp3.c b/apps/metadata/mp3.c
deleted file mode 100644
index feb1a52f77..0000000000
--- a/apps/metadata/mp3.c
+++ /dev/null
@@ -1,193 +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/*
22 * Parts of this code has been stolen from the Ample project and was written
23 * by David H�deman. It has since been extended and enhanced pretty much by
24 * all sorts of friendly Rockbox people.
25 *
26 */
27
28 /* tagResolver and associated code copyright 2003 Thomas Paul Diffenbach
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdbool.h>
35#include "string-extra.h"
36#include "config.h"
37#include "file.h"
38#include "logf.h"
39
40#include "system.h"
41#include "metadata.h"
42#include "mp3data.h"
43#include "metadata_common.h"
44#include "metadata_parsers.h"
45
46/*
47 * Calculates the length (in milliseconds) of an MP3 file.
48 *
49 * Modified to only use integers.
50 *
51 * Arguments: file - the file to calculate the length upon
52 * entry - the entry to update with the length
53 *
54 * Returns: the song length in milliseconds,
55 * 0 means that it couldn't be calculated
56 */
57static int getsonglength(int fd, struct mp3entry *entry)
58{
59 unsigned long filetime = 0;
60 struct mp3info info;
61 long bytecount;
62
63 /* Start searching after ID3v2 header */
64 if(-1 == lseek(fd, entry->id3v2len, SEEK_SET))
65 return 0;
66
67 bytecount = get_mp3file_info(fd, &info);
68
69 logf("Space between ID3V2 tag and first audio frame: 0x%lx bytes",
70 bytecount);
71
72 if(bytecount < 0)
73 return -1;
74
75 bytecount += entry->id3v2len;
76
77 /* Validate byte count, in case the file has been edited without
78 * updating the header.
79 */
80 if (info.byte_count)
81 {
82 const unsigned long expected = entry->filesize - entry->id3v1len
83 - entry->id3v2len;
84 const unsigned long diff = MAX(10240, info.byte_count / 20);
85
86 if ((info.byte_count > expected + diff)
87 || (info.byte_count < expected - diff))
88 {
89 logf("Note: info.byte_count differs from expected value by "
90 "%ld bytes", labs((long) (expected - info.byte_count)));
91 info.byte_count = 0;
92 info.frame_count = 0;
93 info.file_time = 0;
94 info.enc_padding = 0;
95
96 /* Even if the bitrate was based on "known bad" values, it
97 * should still be better for VBR files than using the bitrate
98 * of the first audio frame.
99 */
100 }
101 }
102
103 entry->bitrate = info.bitrate;
104 entry->frequency = info.frequency;
105 entry->layer = info.layer;
106 switch(entry->layer) {
107#if CONFIG_CODEC==SWCODEC
108 case 0:
109 entry->codectype=AFMT_MPA_L1;
110 break;
111#endif
112 case 1:
113 entry->codectype=AFMT_MPA_L2;
114 break;
115 case 2:
116 entry->codectype=AFMT_MPA_L3;
117 break;
118 }
119
120 /* If the file time hasn't been established, this may be a fixed
121 rate MP3, so just use the default formula */
122
123 filetime = info.file_time;
124
125 if(filetime == 0)
126 {
127 /* Prevent a division by zero */
128 if (info.bitrate < 8)
129 filetime = 0;
130 else
131 filetime = (entry->filesize - bytecount) / (info.bitrate / 8);
132 /* bitrate is in kbps so this delivers milliseconds. Doing bitrate / 8
133 * instead of filesize * 8 is exact, because mpeg audio bitrates are
134 * always multiples of 8, and it avoids overflows. */
135 }
136
137 entry->frame_count = info.frame_count;
138
139 entry->vbr = info.is_vbr;
140 entry->has_toc = info.has_toc;
141
142#if CONFIG_CODEC==SWCODEC
143 if (!entry->lead_trim)
144 entry->lead_trim = info.enc_delay;
145 if (!entry->tail_trim)
146 entry->tail_trim = info.enc_padding;
147#endif
148
149 memcpy(entry->toc, info.toc, sizeof(info.toc));
150
151 /* Update the seek point for the first playable frame */
152 entry->first_frame_offset = bytecount;
153 logf("First frame is at %lx", entry->first_frame_offset);
154
155 return filetime;
156}
157
158/*
159 * Checks all relevant information (such as ID3v1 tag, ID3v2 tag, length etc)
160 * about an MP3 file and updates it's entry accordingly.
161 *
162 Note, that this returns true for successful, false for error! */
163bool get_mp3_metadata(int fd, struct mp3entry *entry)
164{
165 entry->title = NULL;
166 entry->filesize = filesize(fd);
167 entry->id3v2len = getid3v2len(fd);
168 entry->tracknum = 0;
169 entry->discnum = 0;
170
171 if (entry->id3v2len)
172 setid3v2title(fd, entry);
173 int len = getsonglength(fd, entry);
174 if (len < 0)
175 return false;
176 entry->length = len;
177
178 /* Subtract the meta information from the file size to get
179 the true size of the MP3 stream */
180 entry->filesize -= entry->first_frame_offset;
181
182 /* only seek to end of file if no id3v2 tags were found */
183 if (!entry->id3v2len) {
184 setid3v1title(fd, entry);
185 }
186
187 if(!entry->length || (entry->filesize < 8 ))
188 /* no song length or less than 8 bytes is hereby considered to be an
189 invalid mp3 and won't be played by us! */
190 return false;
191
192 return true;
193}
diff --git a/apps/metadata/mp4.c b/apps/metadata/mp4.c
deleted file mode 100644
index df164436f5..0000000000
--- a/apps/metadata/mp4.c
+++ /dev/null
@@ -1,842 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "errno.h"
29#include "metadata.h"
30#include "metadata_common.h"
31#include "metadata_parsers.h"
32#include "logf.h"
33#include "debug.h"
34#include "replaygain.h"
35
36#ifdef DEBUGF
37#undef DEBUGF
38#define DEBUGF(...)
39#endif
40
41#define MP4_3gp6 FOURCC('3', 'g', 'p', '6')
42#define MP4_aART FOURCC('a', 'A', 'R', 'T')
43#define MP4_alac FOURCC('a', 'l', 'a', 'c')
44#define MP4_calb FOURCC(0xa9, 'a', 'l', 'b')
45#define MP4_cART FOURCC(0xa9, 'A', 'R', 'T')
46#define MP4_cgrp FOURCC(0xa9, 'g', 'r', 'p')
47#define MP4_cgen FOURCC(0xa9, 'g', 'e', 'n')
48#define MP4_chpl FOURCC('c', 'h', 'p', 'l')
49#define MP4_cnam FOURCC(0xa9, 'n', 'a', 'm')
50#define MP4_cwrt FOURCC(0xa9, 'w', 'r', 't')
51#define MP4_ccmt FOURCC(0xa9, 'c', 'm', 't')
52#define MP4_cday FOURCC(0xa9, 'd', 'a', 'y')
53#define MP4_covr FOURCC('c', 'o', 'v', 'r')
54#define MP4_disk FOURCC('d', 'i', 's', 'k')
55#define MP4_esds FOURCC('e', 's', 'd', 's')
56#define MP4_ftyp FOURCC('f', 't', 'y', 'p')
57#define MP4_gnre FOURCC('g', 'n', 'r', 'e')
58#define MP4_hdlr FOURCC('h', 'd', 'l', 'r')
59#define MP4_ilst FOURCC('i', 'l', 's', 't')
60#define MP4_isom FOURCC('i', 's', 'o', 'm')
61#define MP4_M4A FOURCC('M', '4', 'A', ' ')
62#define MP4_m4a FOURCC('m', '4', 'a', ' ') /*technically its "M4A "*/
63#define MP4_M4B FOURCC('M', '4', 'B', ' ') /*but files exist with lower case*/
64#define MP4_mdat FOURCC('m', 'd', 'a', 't')
65#define MP4_mdia FOURCC('m', 'd', 'i', 'a')
66#define MP4_mdir FOURCC('m', 'd', 'i', 'r')
67#define MP4_meta FOURCC('m', 'e', 't', 'a')
68#define MP4_minf FOURCC('m', 'i', 'n', 'f')
69#define MP4_moov FOURCC('m', 'o', 'o', 'v')
70#define MP4_mp4a FOURCC('m', 'p', '4', 'a')
71#define MP4_mp42 FOURCC('m', 'p', '4', '2')
72#define MP4_qt FOURCC('q', 't', ' ', ' ')
73#define MP4_soun FOURCC('s', 'o', 'u', 'n')
74#define MP4_stbl FOURCC('s', 't', 'b', 'l')
75#define MP4_stsd FOURCC('s', 't', 's', 'd')
76#define MP4_stts FOURCC('s', 't', 't', 's')
77#define MP4_trak FOURCC('t', 'r', 'a', 'k')
78#define MP4_trkn FOURCC('t', 'r', 'k', 'n')
79#define MP4_udta FOURCC('u', 'd', 't', 'a')
80#define MP4_extra FOURCC('-', '-', '-', '-')
81
82/* Read the tag data from an MP4 file, storing up to buffer_size bytes in
83 * buffer.
84 */
85static unsigned long read_mp4_tag(int fd, unsigned int size_left, char* buffer,
86 unsigned int buffer_left)
87{
88 unsigned int bytes_read = 0;
89
90 if (buffer_left == 0)
91 {
92 lseek(fd, size_left, SEEK_CUR); /* Skip everything */
93 }
94 else
95 {
96 /* Skip the data tag header - maybe we should parse it properly? */
97 lseek(fd, 16, SEEK_CUR);
98 size_left -= 16;
99
100 if (size_left > buffer_left)
101 {
102 read(fd, buffer, buffer_left);
103 lseek(fd, size_left - buffer_left, SEEK_CUR);
104 bytes_read = buffer_left;
105 }
106 else
107 {
108 read(fd, buffer, size_left);
109 bytes_read = size_left;
110 }
111 }
112
113 return bytes_read;
114}
115
116/* Read a string tag from an MP4 file */
117static unsigned int read_mp4_tag_string(int fd, int size_left, char** buffer,
118 unsigned int* buffer_left, char** dest)
119{
120 unsigned int bytes_read = read_mp4_tag(fd, size_left, *buffer,
121 *buffer_left > 0 ? *buffer_left - 1 : 0);
122 unsigned int length = 0;
123
124 if (bytes_read)
125 {
126 /* Do not overwrite already available metadata. Especially when reading
127 * tags with e.g. multiple genres / artists. This way only the first
128 * of multiple entries is used, all following are dropped. */
129 if (*dest == NULL)
130 {
131 (*buffer)[bytes_read] = 0; /* zero-terminate for correct strlen().*/
132 length = strlen(*buffer) + 1;
133 length = MIN(length, ID3V2_MAX_ITEM_SIZE); /* Limit item size. */
134
135 *dest = *buffer;
136 (*buffer)[length-1] = 0; /* zero-terminate buffer. */
137 *buffer_left -= length;
138 *buffer += length;
139 }
140 }
141 else
142 {
143 *dest = NULL;
144 }
145
146 return length;
147}
148
149static unsigned int read_mp4_atom(int fd, uint32_t* size,
150 uint32_t* type, uint32_t size_left)
151{
152 read_uint32be(fd, size);
153 read_uint32be(fd, type);
154
155 if (*size == 1)
156 {
157 /* FAT32 doesn't support files this big, so something seems to
158 * be wrong. (64-bit sizes should only be used when required.)
159 */
160 errno = EFBIG;
161 *type = 0;
162 return 0;
163 }
164
165 if (*size > 0)
166 {
167 if (*size > size_left)
168 {
169 size_left = 0;
170 }
171 else
172 {
173 size_left -= *size;
174 }
175
176 *size -= 8;
177 }
178 else
179 {
180 *size = size_left;
181 size_left = 0;
182 }
183
184 return size_left;
185}
186
187static unsigned int read_mp4_length(int fd, uint32_t* size)
188{
189 unsigned int length = 0;
190 int bytes = 0;
191 unsigned char c;
192
193 do
194 {
195 read(fd, &c, 1);
196 bytes++;
197 (*size)--;
198 length = (length << 7) | (c & 0x7F);
199 }
200 while ((c & 0x80) && (bytes < 4) && (*size > 0));
201
202 return length;
203}
204
205static bool read_mp4_esds(int fd, struct mp3entry* id3, uint32_t* size)
206{
207 unsigned char buf[8];
208 bool sbr = false;
209
210 lseek(fd, 4, SEEK_CUR); /* Version and flags. */
211 read(fd, buf, 1); /* Verify ES_DescrTag. */
212 *size -= 5;
213
214 if (*buf == 3)
215 {
216 /* read length */
217 if (read_mp4_length(fd, size) < 20)
218 {
219 return sbr;
220 }
221
222 lseek(fd, 3, SEEK_CUR);
223 *size -= 3;
224 }
225 else
226 {
227 lseek(fd, 2, SEEK_CUR);
228 *size -= 2;
229 }
230
231 read(fd, buf, 1); /* Verify DecoderConfigDescrTab. */
232 *size -= 1;
233
234 if (*buf != 4)
235 {
236 return sbr;
237 }
238
239 if (read_mp4_length(fd, size) < 13)
240 {
241 return sbr;
242 }
243
244 lseek(fd, 13, SEEK_CUR); /* Skip audio type, bit rates, etc. */
245 read(fd, buf, 1);
246 *size -= 14;
247
248 if (*buf != 5) /* Verify DecSpecificInfoTag. */
249 {
250 return sbr;
251 }
252
253 {
254 static const int sample_rates[] =
255 {
256 96000, 88200, 64000, 48000, 44100, 32000,
257 24000, 22050, 16000, 12000, 11025, 8000
258 };
259 unsigned long bits;
260 unsigned int length;
261 unsigned int index;
262 unsigned int type;
263
264 /* Read the (leading part of the) decoder config. */
265 length = read_mp4_length(fd, size);
266 length = MIN(length, *size);
267 length = MIN(length, sizeof(buf));
268 memset(buf, 0, sizeof(buf));
269 read(fd, buf, length);
270 *size -= length;
271
272 /* Maybe time to write a simple read_bits function... */
273
274 /* Decoder config format:
275 * Object type - 5 bits
276 * Frequency index - 4 bits
277 * Channel configuration - 4 bits
278 */
279 bits = get_long_be(buf);
280 type = bits >> 27; /* Object type - 5 bits */
281 index = (bits >> 23) & 0xf; /* Frequency index - 4 bits */
282
283 if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
284 {
285 id3->frequency = sample_rates[index];
286 }
287
288 if (type == 5)
289 {
290 unsigned int old_index = index;
291
292 sbr = true;
293 index = (bits >> 15) & 0xf; /* Frequency index - 4 bits */
294
295 if (index == 15)
296 {
297 /* 17 bits read so far... */
298 bits = get_long_be(&buf[2]);
299 id3->frequency = (bits >> 7) & 0x00ffffff;
300 }
301 else if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
302 {
303 id3->frequency = sample_rates[index];
304 }
305
306 if (old_index == index)
307 {
308 /* Downsampled SBR */
309 id3->frequency *= 2;
310 }
311 }
312 /* Skip 13 bits from above, plus 3 bits, then read 11 bits */
313 else if ((length >= 4) && (((bits >> 5) & 0x7ff) == 0x2b7))
314 {
315 /* We found an extensionAudioObjectType */
316 type = bits & 0x1f; /* Object type - 5 bits*/
317 bits = get_long_be(&buf[4]);
318
319 if (type == 5)
320 {
321 sbr = bits >> 31;
322
323 if (sbr)
324 {
325 unsigned int old_index = index;
326
327 /* 1 bit read so far */
328 index = (bits >> 27) & 0xf; /* Frequency index - 4 bits */
329
330 if (index == 15)
331 {
332 /* 5 bits read so far */
333 id3->frequency = (bits >> 3) & 0x00ffffff;
334 }
335 else if (index < (sizeof(sample_rates) / sizeof(*sample_rates)))
336 {
337 id3->frequency = sample_rates[index];
338 }
339
340 if (old_index == index)
341 {
342 /* Downsampled SBR */
343 id3->frequency *= 2;
344 }
345 }
346 }
347 }
348
349 if (!sbr && (id3->frequency <= 24000) && (length <= 2))
350 {
351 /* Double the frequency for low-frequency files without a "long"
352 * DecSpecificConfig header. The file may or may not contain SBR,
353 * but here we guess it does if the header is short. This can
354 * fail on some files, but it's the best we can do, short of
355 * decoding (parts of) the file.
356 */
357 id3->frequency *= 2;
358 sbr = true;
359 }
360 }
361
362 return sbr;
363}
364
365static bool read_mp4_tags(int fd, struct mp3entry* id3,
366 uint32_t size_left)
367{
368 uint32_t size;
369 uint32_t type;
370 unsigned int buffer_left = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
371 char* buffer = id3->id3v2buf;
372 bool cwrt = false;
373
374 do
375 {
376 size_left = read_mp4_atom(fd, &size, &type, size_left);
377
378 /* DEBUGF("Tag atom: '%c%c%c%c' (%d bytes left)\n", type >> 24 & 0xff,
379 type >> 16 & 0xff, type >> 8 & 0xff, type & 0xff, size); */
380
381 switch (type)
382 {
383 case MP4_cnam:
384 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
385 &id3->title);
386 break;
387
388 case MP4_cART:
389 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
390 &id3->artist);
391 break;
392
393 case MP4_aART:
394 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
395 &id3->albumartist);
396 break;
397
398 case MP4_cgrp:
399 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
400 &id3->grouping);
401 break;
402
403 case MP4_calb:
404 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
405 &id3->album);
406 break;
407
408 case MP4_cwrt:
409 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
410 &id3->composer);
411 cwrt = false;
412 break;
413
414 case MP4_ccmt:
415 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
416 &id3->comment);
417 break;
418
419 case MP4_cday:
420 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
421 &id3->year_string);
422
423 /* Try to parse it as a year, for the benefit of the database.
424 */
425 if(id3->year_string)
426 {
427 id3->year = atoi(id3->year_string);
428 if (id3->year < 1900)
429 {
430 id3->year = 0;
431 }
432 }
433 else
434 id3->year = 0;
435
436 break;
437
438 case MP4_gnre:
439 {
440 unsigned short genre;
441
442 read_mp4_tag(fd, size, (char*) &genre, sizeof(genre));
443 id3->genre_string = id3_get_num_genre(betoh16(genre) - 1);
444 }
445 break;
446
447 case MP4_cgen:
448 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
449 &id3->genre_string);
450 break;
451
452 case MP4_disk:
453 {
454 unsigned short n[2];
455
456 read_mp4_tag(fd, size, (char*) &n, sizeof(n));
457 id3->discnum = betoh16(n[1]);
458 }
459 break;
460
461 case MP4_trkn:
462 {
463 unsigned short n[2];
464
465 read_mp4_tag(fd, size, (char*) &n, sizeof(n));
466 id3->tracknum = betoh16(n[1]);
467 }
468 break;
469
470#ifdef HAVE_ALBUMART
471 case MP4_covr:
472 {
473 int pos = lseek(fd, 0, SEEK_CUR) + 16;
474
475 read_mp4_tag(fd, size, buffer, 8);
476 id3->albumart.type = AA_TYPE_UNKNOWN;
477 if (memcmp(buffer, "\xff\xd8\xff\xe0", 4) == 0)
478 {
479 id3->albumart.type = AA_TYPE_JPG;
480 }
481 else if (memcmp(buffer, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8) == 0)
482 {
483 id3->albumart.type = AA_TYPE_PNG;
484 }
485
486 if (id3->albumart.type != AA_TYPE_UNKNOWN)
487 {
488 id3->albumart.pos = pos;
489 id3->albumart.size = size - 16;
490 id3->has_embedded_albumart = true;
491 }
492 }
493 break;
494#endif
495
496 case MP4_extra:
497 {
498 char tag_name[TAG_NAME_LENGTH];
499 uint32_t sub_size;
500
501 /* "mean" atom */
502 read_uint32be(fd, &sub_size);
503 size -= sub_size;
504 lseek(fd, sub_size - 4, SEEK_CUR);
505 /* "name" atom */
506 read_uint32be(fd, &sub_size);
507 size -= sub_size;
508 lseek(fd, 8, SEEK_CUR);
509 sub_size -= 12;
510
511 if (sub_size > sizeof(tag_name) - 1)
512 {
513 read(fd, tag_name, sizeof(tag_name) - 1);
514 lseek(fd, sub_size - (sizeof(tag_name) - 1), SEEK_CUR);
515 tag_name[sizeof(tag_name) - 1] = 0;
516 }
517 else
518 {
519 read(fd, tag_name, sub_size);
520 tag_name[sub_size] = 0;
521 }
522
523 if ((strcasecmp(tag_name, "composer") == 0) && !cwrt)
524 {
525 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
526 &id3->composer);
527 }
528 else if (strcasecmp(tag_name, "iTunSMPB") == 0)
529 {
530 char value[TAG_VALUE_LENGTH];
531 char* value_p = value;
532 char* any;
533 unsigned int length = sizeof(value);
534
535 read_mp4_tag_string(fd, size, &value_p, &length, &any);
536 id3->lead_trim = get_itunes_int32(value, 1);
537 id3->tail_trim = get_itunes_int32(value, 2);
538 DEBUGF("AAC: lead_trim %d, tail_trim %d\n",
539 id3->lead_trim, id3->tail_trim);
540 }
541 else if (strcasecmp(tag_name, "musicbrainz track id") == 0)
542 {
543 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
544 &id3->mb_track_id);
545 }
546 else if ((strcasecmp(tag_name, "album artist") == 0))
547 {
548 read_mp4_tag_string(fd, size, &buffer, &buffer_left,
549 &id3->albumartist);
550 }
551 else
552 {
553 char* any = NULL;
554 unsigned int length = read_mp4_tag_string(fd, size,
555 &buffer, &buffer_left, &any);
556
557 if (length > 0)
558 {
559 /* Re-use the read buffer as the dest buffer... */
560 buffer -= length;
561 buffer_left += length;
562
563 parse_replaygain(tag_name, buffer, id3);
564 }
565 }
566 }
567 break;
568
569 default:
570 lseek(fd, size, SEEK_CUR);
571 break;
572 }
573 }
574 while ((size_left > 0) && (errno == 0));
575
576 return true;
577}
578
579static bool read_mp4_container(int fd, struct mp3entry* id3,
580 uint32_t size_left)
581{
582 uint32_t size = 0;
583 uint32_t type = 0;
584 uint32_t handler = 0;
585 bool rc = true;
586 bool done = false;
587
588 do
589 {
590 size_left = read_mp4_atom(fd, &size, &type, size_left);
591
592 /* DEBUGF("Atom: '%c%c%c%c' (0x%08lx, %lu bytes left)\n",
593 (int) ((type >> 24) & 0xff), (int) ((type >> 16) & 0xff),
594 (int) ((type >> 8) & 0xff), (int) (type & 0xff),
595 type, size); */
596
597 switch (type)
598 {
599 case MP4_ftyp:
600 {
601 uint32_t id;
602
603 read_uint32be(fd, &id);
604 size -= 4;
605
606 if ((id != MP4_M4A) && (id != MP4_M4B) && (id != MP4_mp42)
607 && (id != MP4_qt) && (id != MP4_3gp6) && (id != MP4_m4a)
608 && (id != MP4_isom))
609 {
610 DEBUGF("Unknown MP4 file type: '%c%c%c%c'\n",
611 (int)(id >> 24 & 0xff), (int)(id >> 16 & 0xff),
612 (int)(id >> 8 & 0xff), (int)(id & 0xff));
613 return false;
614 }
615 }
616 break;
617
618 case MP4_meta:
619 lseek(fd, 4, SEEK_CUR); /* Skip version */
620 size -= 4;
621 /* Fall through */
622
623 case MP4_moov:
624 case MP4_udta:
625 case MP4_mdia:
626 case MP4_stbl:
627 case MP4_trak:
628 rc = read_mp4_container(fd, id3, size);
629 size = 0;
630 break;
631
632 case MP4_ilst:
633 /* We need at least a size of 8 to read the next atom. */
634 if (handler == MP4_mdir && size>8)
635 {
636 rc = read_mp4_tags(fd, id3, size);
637 size = 0;
638 }
639 break;
640
641 case MP4_minf:
642 if (handler == MP4_soun)
643 {
644 rc = read_mp4_container(fd, id3, size);
645 size = 0;
646 }
647 break;
648
649 case MP4_stsd:
650 lseek(fd, 8, SEEK_CUR);
651 size -= 8;
652 rc = read_mp4_container(fd, id3, size);
653 size = 0;
654 break;
655
656 case MP4_hdlr:
657 lseek(fd, 8, SEEK_CUR);
658 read_uint32be(fd, &handler);
659 size -= 12;
660 /* DEBUGF(" Handler '%c%c%c%c'\n", handler >> 24 & 0xff,
661 handler >> 16 & 0xff, handler >> 8 & 0xff,handler & 0xff); */
662 break;
663
664 case MP4_stts:
665 {
666 uint32_t entries;
667 unsigned int i;
668
669 /* Reset to false. */
670 id3->needs_upsampling_correction = false;
671
672 lseek(fd, 4, SEEK_CUR);
673 read_uint32be(fd, &entries);
674 id3->samples = 0;
675
676 for (i = 0; i < entries; i++)
677 {
678 uint32_t n;
679 uint32_t l;
680
681 read_uint32be(fd, &n);
682 read_uint32be(fd, &l);
683
684 /* Some AAC file use HE profile. In this case the number
685 * of output samples is doubled to a maximum of 2048
686 * samples per frame. This means that files which already
687 * report a frame size of 2048 in their header will not
688 * need any further special handling. */
689 if (id3->codectype==AFMT_MP4_AAC_HE && l<=1024)
690 {
691 id3->samples += n * l * 2;
692 id3->needs_upsampling_correction = true;
693 }
694 else
695 {
696 id3->samples += n * l;
697 }
698 }
699
700 size = 0;
701 }
702 break;
703
704 case MP4_mp4a:
705 {
706 uint32_t subsize;
707 uint32_t subtype;
708
709 /* Move to the next expected mp4 atom. */
710 lseek(fd, 28, SEEK_CUR);
711 read_mp4_atom(fd, &subsize, &subtype, size);
712 size -= 36;
713
714 if (subtype == MP4_esds)
715 {
716 /* Read esds metadata and return if AAC-HE/SBR is used. */
717 if (read_mp4_esds(fd, id3, &size))
718 id3->codectype = AFMT_MP4_AAC_HE;
719 else
720 id3->codectype = AFMT_MP4_AAC;
721 }
722 }
723 break;
724
725 case MP4_alac:
726 {
727 uint32_t frequency;
728 uint32_t subsize;
729 uint32_t subtype;
730
731 /* Move to the next expected mp4 atom. */
732 lseek(fd, 28, SEEK_CUR);
733 read_mp4_atom(fd, &subsize, &subtype, size);
734 size -= 36;
735#if 0
736 /* We might need to parse for the alac metadata atom. */
737 while (!((subsize==28) && (subtype==MP4_alac)) && (size>0))
738 {
739 lseek(fd, -7, SEEK_CUR);
740 read_mp4_atom(fd, &subsize, &subtype, size);
741 size -= 1;
742 errno = 0; /* will most likely be set while parsing */
743 }
744#endif
745 if (subtype == MP4_alac)
746 {
747 lseek(fd, 24, SEEK_CUR);
748 read_uint32be(fd, &frequency);
749 size -= 28;
750 id3->frequency = frequency;
751 id3->codectype = AFMT_MP4_ALAC;
752 }
753 }
754 break;
755
756 case MP4_mdat:
757 /* Some AAC files appear to contain additional empty mdat chunks.
758 Ignore them. */
759 if(size == 0)
760 break;
761 id3->filesize = size;
762 if(id3->samples > 0) {
763 /* We've already seen the moov chunk. */
764 done = true;
765 }
766 break;
767
768 case MP4_chpl:
769 {
770 /* ADDME: add support for real chapters. Right now it's only
771 * used for Nero's gapless hack */
772 uint8_t chapters;
773 uint64_t timestamp;
774
775 lseek(fd, 8, SEEK_CUR);
776 read_uint8(fd, &chapters);
777 size -= 9;
778
779 /* the first chapter will be used as the lead_trim */
780 if (chapters > 0) {
781 read_uint64be(fd, &timestamp);
782 id3->lead_trim = (timestamp * id3->frequency) / 10000000;
783 size -= 8;
784 }
785 }
786 break;
787
788 default:
789 break;
790 }
791
792 /* Skip final seek. */
793 if (!done)
794 {
795 lseek(fd, size, SEEK_CUR);
796 }
797 } while (rc && (size_left > 0) && (errno == 0) && !done);
798
799 return rc;
800}
801
802bool get_mp4_metadata(int fd, struct mp3entry* id3)
803{
804 id3->codectype = AFMT_UNKNOWN;
805 id3->filesize = 0;
806 errno = 0;
807
808 if (read_mp4_container(fd, id3, filesize(fd)) && (errno == 0)
809 && (id3->samples > 0) && (id3->frequency > 0)
810 && (id3->filesize > 0))
811 {
812 if (id3->codectype == AFMT_UNKNOWN)
813 {
814 logf("Not an ALAC or AAC file");
815 return false;
816 }
817
818 id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
819
820 id3->vbr = true; /* ALAC is native VBR, AAC very unlikely is CBR. */
821
822 if (id3->length <= 0)
823 {
824 logf("mp4 length invalid!");
825 return false;
826 }
827
828 id3->bitrate = ((int64_t) id3->filesize * 8) / id3->length;
829 DEBUGF("MP4 bitrate %d, frequency %ld Hz, length %ld ms\n",
830 id3->bitrate, id3->frequency, id3->length);
831 }
832 else
833 {
834 logf("MP4 metadata error");
835 DEBUGF("MP4 metadata error. errno %d, samples %ld, frequency %ld, "
836 "filesize %ld\n", errno, id3->samples, id3->frequency,
837 id3->filesize);
838 return false;
839 }
840
841 return true;
842}
diff --git a/apps/metadata/mpc.c b/apps/metadata/mpc.c
deleted file mode 100644
index 0b75ed04dd..0000000000
--- a/apps/metadata/mpc.c
+++ /dev/null
@@ -1,220 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Thom Johansen
11 * Copyright (C) 2010 Andree Buschmann
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include <string.h>
24#include <stdio.h>
25#include <inttypes.h>
26#include "system.h"
27#include "metadata.h"
28#include "metadata_common.h"
29#include "metadata_parsers.h"
30#include "logf.h"
31#include "replaygain.h"
32#include "fixedpoint.h"
33
34/* Needed for replay gain and clipping prevention of SV8 files. */
35#define SV8_TO_SV7_CONVERT_GAIN (6482) /* 64.82 * 100, MPC_OLD_GAIN_REF */
36#define SV8_TO_SV7_CONVERT_PEAK (23119) /* 256 * 20 * log10(32768) */
37
38static int set_replaygain_sv7(struct mp3entry* id3,
39 bool album,
40 long value,
41 long used)
42{
43 long gain = (int16_t) ((value >> 16) & 0xffff);
44 long peak = (uint16_t) (value & 0xffff);
45
46 /* We use a peak value of 0 to indicate a given gain type isn't used. */
47 if (peak != 0) {
48 /* Save the ReplayGain data to id3-structure for further processing. */
49 parse_replaygain_int(album, gain * 512 / 100, peak << 9, id3);
50 }
51
52 return used;
53}
54
55static int set_replaygain_sv8(struct mp3entry* id3,
56 bool album,
57 long gain,
58 long peak,
59 long used)
60{
61 gain = (long)(SV8_TO_SV7_CONVERT_GAIN - ((gain*100)/256));
62
63 /* Transform SV8's logarithmic peak representation to the desired linear
64 * representation: linear = pow(10, peak/256/20).
65 *
66 * FP_BITS = 24 bits = desired fp representation for dsp routines
67 * FRAC_BITS = 12 bits = resolution used for fp_bits
68 * fp_factor(peak*(1<<FRAC_BITS)/256, FRAC_BITS) << (FP_BITS-FRAC_BITS)
69 **/
70 peak = (fp_factor((peak-SV8_TO_SV7_CONVERT_PEAK)*16, 12) << 12);
71
72 /* We use a peak value of 0 to indicate a given gain type isn't used. */
73 if (peak != 0) {
74 /* Save the ReplayGain data to id3-structure for further processing. */
75 parse_replaygain_int(album, gain * 512 / 100, peak, id3);
76 }
77
78 return used;
79}
80
81static int sv8_get_size(uint8_t *buffer, int index, uint64_t *p_size)
82{
83 unsigned char tmp;
84 uint64_t size = 0;
85
86 do {
87 tmp = buffer[index++];
88 size = (size << 7) | (tmp & 0x7F);
89 } while((tmp & 0x80));
90
91 *p_size = size;
92 return index;
93}
94
95bool get_musepack_metadata(int fd, struct mp3entry *id3)
96{
97 static const int32_t sfreqs[4] = { 44100, 48000, 37800, 32000 };
98 uint32_t header[8];
99 uint64_t samples = 0;
100 int i;
101
102 if (!skip_id3v2(fd, id3))
103 return false;
104 if (read(fd, header, 4*8) != 4*8) return false;
105 /* Musepack files are little endian, might need swapping */
106 for (i = 1; i < 8; i++)
107 header[i] = letoh32(header[i]);
108 if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */
109 unsigned int streamversion;
110 header[0] = letoh32(header[0]);
111 streamversion = (header[0] >> 24) & 15;
112 if (streamversion == 7) {
113 unsigned int gapless = (header[5] >> 31) & 0x0001;
114 unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff;
115 unsigned int bufused = 0;
116
117 id3->frequency = sfreqs[(header[2] >> 16) & 0x0003];
118 samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */
119 if (gapless)
120 samples -= 1152 - last_frame_samples;
121 else
122 samples -= 481; /* Musepack subband synth filter delay */
123
124 bufused = set_replaygain_sv7(id3, false, header[3], bufused);
125 bufused = set_replaygain_sv7(id3, true , header[4], bufused);
126
127 id3->codectype = AFMT_MPC_SV7;
128 } else {
129 return false; /* only SV7 is allowed within a "MP+" signature */
130 }
131 } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */
132 uint8_t sv8_header[32];
133 /* 4 bytes 'MPCK' */
134 lseek(fd, 4, SEEK_SET);
135 if (read(fd, sv8_header, 2) != 2) return false; /* read frame ID */
136 if (!memcmp(sv8_header, "SH", 2)) { /* Stream Header ID */
137 int32_t k = 0;
138 uint32_t streamversion;
139 uint64_t size = 0; /* tag size */
140 uint64_t dummy = 0; /* used to dummy read data from header */
141
142 /* 4 bytes 'MPCK' + 2 'SH' */
143 lseek(fd, 6, SEEK_SET);
144 if (read(fd, sv8_header, 32) != 32) return false;
145
146 /* Read the size of 'SH'-tag */
147 k = sv8_get_size(sv8_header, k, &size);
148
149 /* Skip crc32 */
150 k += 4;
151
152 /* Read stream version */
153 streamversion = sv8_header[k++];
154 if (streamversion != 8) return false; /* Only SV8 is allowed. */
155
156 /* Number of samples */
157 k = sv8_get_size(sv8_header, k, &samples);
158
159 /* Number of leading zero-samples */
160 k = sv8_get_size(sv8_header, k, &dummy);
161
162 /* Sampling frequency */
163 id3->frequency = sfreqs[(sv8_header[k++] >> 5) & 0x0003];
164
165 /* Number of channels */
166 id3->channels = (sv8_header[k++] >> 4) + 1;
167
168 /* Skip to next tag: k = size -2 */
169 k = size - 2;
170
171 if (!memcmp(sv8_header+k, "RG", 2)) { /* Replay Gain ID */
172 long peak, gain;
173 int bufused = 0;
174
175 k += 2; /* 2 bytes 'RG' */
176
177 /* sv8_get_size must be called to skip the right amount of
178 * bits within the header data. */
179 k = sv8_get_size(sv8_header, k, &size);
180
181 /* Read and set replay gain */
182 if (sv8_header[k++] == 1) {
183 /* Title's peak and gain */
184 gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
185 peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
186 bufused += set_replaygain_sv8(id3, false, gain, peak, bufused);
187
188 /* Album's peak and gain */
189 gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
190 peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
191 bufused += set_replaygain_sv8(id3, true , gain, peak, bufused);
192 }
193 }
194
195 id3->codectype = AFMT_MPC_SV8;
196 } else {
197 /* No sv8 stream header found */
198 return false;
199 }
200 } else {
201 return false; /* SV4-6 is not supported anymore */
202 }
203
204 id3->vbr = true;
205 /* Estimate bitrate, we should probably subtract the various header sizes
206 here for super-accurate results */
207 id3->length = ((int64_t) samples * 1000) / id3->frequency;
208
209 if (id3->length <= 0)
210 {
211 logf("mpc length invalid!");
212 return false;
213 }
214
215 id3->filesize = filesize(fd);
216 id3->bitrate = id3->filesize * 8 / id3->length;
217
218 read_ape_tags(fd, id3);
219 return true;
220}
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c
deleted file mode 100644
index 2fa6f36b12..0000000000
--- a/apps/metadata/nsf.c
+++ /dev/null
@@ -1,278 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12#include "string-extra.h"
13
14/* NOTE: This file was modified to work properly with the new nsf codec based
15 on Game_Music_Emu */
16
17struct NESM_HEADER
18{
19 uint32_t nHeader;
20 uint8_t nHeaderExtra;
21 uint8_t nVersion;
22 uint8_t nTrackCount;
23 uint8_t nInitialTrack;
24 uint16_t nLoadAddress;
25 uint16_t nInitAddress;
26 uint16_t nPlayAddress;
27 uint8_t szGameTitle[32];
28 uint8_t szArtist[32];
29 uint8_t szCopyright[32];
30 uint16_t nSpeedNTSC;
31 uint8_t nBankSwitch[8];
32 uint16_t nSpeedPAL;
33 uint8_t nNTSC_PAL;
34 uint8_t nExtraChip;
35 uint8_t nExpansion[4];
36} __attribute__((packed));
37
38struct NSFE_INFOCHUNK
39{
40 uint16_t nLoadAddress;
41 uint16_t nInitAddress;
42 uint16_t nPlayAddress;
43 uint8_t nIsPal;
44 uint8_t nExt;
45 uint8_t nTrackCount;
46 uint8_t nStartingTrack;
47} __attribute__((packed));
48
49
50#define CHAR4_CONST(a, b, c, d) FOURCC(a, b, c, d)
51#define CHUNK_INFO 0x0001
52#define CHUNK_DATA 0x0002
53#define CHUNK_NEND 0x0004
54#define CHUNK_plst 0x0008
55#define CHUNK_time 0x0010
56#define CHUNK_fade 0x0020
57#define CHUNK_tlbl 0x0040
58#define CHUNK_auth 0x0080
59#define CHUNK_BANK 0x0100
60
61static bool parse_nsfe(int fd, struct mp3entry *id3)
62{
63 unsigned int chunks_found = 0;
64 long track_count = 0;
65 long playlist_count = 0;
66
67 struct NSFE_INFOCHUNK info;
68 memset(&info, 0, sizeof(struct NSFE_INFOCHUNK));
69
70 /* default values */
71 info.nTrackCount = 1;
72 id3->length = 150 * 1000;
73
74 /* begin reading chunks */
75 while (!(chunks_found & CHUNK_NEND))
76 {
77 uint32_t chunk_size, chunk_type;
78
79 if (read_uint32le(fd, &chunk_size) != (int)sizeof(uint32_t))
80 return false;
81
82 if (read_uint32be(fd, &chunk_type) != (int)sizeof(uint32_t))
83 return false;
84
85 switch (chunk_type)
86 {
87 /* first three types are mandatory (but don't worry about NEND
88 anyway) */
89 case CHAR4_CONST('I', 'N', 'F', 'O'):
90 {
91 if (chunks_found & CHUNK_INFO)
92 return false; /* only one info chunk permitted */
93
94 chunks_found |= CHUNK_INFO;
95
96 /* minimum size */
97 if (chunk_size < 8)
98 return false;
99
100 ssize_t size = MIN(sizeof(struct NSFE_INFOCHUNK), chunk_size);
101
102 if (read(fd, &info, size) != size)
103 return false;
104
105 if (size >= 9)
106 track_count = info.nTrackCount;
107
108 chunk_size -= size;
109 break;
110 }
111
112 case CHAR4_CONST('D', 'A', 'T', 'A'):
113 {
114 if (!(chunks_found & CHUNK_INFO))
115 return false;
116
117 if (chunks_found & CHUNK_DATA)
118 return false; /* only one may exist */
119
120 if (chunk_size < 1)
121 return false;
122
123 chunks_found |= CHUNK_DATA;
124 break;
125 }
126
127 case CHAR4_CONST('N', 'E', 'N', 'D'):
128 {
129 /* just end parsing regardless of whether or not this really is the
130 last chunk/data (but it _should_ be) */
131 chunks_found |= CHUNK_NEND;
132 continue;
133 }
134
135 /* remaining types are optional */
136
137 case CHAR4_CONST('a', 'u', 't', 'h'):
138 {
139 if (chunks_found & CHUNK_auth)
140 return false; /* only one may exist */
141
142 chunks_found |= CHUNK_auth;
143
144 /* szGameTitle, szArtist, szCopyright */
145 char ** const ar[] = { &id3->title, &id3->artist, &id3->album };
146
147 char *p = id3->id3v2buf;
148 long buf_rem = sizeof (id3->id3v2buf);
149 unsigned int i;
150
151 for (i = 0; i < ARRAYLEN(ar) && chunk_size && buf_rem; i++)
152 {
153 long len = read_string(fd, p, buf_rem, '\0', chunk_size);
154
155 if (len < 0)
156 return false;
157
158 *ar[i] = p;
159 p += len;
160 buf_rem -= len;
161
162 if (chunk_size >= (uint32_t)len)
163 chunk_size -= len;
164 else
165 chunk_size = 0;
166 }
167
168 break;
169 }
170
171 case CHAR4_CONST('p', 'l', 's', 't'):
172 {
173 if (chunks_found & CHUNK_plst)
174 return false; /* only one may exist */
175
176 chunks_found |= CHUNK_plst;
177
178 /* each byte is the index of one track */
179 playlist_count = chunk_size;
180 break;
181 }
182
183 case CHAR4_CONST('t', 'i', 'm', 'e'):
184 case CHAR4_CONST('f', 'a', 'd', 'e'):
185 case CHAR4_CONST('t', 'l', 'b', 'l'): /* we unfortunately can't use these anyway */
186 {
187 /* don't care how many of these there are even though there should
188 be only one */
189 if (!(chunks_found & CHUNK_INFO))
190 return false;
191
192 case CHAR4_CONST('B', 'A', 'N', 'K'):
193 break;
194 }
195
196 default: /* unknown chunk */
197 {
198 /* check the first byte */
199 chunk_type = (uint8_t)chunk_type;
200
201 /* chunk is vital... don't continue */
202 if(chunk_type >= 'A' && chunk_type <= 'Z')
203 return false;
204
205 /* otherwise, just skip it */
206 break;
207 }
208 } /* end switch */
209
210 lseek(fd, chunk_size, SEEK_CUR);
211 } /* end while */
212
213 if (track_count | playlist_count)
214 id3->length = MAX(track_count, playlist_count)*1000;
215
216 /* Single subtrack files will be treated differently
217 by gme's nsf codec */
218 if (id3->length <= 1000) id3->length = 150 * 1000;
219
220 /*
221 * if we exited the while loop without a 'return', we must have hit an NEND
222 * chunk if this is the case, the file was layed out as it was expected.
223 * now.. make sure we found both an info chunk, AND a data chunk... since
224 * these are minimum requirements for a valid NSFE file
225 */
226 return (chunks_found & (CHUNK_INFO | CHUNK_DATA)) ==
227 (CHUNK_INFO | CHUNK_DATA);
228}
229
230static bool parse_nesm(int fd, struct mp3entry *id3)
231{
232 struct NESM_HEADER hdr;
233 char *p = id3->id3v2buf;
234
235 lseek(fd, 0, SEEK_SET);
236 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
237 return false;
238
239 /* Length */
240 id3->length = (hdr.nTrackCount > 1 ? hdr.nTrackCount : 150) * 1000;
241
242 /* Title */
243 id3->title = p;
244 p += strlcpy(p, hdr.szGameTitle, 32) + 1;
245
246 /* Artist */
247 id3->artist = p;
248 p += strlcpy(p, hdr.szArtist, 32) + 1;
249
250 /* Copyright (per codec) */
251 id3->album = p;
252 strlcpy(p, hdr.szCopyright, 32);
253
254 return true;
255}
256
257bool get_nsf_metadata(int fd, struct mp3entry* id3)
258{
259 uint32_t nsf_type;
260 if (lseek(fd, 0, SEEK_SET) < 0 ||
261 read_uint32be(fd, &nsf_type) != (int)sizeof(nsf_type))
262 return false;
263
264 id3->vbr = false;
265 id3->filesize = filesize(fd);
266 /* we only render 16 bits, 44.1KHz, Mono */
267 id3->bitrate = 706;
268 id3->frequency = 44100;
269
270 if (nsf_type == CHAR4_CONST('N', 'S', 'F', 'E'))
271 return parse_nsfe(fd, id3);
272 else if (nsf_type == CHAR4_CONST('N', 'E', 'S', 'M'))
273 return parse_nesm(fd, id3);
274
275 /* not a valid format*/
276 return false;
277}
278
diff --git a/apps/metadata/ogg.c b/apps/metadata/ogg.c
deleted file mode 100644
index 3a3cb29998..0000000000
--- a/apps/metadata/ogg.c
+++ /dev/null
@@ -1,215 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33/* A simple parser to read vital metadata from an Ogg Vorbis file.
34 * Can also handle parsing Ogg Speex files for metadata. Returns
35 * false if metadata needed by the codec couldn't be read.
36 */
37bool get_ogg_metadata(int fd, struct mp3entry* id3)
38{
39 /* An Ogg File is split into pages, each starting with the string
40 * "OggS". Each page has a timestamp (in PCM samples) referred to as
41 * the "granule position".
42 *
43 * An Ogg Vorbis has the following structure:
44 * 1) Identification header (containing samplerate, numchannels, etc)
45 * 2) Comment header - containing the Vorbis Comments
46 * 3) Setup header - containing codec setup information
47 * 4) Many audio packets...
48 *
49 * An Ogg Speex has the following structure:
50 * 1) Identification header (containing samplerate, numchannels, etc)
51 * Described in this page: (http://www.speex.org/manual2/node7.html)
52 * 2) Comment header - containing the Vorbis Comments
53 * 3) Many audio packets.
54 */
55
56 /* Use the path name of the id3 structure as a temporary buffer. */
57 unsigned char* buf = (unsigned char *)id3->path;
58 long comment_size;
59 long remaining = 0;
60 long last_serial = 0;
61 long serial, r;
62 int segments, header_size;
63 int i;
64 bool eof = false;
65
66 /* 92 bytes is enough for both Vorbis and Speex headers */
67 if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 92) < 92))
68 {
69 return false;
70 }
71
72 /* All Ogg streams start with OggS */
73 if (memcmp(buf, "OggS", 4) != 0)
74 {
75 return false;
76 }
77
78 /* Check for format magic and then get metadata */
79 if (memcmp(&buf[29], "vorbis", 6) == 0)
80 {
81 id3->codectype = AFMT_OGG_VORBIS;
82 id3->frequency = get_long_le(&buf[40]);
83 id3->vbr = true;
84
85 /* Comments are in second Ogg page (byte 58 onwards for Vorbis) */
86 if (lseek(fd, 58, SEEK_SET) < 0)
87 {
88 return false;
89 }
90 }
91 else if (memcmp(&buf[28], "Speex ", 8) == 0)
92 {
93 id3->codectype = AFMT_SPEEX;
94 id3->frequency = get_slong(&buf[64]);
95 id3->vbr = get_long_le(&buf[88]);
96
97 header_size = get_long_le(&buf[60]);
98
99 /* Comments are in second Ogg page (byte 108 onwards for Speex) */
100 if (lseek(fd, 28 + header_size, SEEK_SET) < 0)
101 {
102 return false;
103 }
104 }
105 else
106 {
107 /* Unsupported format, try to print the marker, catches Ogg/FLAC at least */
108 DEBUGF("Usupported format in Ogg stream: %16s\n", &buf[28]);
109 return false;
110 }
111
112 id3->filesize = filesize(fd);
113
114 /* We need to ensure the serial number from this page is the same as the
115 * one from the last page (since we only support a single bitstream).
116 */
117 serial = get_long_le(&buf[14]);
118 comment_size = read_vorbis_tags(fd, id3, remaining);
119
120 /* We now need to search for the last page in the file - identified by
121 * by ('O','g','g','S',0) and retrieve totalsamples.
122 */
123
124 /* A page is always < 64 kB */
125 if (lseek(fd, -(MIN(64 * 1024, id3->filesize)), SEEK_END) < 0)
126 {
127 return false;
128 }
129
130 remaining = 0;
131
132 while (!eof)
133 {
134 r = read(fd, &buf[remaining], MAX_PATH - remaining);
135
136 if (r <= 0)
137 {
138 eof = true;
139 }
140 else
141 {
142 remaining += r;
143 }
144
145 /* Inefficient (but simple) search */
146 i = 0;
147
148 while (i < (remaining - 3))
149 {
150 if ((buf[i] == 'O') && (memcmp(&buf[i], "OggS", 4) == 0))
151 {
152 if (i < (remaining - 17))
153 {
154 /* Note that this only reads the low 32 bits of a
155 * 64 bit value.
156 */
157 id3->samples = get_long_le(&buf[i + 6]);
158 last_serial = get_long_le(&buf[i + 14]);
159
160 /* If this page is very small the beginning of the next
161 * header could be in buffer. Jump near end of this header
162 * and continue */
163 i += 27;
164 }
165 else
166 {
167 break;
168 }
169 }
170 else
171 {
172 i++;
173 }
174 }
175
176 if (i < remaining)
177 {
178 /* Move the remaining bytes to start of buffer.
179 * Reuse var 'segments' as it is no longer needed */
180 segments = 0;
181 while (i < remaining)
182 {
183 buf[segments++] = buf[i++];
184 }
185 remaining = segments;
186 }
187 else
188 {
189 /* Discard the rest of the buffer */
190 remaining = 0;
191 }
192 }
193
194 /* This file has mutiple vorbis bitstreams (or is corrupt). */
195 /* FIXME we should display an error here. */
196 if (serial != last_serial)
197 {
198 logf("serialno mismatch");
199 logf("%ld", serial);
200 logf("%ld", last_serial);
201 return false;
202 }
203
204 id3->length = ((int64_t) id3->samples * 1000) / id3->frequency;
205 if (id3->length <= 0)
206 {
207 logf("ogg length invalid!");
208 return false;
209 }
210
211 id3->bitrate = (((int64_t) id3->filesize - comment_size) * 8) / id3->length;
212
213 return true;
214}
215
diff --git a/apps/metadata/oma.c b/apps/metadata/oma.c
deleted file mode 100644
index b82c0a4f73..0000000000
--- a/apps/metadata/oma.c
+++ /dev/null
@@ -1,189 +0,0 @@
1/*
2 * Sony OpenMG (OMA) demuxer
3 *
4 * Copyright (c) 2008 Maxim Poliakovski
5 * 2008 Benjamin Larsson
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24/**
25 * @file oma.c
26 * This is a demuxer for Sony OpenMG Music files
27 *
28 * Known file extensions: ".oma", "aa3"
29 * The format of such files consists of three parts:
30 * - "ea3" header carrying overall info and metadata.
31 * - "EA3" header is a Sony-specific header containing information about
32 * the OpenMG file: codec type (usually ATRAC, can also be MP3 or WMA),
33 * codec specific info (packet size, sample rate, channels and so on)
34 * and DRM related info (file encryption, content id).
35 * - Sound data organized in packets follow the EA3 header
36 * (can be encrypted using the Sony DRM!).
37 *
38 * LIMITATIONS: This version supports only plain (unencrypted) OMA files.
39 * If any DRM-protected (encrypted) file is encountered you will get the
40 * corresponding error message. Try to remove the encryption using any
41 * Sony software (for example SonicStage).
42 * CODEC SUPPORT: Only ATRAC3 codec is currently supported!
43 */
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <inttypes.h>
48#include <string.h>
49#include "metadata.h"
50#include "metadata_parsers.h"
51
52#define EA3_HEADER_SIZE 96
53
54#if 0
55#define DEBUGF printf
56#else
57#define DEBUGF(...)
58#endif
59
60/* Various helper macros taken from ffmpeg for reading *
61 * and writing buffers with a specified endianess. */
62# define AV_RB16(x) \
63 ((((const uint8_t*)(x))[0] << 8) | \
64 ((const uint8_t*)(x))[1])
65# define AV_RB24(x) \
66 ((((const uint8_t*)(x))[0] << 16) | \
67 (((const uint8_t*)(x))[1] << 8) | \
68 ((const uint8_t*)(x))[2])
69# define AV_RB32(x) \
70 ((((const uint8_t*)(x))[0] << 24) | \
71 (((const uint8_t*)(x))[1] << 16) | \
72 (((const uint8_t*)(x))[2] << 8) | \
73 ((const uint8_t*)(x))[3])
74# define AV_WL32(p, d) do { \
75 ((uint8_t*)(p))[0] = (d); \
76 ((uint8_t*)(p))[1] = (d)>>8; \
77 ((uint8_t*)(p))[2] = (d)>>16; \
78 ((uint8_t*)(p))[3] = (d)>>24; \
79 } while(0)
80# define AV_WL16(p, d) do { \
81 ((uint8_t*)(p))[0] = (d); \
82 ((uint8_t*)(p))[1] = (d)>>8; \
83 } while(0)
84
85/* Different codecs that could be present in a Sony OMA *
86 * container file. */
87enum {
88 OMA_CODECID_ATRAC3 = 0,
89 OMA_CODECID_ATRAC3P = 1,
90 OMA_CODECID_MP3 = 3,
91 OMA_CODECID_LPCM = 4,
92 OMA_CODECID_WMA = 5,
93};
94
95/* FIXME: This functions currently read different file *
96 * parameters required for decoding. It still *
97 * does not read the metadata - which should be *
98 * present in the ea3 (first) header. The *
99 * metadata in ea3 is stored as a variation of *
100 * the ID3v2 metadata format. */
101static int oma_read_header(int fd, struct mp3entry* id3)
102{
103 static const uint16_t srate_tab[6] = {320,441,480,882,960,0};
104 int ret, ea3_taglen, EA3_pos, jsflag;
105 uint32_t codec_params;
106 int16_t eid;
107 uint8_t buf[EA3_HEADER_SIZE];
108
109 ret = read(fd, buf, 10);
110 if (ret != 10)
111 return -1;
112
113 ea3_taglen = ((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f);
114
115 EA3_pos = ea3_taglen + 10;
116 if (buf[5] & 0x10)
117 EA3_pos += 10;
118
119 lseek(fd, EA3_pos, SEEK_SET);
120 ret = read(fd, buf, EA3_HEADER_SIZE);
121 if (ret != EA3_HEADER_SIZE)
122 return -1;
123
124 if (memcmp(buf, ((const uint8_t[]){'E', 'A', '3'}),3) || buf[4] != 0 || buf[5] != EA3_HEADER_SIZE) {
125 DEBUGF("Couldn't find the EA3 header !\n");
126 return -1;
127 }
128
129 eid = AV_RB16(&buf[6]);
130 if (eid != -1 && eid != -128) {
131 DEBUGF("Encrypted file! Eid: %d\n", eid);
132 return -1;
133 }
134
135 codec_params = AV_RB24(&buf[33]);
136
137 switch (buf[32]) {
138 case OMA_CODECID_ATRAC3:
139 id3->frequency = srate_tab[(codec_params >> 13) & 7]*100;
140 if (id3->frequency != 44100) {
141 DEBUGF("Unsupported sample rate, send sample file to developers: %d\n", id3->frequency);
142 return -1;
143 }
144
145 id3->bytesperframe = (codec_params & 0x3FF) * 8;
146 id3->codectype = AFMT_OMA_ATRAC3;
147 jsflag = (codec_params >> 17) & 1; /* get stereo coding mode, 1 for joint-stereo */
148
149 id3->bitrate = id3->frequency * id3->bytesperframe * 8 / (1024 * 1000);
150
151 /* fake the atrac3 extradata (wav format, makes stream copy to wav work) */
152 /* ATRAC3 expects and extra-data size of 14 bytes for wav format, and *
153 * looks for that in the id3v2buf. */
154 id3->extradata_size = 14;
155 AV_WL16(&id3->id3v2buf[0], 1); // always 1
156 AV_WL32(&id3->id3v2buf[2], id3->frequency); // samples rate
157 AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode
158 AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode
159 AV_WL16(&id3->id3v2buf[10], 1); // always 1
160 AV_WL16(&id3->id3v2buf[12], 0); // always 0
161
162 id3->channels = 2;
163 DEBUGF("sample_rate = %d\n", id3->frequency);
164 DEBUGF("frame_size = %d\n", id3->bytesperframe);
165 DEBUGF("stereo_coding_mode = %d\n", jsflag);
166 break;
167 default:
168 DEBUGF("Unsupported codec %d!\n",buf[32]);
169 return -1;
170 break;
171 }
172
173 /* Store the the offset of the first audio frame, to be able to seek to it *
174 * directly in atrac3_oma.codec. */
175 id3->first_frame_offset = EA3_pos + EA3_HEADER_SIZE;
176 return 0;
177}
178
179bool get_oma_metadata(int fd, struct mp3entry* id3)
180{
181 if(oma_read_header(fd, id3) < 0)
182 return false;
183
184 /* Currently, there's no means of knowing the duration *
185 * directly from the the file so we calculate it. */
186 id3->filesize = filesize(fd);
187 id3->length = ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate;
188 return true;
189}
diff --git a/apps/metadata/rm.c b/apps/metadata/rm.c
deleted file mode 100644
index 27f541cb25..0000000000
--- a/apps/metadata/rm.c
+++ /dev/null
@@ -1,464 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Mohamed Tarek
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include <codecs/librm/rm.h>
28#include "system.h"
29#include "metadata.h"
30#include "metadata_common.h"
31#include "metadata_parsers.h"
32#include "logf.h"
33
34/* Uncomment the following line for debugging */
35//#define DEBUG_RM
36#ifndef DEBUG_RM
37#undef DEBUGF
38#define DEBUGF(...)
39#endif
40
41#define ID3V1_OFFSET -128
42#define METADATA_FOOTER_OFFSET -140
43
44static inline void print_cook_extradata(RMContext *rmctx) {
45
46 DEBUGF(" cook_version = 0x%08lx\n", rm_get_uint32be(rmctx->codec_extradata));
47 DEBUGF(" samples_per_frame_per_channel = %d\n", rm_get_uint16be(&rmctx->codec_extradata[4]));
48 DEBUGF(" number_of_subbands_in_freq_domain = %d\n", rm_get_uint16be(&rmctx->codec_extradata[6]));
49 if(rmctx->extradata_size == 16) {
50 DEBUGF(" joint_stereo_subband_start = %d\n",rm_get_uint16be(&rmctx->codec_extradata[12]));
51 DEBUGF(" joint_stereo_vlc_bits = %d\n", rm_get_uint16be(&rmctx->codec_extradata[14]));
52 }
53}
54
55
56struct real_object_t
57{
58 uint32_t fourcc;
59 uint32_t size;
60 uint16_t version;
61};
62
63static int real_read_object_header(int fd, struct real_object_t* obj)
64{
65 int n;
66
67 if ((n = read_uint32be(fd, &obj->fourcc)) <= 0)
68 return n;
69 if ((n = read_uint32be(fd, &obj->size)) <= 0)
70 return n;
71 if ((n = read_uint16be(fd, &obj->version)) <= 0)
72 return n;
73
74 return 1;
75}
76
77#if (defined(SIMULATOR) && defined(DEBUG_RM))
78static char* fourcc2str(uint32_t f)
79{
80 static char res[5];
81
82 res[0] = (f & 0xff000000) >> 24;
83 res[1] = (f & 0xff0000) >> 16;
84 res[2] = (f & 0xff00) >> 8;
85 res[3] = (f & 0xff);
86 res[4] = 0;
87
88 return res;
89}
90#endif
91
92static inline int real_read_audio_stream_info(int fd, RMContext *rmctx)
93{
94 int skipped = 0;
95 uint32_t version;
96 struct real_object_t obj;
97#ifdef SIMULATOR
98 uint32_t header_size;
99 uint16_t flavor;
100 uint32_t coded_framesize;
101 uint8_t interleaver_id_length;
102 uint8_t fourcc_length;
103#endif
104 uint32_t interleaver_id;
105 uint32_t fourcc = 0;
106
107 memset(&obj,0,sizeof(obj));
108 read_uint32be(fd, &version);
109 skipped += 4;
110
111 DEBUGF(" version=0x%04lx\n",((version >> 16) & 0xff));
112 if (((version >> 16) & 0xff) == 3) {
113 /* Very old version */
114 } else {
115#ifdef SIMULATOR
116 real_read_object_header(fd, &obj);
117 read_uint32be(fd, &header_size);
118 /* obj.size will be filled with an unknown value, replaced with header_size */
119 DEBUGF(" Object: %s, size: %ld bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version);
120
121 read_uint16be(fd, &flavor);
122 read_uint32be(fd, &coded_framesize);
123#else
124 lseek(fd, 20, SEEK_CUR);
125#endif
126 lseek(fd, 12, SEEK_CUR); /* unknown */
127 read_uint16be(fd, &rmctx->sub_packet_h);
128 read_uint16be(fd, &rmctx->block_align);
129 read_uint16be(fd, &rmctx->sub_packet_size);
130 lseek(fd, 2, SEEK_CUR); /* unknown */
131 skipped += 40;
132 if (((version >> 16) & 0xff) == 5)
133 {
134 lseek(fd, 6, SEEK_CUR); /* unknown */
135 skipped += 6;
136 }
137 read_uint16be(fd, &rmctx->sample_rate);
138 lseek(fd, 4, SEEK_CUR); /* unknown */
139 read_uint16be(fd, &rmctx->nb_channels);
140 skipped += 8;
141 if (((version >> 16) & 0xff) == 4)
142 {
143#ifdef SIMULATOR
144 read_uint8(fd, &interleaver_id_length);
145 read_uint32be(fd, &interleaver_id);
146 read_uint8(fd, &fourcc_length);
147#else
148 lseek(fd, 6, SEEK_CUR);
149#endif
150 read_uint32be(fd, &fourcc);
151 skipped += 10;
152 }
153 if (((version >> 16) & 0xff) == 5)
154 {
155 read_uint32be(fd, &interleaver_id);
156 read_uint32be(fd, &fourcc);
157 skipped += 8;
158 }
159 lseek(fd, 3, SEEK_CUR); /* unknown */
160 skipped += 3;
161 if (((version >> 16) & 0xff) == 5)
162 {
163 lseek(fd, 1, SEEK_CUR); /* unknown */
164 skipped += 1;
165 }
166
167 switch(fourcc) {
168 case FOURCC('c','o','o','k'):
169 rmctx->codec_type = CODEC_COOK;
170 read_uint32be(fd, &rmctx->extradata_size);
171 skipped += 4;
172 read(fd, rmctx->codec_extradata, rmctx->extradata_size);
173 skipped += rmctx->extradata_size;
174 break;
175
176 case FOURCC('r','a','a','c'):
177 case FOURCC('r','a','c','p'):
178 rmctx->codec_type = CODEC_AAC;
179 read_uint32be(fd, &rmctx->extradata_size);
180 skipped += 4;
181 read(fd, rmctx->codec_extradata, rmctx->extradata_size);
182 skipped += rmctx->extradata_size;
183 break;
184
185 case FOURCC('d','n','e','t'):
186 rmctx->codec_type = CODEC_AC3;
187 break;
188
189 case FOURCC('a','t','r','c'):
190 rmctx->codec_type = CODEC_ATRAC;
191 read_uint32be(fd, &rmctx->extradata_size);
192 skipped += 4;
193 read(fd, rmctx->codec_extradata, rmctx->extradata_size);
194 skipped += rmctx->extradata_size;
195 break;
196
197 default: /* Not a supported codec */
198 return -1;
199 }
200
201 DEBUGF(" flavor = %d\n",flavor);
202 DEBUGF(" coded_frame_size = %ld\n",coded_framesize);
203 DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h);
204 DEBUGF(" frame_size = %d\n",rmctx->block_align);
205 DEBUGF(" sub_packet_size = %d\n",rmctx->sub_packet_size);
206 DEBUGF(" sample_rate= %d\n",rmctx->sample_rate);
207 DEBUGF(" channels= %d\n",rmctx->nb_channels);
208 DEBUGF(" fourcc = %s\n",fourcc2str(fourcc));
209 DEBUGF(" codec_extra_data_length = %ld\n",rmctx->extradata_size);
210 DEBUGF(" codec_extradata :\n");
211 if(rmctx->codec_type == CODEC_COOK) {
212 DEBUGF(" cook_extradata :\n");
213 print_cook_extradata(rmctx);
214 }
215
216 }
217
218 return skipped;
219}
220
221static int rm_parse_header(int fd, RMContext *rmctx, struct mp3entry *id3)
222{
223 struct real_object_t obj;
224 int res;
225 int skipped;
226 off_t curpos __attribute__((unused));
227 uint8_t len; /* Holds a string_length, which is then passed to read_string() */
228
229#ifdef SIMULATOR
230 uint32_t avg_bitrate = 0;
231 uint32_t max_packet_size;
232 uint32_t avg_packet_size;
233 uint32_t packet_count;
234 uint32_t duration;
235 uint32_t preroll;
236 uint32_t index_offset;
237 uint16_t stream_id;
238 uint32_t start_time;
239 uint32_t codec_data_size;
240#endif
241 uint32_t v;
242 uint32_t max_bitrate;
243 uint16_t num_streams;
244 uint32_t next_data_off;
245 uint8_t header_end;
246
247 memset(&obj,0,sizeof(obj));
248 curpos = lseek(fd, 0, SEEK_SET);
249 res = real_read_object_header(fd, &obj);
250
251 if (obj.fourcc == FOURCC('.','r','a',0xfd))
252 {
253 /* Very old .ra format - not yet supported */
254 return -1;
255 }
256 else if (obj.fourcc != FOURCC('.','R','M','F'))
257 {
258 return -1;
259 }
260
261 lseek(fd, 8, SEEK_CUR); /* unknown */
262
263 DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos);
264
265 res = real_read_object_header(fd, &obj);
266 header_end = 0;
267 while(res)
268 {
269 DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos);
270 skipped = 10;
271 if(obj.fourcc == FOURCC('I','N','D','X'))
272 break;
273 switch (obj.fourcc)
274 {
275 case FOURCC('P','R','O','P'): /* File properties */
276 read_uint32be(fd, &max_bitrate);
277 read_uint32be(fd, &rmctx->bit_rate); /*avg bitrate*/
278#ifdef SIMULATOR
279 read_uint32be(fd, &max_packet_size);
280 read_uint32be(fd, &avg_packet_size);
281 read_uint32be(fd, &packet_count);
282#else
283 lseek(fd, 3*sizeof(uint32_t), SEEK_CUR);
284#endif
285 read_uint32be(fd, &rmctx->duration);
286#ifdef SIMULATOR
287 read_uint32be(fd, &preroll);
288 read_uint32be(fd, &index_offset);
289#else
290 lseek(fd, 2*sizeof(uint32_t), SEEK_CUR);
291#endif
292 read_uint32be(fd, &rmctx->data_offset);
293 read_uint16be(fd, &num_streams);
294 read_uint16be(fd, &rmctx->flags);
295 skipped += 40;
296
297 DEBUGF(" max_bitrate = %ld\n",max_bitrate);
298 DEBUGF(" avg_bitrate = %ld\n",rmctx->bit_rate);
299 DEBUGF(" max_packet_size = %ld\n",max_packet_size);
300 DEBUGF(" avg_packet_size = %ld\n",avg_packet_size);
301 DEBUGF(" packet_count = %ld\n",packet_count);
302 DEBUGF(" duration = %ld\n",rmctx->duration);
303 DEBUGF(" preroll = %ld\n",preroll);
304 DEBUGF(" index_offset = %ld\n",index_offset);
305 DEBUGF(" data_offset = %ld\n",rmctx->data_offset);
306 DEBUGF(" num_streams = %d\n",num_streams);
307 DEBUGF(" flags=0x%04x\n",rmctx->flags);
308 break;
309
310 case FOURCC('C','O','N','T'):
311 /* Four strings - Title, Author, Copyright, Comment */
312 read_uint8(fd,&len);
313 skipped += (int)read_string(fd, id3->id3v1buf[0], sizeof(id3->id3v1buf[0]), '\0', len);
314 read_uint8(fd,&len);
315 skipped += (int)read_string(fd, id3->id3v1buf[1], sizeof(id3->id3v1buf[1]), '\0', len);
316 read_uint8(fd,&len);
317 skipped += (int)read_string(fd, id3->id3v1buf[2], sizeof(id3->id3v1buf[2]), '\0', len);
318 read_uint8(fd,&len);
319 skipped += (int)read_string(fd, id3->id3v1buf[3], sizeof(id3->id3v1buf[3]), '\0', len);
320 skipped += 4;
321
322 DEBUGF(" title=\"%s\"\n",id3->id3v1buf[0]);
323 DEBUGF(" author=\"%s\"\n",id3->id3v1buf[1]);
324 DEBUGF(" copyright=\"%s\"\n",id3->id3v1buf[2]);
325 DEBUGF(" comment=\"%s\"\n",id3->id3v1buf[3]);
326 break;
327
328 case FOURCC('M','D','P','R'): /* Media properties */
329#ifdef SIMULATOR
330 read_uint16be(fd,&stream_id);
331 read_uint32be(fd,&max_bitrate);
332 read_uint32be(fd,&avg_bitrate);
333 read_uint32be(fd,&max_packet_size);
334 read_uint32be(fd,&avg_packet_size);
335 read_uint32be(fd,&start_time);
336 read_uint32be(fd,&preroll);
337 read_uint32be(fd,&duration);
338#else
339 lseek(fd, 30, SEEK_CUR);
340#endif
341 skipped += 30;
342 read_uint8(fd,&len);
343 skipped += 1;
344 lseek(fd, len, SEEK_CUR); /* desc */
345 skipped += len;
346 read_uint8(fd,&len);
347 skipped += 1;
348#ifdef SIMULATOR
349 lseek(fd, len, SEEK_CUR); /* mimetype */
350 read_uint32be(fd,&codec_data_size);
351#else
352 lseek(fd, len + 4, SEEK_CUR);
353#endif
354 skipped += len + 4;
355 read_uint32be(fd,&v);
356 skipped += 4;
357
358 DEBUGF(" stream_id = 0x%04x\n",stream_id);
359 DEBUGF(" max_bitrate = %ld\n",max_bitrate);
360 DEBUGF(" avg_bitrate = %ld\n",avg_bitrate);
361 DEBUGF(" max_packet_size = %ld\n",max_packet_size);
362 DEBUGF(" avg_packet_size = %ld\n",avg_packet_size);
363 DEBUGF(" start_time = %ld\n",start_time);
364 DEBUGF(" preroll = %ld\n",preroll);
365 DEBUGF(" duration = %ld\n",duration);
366 DEBUGF(" codec_data_size = %ld\n",codec_data_size);
367 DEBUGF(" v=\"%s\"\n", fourcc2str(v));
368
369 if (v == FOURCC('.','r','a',0xfd))
370 {
371 int temp;
372 temp= real_read_audio_stream_info(fd, rmctx);
373 if(temp < 0)
374 return -1;
375 else
376 skipped += temp;
377 }
378 else if (v == FOURCC('L','S','D',':'))
379 {
380 DEBUGF("Real audio lossless is not supported.");
381 return -1;
382 }
383 else
384 {
385 /* We shall not abort with -1 here. *.rm file often seem
386 * to have a second media properties header that contains
387 * other metadata. */
388 DEBUGF("Unknown header signature :\"%s\"\n", fourcc2str(v));
389 }
390
391
392 break;
393
394 case FOURCC('D','A','T','A'):
395 read_uint32be(fd,&rmctx->nb_packets);
396 skipped += 4;
397 read_uint32be(fd,&next_data_off);
398 skipped += 4;
399
400 /***
401 * nb_packets correction :
402 * in some samples, number of packets may not exactly form
403 * an integer number of scrambling units. This is corrected
404 * by constructing a partially filled unit out of the few
405 * remaining samples at the end of decoding.
406 ***/
407 if(rmctx->nb_packets % rmctx->sub_packet_h)
408 rmctx->nb_packets += rmctx->sub_packet_h - (rmctx->nb_packets % rmctx->sub_packet_h);
409
410 DEBUGF(" data_nb_packets = %ld\n",rmctx->nb_packets);
411 DEBUGF(" next DATA offset = %ld\n",next_data_off);
412 header_end = 1;
413 break;
414 }
415 if(header_end) break;
416 curpos = lseek(fd, obj.size - skipped, SEEK_CUR);
417 res = real_read_object_header(fd, &obj);
418 }
419
420
421 return 0;
422}
423
424
425bool get_rm_metadata(int fd, struct mp3entry* id3)
426{
427 RMContext *rmctx = (RMContext*) (( (intptr_t)id3->id3v2buf + 3 ) &~ 3);
428 memset(rmctx,0,sizeof(RMContext));
429 if(rm_parse_header(fd, rmctx, id3) < 0)
430 return false;
431
432 if (!setid3v1title(fd, id3)) {
433 /* file has no id3v1 tags, use the tags from CONT chunk */
434 id3->title = id3->id3v1buf[0];
435 id3->artist = id3->id3v1buf[1];
436 id3->comment= id3->id3v1buf[3];
437 }
438
439 switch(rmctx->codec_type)
440 {
441 case CODEC_COOK:
442 /* Already set, do nothing */
443 break;
444 case CODEC_AAC:
445 id3->codectype = AFMT_RM_AAC;
446 break;
447
448 case CODEC_AC3:
449 id3->codectype = AFMT_RM_AC3;
450 break;
451
452 case CODEC_ATRAC:
453 id3->codectype = AFMT_RM_ATRAC3;
454 break;
455 }
456
457 id3->channels = rmctx->nb_channels;
458 id3->extradata_size = rmctx->extradata_size;
459 id3->bitrate = rmctx->bit_rate / 1000;
460 id3->frequency = rmctx->sample_rate;
461 id3->length = rmctx->duration;
462 id3->filesize = filesize(fd);
463 return true;
464}
diff --git a/apps/metadata/sgc.c b/apps/metadata/sgc.c
deleted file mode 100644
index 78cacb9b1b..0000000000
--- a/apps/metadata/sgc.c
+++ /dev/null
@@ -1,67 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13static bool parse_sgc_header(int fd, struct mp3entry* id3)
14{
15 /* Use the trackname part of the id3 structure as a temporary buffer */
16 unsigned char* buf = (unsigned char *)id3->path;
17
18 lseek(fd, 0, SEEK_SET);
19 if (read(fd, buf, 0xA0) < 0xA0)
20 return false;
21
22 /* calculate track length with number of tracks */
23 id3->length = buf[37] * 1000;
24
25 /* If meta info was found in the m3u skip next step */
26 if (id3->title && id3->title[0]) return true;
27
28 char *p = id3->id3v2buf;
29
30 /* Some metadata entries have 32 bytes length */
31 /* Game */
32 memcpy(p, &buf[64], 32); *(p + 33) = '\0';
33 id3->title = p;
34 p += strlen(p)+1;
35
36 /* Artist */
37 memcpy(p, &buf[96], 32); *(p + 33) = '\0';
38 id3->artist = p;
39 p += strlen(p)+1;
40
41 /* Copyright */
42 memcpy(p, &buf[128], 32); *(p + 33) = '\0';
43 id3->album = p;
44 p += strlen(p)+1;
45 return true;
46}
47
48
49bool get_sgc_metadata(int fd, struct mp3entry* id3)
50{
51 uint32_t sgc_type;
52 if ((lseek(fd, 0, SEEK_SET) < 0) ||
53 read_uint32be(fd, &sgc_type) != (int)sizeof(sgc_type))
54 return false;
55
56 id3->vbr = false;
57 id3->filesize = filesize(fd);
58 /* we only render 16 bits, 44.1KHz, Stereo */
59 id3->bitrate = 706;
60 id3->frequency = 44100;
61
62 /* Make sure this is an SGC file */
63 if (sgc_type != FOURCC('S','G','C',0x1A))
64 return false;
65
66 return parse_sgc_header(fd, id3);
67}
diff --git a/apps/metadata/sid.c b/apps/metadata/sid.c
deleted file mode 100644
index 50b879b56d..0000000000
--- a/apps/metadata/sid.c
+++ /dev/null
@@ -1,89 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "rbunicode.h"
32
33/* PSID metadata info is available here:
34 http://www.unusedino.de/ec64/technical/formats/sidplay.html */
35bool get_sid_metadata(int fd, struct mp3entry* id3)
36{
37 /* Use the trackname part of the id3 structure as a temporary buffer */
38 unsigned char* buf = (unsigned char *)id3->path;
39 char *p;
40
41
42 if ((lseek(fd, 0, SEEK_SET) < 0)
43 || (read(fd, buf, 0x80) < 0x80))
44 {
45 return false;
46 }
47
48 if ((memcmp(buf, "PSID", 4) != 0))
49 {
50 return false;
51 }
52
53 p = id3->id3v2buf;
54
55 /* Copy Title (assumed max 0x1f letters + 1 zero byte) */
56 id3->title = p;
57 buf[0x16+0x1f] = 0;
58 p = iso_decode(&buf[0x16], p, 0, strlen(&buf[0x16])+1);
59
60 /* Copy Artist (assumed max 0x1f letters + 1 zero byte) */
61 id3->artist = p;
62 buf[0x36+0x1f] = 0;
63 p = iso_decode(&buf[0x36], p, 0, strlen(&buf[0x36])+1);
64
65 /* Copy Year (assumed max 4 letters + 1 zero byte) */
66 buf[0x56+0x4] = 0;
67 id3->year = atoi(&buf[0x56]);
68
69 /* Copy Album (assumed max 0x1f-0x05 letters + 1 zero byte) */
70 id3->album = p;
71 buf[0x56+0x1f] = 0;
72 iso_decode(&buf[0x5b], p, 0, strlen(&buf[0x5b])+1);
73
74 id3->bitrate = 706;
75 id3->frequency = 44100;
76 /* New idea as posted by Marco Alanen (ravon):
77 * Set the songlength in seconds to the number of subsongs
78 * so every second represents a subsong.
79 * Users can then skip the current subsong by seeking
80 *
81 * Note: the number of songs is a 16bit value at 0xE, so this code only
82 * uses the lower 8 bits of the counter.
83 */
84 id3->length = (buf[0xf]-1)*1000;
85 id3->vbr = false;
86 id3->filesize = filesize(fd);
87
88 return true;
89}
diff --git a/apps/metadata/smaf.c b/apps/metadata/smaf.c
deleted file mode 100644
index 1b745d3fa1..0000000000
--- a/apps/metadata/smaf.c
+++ /dev/null
@@ -1,470 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <inttypes.h>
22#include <stdio.h>
23
24#include "string-extra.h"
25#include "system.h"
26#include "metadata.h"
27#include "metadata_common.h"
28#include "metadata_parsers.h"
29#include "rbunicode.h"
30#include "logf.h"
31
32static const int basebits[4] = { 4, 8, 12, 16 };
33
34static const int frequency[5] = { 4000, 8000, 11025, 22050, 44100 };
35
36static const int support_codepages[5] = {
37#ifdef HAVE_LCD_BITMAP
38 SJIS, ISO_8859_1, -1, GB_2312, BIG_5,
39#else
40 -1, ISO_8859_1, -1, -1, -1,
41#endif
42};
43
44/* extra codepage */
45#define UCS2 (NUM_CODEPAGES + 1)
46
47/* support id3 tag */
48#define TAG_TITLE (('S'<<8)|'T')
49#define TAG_ARTIST (('A'<<8)|'N')
50#define TAG_COMPOSER (('S'<<8)|'W')
51
52/* convert functions */
53#define CONVERT_SMAF_CHANNELS(c) (((c) >> 7) + 1)
54
55
56static inline int convert_smaf_audio_basebit(unsigned int basebit)
57{
58 if (basebit > 3)
59 return 0;
60 return basebits[basebit];
61}
62
63static inline int convert_smaf_audio_frequency(unsigned int freq)
64{
65 if (freq > 4)
66 return 0;
67 return frequency[freq];
68}
69
70static int convert_smaf_codetype(unsigned int codetype)
71{
72 if (codetype < 5)
73 return support_codepages[codetype];
74 else if (codetype == 0x20 || codetype == 0x24) /* In Rockbox, UCS2 and UTF-16 are same. */
75 return UCS2;
76 else if (codetype == 0x23)
77 return UTF_8;
78 else if (codetype == 0xff)
79 return ISO_8859_1;
80 return -1;
81}
82
83static void set_length(struct mp3entry *id3, unsigned int ch, unsigned int basebit,
84 unsigned int numbytes)
85{
86 int bitspersample = convert_smaf_audio_basebit(basebit);
87
88 if (bitspersample != 0 && id3->frequency != 0)
89 {
90 /* Calculate track length [ms] and bitrate [kbit/s] */
91 id3->length = (uint64_t)numbytes * 8000LL
92 / (bitspersample * CONVERT_SMAF_CHANNELS(ch) * id3->frequency);
93 id3->bitrate = bitspersample * id3->frequency / 1000;
94 }
95
96 /* output contents/wave data/id3 info (for debug) */
97 DEBUGF("contents info ----\n");
98 DEBUGF(" TITLE: %s\n", (id3->title)? id3->title : "(NULL)");
99 DEBUGF(" ARTIST: %s\n", (id3->artist)? id3->artist : "(NULL)");
100 DEBUGF(" COMPOSER: %s\n", (id3->composer)? id3->composer : "(NULL)");
101 DEBUGF("wave data info ----\n");
102 DEBUGF(" channels: %u\n", CONVERT_SMAF_CHANNELS(ch));
103 DEBUGF(" bitspersample: %d\n", bitspersample);
104 DEBUGF(" numbytes; %u\n", numbytes);
105 DEBUGF("id3 info ----\n");
106 DEBUGF(" frquency: %u\n", (unsigned int)id3->frequency);
107 DEBUGF(" bitrate: %d\n", id3->bitrate);
108 DEBUGF(" length: %u\n", (unsigned int)id3->length);
109}
110
111/* contents parse functions */
112
113/* Note:
114 * 1) When the codepage is UTF-8 or UCS2, contents data do not start BOM.
115 * 2) The byte order of contents data is big endian.
116 */
117
118static void decode2utf8(const unsigned char *src, unsigned char **dst,
119 int srcsize, int *dstsize, int codepage)
120{
121 unsigned char tmpbuf[srcsize * 3 + 1];
122 unsigned char *p;
123 int utf8size;
124
125 if (codepage < NUM_CODEPAGES)
126 p = iso_decode(src, tmpbuf, codepage, srcsize);
127 else /* codepage == UCS2 */
128 p = utf16BEdecode(src, tmpbuf, srcsize);
129
130 *p = '\0';
131
132 strlcpy(*dst, tmpbuf, *dstsize);
133 utf8size = (p - tmpbuf) + 1;
134 if (utf8size > *dstsize)
135 {
136 DEBUGF("metadata warning: data length: %d > contents store buffer size: %d\n",
137 utf8size, *dstsize);
138 utf8size = *dstsize;
139 }
140 *dst += utf8size;
141 *dstsize -= utf8size;
142}
143
144static int read_audio_track_contets(int fd, int codepage, unsigned char **dst,
145 int *dstsize)
146{
147 /* value length <= 256 bytes */
148 unsigned char buf[256];
149 unsigned char *p = buf;
150 unsigned char *q = buf;
151 int datasize;
152
153 read(fd, buf, 256);
154
155 while (p - buf < 256 && *p != ',')
156 {
157 /* skip yen mark */
158 if (codepage != UCS2)
159 {
160 if (*p == '\\')
161 p++;
162 }
163 else if (*p == '\0' && *(p+1) == '\\')
164 p += 2;
165
166 if (*p > 0x7f)
167 {
168 if (codepage == UTF_8)
169 {
170 while ((*p & MASK) != COMP)
171 *q++ = *p++;
172 }
173#ifdef HAVE_LCD_BITMAP
174 else if (codepage == SJIS)
175 {
176 if (*p <= 0xa0 || *p >= 0xe0)
177 *q++ = *p++;
178 }
179#endif
180 }
181
182 *q++ = *p++;
183 if (codepage == UCS2)
184 *q++ = *p++;
185 }
186 datasize = p - buf + 1;
187 lseek(fd, datasize - 256, SEEK_CUR);
188
189 if (dst != NULL)
190 decode2utf8(buf, dst, q - buf, dstsize, codepage);
191
192 return datasize;
193}
194
195static void read_score_track_contets(int fd, int codepage, int datasize,
196 unsigned char **dst, int *dstsize)
197{
198 unsigned char buf[datasize];
199
200 read(fd, buf, datasize);
201 decode2utf8(buf, dst, datasize, dstsize, codepage);
202}
203
204/* traverse chunk functions */
205
206static unsigned int search_chunk(int fd, const unsigned char *name, int nlen)
207{
208 unsigned char buf[8];
209 unsigned int chunksize;
210
211 while (read(fd, buf, 8) > 0)
212 {
213 chunksize = get_long_be(buf + 4);
214 if (memcmp(buf, name, nlen) == 0)
215 return chunksize;
216
217 lseek(fd, chunksize, SEEK_CUR);
218 }
219 DEBUGF("metadata error: missing '%s' chunk\n", name);
220 return 0;
221}
222
223static bool parse_smaf_audio_track(int fd, struct mp3entry *id3, unsigned int datasize)
224{
225 /* temporary buffer */
226 unsigned char *tmp = (unsigned char*)id3->path;
227 /* contents stored buffer */
228 unsigned char *buf = id3->id3v2buf;
229 int bufsize = sizeof(id3->id3v2buf);
230
231 unsigned int chunksize = datasize;
232 int valsize;
233
234 int codepage;
235
236 /* parse contents info */
237 read(fd, tmp, 5);
238 codepage = convert_smaf_codetype(tmp[2]);
239 if (codepage < 0)
240 {
241 DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[2]);
242 return false;
243 }
244
245 datasize -= 5;
246 while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL)
247 && (datasize > 0 && bufsize > 0))
248 {
249 if (read(fd, tmp, 3) <= 0)
250 return false;
251
252 if (tmp[2] != ':')
253 {
254 DEBUGF("metadata error: illegal tag: %c%c%c\n", tmp[0], tmp[1], tmp[2]);
255 return false;
256 }
257 switch ((tmp[0]<<8)|tmp[1])
258 {
259 case TAG_TITLE:
260 id3->title = buf;
261 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
262 break;
263 case TAG_ARTIST:
264 id3->artist = buf;
265 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
266 break;
267 case TAG_COMPOSER:
268 id3->composer = buf;
269 valsize = read_audio_track_contets(fd, codepage, &buf, &bufsize);
270 break;
271 default:
272 valsize = read_audio_track_contets(fd, codepage, NULL, &bufsize);
273 break;
274 }
275 datasize -= (valsize + 3);
276 }
277
278 /* search PCM Audio Track Chunk */
279 lseek(fd, 16 + chunksize, SEEK_SET);
280
281 chunksize = search_chunk(fd, "ATR", 3);
282 if (chunksize == 0)
283 {
284 DEBUGF("metadata error: missing PCM Audio Track Chunk\n");
285 return false;
286 }
287
288 /*
289 * get format
290 * tmp
291 * +0: Format Type
292 * +1: Sequence Type
293 * +2: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: frequency
294 * +3: bit 4-7: base bit
295 * +4: TimeBase_D
296 * +5: TimeBase_G
297 *
298 * Note: If PCM Audio Track does not include Sequence Data Chunk,
299 * tmp+6 is the start position of Wave Data Chunk.
300 */
301 read(fd, tmp, 6);
302
303 /* search Wave Data Chunk */
304 chunksize = search_chunk(fd, "Awa", 3);
305 if (chunksize == 0)
306 {
307 DEBUGF("metadata error: missing Wave Data Chunk\n");
308 return false;
309 }
310
311 /* set track length and bitrate */
312 id3->frequency = convert_smaf_audio_frequency(tmp[2] & 0x0f);
313 set_length(id3, tmp[2], tmp[3] >> 4, chunksize);
314 return true;
315}
316
317static bool parse_smaf_score_track(int fd, struct mp3entry *id3)
318{
319 /* temporary buffer */
320 unsigned char *tmp = (unsigned char*)id3->path;
321 unsigned char *p = tmp;
322 /* contents stored buffer */
323 unsigned char *buf = id3->id3v2buf;
324 int bufsize = sizeof(id3->id3v2buf);
325
326 unsigned int chunksize;
327 unsigned int datasize;
328 int valsize;
329
330 int codepage;
331
332 /* parse Optional Data Chunk */
333 read(fd, tmp, 21);
334 if (memcmp(tmp + 5, "OPDA", 4) != 0)
335 {
336 DEBUGF("metadata error: missing Optional Data Chunk\n");
337 return false;
338 }
339
340 /* Optional Data Chunk size */
341 chunksize = get_long_be(tmp + 9);
342
343 /* parse Data Chunk */
344 if (memcmp(tmp + 13, "Dch", 3) != 0)
345 {
346 DEBUGF("metadata error: missing Data Chunk\n");
347 return false;
348 }
349
350 codepage = convert_smaf_codetype(tmp[16]);
351 if (codepage < 0)
352 {
353 DEBUGF("metadata error: smaf unsupport codetype: %d\n", tmp[16]);
354 return false;
355 }
356
357 /* Data Chunk size */
358 datasize = get_long_be(tmp + 17);
359 while ((id3->title == NULL || id3->artist == NULL || id3->composer == NULL)
360 && (datasize > 0 && bufsize > 0))
361 {
362 if (read(fd, tmp, 4) <= 0)
363 return false;
364
365 valsize = (tmp[2] << 8) | tmp[3];
366 datasize -= (valsize + 4);
367 switch ((tmp[0]<<8)|tmp[1])
368 {
369 case TAG_TITLE:
370 id3->title = buf;
371 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
372 break;
373 case TAG_ARTIST:
374 id3->artist = buf;
375 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
376 break;
377 case TAG_COMPOSER:
378 id3->composer = buf;
379 read_score_track_contets(fd, codepage, valsize, &buf, &bufsize);
380 break;
381 default:
382 lseek(fd, valsize, SEEK_CUR);
383 break;
384 }
385 }
386
387 /* search Score Track Chunk */
388 lseek(fd, 29 + chunksize, SEEK_SET);
389
390 if (search_chunk(fd, "MTR", 3) == 0)
391 {
392 DEBUGF("metadata error: missing Score Track Chunk\n");
393 return false;
394 }
395
396 /*
397 * search next chunk
398 * usually, next chunk ('M***') found within 40 bytes.
399 */
400 chunksize = 40;
401 read(fd, tmp, chunksize);
402
403 tmp[chunksize] = 'M'; /* stopper */
404 while (*p != 'M')
405 p++;
406
407 chunksize -= (p - tmp);
408 if (chunksize == 0)
409 {
410 DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk");
411 return false;
412 }
413
414 /* search Score Track Stream PCM Data Chunk */
415 lseek(fd, -chunksize, SEEK_CUR);
416 if (search_chunk(fd, "Mtsp", 4) == 0)
417 {
418 DEBUGF("metadata error: missing Score Track Stream PCM Data Chunk\n");
419 return false;
420 }
421
422 /*
423 * parse Score Track Stream Wave Data Chunk
424 * tmp
425 * +4-7: chunk size (WaveType(3bytes) + wave data count)
426 * +8: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: base bit
427 * +9: frequency (MSB)
428 * +10: frequency (LSB)
429 */
430 read(fd, tmp, 11);
431 if (memcmp(tmp, "Mwa", 3) != 0)
432 {
433 DEBUGF("metadata error: missing Score Track Stream Wave Data Chunk\n");
434 return false;
435 }
436
437 /* set track length and bitrate */
438 id3->frequency = (tmp[9] << 8) | tmp[10];
439 set_length(id3, tmp[8], tmp[8] & 0x0f, get_long_be(tmp + 4) - 3);
440 return true;
441}
442
443bool get_smaf_metadata(int fd, struct mp3entry* id3)
444{
445 /* temporary buffer */
446 unsigned char *tmp = (unsigned char *)id3->path;
447 unsigned int chunksize;
448
449 id3->title = NULL;
450 id3->artist = NULL;
451 id3->composer = NULL;
452
453 id3->vbr = false; /* All SMAF files are CBR */
454 id3->filesize = filesize(fd);
455
456 /* check File Chunk and Contents Info Chunk */
457 lseek(fd, 0, SEEK_SET);
458 read(fd, tmp, 16);
459 if ((memcmp(tmp, "MMMD", 4) != 0) || (memcmp(tmp + 8, "CNTI", 4) != 0))
460 {
461 DEBUGF("metadata error: does not smaf format\n");
462 return false;
463 }
464
465 chunksize = get_long_be(tmp + 12);
466 if (chunksize > 5)
467 return parse_smaf_audio_track(fd, id3, chunksize);
468
469 return parse_smaf_score_track(fd, id3);
470}
diff --git a/apps/metadata/spc.c b/apps/metadata/spc.c
deleted file mode 100644
index 1c0206205d..0000000000
--- a/apps/metadata/spc.c
+++ /dev/null
@@ -1,130 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "debug.h"
32#include "rbunicode.h"
33
34bool get_spc_metadata(int fd, struct mp3entry* id3)
35{
36 /* Use the trackname part of the id3 structure as a temporary buffer */
37 unsigned char * buf = (unsigned char *)id3->path;
38 char * p;
39
40 unsigned long length;
41 unsigned long fade;
42 bool isbinary = true;
43 int i;
44
45 /* try to get the ID666 tag */
46 if ((lseek(fd, 0x2e, SEEK_SET) < 0)
47 || (read(fd, buf, 0xD2) < 0xD2))
48 {
49 DEBUGF("lseek or read failed\n");
50 return false;
51 }
52
53 p = id3->id3v2buf;
54
55 id3->title = p;
56 buf[31] = 0;
57 p = iso_decode(buf, p, 0, 32);
58 buf += 32;
59
60 id3->album = p;
61 buf[31] = 0;
62 p = iso_decode(buf, p, 0, 32);
63 buf += 48;
64
65 id3->comment = p;
66 buf[31] = 0;
67 p = iso_decode(buf, p, 0, 32);
68 buf += 32;
69
70 /* Date check */
71 if(buf[2] == '/' && buf[5] == '/')
72 isbinary = false;
73
74 /* Reserved bytes check */
75 if(buf[0xD2 - 0x2E - 112] >= '0' &&
76 buf[0xD2 - 0x2E - 112] <= '9' &&
77 buf[0xD3 - 0x2E - 112] == 0x00)
78 isbinary = false;
79
80 /* is length & fade only digits? */
81 for (i=0;i<8 && (
82 (buf[0xA9 - 0x2E - 112+i]>='0'&&buf[0xA9 - 0x2E - 112+i]<='9') ||
83 buf[0xA9 - 0x2E - 112+i]=='\0');
84 i++);
85 if (i==8) isbinary = false;
86
87 if(isbinary) {
88 id3->year = buf[0] | (buf[1]<<8);
89 buf += 11;
90
91 length = (buf[0] | (buf[1]<<8) | (buf[2]<<16)) * 1000;
92 buf += 3;
93
94 fade = (buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24));
95 buf += 4;
96 } else {
97 char tbuf[6];
98
99 buf += 6;
100 buf[4] = 0;
101 id3->year = atoi(buf);
102 buf += 5;
103
104 memcpy(tbuf, buf, 3);
105 tbuf[3] = 0;
106 length = atoi(tbuf) * 1000;
107 buf += 3;
108
109 memcpy(tbuf, buf, 5);
110 tbuf[5] = 0;
111 fade = atoi(tbuf);
112 buf += 5;
113 }
114
115 id3->artist = p;
116 buf[31] = 0;
117 iso_decode(buf, p, 0, 32);
118
119 if (length==0) {
120 length=3*60*1000; /* 3 minutes */
121 fade=5*1000; /* 5 seconds */
122 }
123
124 id3->length = length+fade;
125
126 id3->filesize = filesize(fd);
127 id3->genre_string = id3_get_num_genre(36);
128
129 return true;
130}
diff --git a/apps/metadata/tta.c b/apps/metadata/tta.c
deleted file mode 100644
index 1d3d95f118..0000000000
--- a/apps/metadata/tta.c
+++ /dev/null
@@ -1,123 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33#define TTA1_SIGN 0x31415454
34
35#define TTA_HEADER_ID 0
36#define TTA_HEADER_AUDIO_FORMAT (TTA_HEADER_ID + sizeof(unsigned int))
37#define TTA_HEADER_NUM_CHANNELS (TTA_HEADER_AUDIO_FORMAT + sizeof(unsigned short))
38#define TTA_HEADER_BITS_PER_SAMPLE (TTA_HEADER_NUM_CHANNELS + sizeof(unsigned short))
39#define TTA_HEADER_SAMPLE_RATE (TTA_HEADER_BITS_PER_SAMPLE + sizeof(unsigned short))
40#define TTA_HEADER_DATA_LENGTH (TTA_HEADER_SAMPLE_RATE + sizeof(unsigned int))
41#define TTA_HEADER_CRC32 (TTA_HEADER_DATA_LENGTH + sizeof(unsigned int))
42#define TTA_HEADER_SIZE (TTA_HEADER_CRC32 + sizeof(unsigned int))
43
44#define TTA_HEADER_GETTER_ID(x) get_long_le(x)
45#define TTA_HEADER_GETTER_AUDIO_FORMAT(x) get_short_le(x)
46#define TTA_HEADER_GETTER_NUM_CHANNELS(x) get_short_le(x)
47#define TTA_HEADER_GETTER_BITS_PER_SAMPLE(x) get_short_le(x)
48#define TTA_HEADER_GETTER_SAMPLE_RATE(x) get_long_le(x)
49#define TTA_HEADER_GETTER_DATA_LENGTH(x) get_long_le(x)
50#define TTA_HEADER_GETTER_CRC32(x) get_long_le(x)
51
52#define GET_HEADER(x, tag) TTA_HEADER_GETTER_ ## tag((x) + TTA_HEADER_ ## tag)
53
54static void read_id3_tags(int fd, struct mp3entry* id3)
55{
56 id3->title = NULL;
57 id3->filesize = filesize(fd);
58 id3->id3v2len = getid3v2len(fd);
59 id3->tracknum = 0;
60 id3->discnum = 0;
61 id3->vbr = false; /* All TTA files are CBR */
62
63 /* first get id3v2 tags. if no id3v2 tags ware found, get id3v1 tags */
64 if (id3->id3v2len)
65 {
66 setid3v2title(fd, id3);
67 id3->first_frame_offset = id3->id3v2len;
68 return;
69 }
70 setid3v1title(fd, id3);
71}
72
73bool get_tta_metadata(int fd, struct mp3entry* id3)
74{
75 unsigned char ttahdr[TTA_HEADER_SIZE];
76 unsigned int datasize;
77 unsigned int origsize;
78 int bps;
79
80 lseek(fd, 0, SEEK_SET);
81
82 /* read id3 tags */
83 read_id3_tags(fd, id3);
84 lseek(fd, id3->id3v2len, SEEK_SET);
85
86 /* read TTA header */
87 if (read(fd, ttahdr, TTA_HEADER_SIZE) < 0)
88 return false;
89
90 /* check for TTA3 signature */
91 if ((GET_HEADER(ttahdr, ID)) != TTA1_SIGN)
92 return false;
93
94 /* skip check CRC */
95
96 id3->channels = (GET_HEADER(ttahdr, NUM_CHANNELS));
97 id3->frequency = (GET_HEADER(ttahdr, SAMPLE_RATE));
98 id3->length = ((GET_HEADER(ttahdr, DATA_LENGTH)) / id3->frequency) * 1000LL;
99 bps = (GET_HEADER(ttahdr, BITS_PER_SAMPLE));
100
101 datasize = id3->filesize - id3->first_frame_offset;
102 origsize = (GET_HEADER(ttahdr, DATA_LENGTH)) * ((bps + 7) / 8) * id3->channels;
103
104 id3->bitrate = (int) ((uint64_t) datasize * id3->frequency * id3->channels * bps
105 / (origsize * 1000LL));
106
107 /* output header info (for debug) */
108 DEBUGF("TTA header info ----\n");
109 DEBUGF("id: %x\n", (unsigned int)(GET_HEADER(ttahdr, ID)));
110 DEBUGF("channels: %d\n", id3->channels);
111 DEBUGF("frequency: %ld\n", id3->frequency);
112 DEBUGF("length: %ld\n", id3->length);
113 DEBUGF("bitrate: %d\n", id3->bitrate);
114 DEBUGF("bits per sample: %d\n", bps);
115 DEBUGF("compressed size: %d\n", datasize);
116 DEBUGF("original size: %d\n", origsize);
117 DEBUGF("id3----\n");
118 DEBUGF("artist: %s\n", id3->artist);
119 DEBUGF("title: %s\n", id3->title);
120 DEBUGF("genre: %s\n", id3->genre_string);
121
122 return true;
123}
diff --git a/apps/metadata/vgm.c b/apps/metadata/vgm.c
deleted file mode 100644
index 9ea95b3939..0000000000
--- a/apps/metadata/vgm.c
+++ /dev/null
@@ -1,195 +0,0 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <ctype.h>
5#include <inttypes.h>
6
7#include "system.h"
8#include "metadata.h"
9#include "metadata_common.h"
10#include "metadata_parsers.h"
11#include "rbunicode.h"
12
13/* Ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
14
15typedef unsigned char byte;
16
17enum { header_size = 0x40 };
18enum { max_field = 64 };
19
20struct header_t
21{
22 char tag [4];
23 byte data_size [4];
24 byte version [4];
25 byte psg_rate [4];
26 byte ym2413_rate [4];
27 byte gd3_offset [4];
28 byte track_duration [4];
29 byte loop_offset [4];
30 byte loop_duration [4];
31 byte frame_rate [4];
32 byte noise_feedback [2];
33 byte noise_width;
34 byte unused1;
35 byte ym2612_rate [4];
36 byte ym2151_rate [4];
37 byte data_offset [4];
38 byte unused2 [8];
39};
40
41static byte const* skip_gd3_str( byte const* in, byte const* end )
42{
43 while ( end - in >= 2 )
44 {
45 in += 2;
46 if ( !(in [-2] | in [-1]) )
47 break;
48 }
49 return in;
50}
51
52static byte const* get_gd3_str( byte const* in, byte const* end, char* field )
53{
54 byte const* mid = skip_gd3_str( in, end );
55 int len = (mid - in) / 2 - 1;
56 if ( field && len > 0 )
57 {
58 len = len < (int) max_field ? len : (int) max_field;
59
60 field [len] = 0;
61 /* Conver to utf8 */
62 utf16LEdecode( in, field, len );
63
64 /* Copy string back to id3v2buf */
65 strcpy( (char*) in, field );
66 }
67 return mid;
68}
69
70static byte const* get_gd3_pair( byte const* in, byte const* end, char* field )
71{
72 return skip_gd3_str( get_gd3_str( in, end, field ), end );
73}
74
75static void parse_gd3( byte const* in, byte const* end, struct mp3entry* id3 )
76{
77 char* p = id3->path;
78 id3->title = (char *) in;
79 in = get_gd3_pair( in, end, p ); /* Song */
80
81 id3->album = (char *) in;
82 in = get_gd3_pair( in, end, p ); /* Game */
83
84 in = get_gd3_pair( in, end, NULL ); /* System */
85
86 id3->artist = (char *) in;
87 in = get_gd3_pair( in, end, p ); /* Author */
88
89#if MEMORYSIZE > 2
90 in = get_gd3_str ( in, end, NULL ); /* Copyright */
91 in = get_gd3_pair( in, end, NULL ); /* Dumper */
92
93 id3->comment = (char *) in;
94 in = get_gd3_str ( in, end, p ); /* Comment */
95#endif
96}
97
98int const gd3_header_size = 12;
99
100static long check_gd3_header( byte* h, long remain )
101{
102 if ( remain < gd3_header_size ) return 0;
103 if ( memcmp( h, "Gd3 ", 4 ) ) return 0;
104 if ( get_long_le( h + 4 ) >= 0x200 ) return 0;
105
106 long gd3_size = get_long_le( h + 8 );
107 if ( gd3_size > remain - gd3_header_size )
108 gd3_size = remain - gd3_header_size;
109
110 return gd3_size;
111}
112
113static void get_vgm_length( struct header_t* h, struct mp3entry* id3 )
114{
115 long length = get_long_le( h->track_duration ) * 10 / 441;
116 if ( length > 0 )
117 {
118 long loop_length = 0, intro_length = 0;
119 long loop = get_long_le( h->loop_duration );
120 if ( loop > 0 && get_long_le( h->loop_offset ) )
121 {
122 loop_length = loop * 10 / 441;
123 intro_length = length - loop_length;
124 }
125 else
126 {
127 intro_length = length; /* make it clear that track is no longer than length */
128 loop_length = 0;
129 }
130
131 id3->length = intro_length + 2 * loop_length; /* intro + 2 loops */
132 return;
133 }
134
135 id3->length = 150 * 1000; /* 2.5 minutes */
136}
137
138bool get_vgm_metadata(int fd, struct mp3entry* id3)
139{
140 /* Use the id3v2 part of the id3 structure as a temporary buffer */
141 unsigned char* buf = (unsigned char *)id3->id3v2buf;
142 int read_bytes;
143
144 memset(buf, 0, ID3V2_BUF_SIZE);
145 if ((lseek(fd, 0, SEEK_SET) < 0)
146 || ((read_bytes = read(fd, buf, header_size)) < header_size))
147 {
148 return false;
149 }
150
151 id3->vbr = false;
152 id3->filesize = filesize(fd);
153
154 id3->bitrate = 706;
155 id3->frequency = 44100;
156
157 /* If file is gzipped, will get metadata later */
158 if (memcmp(buf, "Vgm ", 4))
159 {
160 /* We must set a default song length here because
161 the codec can't do it anymore */
162 id3->length = 150 * 1000; /* 2.5 minutes */
163 return true;
164 }
165
166 /* Get song length from header */
167 struct header_t* header = (struct header_t*) buf;
168 get_vgm_length( header, id3 );
169
170 long gd3_offset = get_long_le( header->gd3_offset ) - 0x2C;
171
172 /* No gd3 tag found */
173 if ( gd3_offset < 0 )
174 return true;
175
176 /* Seek to gd3 offset and read as
177 many bytes posible */
178 gd3_offset = id3->filesize - (header_size + gd3_offset);
179 if ((lseek(fd, -gd3_offset, SEEK_END) < 0)
180 || ((read_bytes = read(fd, buf, ID3V2_BUF_SIZE)) <= 0))
181 return true;
182
183 byte* gd3 = buf;
184 long gd3_size = check_gd3_header( gd3, read_bytes );
185
186 /* GD3 tag is zero */
187 if ( gd3_size == 0 )
188 return true;
189
190 /* Finally, parse gd3 tag */
191 if ( gd3 )
192 parse_gd3( gd3 + gd3_header_size, gd3 + read_bytes, id3 );
193
194 return true;
195}
diff --git a/apps/metadata/vorbis.c b/apps/metadata/vorbis.c
deleted file mode 100644
index 58bd781873..0000000000
--- a/apps/metadata/vorbis.c
+++ /dev/null
@@ -1,381 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "structec.h"
32
33/* Define LOGF_ENABLE to enable logf output in this file */
34/*#define LOGF_ENABLE*/
35#include "logf.h"
36
37struct file
38{
39 int fd;
40 bool packet_ended;
41 long packet_remaining;
42};
43
44
45/* Read an Ogg page header. file->packet_remaining is set to the size of the
46 * first packet on the page; file->packet_ended is set to true if the packet
47 * ended on the current page. Returns true if the page header was
48 * successfully read.
49 */
50static bool file_read_page_header(struct file* file)
51{
52 unsigned char buffer[64];
53 ssize_t table_left;
54
55 /* Size of page header without segment table */
56 if (read(file->fd, buffer, 27) != 27)
57 {
58 return false;
59 }
60
61 if (memcmp("OggS", buffer, 4))
62 {
63 return false;
64 }
65
66 /* Skip pattern (4), version (1), flags (1), granule position (8),
67 * serial (4), pageno (4), checksum (4)
68 */
69 table_left = buffer[26];
70 file->packet_remaining = 0;
71
72 /* Read segment table for the first packet */
73 do
74 {
75 ssize_t count = MIN(sizeof(buffer), (size_t) table_left);
76 int i;
77
78 if (read(file->fd, buffer, count) < count)
79 {
80 return false;
81 }
82
83 table_left -= count;
84
85 for (i = 0; i < count; i++)
86 {
87 file->packet_remaining += buffer[i];
88
89 if (buffer[i] < 255)
90 {
91 file->packet_ended = true;
92
93 /* Skip remainder of the table */
94 if (lseek(file->fd, table_left, SEEK_CUR) < 0)
95 {
96 return false;
97 }
98
99 table_left = 0;
100 break;
101 }
102 }
103 }
104 while (table_left > 0);
105
106 return true;
107}
108
109
110/* Read (up to) buffer_size of data from the file. If buffer is NULL, just
111 * skip ahead buffer_size bytes (like lseek). Returns number of bytes read,
112 * 0 if there is no more data to read (in the packet or the file), < 0 if a
113 * read error occurred.
114 */
115static ssize_t file_read(struct file* file, void* buffer, size_t buffer_size)
116{
117 ssize_t done = 0;
118 ssize_t count = -1;
119
120 do
121 {
122 if (file->packet_remaining <= 0)
123 {
124 if (file->packet_ended)
125 {
126 break;
127 }
128
129 if (!file_read_page_header(file))
130 {
131 count = -1;
132 break;
133 }
134 }
135
136 count = MIN(buffer_size, (size_t) file->packet_remaining);
137
138 if (buffer)
139 {
140 count = read(file->fd, buffer, count);
141 }
142 else
143 {
144 if (lseek(file->fd, count, SEEK_CUR) < 0)
145 {
146 count = -1;
147 }
148 }
149
150 if (count <= 0)
151 {
152 break;
153 }
154
155 if (buffer)
156 {
157 buffer += count;
158 }
159
160 buffer_size -= count;
161 done += count;
162 file->packet_remaining -= count;
163 }
164 while (buffer_size > 0);
165
166 return (count < 0 ? count : done);
167}
168
169
170/* Read an int32 from file. Returns false if a read error occurred.
171 */
172static bool file_read_int32(struct file* file, int32_t* value)
173{
174 char buf[sizeof(int32_t)];
175
176 if (file_read(file, buf, sizeof(buf)) < (ssize_t) sizeof(buf))
177 {
178 return false;
179 }
180
181 *value = get_long_le(buf);
182 return true;
183}
184
185
186/* Read a string from the file. Read up to buffer_size bytes, or, if eos
187 * != -1, until the eos character is found (eos is not stored in buf,
188 * unless it is nil). Writes up to buffer_size chars to buf, always
189 * terminating with a nil. Returns number of chars read or < 0 if a read
190 * error occurred.
191 *
192 * Unfortunately this is a slightly modified copy of read_string() in
193 * metadata_common.c...
194 */
195static long file_read_string(struct file* file, char* buffer,
196 long buffer_size, int eos, long size)
197{
198 long read_bytes = 0;
199
200 while (size > 0)
201 {
202 char c;
203
204 if (file_read(file, &c, 1) != 1)
205 {
206 read_bytes = -1;
207 break;
208 }
209
210 read_bytes++;
211 size--;
212
213 if ((eos != -1) && (eos == (unsigned char) c))
214 {
215 break;
216 }
217
218 if (buffer_size > 1)
219 {
220 *buffer++ = c;
221 buffer_size--;
222 }
223 else if (eos == -1)
224 {
225 /* No point in reading any more, skip remaining data */
226 if (file_read(file, NULL, size) < 0)
227 {
228 read_bytes = -1;
229 }
230 else
231 {
232 read_bytes += size;
233 }
234
235 break;
236 }
237 }
238
239 *buffer = 0;
240 return read_bytes;
241}
242
243
244/* Init struct file for reading from fd. type is the AFMT_* codec type of
245 * the file, and determines if Ogg pages are to be read. remaining is the
246 * max amount to read if codec type is FLAC; it is ignored otherwise.
247 * Returns true if the file was successfully initialized.
248 */
249static bool file_init(struct file* file, int fd, int type, int remaining)
250{
251 memset(file, 0, sizeof(*file));
252 file->fd = fd;
253
254 if (type == AFMT_OGG_VORBIS || type == AFMT_SPEEX)
255 {
256 if (!file_read_page_header(file))
257 {
258 return false;
259 }
260 }
261
262 if (type == AFMT_OGG_VORBIS)
263 {
264 char buffer[7];
265
266 /* Read packet header (type and id string) */
267 if (file_read(file, buffer, sizeof(buffer)) < (ssize_t) sizeof(buffer))
268 {
269 return false;
270 }
271
272 /* The first byte of a packet is the packet type; comment packets
273 * are type 3.
274 */
275 if (buffer[0] != 3)
276 {
277 return false;
278 }
279 }
280 else if (type == AFMT_FLAC)
281 {
282 file->packet_remaining = remaining;
283 file->packet_ended = true;
284 }
285
286 return true;
287}
288
289
290/* Read the items in a Vorbis comment packet. For Ogg files, the file must
291 * be located on a page start, for other files, the beginning of the comment
292 * data (i.e., the vendor string length). Returns total size of the
293 * comments, or 0 if there was a read error.
294 */
295long read_vorbis_tags(int fd, struct mp3entry *id3,
296 long tag_remaining)
297{
298 struct file file;
299 char *buf = id3->id3v2buf;
300 int32_t comment_count;
301 int32_t len;
302 long comment_size = 0;
303 int buf_remaining = sizeof(id3->id3v2buf) + sizeof(id3->id3v1buf);
304 int i;
305
306 if (!file_init(&file, fd, id3->codectype, tag_remaining))
307 {
308 return 0;
309 }
310
311 /* Skip vendor string */
312
313 if (!file_read_int32(&file, &len) || (file_read(&file, NULL, len) < 0))
314 {
315 return 0;
316 }
317
318 if (!file_read_int32(&file, &comment_count))
319 {
320 return 0;
321 }
322
323 comment_size += 4 + len + 4;
324
325 for (i = 0; i < comment_count && file.packet_remaining > 0; i++)
326 {
327 char name[TAG_NAME_LENGTH];
328 int32_t read_len;
329
330 if (!file_read_int32(&file, &len))
331 {
332 return 0;
333 }
334
335 comment_size += 4 + len;
336 read_len = file_read_string(&file, name, sizeof(name), '=', len);
337
338 if (read_len < 0)
339 {
340 return 0;
341 }
342
343 len -= read_len;
344 read_len = file_read_string(&file, id3->path, sizeof(id3->path), -1, len);
345
346 if (read_len < 0)
347 {
348 return 0;
349 }
350
351 logf("Vorbis comment %d: %s=%s", i, name, id3->path);
352
353 /* Is it an embedded cuesheet? */
354 if (!strcasecmp(name, "CUESHEET"))
355 {
356 id3->has_embedded_cuesheet = true;
357 id3->embedded_cuesheet.pos = lseek(file.fd, 0, SEEK_CUR) - read_len;
358 id3->embedded_cuesheet.size = len;
359 id3->embedded_cuesheet.encoding = CHAR_ENC_UTF_8;
360 }
361 else
362 {
363 len = parse_tag(name, id3->path, id3, buf, buf_remaining,
364 TAGTYPE_VORBIS);
365 }
366
367 buf += len;
368 buf_remaining -= len;
369 }
370
371 /* Skip to the end of the block (needed by FLAC) */
372 if (file.packet_remaining)
373 {
374 if (file_read(&file, NULL, file.packet_remaining) < 0)
375 {
376 return 0;
377 }
378 }
379
380 return comment_size;
381}
diff --git a/apps/metadata/vox.c b/apps/metadata/vox.c
deleted file mode 100644
index f6bc849a88..0000000000
--- a/apps/metadata/vox.c
+++ /dev/null
@@ -1,49 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33bool get_vox_metadata(int fd, struct mp3entry* id3)
34{
35 /*
36 * vox is headerless format
37 *
38 * frequency: 8000 Hz
39 * channels: mono
40 * bitspersample: 4
41 */
42 id3->frequency = 8000;
43 id3->bitrate = 8000 * 4 / 1000;
44 id3->vbr = false; /* All VOX files are CBR */
45 id3->filesize = filesize(fd);
46 id3->length = id3->filesize >> 2;
47
48 return true;
49}
diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c
deleted file mode 100644
index 45acea1fa1..0000000000
--- a/apps/metadata/wave.c
+++ /dev/null
@@ -1,432 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 * Copyright (C) 2010 Yoshihisa Uchida
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25
26#include "system.h"
27#include "metadata.h"
28#include "metadata_common.h"
29#include "metadata_parsers.h"
30#include "rbunicode.h"
31#include "logf.h"
32
33#ifdef DEBUGF
34#undef DEBUGF
35#define DEBUGF(...)
36#endif
37
38/* Wave(RIFF)/Wave64 format */
39
40
41# define AV_WL32(p, d) do { \
42 ((uint8_t*)(p))[0] = (d); \
43 ((uint8_t*)(p))[1] = (d)>>8; \
44 ((uint8_t*)(p))[2] = (d)>>16; \
45 ((uint8_t*)(p))[3] = (d)>>24; \
46 } while(0)
47# define AV_WL16(p, d) do { \
48 ((uint8_t*)(p))[0] = (d); \
49 ((uint8_t*)(p))[1] = (d)>>8; \
50 } while(0)
51
52enum {
53 RIFF_CHUNK = 0,
54 WAVE_CHUNK,
55 FMT_CHUNK,
56 FACT_CHUNK,
57 DATA_CHUNK,
58 LIST_CHUNK,
59};
60
61/* Wave chunk names */
62#define WAVE_CHUNKNAME_LENGTH 4
63#define WAVE_CHUNKSIZE_LENGTH 4
64
65static const unsigned char * const wave_chunklist
66 = "RIFF"
67 "WAVE"
68 "fmt "
69 "fact"
70 "data"
71 "LIST";
72
73/* Wave64 GUIDs */
74#define WAVE64_CHUNKNAME_LENGTH 16
75#define WAVE64_CHUNKSIZE_LENGTH 8
76
77static const unsigned char * const wave64_chunklist
78 = "riff\x2e\x91\xcf\x11\xa5\xd6\x28\xdb\x04\xc1\x00\x00"
79 "wave\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
80 "fmt \xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
81 "fact\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
82 "data\xf3\xac\xd3\x11\x8c\xd1\x00\xc0\x4f\x8e\xdb\x8a"
83 "\xbc\x94\x5f\x92\x5a\x52\xd2\x11\x86\xdc\x00\xc0\x4f\x8e\xdb\x8a";
84
85/* list/info chunk */
86
87struct info_chunk {
88 const unsigned char* tag;
89 size_t offset;
90};
91
92/* info chunk names are common wave/wave64 */
93static const struct info_chunk info_chunks[] = {
94 { "INAM", offsetof(struct mp3entry, title), }, /* title */
95 { "IART", offsetof(struct mp3entry, artist), }, /* artist */
96 { "ISBJ", offsetof(struct mp3entry, albumartist), }, /* albumartist */
97 { "IPRD", offsetof(struct mp3entry, album), }, /* album */
98 { "IWRI", offsetof(struct mp3entry, composer), }, /* composer */
99 { "ICMT", offsetof(struct mp3entry, comment), }, /* comment */
100 { "ISRF", offsetof(struct mp3entry, grouping), }, /* grouping */
101 { "IGNR", offsetof(struct mp3entry, genre_string), }, /* genre */
102 { "ICRD", offsetof(struct mp3entry, year_string), }, /* date */
103 { "IPRT", offsetof(struct mp3entry, track_string), }, /* track/trackcount */
104 { "IFRM", offsetof(struct mp3entry, disc_string), }, /* disc/disccount */
105};
106
107#define INFO_CHUNK_COUNT ((int)ARRAYLEN(info_chunks))
108
109/* support formats */
110enum
111{
112 WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */
113 WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */
114 WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */
115 WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */
116 WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */
117 WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */
118 WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */
119 WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */
120 WAVE_FORMAT_XBOX_ADPCM = 0x0069, /* XBOX ADPCM */
121 IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */
122 IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */
123 WAVE_FORMAT_ATRAC3 = 0x0270, /* Atrac3 stream */
124 WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */
125 WAVE_FORMAT_EXTENSIBLE = 0xFFFE,
126};
127
128struct wave_fmt {
129 unsigned int formattag;
130 unsigned int channels;
131 unsigned int blockalign;
132 unsigned int bitspersample;
133 unsigned int samplesperblock;
134 uint32_t totalsamples;
135 uint64_t numbytes;
136};
137
138static unsigned char *convert_utf8(const unsigned char *src, unsigned char *dst,
139 int size, bool is_64)
140{
141 if (is_64)
142 {
143 /* Note: wave64: metadata codepage is UTF-16 only */
144 return utf16LEdecode(src, dst, size);
145 }
146 return iso_decode(src, dst, -1, size);
147}
148
149static void set_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3)
150{
151 switch (fmt->formattag)
152 {
153 case WAVE_FORMAT_PCM:
154 case WAVE_FORMAT_IEEE_FLOAT:
155 case WAVE_FORMAT_ALAW:
156 case WAVE_FORMAT_MULAW:
157 case IBM_FORMAT_ALAW:
158 case IBM_FORMAT_MULAW:
159 fmt->blockalign = fmt->bitspersample * fmt->channels >> 3;
160 fmt->samplesperblock = 1;
161 break;
162 case WAVE_FORMAT_YAMAHA_ADPCM:
163 if (id3->channels != 0)
164 {
165 fmt->samplesperblock =
166 (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels)?
167 id3->frequency / 30 : (fmt->blockalign << 1) / fmt->channels;
168 }
169 break;
170 case WAVE_FORMAT_DIALOGIC_OKI_ADPCM:
171 fmt->blockalign = 1;
172 fmt->samplesperblock = 2;
173 break;
174 case WAVE_FORMAT_SWF_ADPCM:
175 if (fmt->bitspersample != 0 && id3->channels != 0)
176 {
177 fmt->samplesperblock
178 = (((fmt->blockalign << 3) - 2) / fmt->channels - 22)
179 / fmt->bitspersample + 1;
180 }
181 break;
182 default:
183 break;
184 }
185
186 if (fmt->blockalign != 0)
187 fmt->totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock;
188}
189
190static void parse_riff_format(unsigned char* buf, int fmtsize, struct wave_fmt *fmt,
191 struct mp3entry* id3)
192{
193 /* wFormatTag */
194 fmt->formattag = buf[0] | (buf[1] << 8);
195 /* wChannels */
196 fmt->channels = buf[2] | (buf[3] << 8);
197 /* dwSamplesPerSec */
198 id3->frequency = get_long_le(&buf[4]);
199 /* dwAvgBytesPerSec */
200 id3->bitrate = (get_long_le(&buf[8]) * 8) / 1000;
201 /* wBlockAlign */
202 fmt->blockalign = buf[12] | (buf[13] << 8);
203 /* wBitsPerSample */
204 fmt->bitspersample = buf[14] | (buf[15] << 8);
205
206 if (fmt->formattag != WAVE_FORMAT_EXTENSIBLE)
207 {
208 if (fmtsize > 19)
209 {
210 /* wSamplesPerBlock */
211 fmt->samplesperblock = buf[18] | (buf[19] << 8);
212 }
213 }
214 else if (fmtsize > 25)
215 {
216 /* wValidBitsPerSample */
217 fmt->bitspersample = buf[18] | (buf[19] << 8);
218 /* SubFormat */
219 fmt->formattag = buf[24] | (buf[25] << 8);
220 }
221
222 /* Check for ATRAC3 stream */
223 if (fmt->formattag == WAVE_FORMAT_ATRAC3)
224 {
225 int jsflag = 0;
226 if(id3->bitrate == 66 || id3->bitrate == 94)
227 jsflag = 1;
228
229 id3->extradata_size = 14;
230 id3->channels = 2;
231 id3->codectype = AFMT_OMA_ATRAC3;
232 id3->bytesperframe = fmt->blockalign;
233
234 /* Store the extradata for the codec */
235 AV_WL16(&id3->id3v2buf[0], 1); // always 1
236 AV_WL32(&id3->id3v2buf[2], id3->frequency);// samples rate
237 AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode
238 AV_WL16(&id3->id3v2buf[8], jsflag); // coding mode
239 AV_WL16(&id3->id3v2buf[10], 1); // always 1
240 AV_WL16(&id3->id3v2buf[12], 0); // always 0
241 }
242}
243
244static void parse_list_chunk(int fd, struct mp3entry* id3, int chunksize, bool is_64)
245{
246 unsigned char tmpbuf[ID3V2_BUF_SIZE];
247 unsigned char *bp = tmpbuf;
248 unsigned char *endp;
249 unsigned char *data_pos;
250 unsigned char *tag_pos = id3->id3v2buf;
251 int datasize;
252 int infosize;
253 int remain;
254 int i;
255
256 if (is_64)
257 lseek(fd, 4, SEEK_CUR);
258 else if (read(fd, bp, 4) < 4 || memcmp(bp, "INFO", 4))
259 return;
260
261 /* decrease skip bytes */
262 chunksize -= 4;
263
264 infosize = read(fd, bp, (ID3V2_BUF_SIZE > chunksize)? chunksize : ID3V2_BUF_SIZE);
265 if (infosize <= 8)
266 return;
267
268 endp = bp + infosize;
269 while (bp < endp)
270 {
271 datasize = get_long_le(bp + 4);
272 data_pos = bp + 8;
273 remain = ID3V2_BUF_SIZE - (tag_pos - (unsigned char*)id3->id3v2buf);
274 if (remain < 1)
275 break;
276
277 for (i = 0; i < INFO_CHUNK_COUNT; i++)
278 {
279 if (memcmp(bp, info_chunks[i].tag, 4) == 0)
280 {
281 *((char **)(((char*)id3) + info_chunks[i].offset)) = tag_pos;
282 tag_pos = convert_utf8(data_pos, tag_pos,
283 (datasize + 1 >= remain )? remain - 1 : datasize,
284 is_64);
285 *tag_pos++ = 0;
286 break;
287 }
288 }
289 bp = data_pos + datasize + (datasize & 1);
290 };
291}
292
293static bool read_header(int fd, struct mp3entry* id3, const unsigned char *chunknames,
294 bool is_64)
295{
296 /* Use the temporary buffer */
297 unsigned char* buf = (unsigned char *)id3->path;
298
299 struct wave_fmt fmt;
300
301 const unsigned int namelen = (is_64)? WAVE64_CHUNKNAME_LENGTH : WAVE_CHUNKNAME_LENGTH;
302 const unsigned int sizelen = (is_64)? WAVE64_CHUNKSIZE_LENGTH : WAVE_CHUNKSIZE_LENGTH;
303 const unsigned int len = namelen + sizelen;
304 uint64_t chunksize;
305 uint64_t offset = len + namelen;
306 int read_data;
307
308 memset(&fmt, 0, sizeof(struct wave_fmt));
309
310 id3->vbr = false; /* All Wave/Wave64 files are CBR */
311 id3->filesize = filesize(fd);
312
313 /* get RIFF chunk header */
314 lseek(fd, 0, SEEK_SET);
315 read(fd, buf, offset);
316
317 if ((memcmp(buf, chunknames + RIFF_CHUNK * namelen, namelen) != 0) ||
318 (memcmp(buf + len, chunknames + WAVE_CHUNK * namelen, namelen) != 0))
319 {
320 DEBUGF("metadata error: missing riff header.\n");
321 return false;
322 }
323
324 /* iterate over WAVE chunks until 'data' chunk */
325 while (read(fd, buf, len) > 0)
326 {
327 offset += len;
328
329 /* get chunk size (when the header is wave64, chunksize includes GUID and data length) */
330 chunksize = (is_64) ? get_uint64_le(buf + namelen) - len :
331 get_long_le(buf + namelen);
332
333 read_data = 0;
334 if (memcmp(buf, chunknames + FMT_CHUNK * namelen, namelen) == 0)
335 {
336 DEBUGF("find 'fmt ' chunk\n");
337
338 if (chunksize < 16)
339 {
340 DEBUGF("metadata error: 'fmt ' chunk is too small: %d\n", (int)chunksize);
341 return false;
342 }
343
344 /* get and parse format */
345 read_data = (chunksize > 25)? 26 : chunksize;
346
347 read(fd, buf, read_data);
348 parse_riff_format(buf, read_data, &fmt, id3);
349 }
350 else if (memcmp(buf, chunknames + FACT_CHUNK * namelen, namelen) == 0)
351 {
352 DEBUGF("find 'fact' chunk\n");
353
354 /* dwSampleLength */
355 if (chunksize >= sizelen)
356 {
357 /* get totalsamples */
358 read_data = sizelen;
359 read(fd, buf, read_data);
360 fmt.totalsamples = (is_64)? get_uint64_le(buf) : get_long_le(buf);
361 }
362 }
363 else if (memcmp(buf, chunknames + DATA_CHUNK * namelen, namelen) == 0)
364 {
365 DEBUGF("find 'data' chunk\n");
366 fmt.numbytes = chunksize;
367 if (fmt.formattag == WAVE_FORMAT_ATRAC3)
368 id3->first_frame_offset = offset;
369 }
370 else if (memcmp(buf, chunknames + LIST_CHUNK * namelen, namelen) == 0)
371 {
372 DEBUGF("find 'LIST' chunk\n");
373 parse_list_chunk(fd, id3, chunksize, is_64);
374 lseek(fd, offset, SEEK_SET);
375 }
376
377 /* padded to next chunk */
378 chunksize += ((is_64)? ((1 + ~chunksize) & 0x07) : (chunksize & 1));
379
380 offset += chunksize;
381 if (offset >= id3->filesize)
382 break;
383
384 lseek(fd, chunksize - read_data, SEEK_CUR);
385 }
386
387 if (fmt.numbytes == 0)
388 {
389 DEBUGF("metadata error: read error or missing 'data' chunk.\n");
390 return false;
391 }
392
393 if (fmt.totalsamples == 0)
394 set_totalsamples(&fmt, id3);
395
396 if (id3->frequency == 0 || id3->bitrate == 0)
397 {
398 DEBUGF("metadata error: frequency or bitrate is 0\n");
399 return false;
400 }
401
402 /* Calculate track length (in ms) and estimate the bitrate (in kbit/s) */
403 id3->length = (fmt.formattag != WAVE_FORMAT_ATRAC3)?
404 (uint64_t)fmt.totalsamples * 1000 / id3->frequency :
405 ((id3->filesize - id3->first_frame_offset) * 8) / id3->bitrate;
406
407 /* output header/id3 info (for debug) */
408 DEBUGF("%s header info ----\n", (is_64)? "wave64" : "wave");
409 DEBUGF(" format: %04x\n", (int)fmt.formattag);
410 DEBUGF(" channels: %u\n", fmt.channels);
411 DEBUGF(" blockalign: %u\n", fmt.blockalign);
412 DEBUGF(" bitspersample: %u\n", fmt.bitspersample);
413 DEBUGF(" samplesperblock: %u\n", fmt.samplesperblock);
414 DEBUGF(" totalsamples: %u\n", (unsigned int)fmt.totalsamples);
415 DEBUGF(" numbytes: %u\n", (unsigned int)fmt.numbytes);
416 DEBUGF("id3 info ----\n");
417 DEBUGF(" frequency: %u\n", (unsigned int)id3->frequency);
418 DEBUGF(" bitrate: %d\n", id3->bitrate);
419 DEBUGF(" length: %u\n", (unsigned int)id3->length);
420
421 return true;
422}
423
424bool get_wave_metadata(int fd, struct mp3entry* id3)
425{
426 return read_header(fd, id3, wave_chunklist, false);
427}
428
429bool get_wave64_metadata(int fd, struct mp3entry* id3)
430{
431 return read_header(fd, id3, wave64_chunklist, true);
432}
diff --git a/apps/metadata/wavpack.c b/apps/metadata/wavpack.c
deleted file mode 100644
index f2811df8f3..0000000000
--- a/apps/metadata/wavpack.c
+++ /dev/null
@@ -1,160 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 David Bryant
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include <inttypes.h>
26
27#include "system.h"
28#include "metadata.h"
29#include "metadata_common.h"
30#include "metadata_parsers.h"
31#include "logf.h"
32
33#define ID_UNIQUE 0x3f
34#define ID_LARGE 0x80
35#define ID_SAMPLE_RATE 0x27
36
37#define MONO_FLAG 4
38#define HYBRID_FLAG 8
39
40static const long wavpack_sample_rates [] =
41{
42 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
43 32000, 44100, 48000, 64000, 88200, 96000, 192000
44};
45
46/* A simple parser to read basic information from a WavPack file. This
47 * now works with self-extrating WavPack files and also will scan the
48 * metadata for non-standard sampling rates. This no longer fails on
49 * WavPack files containing floating-point audio data because these are
50 * now converted to standard Rockbox format in the decoder, and also
51 * handles the case where up to 15 non-audio blocks might occur at the
52 * beginning of the file.
53 */
54
55bool get_wavpack_metadata(int fd, struct mp3entry* id3)
56{
57 /* Use the trackname part of the id3 structure as a temporary buffer */
58 unsigned char* buf = (unsigned char *)id3->path;
59 uint32_t totalsamples = (uint32_t) -1;
60 int i;
61
62 for (i = 0; i < 256; ++i) {
63
64 /* at every 256 bytes into file, try to read a WavPack header */
65
66 if ((lseek(fd, i * 256, SEEK_SET) < 0) || (read(fd, buf, 32) < 32))
67 return false;
68
69 /* if valid WavPack 4 header version, break */
70
71 if (memcmp (buf, "wvpk", 4) == 0 && buf [9] == 4 &&
72 (buf [8] >= 2 && buf [8] <= 0x10))
73 break;
74 }
75
76 if (i == 256) {
77 logf ("Not a WavPack file");
78 return false;
79 }
80
81 id3->vbr = true; /* All WavPack files are VBR */
82 id3->filesize = filesize (fd);
83
84 /* check up to 16 headers before we give up finding one with audio */
85
86 for (i = 0; i < 16; ++i) {
87 uint32_t meta_bytes = get_long_le(&buf [4]) - 24;
88 uint32_t trial_totalsamples = get_long_le(&buf[12]);
89 uint32_t blockindex = get_long_le(&buf[16]);
90 uint32_t blocksamples = get_long_le(&buf[20]);
91 uint32_t flags = get_long_le(&buf[24]);
92
93 if (totalsamples == (uint32_t) -1 && blockindex == 0)
94 totalsamples = trial_totalsamples;
95
96 if (blocksamples) {
97 int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14);
98
99 if (srindx == 15) {
100 uint32_t meta_size;
101
102 id3->frequency = 44100;
103
104 while (meta_bytes >= 6) {
105 if (read(fd, buf, 2) < 2)
106 break;
107
108 if (buf [0] & ID_LARGE) {
109 if (read(fd, buf + 2, 2) < 2)
110 break;
111
112 meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17);
113 meta_bytes -= meta_size + 4;
114 }
115 else {
116 meta_size = buf [1] << 1;
117 meta_bytes -= meta_size + 2;
118
119 if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) {
120 if (meta_size == 4 && read(fd, buf + 2, 4) == 4)
121 id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16);
122
123 break;
124 }
125 }
126
127 if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0)
128 break;
129 }
130 }
131 else
132 id3->frequency = wavpack_sample_rates[srindx];
133
134 /* if the total number of samples is still unknown, make a guess on the high side (for now) */
135
136 if (totalsamples == (uint32_t) -1) {
137 totalsamples = id3->filesize * 3;
138
139 if (!(flags & HYBRID_FLAG))
140 totalsamples /= 2;
141
142 if (!(flags & MONO_FLAG))
143 totalsamples /= 2;
144 }
145
146 id3->length = ((int64_t) totalsamples * 1000) / id3->frequency;
147 id3->bitrate = id3->filesize / (id3->length / 8);
148
149 read_ape_tags(fd, id3);
150 return true;
151 }
152 else { /* block did not contain audio, so seek to the end and see if there's another */
153 if ((meta_bytes > 0 && lseek(fd, meta_bytes, SEEK_CUR) < 0) ||
154 read(fd, buf, 32) < 32 || memcmp (buf, "wvpk", 4) != 0)
155 break;
156 }
157 }
158
159 return false;
160}
diff --git a/apps/mp3data.c b/apps/mp3data.c
deleted file mode 100644
index 13ff0a87a7..0000000000
--- a/apps/mp3data.c
+++ /dev/null
@@ -1,849 +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
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 "system.h"
42
43//#define DEBUG_VERBOSE
44
45#ifdef DEBUG_VERBOSE
46#define VDEBUGF DEBUGF
47#else
48#define VDEBUGF(...) do { } while(0)
49#endif
50
51#define SYNC_MASK (0x7ffL << 21)
52#define VERSION_MASK (3L << 19)
53#define LAYER_MASK (3L << 17)
54#define PROTECTION_MASK (1L << 16)
55#define BITRATE_MASK (0xfL << 12)
56#define SAMPLERATE_MASK (3L << 10)
57#define PADDING_MASK (1L << 9)
58#define PRIVATE_MASK (1L << 8)
59#define CHANNELMODE_MASK (3L << 6)
60#define MODE_EXT_MASK (3L << 4)
61#define COPYRIGHT_MASK (1L << 3)
62#define ORIGINAL_MASK (1L << 2)
63#define EMPHASIS_MASK (3L)
64
65/* Maximum number of bytes needed by Xing/Info/VBRI parser. */
66#define VBR_HEADER_MAX_SIZE (180)
67
68/* MPEG Version table, sorted by version index */
69static const signed char version_table[4] = {
70 MPEG_VERSION2_5, -1, MPEG_VERSION2, MPEG_VERSION1
71};
72
73/* Bitrate table for mpeg audio, indexed by row index and birate index */
74static const short bitrates[5][16] = {
75 {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* V1 L1 */
76 {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* V1 L2 */
77 {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* V1 L3 */
78 {0,32,48,56, 64, 80, 96,112,128,144,160,176,192,224,256,0}, /* V2 L1 */
79 {0, 8,16,24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0} /* V2 L2+L3 */
80};
81
82/* Bitrate pointer table, indexed by version and layer */
83static const short *bitrate_table[3][3] =
84{
85 {bitrates[0], bitrates[1], bitrates[2]},
86 {bitrates[3], bitrates[4], bitrates[4]},
87 {bitrates[3], bitrates[4], bitrates[4]}
88};
89
90/* Sampling frequency table, indexed by version and frequency index */
91static const unsigned short freq_table[3][3] =
92{
93 {44100, 48000, 32000}, /* MPEG Version 1 */
94 {22050, 24000, 16000}, /* MPEG version 2 */
95 {11025, 12000, 8000}, /* MPEG version 2.5 */
96};
97
98unsigned long bytes2int(unsigned long b0, unsigned long b1,
99 unsigned long b2, unsigned long b3)
100{
101 return (b0 & 0xFF) << (3*8) |
102 (b1 & 0xFF) << (2*8) |
103 (b2 & 0xFF) << (1*8) |
104 (b3 & 0xFF) << (0*8);
105}
106
107/* check if 'head' is a valid mp3 frame header */
108static bool is_mp3frameheader(unsigned long head)
109{
110 if ((head & SYNC_MASK) != (unsigned long)SYNC_MASK) /* bad sync? */
111 return false;
112 if ((head & VERSION_MASK) == (1L << 19)) /* bad version? */
113 return false;
114 if (!(head & LAYER_MASK)) /* no layer? */
115 return false;
116#if CONFIG_CODEC != SWCODEC
117 /* The MAS can't decode layer 1, so treat layer 1 data as invalid */
118 if ((head & LAYER_MASK) == LAYER_MASK)
119 return false;
120#endif
121 if ((head & BITRATE_MASK) == BITRATE_MASK) /* bad bitrate? */
122 return false;
123 if (!(head & BITRATE_MASK)) /* no bitrate? */
124 return false;
125 if ((head & SAMPLERATE_MASK) == SAMPLERATE_MASK) /* bad sample rate? */
126 return false;
127
128 return true;
129}
130
131static bool mp3headerinfo(struct mp3info *info, unsigned long header)
132{
133 int bitindex, freqindex;
134
135 /* MPEG Audio Version */
136 if ((header & VERSION_MASK) >> 19 >= sizeof(version_table))
137 return false;
138
139 info->version = version_table[(header & VERSION_MASK) >> 19];
140 if (info->version < 0)
141 return false;
142
143 /* Layer */
144 info->layer = 3 - ((header & LAYER_MASK) >> 17);
145 if (info->layer == 3)
146 return false;
147
148/* Rockbox: not used
149 info->protection = (header & PROTECTION_MASK) ? true : false;
150*/
151
152 /* Bitrate */
153 bitindex = (header & BITRATE_MASK) >> 12;
154 info->bitrate = bitrate_table[info->version][info->layer][bitindex];
155 if(info->bitrate == 0)
156 return false;
157
158 /* Sampling frequency */
159 freqindex = (header & SAMPLERATE_MASK) >> 10;
160 if (freqindex == 3)
161 return false;
162 info->frequency = freq_table[info->version][freqindex];
163
164 info->padding = (header & PADDING_MASK) ? 1 : 0;
165
166 /* Calculate number of bytes, calculation depends on layer */
167 if (info->layer == 0) {
168 info->frame_samples = 384;
169 info->frame_size = (12000 * info->bitrate / info->frequency
170 + info->padding) * 4;
171 }
172 else {
173 if ((info->version > MPEG_VERSION1) && (info->layer == 2))
174 info->frame_samples = 576;
175 else
176 info->frame_samples = 1152;
177 info->frame_size = (1000/8) * info->frame_samples * info->bitrate
178 / info->frequency + info->padding;
179 }
180
181 /* Frametime fraction denominator */
182 if (freqindex != 0) { /* 48/32/24/16/12/8 kHz */
183 info->ft_den = 1; /* integer number of milliseconds */
184 }
185 else { /* 44.1/22.05/11.025 kHz */
186 if (info->layer == 0) /* layer 1 */
187 info->ft_den = 147;
188 else /* layer 2+3 */
189 info->ft_den = 49;
190 }
191 /* Frametime fraction numerator */
192 info->ft_num = 1000 * info->ft_den * info->frame_samples / info->frequency;
193
194 info->channel_mode = (header & CHANNELMODE_MASK) >> 6;
195/* Rockbox: not used
196 info->mode_extension = (header & MODE_EXT_MASK) >> 4;
197 info->emphasis = header & EMPHASIS_MASK;
198*/
199 VDEBUGF( "Header: %08lx, Ver %d, lay %d, bitr %d, freq %ld, "
200 "chmode %d, bytes: %d time: %d/%d\n",
201 header, info->version, info->layer+1, info->bitrate,
202 info->frequency, info->channel_mode,
203 info->frame_size, info->ft_num, info->ft_den);
204 return true;
205}
206
207static bool headers_have_same_type(unsigned long header1,
208 unsigned long header2)
209{
210 /* Compare MPEG version, layer and sampling frequency. If header1 is zero
211 * it is assumed both frame headers are of same type. */
212 unsigned int mask = SYNC_MASK | VERSION_MASK | LAYER_MASK | SAMPLERATE_MASK;
213 header1 &= mask;
214 header2 &= mask;
215 return header1 ? (header1 == header2) : true;
216}
217
218/* Helper function to read 4-byte in big endian format. */
219static void read_uint32be_mp3data(int fd, unsigned long *data)
220{
221#ifdef ROCKBOX_BIG_ENDIAN
222 (void)read(fd, (char*)data, 4);
223#else
224 (void)read(fd, (char*)data, 4);
225 *data = betoh32(*data);
226#endif
227}
228
229static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
230 unsigned long reference_header,
231 int(*getfunc)(int fd, unsigned char *c),
232 bool single_header)
233{
234 unsigned long header=0;
235 unsigned char tmp;
236 long pos = 0;
237
238 /* We will search until we find two consecutive MPEG frame headers with
239 * the same MPEG version, layer and sampling frequency. The first header
240 * of this pair is assumed to be the first valid MPEG frame header of the
241 * whole stream. */
242 do {
243 /* Read 1 new byte. */
244 header <<= 8;
245 if (!getfunc(fd, &tmp))
246 return 0;
247 header |= tmp;
248 pos++;
249
250 /* Abort if max_offset is reached. Stop parsing. */
251 if (max_offset > 0 && pos > max_offset)
252 return 0;
253
254 if (is_mp3frameheader(header)) {
255 if (single_header) {
256 /* We search for one _single_ valid header that has the same
257 * type as the reference_header (if reference_header != 0).
258 * In this case we are finished. */
259 if (headers_have_same_type(reference_header, header))
260 break;
261 } else {
262 /* The current header is valid. Now gather the frame size,
263 * seek to this byte position and check if there is another
264 * valid MPEG frame header of the same type. */
265 struct mp3info info;
266
267 /* Gather frame size from given header and seek to next
268 * frame header. */
269 mp3headerinfo(&info, header);
270 lseek(fd, info.frame_size-4, SEEK_CUR);
271
272 /* Read possible next frame header and seek back to last frame
273 * headers byte position. */
274 reference_header = 0;
275 read_uint32be_mp3data(fd, &reference_header);
276 //
277 lseek(fd, -info.frame_size, SEEK_CUR);
278
279 /* If the current header is of the same type as the previous
280 * header we are finished. */
281 if (headers_have_same_type(header, reference_header))
282 break;
283 }
284 }
285
286 } while (true);
287
288 *offset = pos - 4;
289
290 if(*offset)
291 VDEBUGF("Warning: skipping %ld bytes of garbage\n", *offset);
292
293 return header;
294}
295
296static int fileread(int fd, unsigned char *c)
297{
298 return read(fd, c, 1);
299}
300
301unsigned long find_next_frame(int fd,
302 long *offset,
303 long max_offset,
304 unsigned long reference_header)
305{
306 return __find_next_frame(fd, offset, max_offset, reference_header,
307 fileread, true);
308}
309
310#ifndef __PCTOOL__
311static int fnf_read_index;
312static int fnf_buf_len;
313static unsigned char *fnf_buf;
314
315static int buf_getbyte(int fd, unsigned char *c)
316{
317 if(fnf_read_index < fnf_buf_len)
318 {
319 *c = fnf_buf[fnf_read_index++];
320 return 1;
321 }
322 else
323 {
324 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
325 if(fnf_buf_len < 0)
326 return -1;
327
328 fnf_read_index = 0;
329
330 if(fnf_buf_len > 0)
331 {
332 *c = fnf_buf[fnf_read_index++];
333 return 1;
334 }
335 else
336 return 0;
337 }
338 return 0;
339}
340
341static int buf_seek(int fd, int len)
342{
343 fnf_read_index += len;
344 if(fnf_read_index > fnf_buf_len)
345 {
346 len = fnf_read_index - fnf_buf_len;
347
348 fnf_buf_len = read(fd, fnf_buf, fnf_buf_len);
349 if(fnf_buf_len < 0)
350 return -1;
351
352 fnf_read_index = 0;
353 fnf_read_index += len;
354 }
355
356 if(fnf_read_index > fnf_buf_len)
357 {
358 return -1;
359 }
360 else
361 return 0;
362}
363
364static void buf_init(unsigned char* buf, size_t buflen)
365{
366 fnf_buf = buf;
367 fnf_buf_len = buflen;
368 fnf_read_index = 0;
369}
370
371static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
372{
373 return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
374}
375
376static size_t mem_buflen;
377static unsigned char* mem_buf;
378static size_t mem_pos;
379static int mem_cnt;
380static int mem_maxlen;
381
382static int mem_getbyte(int dummy, unsigned char *c)
383{
384 (void)dummy;
385
386 *c = mem_buf[mem_pos++];
387 if(mem_pos >= mem_buflen)
388 mem_pos = 0;
389
390 if(mem_cnt++ >= mem_maxlen)
391 return 0;
392 else
393 return 1;
394}
395
396unsigned long mem_find_next_frame(int startpos,
397 long *offset,
398 long max_offset,
399 unsigned long reference_header,
400 unsigned char* buf, size_t buflen)
401{
402 mem_buf = buf;
403 mem_buflen = buflen;
404 mem_pos = startpos;
405 mem_cnt = 0;
406 mem_maxlen = max_offset;
407
408 return __find_next_frame(0, offset, max_offset, reference_header,
409 mem_getbyte, true);
410}
411#endif
412
413/* Extract information from a 'Xing' or 'Info' header. */
414static void get_xing_info(struct mp3info *info, unsigned char *buf)
415{
416 int i = 8;
417
418 /* Is it a VBR file? */
419 info->is_vbr = !memcmp(buf, "Xing", 4);
420
421 if (buf[7] & VBR_FRAMES_FLAG) /* Is the frame count there? */
422 {
423 info->frame_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
424 if (info->frame_count <= ULONG_MAX / info->ft_num)
425 info->file_time = info->frame_count * info->ft_num / info->ft_den;
426 else
427 info->file_time = info->frame_count / info->ft_den * info->ft_num;
428 i += 4;
429 }
430
431 if (buf[7] & VBR_BYTES_FLAG) /* Is byte count there? */
432 {
433 info->byte_count = bytes2int(buf[i], buf[i+1], buf[i+2], buf[i+3]);
434 i += 4;
435 }
436
437 if (info->file_time && info->byte_count)
438 {
439 if (info->byte_count <= (ULONG_MAX/8))
440 info->bitrate = info->byte_count * 8 / info->file_time;
441 else
442 info->bitrate = info->byte_count / (info->file_time >> 3);
443 }
444
445 if (buf[7] & VBR_TOC_FLAG) /* Is table-of-contents there? */
446 {
447 info->has_toc = true;
448 memcpy( info->toc, buf+i, 100 );
449 i += 100;
450 }
451 if (buf[7] & VBR_QUALITY_FLAG)
452 {
453 /* We don't care about this, but need to skip it */
454 i += 4;
455 }
456#if CONFIG_CODEC==SWCODEC
457 i += 21;
458 info->enc_delay = ((int)buf[i ] << 4) | (buf[i+1] >> 4);
459 info->enc_padding = ((int)(buf[i+1]&0xF) << 8) | buf[i+2];
460 /* TODO: This sanity checking is rather silly, seeing as how the LAME
461 header contains a CRC field that can be used to verify integrity. */
462 if (!(info->enc_delay >= 0 && info->enc_delay <= 2880 &&
463 info->enc_padding >= 0 && info->enc_padding <= 2*1152))
464 {
465 /* Invalid data */
466 info->enc_delay = -1;
467 info->enc_padding = -1;
468 }
469#endif
470}
471
472/* Extract information from a 'VBRI' header. */
473static void get_vbri_info(struct mp3info *info, unsigned char *buf)
474{
475 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
476 /*
477 int i, num_offsets, offset = 0;
478 */
479
480 info->is_vbr = true; /* Yes, it is a FhG VBR file */
481 info->has_toc = false; /* We don't parse the TOC (yet) */
482
483 info->byte_count = bytes2int(buf[10], buf[11], buf[12], buf[13]);
484 info->frame_count = bytes2int(buf[14], buf[15], buf[16], buf[17]);
485 if (info->frame_count <= ULONG_MAX / info->ft_num)
486 info->file_time = info->frame_count * info->ft_num / info->ft_den;
487 else
488 info->file_time = info->frame_count / info->ft_den * info->ft_num;
489
490 if (info->byte_count <= (ULONG_MAX/8))
491 info->bitrate = info->byte_count * 8 / info->file_time;
492 else
493 info->bitrate = info->byte_count / (info->file_time >> 3);
494
495 VDEBUGF("Frame size (%dkpbs): %d bytes (0x%x)\n",
496 info->bitrate, info->frame_size, info->frame_size);
497 VDEBUGF("Frame count: %lx\n", info->frame_count);
498 VDEBUGF("Byte count: %lx\n", info->byte_count);
499
500 /* We don't parse the TOC, since we don't yet know how to (FIXME) */
501 /*
502 num_offsets = bytes2int(0, 0, buf[18], buf[19]);
503 VDEBUGF("Offsets: %d\n", num_offsets);
504 VDEBUGF("Frames/entry: %ld\n", bytes2int(0, 0, buf[24], buf[25]));
505
506 for(i = 0; i < num_offsets; i++)
507 {
508 offset += bytes2int(0, 0, buf[26+i*2], buf[27+i*2]);;
509 VDEBUGF("%03d: %lx\n", i, offset - bytecount,);
510 }
511 */
512}
513
514/* Seek to next mpeg header and extract relevant information. */
515static int get_next_header_info(int fd, long *bytecount, struct mp3info *info,
516 bool single_header)
517{
518 long tmp;
519 unsigned long header = 0;
520
521 header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header);
522 if(header == 0)
523 return -1;
524
525 if(!mp3headerinfo(info, header))
526 return -2;
527
528 /* Next frame header is tmp bytes away. */
529 *bytecount += tmp;
530
531 return 0;
532}
533
534int get_mp3file_info(int fd, struct mp3info *info)
535{
536 unsigned char frame[VBR_HEADER_MAX_SIZE], *vbrheader;
537 long bytecount = 0;
538 int result, buf_size;
539
540 /* Initialize info and frame */
541 memset(info, 0, sizeof(struct mp3info));
542 memset(frame, 0, sizeof(frame));
543
544#if CONFIG_CODEC==SWCODEC
545 /* These two are needed for proper LAME gapless MP3 playback */
546 info->enc_delay = -1;
547 info->enc_padding = -1;
548#endif
549
550 /* Get the very first single MPEG frame. */
551 result = get_next_header_info(fd, &bytecount, info, true);
552 if(result)
553 return result;
554
555 /* Read the amount of frame data to the buffer that is required for the
556 * vbr tag parsing. Skip the rest. */
557 buf_size = MIN(info->frame_size-4, (int)sizeof(frame));
558 if(read(fd, frame, buf_size) < 0)
559 return -3;
560 lseek(fd, info->frame_size - 4 - buf_size, SEEK_CUR);
561
562 /* Calculate position of a possible VBR header */
563 if (info->version == MPEG_VERSION1) {
564 if (info->channel_mode == 3) /* mono */
565 vbrheader = frame + 17;
566 else
567 vbrheader = frame + 32;
568 } else {
569 if (info->channel_mode == 3) /* mono */
570 vbrheader = frame + 9;
571 else
572 vbrheader = frame + 17;
573 }
574
575 if (!memcmp(vbrheader, "Xing", 4) || !memcmp(vbrheader, "Info", 4))
576 {
577 VDEBUGF("-- XING header --\n");
578
579 /* We want to skip the Xing frame when playing the stream */
580 bytecount += info->frame_size;
581
582 /* Now get the next frame to read the real info about the mp3 stream */
583 result = get_next_header_info(fd, &bytecount, info, false);
584 if(result)
585 return result;
586
587 get_xing_info(info, vbrheader);
588 }
589 else if (!memcmp(vbrheader, "VBRI", 4))
590 {
591 VDEBUGF("-- VBRI header --\n");
592
593 /* We want to skip the VBRI frame when playing the stream */
594 bytecount += info->frame_size;
595
596 /* Now get the next frame to read the real info about the mp3 stream */
597 result = get_next_header_info(fd, &bytecount, info, false);
598 if(result)
599 return result;
600
601 get_vbri_info(info, vbrheader);
602 }
603 else
604 {
605 VDEBUGF("-- No VBR header --\n");
606
607 /* There was no VBR header found. So, we seek back to beginning and
608 * search for the first MPEG frame header of the mp3 stream. */
609 lseek(fd, -info->frame_size, SEEK_CUR);
610 result = get_next_header_info(fd, &bytecount, info, false);
611 if(result)
612 return result;
613 }
614
615 return bytecount;
616}
617
618#ifndef __PCTOOL__
619static void long2bytes(unsigned char *buf, long val)
620{
621 buf[0] = (val >> 24) & 0xff;
622 buf[1] = (val >> 16) & 0xff;
623 buf[2] = (val >> 8) & 0xff;
624 buf[3] = val & 0xff;
625}
626
627int count_mp3_frames(int fd, int startpos, int filesize,
628 void (*progressfunc)(int),
629 unsigned char* buf, size_t buflen)
630{
631 unsigned long header = 0;
632 struct mp3info info;
633 int num_frames;
634 long bytes;
635 int cnt;
636 long progress_chunk = filesize / 50; /* Max is 50%, in 1% increments */
637 int progress_cnt = 0;
638 bool is_vbr = false;
639 int last_bitrate = 0;
640 int header_template = 0;
641
642 if(lseek(fd, startpos, SEEK_SET) < 0)
643 return -1;
644
645 buf_init(buf, buflen);
646
647 /* Find out the total number of frames */
648 num_frames = 0;
649 cnt = 0;
650
651 while((header = buf_find_next_frame(fd, &bytes, header_template))) {
652 mp3headerinfo(&info, header);
653
654 if(!header_template)
655 header_template = header;
656
657 /* See if this really is a VBR file */
658 if(last_bitrate && info.bitrate != last_bitrate)
659 {
660 is_vbr = true;
661 }
662 last_bitrate = info.bitrate;
663
664 buf_seek(fd, info.frame_size-4);
665 num_frames++;
666 if(progressfunc)
667 {
668 cnt += bytes + info.frame_size;
669 if(cnt > progress_chunk)
670 {
671 progress_cnt++;
672 progressfunc(progress_cnt);
673 cnt = 0;
674 }
675 }
676 }
677 VDEBUGF("Total number of frames: %d\n", num_frames);
678
679 if(is_vbr)
680 return num_frames;
681 else
682 {
683 DEBUGF("Not a VBR file\n");
684 return 0;
685 }
686}
687
688static const char cooltext[] = "Rockbox - rocks your box";
689
690/* buf needs to be the audio buffer with TOC generation enabled,
691 and at least MAX_XING_HEADER_SIZE bytes otherwise */
692int create_xing_header(int fd, long startpos, long filesize,
693 unsigned char *buf, unsigned long num_frames,
694 unsigned long rec_time, unsigned long header_template,
695 void (*progressfunc)(int), bool generate_toc,
696 unsigned char *tempbuf, size_t tempbuflen )
697{
698 struct mp3info info;
699 unsigned char toc[100];
700 unsigned long header = 0;
701 unsigned long xing_header_template = header_template;
702 unsigned long filepos;
703 long pos, last_pos;
704 long j;
705 long bytes;
706 int i;
707 int index;
708
709 DEBUGF("create_xing_header()\n");
710
711 if(generate_toc)
712 {
713 lseek(fd, startpos, SEEK_SET);
714 buf_init(tempbuf, tempbuflen);
715
716 /* Generate filepos table */
717 last_pos = 0;
718 filepos = 0;
719 header = 0;
720 for(i = 0;i < 100;i++) {
721 /* Calculate the absolute frame number for this seek point */
722 pos = i * num_frames / 100;
723
724 /* Advance from the last seek point to this one */
725 for(j = 0;j < pos - last_pos;j++)
726 {
727 header = buf_find_next_frame(fd, &bytes, header_template);
728 filepos += bytes;
729 mp3headerinfo(&info, header);
730 buf_seek(fd, info.frame_size-4);
731 filepos += info.frame_size;
732
733 if(!header_template)
734 header_template = header;
735 }
736
737 /* Save a header for later use if header_template is empty.
738 We only save one header, and we want to save one in the
739 middle of the stream, just in case the first and the last
740 headers are corrupt. */
741 if(!xing_header_template && i == 1)
742 xing_header_template = header;
743
744 if(progressfunc)
745 {
746 progressfunc(50 + i/2);
747 }
748
749 /* Fill in the TOC entry */
750 /* each toc is a single byte indicating how many 256ths of the
751 * way through the file, is that percent of the way through the
752 * song. the easy method, filepos*256/filesize, chokes when
753 * the upper 8 bits of the file position are nonzero
754 * (i.e. files over 16mb in size).
755 */
756 if (filepos > (ULONG_MAX/256))
757 {
758 /* instead of multiplying filepos by 256, we divide
759 * filesize by 256.
760 */
761 toc[i] = filepos / (filesize >> 8);
762 }
763 else
764 {
765 toc[i] = filepos * 256 / filesize;
766 }
767
768 VDEBUGF("Pos %d: %ld relpos: %ld filepos: %lx tocentry: %x\n",
769 i, pos, pos-last_pos, filepos, toc[i]);
770
771 last_pos = pos;
772 }
773 }
774
775 /* Use the template header and create a new one.
776 We ignore the Protection bit even if the rest of the stream is
777 protected. */
778 header = xing_header_template & ~(BITRATE_MASK|PROTECTION_MASK|PADDING_MASK);
779 header |= 8 << 12; /* This gives us plenty of space, 192..576 bytes */
780
781 if (!mp3headerinfo(&info, header))
782 return 0; /* invalid header */
783
784 if (num_frames == 0 && rec_time) {
785 /* estimate the number of frames based on the recording time */
786 if (rec_time <= ULONG_MAX / info.ft_den)
787 num_frames = rec_time * info.ft_den / info.ft_num;
788 else
789 num_frames = rec_time / info.ft_num * info.ft_den;
790 }
791
792 /* Clear the frame */
793 memset(buf, 0, MAX_XING_HEADER_SIZE);
794
795 /* Write the header to the buffer */
796 long2bytes(buf, header);
797
798 /* Calculate position of VBR header */
799 if (info.version == MPEG_VERSION1) {
800 if (info.channel_mode == 3) /* mono */
801 index = 21;
802 else
803 index = 36;
804 }
805 else {
806 if (info.channel_mode == 3) /* mono */
807 index = 13;
808 else
809 index = 21;
810 }
811
812 /* Create the Xing data */
813 memcpy(&buf[index], "Xing", 4);
814 long2bytes(&buf[index+4], (num_frames ? VBR_FRAMES_FLAG : 0)
815 | (filesize ? VBR_BYTES_FLAG : 0)
816 | (generate_toc ? VBR_TOC_FLAG : 0));
817 index += 8;
818 if(num_frames)
819 {
820 long2bytes(&buf[index], num_frames);
821 index += 4;
822 }
823
824 if(filesize)
825 {
826 long2bytes(&buf[index], filesize - startpos);
827 index += 4;
828 }
829
830 /* Copy the TOC */
831 memcpy(buf + index, toc, 100);
832
833 /* And some extra cool info */
834 memcpy(buf + index + 100, cooltext, sizeof(cooltext));
835
836#ifdef DEBUG
837 for(i = 0;i < info.frame_size;i++)
838 {
839 if(i && !(i % 16))
840 DEBUGF("\n");
841
842 DEBUGF("%02x ", buf[i]);
843 }
844#endif
845
846 return info.frame_size;
847}
848
849#endif
diff --git a/apps/mp3data.h b/apps/mp3data.h
deleted file mode 100644
index 762c2f4583..0000000000
--- a/apps/mp3data.h
+++ /dev/null
@@ -1,89 +0,0 @@
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
29#include <string.h> /* size_t */
30
31struct mp3info {
32 /* Standard MP3 frame header fields */
33 int version;
34 int layer;
35 int bitrate;
36 long frequency;
37 int padding;
38 int channel_mode;
39 int frame_size; /* Frame size in bytes */
40 int frame_samples;/* Samples per frame */
41 int ft_num; /* Numerator of frametime in milliseconds */
42 int ft_den; /* Denominator of frametime in milliseconds */
43
44 bool is_vbr; /* True if the file is VBR */
45 bool has_toc; /* True if there is a VBR header in the file */
46 unsigned char toc[100];
47 unsigned long frame_count; /* Number of frames in the file (if VBR) */
48 unsigned long byte_count; /* File size in bytes */
49 unsigned long file_time; /* Length of the whole file in milliseconds */
50 int enc_delay; /* Encoder delay, fetched from LAME header */
51 int enc_padding; /* Padded samples added to last frame. LAME header */
52};
53
54/* Xing header information */
55#define VBR_FRAMES_FLAG 0x01
56#define VBR_BYTES_FLAG 0x02
57#define VBR_TOC_FLAG 0x04
58#define VBR_QUALITY_FLAG 0x08
59
60#define MAX_XING_HEADER_SIZE 576
61
62unsigned long find_next_frame(int fd,
63 long *offset,
64 long max_offset,
65 unsigned long reference_header);
66unsigned long mem_find_next_frame(int startpos,
67 long *offset,
68 long max_offset,
69 unsigned long reference_header,
70 unsigned char* buf, size_t buflen);
71int get_mp3file_info(int fd,
72 struct mp3info *info);
73
74int count_mp3_frames(int fd, int startpos, int filesize,
75 void (*progressfunc)(int),
76 unsigned char* buf, size_t buflen);
77
78int create_xing_header(int fd, long startpos, long filesize,
79 unsigned char *buf, unsigned long num_frames,
80 unsigned long rec_time, unsigned long header_template,
81 void (*progressfunc)(int), bool generate_toc,
82 unsigned char *tempbuf, size_t tempbuflen );
83
84extern unsigned long bytes2int(unsigned long b0,
85 unsigned long b1,
86 unsigned long b2,
87 unsigned long b3);
88
89#endif
diff --git a/apps/plugins/lrcplayer.c b/apps/plugins/lrcplayer.c
index cc0128b401..97385ff047 100644
--- a/apps/plugins/lrcplayer.c
+++ b/apps/plugins/lrcplayer.c
@@ -1113,7 +1113,6 @@ static void load_lrc_file(void)
1113/******************************* 1113/*******************************
1114 * read lyrics from id3 1114 * read lyrics from id3
1115 *******************************/ 1115 *******************************/
1116/* taken from apps/metadata/mp3.c */
1117static unsigned long unsync(unsigned long b0, unsigned long b1, 1116static unsigned long unsync(unsigned long b0, unsigned long b1,
1118 unsigned long b2, unsigned long b3) 1117 unsigned long b2, unsigned long b3)
1119{ 1118{
diff --git a/apps/replaygain.c b/apps/replaygain.c
deleted file mode 100644
index a178321385..0000000000
--- a/apps/replaygain.c
+++ /dev/null
@@ -1,222 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <ctype.h>
23#include <math.h>
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include "strlcpy.h"
29#include "strcasecmp.h"
30#include "system.h"
31#include "metadata.h"
32#include "debug.h"
33#include "replaygain.h"
34#include "fixedpoint.h"
35
36#define FP_BITS (12)
37#define FP_ONE (1 << FP_BITS)
38#define FP_MIN (-48 * FP_ONE)
39#define FP_MAX ( 17 * FP_ONE)
40
41void replaygain_itoa(char* buffer, int length, long int_gain)
42{
43 /* int_gain uses Q19.12 format. */
44 int one = abs(int_gain) >> FP_BITS;
45 int cent = ((abs(int_gain) & 0x0fff) * 100 + (FP_ONE/2)) >> FP_BITS;
46 snprintf(buffer, length, "%s%d.%02d dB", (int_gain<0) ? "-":"", one, cent);
47}
48
49static long fp_atof(const char* s, int precision)
50{
51 long int_part = 0;
52 long int_one = BIT_N(precision);
53 long frac_part = 0;
54 long frac_count = 0;
55 long frac_max = ((precision * 4) + 12) / 13;
56 long frac_max_int = 1;
57 long sign = 1;
58 bool point = false;
59
60 while ((*s != '\0') && isspace(*s))
61 {
62 s++;
63 }
64
65 if (*s == '-')
66 {
67 sign = -1;
68 s++;
69 }
70 else if (*s == '+')
71 {
72 s++;
73 }
74
75 while (*s != '\0')
76 {
77 if (*s == '.')
78 {
79 if (point)
80 {
81 break;
82 }
83
84 point = true;
85 }
86 else if (isdigit(*s))
87 {
88 if (point)
89 {
90 if (frac_count < frac_max)
91 {
92 frac_part = frac_part * 10 + (*s - '0');
93 frac_count++;
94 frac_max_int *= 10;
95 }
96 }
97 else
98 {
99 int_part = int_part * 10 + (*s - '0');
100 }
101 }
102 else
103 {
104 break;
105 }
106
107 s++;
108 }
109
110 while (frac_count < frac_max)
111 {
112 frac_part *= 10;
113 frac_count++;
114 frac_max_int *= 10;
115 }
116
117 return sign * ((int_part * int_one)
118 + (((int64_t) frac_part * int_one) / frac_max_int));
119}
120
121static long convert_gain(long gain)
122{
123 /* Don't allow unreasonably low or high gain changes.
124 * Our math code can't handle it properly anyway. :) */
125 gain = MAX(gain, FP_MIN);
126 gain = MIN(gain, FP_MAX);
127
128 return fp_factor(gain, FP_BITS) << (24 - FP_BITS);
129}
130
131/* Get the sample scale factor in Q19.12 format from a gain value. Returns 0
132 * for no gain.
133 *
134 * str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored.
135 */
136static long get_replaygain(const char* str)
137{
138 return fp_atof(str, FP_BITS);
139}
140
141/* Get the peak volume in Q7.24 format.
142 *
143 * str Peak volume. Full scale is specified as "1.0". Returns 0 for no peak.
144 */
145static long get_replaypeak(const char* str)
146{
147 return fp_atof(str, 24);
148}
149
150/* Get a sample scale factor in Q7.24 format from a gain value.
151 *
152 * int_gain Gain in dB, multiplied by 100.
153 */
154long get_replaygain_int(long int_gain)
155{
156 return convert_gain(int_gain * FP_ONE / 100);
157}
158
159/* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a
160 * valid tag is found, update mp3entry struct accordingly. Existing values
161 * are not overwritten.
162 *
163 * key Name of the tag.
164 * value Value of the tag.
165 * entry mp3entry struct to update.
166 */
167void parse_replaygain(const char* key, const char* value,
168 struct mp3entry* entry)
169{
170 if (((strcasecmp(key, "replaygain_track_gain") == 0) ||
171 (strcasecmp(key, "rg_radio") == 0)) &&
172 !entry->track_gain)
173 {
174 entry->track_level = get_replaygain(value);
175 entry->track_gain = convert_gain(entry->track_level);
176 }
177 else if (((strcasecmp(key, "replaygain_album_gain") == 0) ||
178 (strcasecmp(key, "rg_audiophile") == 0)) &&
179 !entry->album_gain)
180 {
181 entry->album_level = get_replaygain(value);
182 entry->album_gain = convert_gain(entry->album_level);
183 }
184 else if (((strcasecmp(key, "replaygain_track_peak") == 0) ||
185 (strcasecmp(key, "rg_peak") == 0)) &&
186 !entry->track_peak)
187 {
188 entry->track_peak = get_replaypeak(value);
189 }
190 else if ((strcasecmp(key, "replaygain_album_peak") == 0) &&
191 !entry->album_peak)
192 {
193 entry->album_peak = get_replaypeak(value);
194 }
195}
196
197/* Set ReplayGain values from integers. Existing values are not overwritten.
198 *
199 * album If true, set album values, otherwise set track values.
200 * gain Gain value in dB, multiplied by 512. 0 for no gain.
201 * peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no
202 * peak volume.
203 * entry mp3entry struct to update.
204 */
205void parse_replaygain_int(bool album, long gain, long peak,
206 struct mp3entry* entry)
207{
208 gain = gain * FP_ONE / 512;
209
210 if (album)
211 {
212 entry->album_level = gain;
213 entry->album_gain = convert_gain(gain);
214 entry->album_peak = peak;
215 }
216 else
217 {
218 entry->track_level = gain;
219 entry->track_gain = convert_gain(gain);
220 entry->track_peak = peak;
221 }
222}
diff --git a/apps/replaygain.h b/apps/replaygain.h
deleted file mode 100644
index 215464dfdf..0000000000
--- a/apps/replaygain.h
+++ /dev/null
@@ -1,34 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
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 _REPLAYGAIN_H
23#define _REPLAYGAIN_H
24
25#include "metadata.h"
26
27long get_replaygain_int(long int_gain);
28void parse_replaygain(const char* key, const char* value,
29 struct mp3entry* entry);
30void parse_replaygain_int(bool album, long gain, long peak,
31 struct mp3entry* entry);
32void replaygain_itoa(char* buffer, int length, long int_gain);
33
34#endif
diff --git a/apps/tdspeed.c b/apps/tdspeed.c
deleted file mode 100644
index 731be12621..0000000000
--- a/apps/tdspeed.c
+++ /dev/null
@@ -1,450 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org>
11 * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include <inttypes.h>
24#include <stddef.h>
25#include <stdio.h>
26#include <string.h>
27#include "sound.h"
28#include "core_alloc.h"
29#include "system.h"
30#include "tdspeed.h"
31#include "settings.h"
32
33#define assert(cond)
34
35#define MIN_RATE 8000
36#define MAX_RATE 48000 /* double buffer for double rate */
37#define MINFREQ 100
38
39#define FIXED_BUFSIZE 3072 /* 48KHz factor 3.0 */
40
41static int32_t** dsp_src;
42static int handles[4];
43static int32_t *overlap_buffer[2] = { NULL, NULL };
44static int32_t *outbuf[2] = { NULL, NULL };
45
46static int move_callback(int handle, void* current, void* new)
47{
48 /* TODO */
49 (void)handle;
50 if (dsp_src)
51 {
52 int ch = (current == outbuf[0]) ? 0 : 1;
53 dsp_src[ch] = outbuf[ch] = new;
54 }
55 return BUFLIB_CB_OK;
56}
57
58static struct buflib_callbacks ops = {
59 .move_callback = move_callback,
60 .shrink_callback = NULL,
61};
62
63static int ovl_move_callback(int handle, void* current, void* new)
64{
65 /* TODO */
66 (void)handle;
67 if (dsp_src)
68 {
69 int ch = (current == overlap_buffer[0]) ? 0 : 1;
70 overlap_buffer[ch] = new;
71 }
72 return BUFLIB_CB_OK;
73}
74
75static struct buflib_callbacks ovl_ops = {
76 .move_callback = ovl_move_callback,
77 .shrink_callback = NULL,
78};
79
80
81static struct tdspeed_state_s
82{
83 bool stereo;
84 int32_t shift_max; /* maximum displacement on a frame */
85 int32_t src_step; /* source window pace */
86 int32_t dst_step; /* destination window pace */
87 int32_t dst_order; /* power of two for dst_step */
88 int32_t ovl_shift; /* overlap buffer frame shift */
89 int32_t ovl_size; /* overlap buffer used size */
90 int32_t ovl_space; /* overlap buffer size */
91 int32_t *ovl_buff[2]; /* overlap buffer */
92} tdspeed_state;
93
94void tdspeed_init(void)
95{
96 if (!global_settings.timestretch_enabled)
97 return;
98
99 /* Allocate buffers */
100 if (overlap_buffer[0] == NULL)
101 {
102 handles[0] = core_alloc_ex("tdspeed ovl left", FIXED_BUFSIZE * sizeof(int32_t), &ovl_ops);
103 overlap_buffer[0] = core_get_data(handles[0]);
104 }
105 if (overlap_buffer[1] == NULL)
106 {
107 handles[1] = core_alloc_ex("tdspeed ovl right", FIXED_BUFSIZE * sizeof(int32_t), &ovl_ops);
108 overlap_buffer[1] = core_get_data(handles[1]);
109 }
110 if (outbuf[0] == NULL)
111 {
112 handles[2] = core_alloc_ex("tdspeed left", TDSPEED_OUTBUFSIZE * sizeof(int32_t), &ops);
113 outbuf[0] = core_get_data(handles[2]);
114 }
115 if (outbuf[1] == NULL)
116 {
117 handles[3] = core_alloc_ex("tdspeed right", TDSPEED_OUTBUFSIZE * sizeof(int32_t), &ops);
118 outbuf[1] = core_get_data(handles[3]);
119 }
120}
121
122void tdspeed_finish(void)
123{
124 for(unsigned i = 0; i < ARRAYLEN(handles); i++)
125 {
126 if (handles[i] > 0)
127 {
128 core_free(handles[i]);
129 handles[i] = 0;
130 }
131 }
132 overlap_buffer[0] = overlap_buffer[1] = NULL;
133 outbuf[0] = outbuf[1] = NULL;
134}
135
136bool tdspeed_config(int samplerate, bool stereo, int32_t factor)
137{
138 struct tdspeed_state_s *st = &tdspeed_state;
139 int src_frame_sz;
140
141 /* Check buffers were allocated ok */
142 if (overlap_buffer[0] == NULL || overlap_buffer[1] == NULL)
143 return false;
144
145 if (outbuf[0] == NULL || outbuf[1] == NULL)
146 return false;
147
148 /* Check parameters */
149 if (factor == PITCH_SPEED_100)
150 return false;
151
152 if (samplerate < MIN_RATE || samplerate > MAX_RATE)
153 return false;
154
155 if (factor < STRETCH_MIN || factor > STRETCH_MAX)
156 return false;
157
158 st->stereo = stereo;
159 st->dst_step = samplerate / MINFREQ;
160
161 if (factor > PITCH_SPEED_100)
162 st->dst_step = st->dst_step * PITCH_SPEED_100 / factor;
163
164 st->dst_order = 1;
165
166 while (st->dst_step >>= 1)
167 st->dst_order++;
168
169 st->dst_step = (1 << st->dst_order);
170 st->src_step = st->dst_step * factor / PITCH_SPEED_100;
171 st->shift_max = (st->dst_step > st->src_step) ? st->dst_step : st->src_step;
172
173 src_frame_sz = st->shift_max + st->dst_step;
174
175 if (st->dst_step > st->src_step)
176 src_frame_sz += st->dst_step - st->src_step;
177
178 st->ovl_space = ((src_frame_sz - 2) / st->src_step) * st->src_step
179 + src_frame_sz;
180
181 if (st->src_step > st->dst_step)
182 st->ovl_space += 2*st->src_step - st->dst_step;
183
184 if (st->ovl_space > FIXED_BUFSIZE)
185 st->ovl_space = FIXED_BUFSIZE;
186
187 st->ovl_size = 0;
188 st->ovl_shift = 0;
189
190 st->ovl_buff[0] = overlap_buffer[0];
191
192 if (stereo)
193 st->ovl_buff[1] = overlap_buffer[1];
194 else
195 st->ovl_buff[1] = st->ovl_buff[0];
196
197 return true;
198}
199
200static int tdspeed_apply(int32_t *buf_out[2], int32_t *buf_in[2],
201 int data_len, int last, int out_size)
202/* data_len in samples */
203{
204 struct tdspeed_state_s *st = &tdspeed_state;
205 int32_t *dest[2];
206 int32_t next_frame, prev_frame, src_frame_sz;
207 bool stereo = buf_in[0] != buf_in[1];
208
209 assert(stereo == st->stereo);
210
211 src_frame_sz = st->shift_max + st->dst_step;
212
213 if (st->dst_step > st->src_step)
214 src_frame_sz += st->dst_step - st->src_step;
215
216 /* deal with overlap data first, if any */
217 if (st->ovl_size)
218 {
219 int32_t have, copy, steps;
220 have = st->ovl_size;
221
222 if (st->ovl_shift > 0)
223 have -= st->ovl_shift;
224
225 /* append just enough data to have all of the overlap buffer consumed */
226 steps = (have - 1) / st->src_step;
227 copy = steps * st->src_step + src_frame_sz - have;
228
229 if (copy < src_frame_sz - st->dst_step)
230 copy += st->src_step; /* one more step to allow for pregap data */
231
232 if (copy > data_len)
233 copy = data_len;
234
235 assert(st->ovl_size + copy <= FIXED_BUFSIZE);
236 memcpy(st->ovl_buff[0] + st->ovl_size, buf_in[0],
237 copy * sizeof(int32_t));
238
239 if (stereo)
240 memcpy(st->ovl_buff[1] + st->ovl_size, buf_in[1],
241 copy * sizeof(int32_t));
242
243 if (!last && have + copy < src_frame_sz)
244 {
245 /* still not enough to process at least one frame */
246 st->ovl_size += copy;
247 return 0;
248 }
249
250 /* recursively call ourselves to process the overlap buffer */
251 have = st->ovl_size;
252 st->ovl_size = 0;
253
254 if (copy == data_len)
255 {
256 assert(have + copy <= FIXED_BUFSIZE);
257 return tdspeed_apply(buf_out, st->ovl_buff, have+copy, last,
258 out_size);
259 }
260
261 assert(have + copy <= FIXED_BUFSIZE);
262 int i = tdspeed_apply(buf_out, st->ovl_buff, have+copy, -1, out_size);
263
264 dest[0] = buf_out[0] + i;
265 dest[1] = buf_out[1] + i;
266
267 /* readjust pointers to account for data already consumed */
268 next_frame = copy - src_frame_sz + st->src_step;
269 prev_frame = next_frame - st->ovl_shift;
270 }
271 else
272 {
273 dest[0] = buf_out[0];
274 dest[1] = buf_out[1];
275
276 next_frame = prev_frame = 0;
277
278 if (st->ovl_shift > 0)
279 next_frame += st->ovl_shift;
280 else
281 prev_frame += -st->ovl_shift;
282 }
283
284 st->ovl_shift = 0;
285
286 /* process all complete frames */
287 while (data_len - next_frame >= src_frame_sz)
288 {
289 /* find frame overlap by autocorelation */
290 int const INC1 = 8;
291 int const INC2 = 32;
292
293 int64_t min_delta = INT64_MAX; /* most positive */
294 int shift = 0;
295
296 /* Power of 2 of a 28bit number requires 56bits, can accumulate
297 256times in a 64bit variable. */
298 assert(st->dst_step / INC2 <= 256);
299 assert(next_frame + st->shift_max - 1 + st->dst_step - 1 < data_len);
300 assert(prev_frame + st->dst_step - 1 < data_len);
301
302 for (int i = 0; i < st->shift_max; i += INC1)
303 {
304 int64_t delta = 0;
305
306 int32_t *curr = buf_in[0] + next_frame + i;
307 int32_t *prev = buf_in[0] + prev_frame;
308
309 for (int j = 0; j < st->dst_step; j += INC2, curr += INC2, prev += INC2)
310 {
311 int32_t diff = *curr - *prev;
312 delta += abs(diff);
313
314 if (delta >= min_delta)
315 goto skip;
316 }
317
318 if (stereo)
319 {
320 curr = buf_in[1] + next_frame + i;
321 prev = buf_in[1] + prev_frame;
322
323 for (int j = 0; j < st->dst_step; j += INC2, curr += INC2, prev += INC2)
324 {
325 int32_t diff = *curr - *prev;
326 delta += abs(diff);
327
328 if (delta >= min_delta)
329 goto skip;
330 }
331 }
332
333 min_delta = delta;
334 shift = i;
335skip:;
336 }
337
338 /* overlap fading-out previous frame with fading-in current frame */
339 int32_t *curr = buf_in[0] + next_frame + shift;
340 int32_t *prev = buf_in[0] + prev_frame;
341
342 int32_t *d = dest[0];
343
344 assert(next_frame + shift + st->dst_step - 1 < data_len);
345 assert(prev_frame + st->dst_step - 1 < data_len);
346 assert(dest[0] - buf_out[0] + st->dst_step - 1 < out_size);
347
348 for (int i = 0, j = st->dst_step; j; i++, j--)
349 {
350 *d++ = (*curr++ * (int64_t)i +
351 *prev++ * (int64_t)j) >> st->dst_order;
352 }
353
354 dest[0] = d;
355
356 if (stereo)
357 {
358 curr = buf_in[1] + next_frame + shift;
359 prev = buf_in[1] + prev_frame;
360
361 d = dest[1];
362
363 for (int i = 0, j = st->dst_step; j; i++, j--)
364 {
365 assert(d < buf_out[1] + out_size);
366
367 *d++ = (*curr++ * (int64_t)i +
368 *prev++ * (int64_t)j) >> st->dst_order;
369 }
370
371 dest[1] = d;
372 }
373
374 /* adjust pointers for next frame */
375 prev_frame = next_frame + shift + st->dst_step;
376 next_frame += st->src_step;
377
378 /* here next_frame - prev_frame = src_step - dst_step - shift */
379 assert(next_frame - prev_frame == st->src_step - st->dst_step - shift);
380 }
381
382 /* now deal with remaining partial frames */
383 if (last == -1)
384 {
385 /* special overlap buffer processing: remember frame shift only */
386 st->ovl_shift = next_frame - prev_frame;
387 }
388 else if (last != 0)
389 {
390 /* last call: purge all remaining data to output buffer */
391 int i = data_len - prev_frame;
392
393 assert(dest[0] + i <= buf_out[0] + out_size);
394 memcpy(dest[0], buf_in[0] + prev_frame, i * sizeof(int32_t));
395
396 dest[0] += i;
397
398 if (stereo)
399 {
400 assert(dest[1] + i <= buf_out[1] + out_size);
401 memcpy(dest[1], buf_in[1] + prev_frame, i * sizeof(int32_t));
402 dest[1] += i;
403 }
404 }
405 else
406 {
407 /* preserve remaining data + needed overlap data for next call */
408 st->ovl_shift = next_frame - prev_frame;
409 int i = (st->ovl_shift < 0) ? next_frame : prev_frame;
410 st->ovl_size = data_len - i;
411
412 assert(st->ovl_size <= FIXED_BUFSIZE);
413 memcpy(st->ovl_buff[0], buf_in[0] + i, st->ovl_size * sizeof(int32_t));
414
415 if (stereo)
416 memcpy(st->ovl_buff[1], buf_in[1] + i, st->ovl_size * sizeof(int32_t));
417 }
418
419 return dest[0] - buf_out[0];
420}
421
422long tdspeed_est_output_size()
423{
424 return TDSPEED_OUTBUFSIZE;
425}
426
427long tdspeed_est_input_size(long size)
428{
429 struct tdspeed_state_s *st = &tdspeed_state;
430
431 size = (size - st->ovl_size) * st->src_step / st->dst_step;
432
433 if (size < 0)
434 size = 0;
435
436 return size;
437}
438
439int tdspeed_doit(int32_t *src[], int count)
440{
441 dsp_src = src;
442 count = tdspeed_apply( (int32_t *[2]) { outbuf[0], outbuf[1] },
443 src, count, 0, TDSPEED_OUTBUFSIZE);
444
445 src[0] = outbuf[0];
446 src[1] = outbuf[1];
447
448 return count;
449}
450
diff --git a/apps/tdspeed.h b/apps/tdspeed.h
deleted file mode 100644
index e91eeb1701..0000000000
--- a/apps/tdspeed.h
+++ /dev/null
@@ -1,49 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Nicolas Pitre <nico@cam.org>
11 * Copyright (C) 2006-2007 by Stéphane Doyon <s.doyon@videotron.ca>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#ifndef _TDSPEED_H
24#define _TDSPEED_H
25
26#include "dsp.h"
27
28#define TDSPEED_OUTBUFSIZE 4096
29
30/* some #define functions to get the pitch, stretch and speed values based on */
31/* two known values. Remember that params are alphabetical. */
32#define GET_SPEED(pitch, stretch) \
33 ((pitch * stretch + PITCH_SPEED_100 / 2L) / PITCH_SPEED_100)
34#define GET_PITCH(speed, stretch) \
35 ((speed * PITCH_SPEED_100 + stretch / 2L) / stretch)
36#define GET_STRETCH(pitch, speed) \
37 ((speed * PITCH_SPEED_100 + pitch / 2L) / pitch)
38
39void tdspeed_init(void);
40void tdspeed_finish(void);
41bool tdspeed_config(int samplerate, bool stereo, int32_t factor);
42long tdspeed_est_output_size(void);
43long tdspeed_est_input_size(long size);
44int tdspeed_doit(int32_t *src[], int count);
45
46#define STRETCH_MAX (250L * PITCH_SPEED_PRECISION) /* 250% */
47#define STRETCH_MIN (35L * PITCH_SPEED_PRECISION) /* 35% */
48
49#endif