summaryrefslogtreecommitdiff
path: root/firmware/replaygain.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/replaygain.c')
-rw-r--r--firmware/replaygain.c110
1 files changed, 93 insertions, 17 deletions
diff --git a/firmware/replaygain.c b/firmware/replaygain.c
index a8331ae483..ffabb4b2ac 100644
--- a/firmware/replaygain.c
+++ b/firmware/replaygain.c
@@ -28,6 +28,10 @@
28#include "id3.h" 28#include "id3.h"
29#include "debug.h" 29#include "debug.h"
30 30
31/* Type of channel for RVA2 frame. There are more than this defined in the spec
32 but we don't use them. */
33#define MASTER_CHANNEL 1
34
31/* The fixed point math routines (with the exception of fp_atof) are based 35/* The fixed point math routines (with the exception of fp_atof) are based
32 * on oMathFP by Dan Carter (http://orbisstudios.com). 36 * on oMathFP by Dan Carter (http://orbisstudios.com).
33 */ 37 */
@@ -278,7 +282,7 @@ static long fp_atof(const char* s, int precision)
278 frac_max_int *= 10; 282 frac_max_int *= 10;
279 } 283 }
280 284
281 return sign * ((int_part * int_one) 285 return sign * ((int_part * int_one)
282 + (((int64_t) frac_part * int_one) / frac_max_int)); 286 + (((int64_t) frac_part * int_one) / frac_max_int));
283} 287}
284 288
@@ -286,14 +290,14 @@ static long convert_gain(long gain)
286{ 290{
287 if (gain != 0) 291 if (gain != 0)
288 { 292 {
289 /* Don't allow unreasonably low or high gain changes. 293 /* Don't allow unreasonably low or high gain changes.
290 * Our math code can't handle it properly anyway. :) 294 * Our math code can't handle it properly anyway. :)
291 */ 295 */
292 if (gain < (-48 * FP_ONE)) 296 if (gain < (-48 * FP_ONE))
293 { 297 {
294 gain = -48 * FP_ONE; 298 gain = -48 * FP_ONE;
295 } 299 }
296 300
297 if (gain > (17 * FP_ONE)) 301 if (gain > (17 * FP_ONE))
298 { 302 {
299 gain = 17 * FP_ONE; 303 gain = 17 * FP_ONE;
@@ -301,55 +305,55 @@ static long convert_gain(long gain)
301 305
302 gain = fp_exp10(gain / 20) << (24 - FP_BITS); 306 gain = fp_exp10(gain / 20) << (24 - FP_BITS);
303 } 307 }
304 308
305 return gain; 309 return gain;
306} 310}
307 311
308long get_replaygain_int(long int_gain) 312long get_replaygain_int(long int_gain)
309{ 313{
310 long gain = 0; 314 long gain = 0;
311 315
312 if (int_gain) 316 if (int_gain)
313 { 317 {
314 gain = convert_gain(int_gain * FP_ONE / 100); 318 gain = convert_gain(int_gain * FP_ONE / 100);
315 } 319 }
316 320
317 return gain; 321 return gain;
318} 322}
319 323
320long get_replaygain(const char* str) 324long get_replaygain(const char* str)
321{ 325{
322 long gain = 0; 326 long gain = 0;
323 327
324 if (str) 328 if (str)
325 { 329 {
326 gain = fp_atof(str, FP_BITS); 330 gain = fp_atof(str, FP_BITS);
327 gain = convert_gain(gain); 331 gain = convert_gain(gain);
328 } 332 }
329 333
330 return gain; 334 return gain;
331} 335}
332 336
333long get_replaypeak(const char* str) 337long get_replaypeak(const char* str)
334{ 338{
335 long peak = 0; 339 long peak = 0;
336 340
337 if (str) 341 if (str)
338 { 342 {
339 peak = fp_atof(str, 24); 343 peak = fp_atof(str, 24);
340 } 344 }
341 345
342 return peak; 346 return peak;
343} 347}
344 348
345/* Check for a ReplayGain tag conforming to the "VorbisGain standard". If 349/* Check for a ReplayGain tag conforming to the "VorbisGain standard". If
346 * found, set the mp3entry accordingly. buffer is where to store the text 350 * found, set the mp3entry accordingly. buffer is where to store the text
347 * contents of the gain tags; up to length bytes (including end nil) can be 351 * contents of the gain tags; up to length bytes (including end nil) can be
348 * written. Returns number of bytes written to the tag text buffer, or zero 352 * written. Returns number of bytes written to the tag text buffer, or zero
349 * if no ReplayGain tag was found (or nothing was copied to the buffer for 353 * if no ReplayGain tag was found (or nothing was copied to the buffer for
350 * other reasons). 354 * other reasons).
351 */ 355 */
352long parse_replaygain(const char* key, const char* value, 356long parse_replaygain(const char* key, const char* value,
353 struct mp3entry* entry, char* buffer, int length) 357 struct mp3entry* entry, char* buffer, int length)
354{ 358{
355 char **p = NULL; 359 char **p = NULL;
@@ -359,7 +363,7 @@ long parse_replaygain(const char* key, const char* value,
359 { 363 {
360 entry->track_gain = get_replaygain(value); 364 entry->track_gain = get_replaygain(value);
361 p = &(entry->track_gain_string); 365 p = &(entry->track_gain_string);
362 } 366 }
363 else if ((strcasecmp(key, "replaygain_album_gain") == 0) 367 else if ((strcasecmp(key, "replaygain_album_gain") == 0)
364 || ((strcasecmp(key, "rg_audiophile") == 0) && !entry->album_gain)) 368 || ((strcasecmp(key, "rg_audiophile") == 0) && !entry->album_gain))
365 { 369 {
@@ -370,7 +374,7 @@ long parse_replaygain(const char* key, const char* value,
370 || ((strcasecmp(key, "rg_peak") == 0) && !entry->track_peak)) 374 || ((strcasecmp(key, "rg_peak") == 0) && !entry->track_peak))
371 { 375 {
372 entry->track_peak = get_replaypeak(value); 376 entry->track_peak = get_replaypeak(value);
373 } 377 }
374 else if (strcasecmp(key, "replaygain_album_peak") == 0) 378 else if (strcasecmp(key, "replaygain_album_peak") == 0)
375 { 379 {
376 entry->album_peak = get_replaypeak(value); 380 entry->album_peak = get_replaypeak(value);
@@ -379,7 +383,7 @@ long parse_replaygain(const char* key, const char* value,
379 if (p) 383 if (p)
380 { 384 {
381 int len = strlen(value); 385 int len = strlen(value);
382 386
383 len = MIN(len, length - 1); 387 len = MIN(len, length - 1);
384 388
385 /* A few characters just isn't interesting... */ 389 /* A few characters just isn't interesting... */
@@ -394,3 +398,75 @@ long parse_replaygain(const char* key, const char* value,
394 398
395 return 0; 399 return 0;
396} 400}
401
402static long get_rva_values(const char *frame, long *gain, long *peak,
403 char **string, char *buffer, int length)
404{
405 long value, len;
406 int negative = 0;
407 char tmpbuf[10];
408 int peakbits, peakbytes, shift;
409 unsigned long peakvalue = 0;
410
411 value = 256 * ((unsigned char)*frame) + ((unsigned char)*(frame + 1));
412 if (value & 0x8000)
413 {
414 value = -(value | ~0xFFFF);
415 negative = 1;
416 }
417
418 len = snprintf(tmpbuf, sizeof(tmpbuf), "%s%d.%02d dB", negative ? "-" : "",
419 value / 512, (value & 0x1FF) * 195 / 1000);
420
421 *gain = get_replaygain(tmpbuf);
422
423 len = MIN(len, length - 1);
424 if (len > 1)
425 {
426 strncpy(buffer, tmpbuf, len);
427 buffer[len] = 0;
428 *string = buffer;
429 }
430
431 frame += 2;
432 peakbits = *(unsigned char *)frame++;
433 peakbytes = MIN(4, (peakbits + 7) >> 3);
434 shift = ((8 - (peakbits & 7)) & 7) + (4 - peakbytes) * 8;
435
436 for (; peakbytes; peakbytes--)
437 {
438 peakvalue <<= 8;
439 peakvalue += (unsigned long)*frame++;
440 }
441
442 peakvalue <<= shift;
443
444 if (peakbits > 32)
445 peakvalue += (unsigned long)*frame >> (8 - shift);
446
447 snprintf(tmpbuf, sizeof(tmpbuf), "%d.%06d", peakvalue >> 31,
448 (peakvalue & ~(1 << 31)) / 2147);
449
450 *peak = get_replaypeak(tmpbuf);
451
452 return len + 1;
453}
454
455long parse_replaygain_rva(const char* key, const char* value,
456 struct mp3entry* entry, char* buffer, int length)
457{
458 if ((strcasecmp(key, "track") == 0) && *value == MASTER_CHANNEL
459 && !entry->track_gain && !entry->track_peak)
460 {
461 return get_rva_values(value + 1, &(entry->track_gain), &(entry->track_peak),
462 &(entry->track_gain_string), buffer, length);
463 }
464 else if ((strcasecmp(key, "album") == 0) && *value == MASTER_CHANNEL
465 && !entry->album_gain && !entry->album_peak)
466 {
467 return get_rva_values(value + 1, &(entry->album_gain), &(entry->album_peak),
468 &(entry->album_gain_string), buffer, length);
469 }
470
471 return 0;
472}