Tweak ZXBox colours: 1) 'Bright' black is the same as normal black on a real Spectrum...
[kugel-rb.git] / firmware / replaygain.c
blob8871b1f25b335a7d59e11dce60e5d5e760c253d5
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Magnus Holmgren
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <ctype.h>
21 #include <inttypes.h>
22 #include <math.h>
23 #include <stdbool.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <system.h>
28 #include "id3.h"
29 #include "debug.h"
30 #include "replaygain.h"
32 /* The fixed point math routines (with the exception of fp_atof) are based
33 * on oMathFP by Dan Carter (http://orbisstudios.com).
36 /* 12 bits of precision gives fairly accurate result, but still allows a
37 * compact implementation. The math code supports up to 13...
40 #define FP_BITS (12)
41 #define FP_MASK ((1 << FP_BITS) - 1)
42 #define FP_ONE (1 << FP_BITS)
43 #define FP_TWO (2 << FP_BITS)
44 #define FP_HALF (1 << (FP_BITS - 1))
45 #define FP_LN2 ( 45426 >> (16 - FP_BITS))
46 #define FP_LN2_INV ( 94548 >> (16 - FP_BITS))
47 #define FP_EXP_ZERO ( 10922 >> (16 - FP_BITS))
48 #define FP_EXP_ONE ( -182 >> (16 - FP_BITS))
49 #define FP_EXP_TWO ( 4 >> (16 - FP_BITS))
50 #define FP_INF (0x7fffffff)
51 #define FP_LN10 (150902 >> (16 - FP_BITS))
53 #define FP_MAX_DIGITS (4)
54 #define FP_MAX_DIGITS_INT (10000)
56 #define FP_FAST_MUL_DIV
58 #ifdef FP_FAST_MUL_DIV
60 /* These macros can easily overflow, but they are good enough for our uses,
61 * and saves some code.
63 #define fp_mul(x, y) (((x) * (y)) >> FP_BITS)
64 #define fp_div(x, y) (((x) << FP_BITS) / (y))
66 #else
68 static long fp_mul(long x, long y)
70 long x_neg = 0;
71 long y_neg = 0;
72 long rc;
74 if ((x == 0) || (y == 0))
76 return 0;
79 if (x < 0)
81 x_neg = 1;
82 x = -x;
85 if (y < 0)
87 y_neg = 1;
88 y = -y;
91 rc = (((x >> FP_BITS) * (y >> FP_BITS)) << FP_BITS)
92 + (((x & FP_MASK) * (y & FP_MASK)) >> FP_BITS)
93 + ((x & FP_MASK) * (y >> FP_BITS))
94 + ((x >> FP_BITS) * (y & FP_MASK));
96 if ((x_neg ^ y_neg) == 1)
98 rc = -rc;
101 return rc;
104 static long fp_div(long x, long y)
106 long x_neg = 0;
107 long y_neg = 0;
108 long shifty;
109 long rc;
110 int msb = 0;
111 int lsb = 0;
113 if (x == 0)
115 return 0;
118 if (y == 0)
120 return (x < 0) ? -FP_INF : FP_INF;
123 if (x < 0)
125 x_neg = 1;
126 x = -x;
129 if (y < 0)
131 y_neg = 1;
132 y = -y;
135 while ((x & (1 << (30 - msb))) == 0)
137 msb++;
140 while ((y & (1 << lsb)) == 0)
142 lsb++;
145 shifty = FP_BITS - (msb + lsb);
146 rc = ((x << msb) / (y >> lsb));
148 if (shifty > 0)
150 rc <<= shifty;
152 else
154 rc >>= -shifty;
157 if ((x_neg ^ y_neg) == 1)
159 rc = -rc;
162 return rc;
165 #endif /* FP_FAST_MUL_DIV */
167 static long fp_exp(long x)
169 long k;
170 long z;
171 long R;
172 long xp;
174 if (x == 0)
176 return FP_ONE;
179 k = (fp_mul(abs(x), FP_LN2_INV) + FP_HALF) & ~FP_MASK;
181 if (x < 0)
183 k = -k;
186 x -= fp_mul(k, FP_LN2);
187 z = fp_mul(x, x);
188 R = FP_TWO + fp_mul(z, FP_EXP_ZERO + fp_mul(z, FP_EXP_ONE
189 + fp_mul(z, FP_EXP_TWO)));
190 xp = FP_ONE + fp_div(fp_mul(FP_TWO, x), R - x);
192 if (k < 0)
194 k = FP_ONE >> (-k >> FP_BITS);
196 else
198 k = FP_ONE << (k >> FP_BITS);
201 return fp_mul(k, xp);
204 static long fp_exp10(long x)
206 if (x == 0)
208 return FP_ONE;
211 return fp_exp(fp_mul(FP_LN10, x));
214 static long fp_atof(const char* s, int precision)
216 long int_part = 0;
217 long int_one = 1 << precision;
218 long frac_part = 0;
219 long frac_count = 0;
220 long frac_max = ((precision * 4) + 12) / 13;
221 long frac_max_int = 1;
222 long sign = 1;
223 bool point = false;
225 while ((*s != '\0') && isspace(*s))
227 s++;
230 if (*s == '-')
232 sign = -1;
233 s++;
235 else if (*s == '+')
237 s++;
240 while (*s != '\0')
242 if (*s == '.')
244 if (point)
246 break;
249 point = true;
251 else if (isdigit(*s))
253 if (point)
255 if (frac_count < frac_max)
257 frac_part = frac_part * 10 + (*s - '0');
258 frac_count++;
259 frac_max_int *= 10;
262 else
264 int_part = int_part * 10 + (*s - '0');
267 else
269 break;
272 s++;
275 while (frac_count < frac_max)
277 frac_part *= 10;
278 frac_count++;
279 frac_max_int *= 10;
282 return sign * ((int_part * int_one)
283 + (((int64_t) frac_part * int_one) / frac_max_int));
286 static long convert_gain(long gain)
288 /* Don't allow unreasonably low or high gain changes.
289 * Our math code can't handle it properly anyway. :)
291 if (gain < (-48 * FP_ONE))
293 gain = -48 * FP_ONE;
296 if (gain > (17 * FP_ONE))
298 gain = 17 * FP_ONE;
301 gain = fp_exp10(gain / 20) << (24 - FP_BITS);
303 return gain;
306 /* Get the sample scale factor in Q7.24 format from a gain value. Returns 0
307 * for no gain.
309 * str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored.
311 static long get_replaygain(const char* str)
313 long gain = 0;
315 if (str)
317 gain = fp_atof(str, FP_BITS);
318 gain = convert_gain(gain);
321 return gain;
324 /* Get the peak volume in Q7.24 format.
326 * str Peak volume. Full scale is specified as "1.0". Returns 0 for no peak.
328 static long get_replaypeak(const char* str)
330 long peak = 0;
332 if (str)
334 peak = fp_atof(str, 24);
337 return peak;
340 /* Get a sample scale factor in Q7.24 format from a gain value.
342 * int_gain Gain in dB, multiplied by 100.
344 long get_replaygain_int(long int_gain)
346 return convert_gain(int_gain * FP_ONE / 100);
349 /* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a
350 * valid tag is found, update mp3entry struct accordingly. Existing values
351 * are not overwritten. Returns number of bytes written to buffer.
353 * key Name of the tag.
354 * value Value of the tag.
355 * entry mp3entry struct to update.
356 * buffer Where to store the text for gain values (for later display).
357 * length Bytes left in buffer.
359 long parse_replaygain(const char* key, const char* value,
360 struct mp3entry* entry, char* buffer, int length)
362 char **p = NULL;
364 if (((strcasecmp(key, "replaygain_track_gain") == 0)
365 || (strcasecmp(key, "rg_radio") == 0)) && !entry->track_gain)
367 entry->track_gain = get_replaygain(value);
368 p = &(entry->track_gain_string);
370 else if (((strcasecmp(key, "replaygain_album_gain") == 0)
371 || (strcasecmp(key, "rg_audiophile") == 0)) && !entry->album_gain)
373 entry->album_gain = get_replaygain(value);
374 p = &(entry->album_gain_string);
376 else if (((strcasecmp(key, "replaygain_track_peak") == 0)
377 || (strcasecmp(key, "rg_peak") == 0)) && !entry->track_peak)
379 entry->track_peak = get_replaypeak(value);
381 else if ((strcasecmp(key, "replaygain_album_peak") == 0)
382 && !entry->album_peak)
384 entry->album_peak = get_replaypeak(value);
387 if (p)
389 int len = strlen(value);
391 len = MIN(len, length - 1);
393 /* A few characters just isn't interesting... */
394 if (len > 1)
396 strncpy(buffer, value, len);
397 buffer[len] = 0;
398 *p = buffer;
399 return len + 1;
403 return 0;
406 /* Set ReplayGain values from integers. Existing values are not overwritten.
407 * Returns number of bytes written to buffer.
409 * album If true, set album values, otherwise set track values.
410 * gain Gain value in dB, multiplied by 512. 0 for no gain.
411 * peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no
412 * peak volume.
413 * buffer Where to store the text for gain values (for later display).
414 * length Bytes left in buffer.
416 long parse_replaygain_int(bool album, long gain, long peak,
417 struct mp3entry* entry, char* buffer, int length)
419 long len = 0;
421 if (buffer != NULL)
423 len = snprintf(buffer, length, "%d.%02d dB", gain / 512,
424 ((abs(gain) & 0x01ff) * 100 + 256) / 512);
425 len++;
428 if (gain != 0)
430 gain = convert_gain(gain * FP_ONE / 512);
433 if (album)
435 entry->album_gain = gain;
436 entry->album_gain_string = buffer;
438 if (peak)
440 entry->album_peak = peak;
443 else
445 entry->track_gain = gain;
446 entry->track_gain_string = buffer;
448 if (peak)
450 entry->track_peak = peak;
454 return len;