Commit 65b18644 authored by Pauli Virtanen's avatar Pauli Virtanen Committed by Max Kellermann

Add RVA2 tag support to MPD

This patch adds RVA2 (relative volume adjustment) tag support to mpd, as a fallback if no replaygain tags are found. The code is almost directly from madplay (GPL). RVA2 tags are generated for example by the "normalize" utility. Updated by: Avuton Olrich <avuton@gmail.com>
parent ed9668f6
...@@ -203,6 +203,95 @@ mp3_fill_buffer(struct mp3_data *data) ...@@ -203,6 +203,95 @@ mp3_fill_buffer(struct mp3_data *data)
} }
#ifdef HAVE_ID3TAG #ifdef HAVE_ID3TAG
/* Parse mp3 RVA2 frame. Shamelessly stolen from madplay. */
static int parse_rva2(struct id3_tag * tag, struct replay_gain_info * replay_gain_info)
{
struct id3_frame const * frame;
id3_latin1_t const *id;
id3_byte_t const *data;
id3_length_t length;
int found;
enum {
CHANNEL_OTHER = 0x00,
CHANNEL_MASTER_VOLUME = 0x01,
CHANNEL_FRONT_RIGHT = 0x02,
CHANNEL_FRONT_LEFT = 0x03,
CHANNEL_BACK_RIGHT = 0x04,
CHANNEL_BACK_LEFT = 0x05,
CHANNEL_FRONT_CENTRE = 0x06,
CHANNEL_BACK_CENTRE = 0x07,
CHANNEL_SUBWOOFER = 0x08
};
found = 0;
/* relative volume adjustment information */
frame = id3_tag_findframe(tag, "RVA2", 0);
if (!frame) return 0;
id = id3_field_getlatin1(id3_frame_field(frame, 0));
data = id3_field_getbinarydata(id3_frame_field(frame, 1),
&length);
if (!id || !data) return 0;
/*
* "The 'identification' string is used to identify the
* situation and/or device where this adjustment should apply.
* The following is then repeated for every channel
*
* Type of channel $xx
* Volume adjustment $xx xx
* Bits representing peak $xx
* Peak volume $xx (xx ...)"
*/
while (length >= 4) {
unsigned int peak_bytes;
peak_bytes = (data[3] + 7) / 8;
if (4 + peak_bytes > length)
break;
if (data[0] == CHANNEL_MASTER_VOLUME) {
signed int voladj_fixed;
double voladj_float;
/*
* "The volume adjustment is encoded as a fixed
* point decibel value, 16 bit signed integer
* representing (adjustment*512), giving +/- 64
* dB with a precision of 0.001953125 dB."
*/
voladj_fixed = (data[1] << 8) | (data[2] << 0);
voladj_fixed |= -(voladj_fixed & 0x8000);
voladj_float = (double) voladj_fixed / 512;
replay_gain_info->tuples[REPLAY_GAIN_TRACK].peak = voladj_float;
replay_gain_info->tuples[REPLAY_GAIN_ALBUM].peak = voladj_float;
g_debug("parseRVA2: Relative Volume "
"%+.1f dB adjustment (%s)\n",
voladj_float, id);
found = 1;
break;
}
data += 4 + peak_bytes;
length -= 4 + peak_bytes;
}
return found;
}
#endif
#ifdef HAVE_ID3TAG
static struct replay_gain_info * static struct replay_gain_info *
parse_id3_replay_gain_info(struct id3_tag *tag) parse_id3_replay_gain_info(struct id3_tag *tag)
{ {
...@@ -244,6 +333,11 @@ parse_id3_replay_gain_info(struct id3_tag *tag) ...@@ -244,6 +333,11 @@ parse_id3_replay_gain_info(struct id3_tag *tag)
free(value); free(value);
} }
if (!found) {
/* fall back on RVA2 if no replaygain tags found */
found = parse_rva2(tag, replay_gain_info);
}
if (found) if (found)
return replay_gain_info; return replay_gain_info;
replay_gain_info_free(replay_gain_info); replay_gain_info_free(replay_gain_info);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment