summaryrefslogtreecommitdiff
path: root/firmware/replaygain.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/replaygain.c')
-rw-r--r--firmware/replaygain.c149
1 files changed, 76 insertions, 73 deletions
diff --git a/firmware/replaygain.c b/firmware/replaygain.c
index c934586f4b..07726f19da 100644
--- a/firmware/replaygain.c
+++ b/firmware/replaygain.c
@@ -28,10 +28,6 @@
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
35/* The fixed point math routines (with the exception of fp_atof) are based 31/* The fixed point math routines (with the exception of fp_atof) are based
36 * on oMathFP by Dan Carter (http://orbisstudios.com). 32 * on oMathFP by Dan Carter (http://orbisstudios.com).
37 */ 33 */
@@ -306,12 +302,12 @@ static long convert_gain(long gain)
306 return gain; 302 return gain;
307} 303}
308 304
309long get_replaygain_int(long int_gain) 305/* Get the sample scale factor in Q7.24 format from a gain value. Returns 0
310{ 306 * for no gain.
311 return convert_gain(int_gain * FP_ONE / 100); 307 *
312} 308 * str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored.
313 309 */
314long get_replaygain(const char* str) 310static long get_replaygain(const char* str)
315{ 311{
316 long gain = 0; 312 long gain = 0;
317 313
@@ -324,7 +320,11 @@ long get_replaygain(const char* str)
324 return gain; 320 return gain;
325} 321}
326 322
327long get_replaypeak(const char* str) 323/* Get the peak volume in Q7.24 format.
324 *
325 * str Peak volume. Full scale is specified as "1.0". Returns 0 for no peak.
326 */
327static long get_replaypeak(const char* str)
328{ 328{
329 long peak = 0; 329 long peak = 0;
330 330
@@ -336,12 +336,24 @@ long get_replaypeak(const char* str)
336 return peak; 336 return peak;
337} 337}
338 338
339/* Check for a ReplayGain tag conforming to the "VorbisGain standard". If 339/* Get a sample scale factor in Q7.24 format from a gain value.
340 * found, set the mp3entry accordingly. buffer is where to store the text 340 *
341 * contents of the gain tags; up to length bytes (including end nil) can be 341 * int_gain Gain in dB, multiplied by 100.
342 * written. Returns number of bytes written to the tag text buffer, or zero 342 */
343 * if no ReplayGain tag was found (or nothing was copied to the buffer for 343long get_replaygain_int(long int_gain)
344 * other reasons). 344{
345 return convert_gain(int_gain * FP_ONE / 100);
346}
347
348/* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a
349 * valid tag is found, update mp3entry struct accordingly. Existing values
350 * are not overwritten. Returns number of bytes written to buffer.
351 *
352 * key Name of the tag.
353 * value Value of the tag.
354 * entry mp3entry struct to update.
355 * buffer Where to store the text for gain values (for later display).
356 * length Bytes left in buffer.
345 */ 357 */
346long parse_replaygain(const char* key, const char* value, 358long parse_replaygain(const char* key, const char* value,
347 struct mp3entry* entry, char* buffer, int length) 359 struct mp3entry* entry, char* buffer, int length)
@@ -390,74 +402,65 @@ long parse_replaygain(const char* key, const char* value,
390 return 0; 402 return 0;
391} 403}
392 404
393static long get_rva_values(const char *frame, long *gain, long *peak, 405/* Set ReplayGain values from integers. Existing values are not overwritten.
394 char **string, char *buffer, int length) 406 * Returns number of bytes written to buffer.
407 *
408 * album If true, set album values, otherwise set track values.
409 * gain Gain value in dB, multiplied by 512. 0 for no gain.
410 * peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no
411 * peak volume.
412 * buffer Where to store the text for gain values (for later display).
413 * length Bytes left in buffer.
414 */
415long parse_replaygain_int(bool album, long gain, long peak,
416 struct mp3entry* entry, char* buffer, int length)
395{ 417{
396 long value, len; 418 long len = 0;
397 int negative = 0;
398 char tmpbuf[10];
399 int peakbits, peakbytes, shift;
400 unsigned long peakvalue = 0;
401 419
402 value = 256 * ((unsigned char)*frame) + ((unsigned char)*(frame + 1)); 420 if (buffer != NULL)
403 if (value & 0x8000)
404 { 421 {
405 value = -(value | ~0xFFFF); 422 len = snprintf(buffer, length, "%d.%02d dB", gain / 512,
406 negative = 1; 423 ((abs(gain) & 0x01ff) * 100 + 256) / 512);
424 len++;
407 } 425 }
408 426
409 len = snprintf(tmpbuf, sizeof(tmpbuf), "%s%d.%02d dB", negative ? "-" : "", 427 if (gain != 0)
410 value / 512, (value & 0x1FF) * 195 / 1000);
411
412 *gain = get_replaygain(tmpbuf);
413
414 len = MIN(len, length - 1);
415 if (len > 1)
416 { 428 {
417 strncpy(buffer, tmpbuf, len); 429 gain = convert_gain(gain * FP_ONE / 512);
418 buffer[len] = 0;
419 *string = buffer;
420 } 430 }
421 431
422 frame += 2; 432 DEBUGF(" Album: %d\n", album);
423 peakbits = *(unsigned char *)frame++; 433 DEBUGF(" Gain: %ld.%06ld\n", gain >> 24,
424 peakbytes = MIN(4, (peakbits + 7) >> 3); 434 (long) (((long long) (abs(gain) & 0x00ffffff) * 1000000) / 0x01000000));
425 shift = ((8 - (peakbits & 7)) & 7) + (4 - peakbytes) * 8; 435 DEBUGF(" Peak: %ld.%06ld\n", peak >> 24,
436 (long) (((long long) (abs(peak) & 0x00ffffff) * 1000000) / 0x01000000));
426 437
427 for (; peakbytes; peakbytes--) 438 if (album)
428 { 439 {
429 peakvalue <<= 8; 440 if (!entry->album_gain)
430 peakvalue += (unsigned long)*frame++; 441 {
431 } 442 entry->album_gain = gain;
432 443 entry->album_gain_string = buffer;
433 peakvalue <<= shift; 444 }
434
435 if (peakbits > 32)
436 peakvalue += (unsigned long)*frame >> (8 - shift);
437
438 snprintf(tmpbuf, sizeof(tmpbuf), "%d.%06d", peakvalue >> 31,
439 (peakvalue & ~(1 << 31)) / 2147);
440
441 *peak = get_replaypeak(tmpbuf);
442
443 return len + 1;
444}
445 445
446long parse_replaygain_rva(const char* key, const char* value, 446 if (!entry->album_peak)
447 struct mp3entry* entry, char* buffer, int length) 447 {
448{ 448 entry->album_peak = peak;
449 /* Values will be overwritten if they already exist. This gives priority to 449 }
450 replaygain in RVA2 fields over TXXX fields for ID3v2.4. */
451 if ((strcasecmp(key, "track") == 0) && *value == MASTER_CHANNEL)
452 {
453 return get_rva_values(value + 1, &(entry->track_gain), &(entry->track_peak),
454 &(entry->track_gain_string), buffer, length);
455 } 450 }
456 else if ((strcasecmp(key, "album") == 0) && *value == MASTER_CHANNEL) 451 else
457 { 452 {
458 return get_rva_values(value + 1, &(entry->album_gain), &(entry->album_peak), 453 if (!entry->track_gain)
459 &(entry->album_gain_string), buffer, length); 454 {
460 } 455 entry->track_gain = gain;
456 entry->track_gain_string = buffer;
457 }
461 458
462 return 0; 459 if (!entry->track_peak)
460 {
461 entry->track_peak = peak;
462 }
463 }
464
465 return len;
463} 466}