Add support for MixRamp tags
Adds mixrampdb and mixrampdelay commands. Reads MIXRAP_START and MIXRAMP_END tags from FLAC files and overlaps instead of crossfading.
This commit is contained in:

committed by
Max Kellermann

parent
e9b75d462c
commit
e7a515c8b1
@@ -102,11 +102,6 @@ flac_got_stream_info(struct flac_data *data,
|
||||
if (data->total_frames == 0)
|
||||
data->total_frames = stream_info->total_samples;
|
||||
|
||||
decoder_initialized(data->decoder, &data->audio_format,
|
||||
data->input_stream->seekable,
|
||||
(float)data->total_frames /
|
||||
(float)data->audio_format.sample_rate);
|
||||
|
||||
data->initialized = true;
|
||||
}
|
||||
|
||||
@@ -117,6 +112,8 @@ void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
|
||||
return;
|
||||
|
||||
struct replay_gain_info rgi;
|
||||
char *mixramp_start;
|
||||
char *mixramp_end;
|
||||
|
||||
switch (block->type) {
|
||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||
@@ -126,6 +123,10 @@ void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
|
||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||
if (flac_parse_replay_gain(&rgi, block))
|
||||
decoder_replay_gain(data->decoder, &rgi);
|
||||
if (flac_parse_mixramp(&mixramp_start, &mixramp_end, block)) {
|
||||
g_debug("setting mixramp_tags");
|
||||
decoder_mixramp(data->decoder, mixramp_start, mixramp_end);
|
||||
}
|
||||
|
||||
if (data->tag != NULL)
|
||||
flac_vorbis_comments_to_tag(data->tag, NULL,
|
||||
|
@@ -247,9 +247,14 @@ flac_decoder_initialize(struct flac_data *data, FLAC__StreamDecoder *sd,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data->initialized)
|
||||
if (data->initialized) {
|
||||
/* done */
|
||||
decoder_initialized(data->decoder, &data->audio_format,
|
||||
data->input_stream->seekable,
|
||||
(float)data->total_frames /
|
||||
(float)data->audio_format.sample_rate);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (data->input_stream->seekable)
|
||||
/* allow the workaround below only for nonseekable
|
||||
|
@@ -80,6 +80,49 @@ flac_parse_replay_gain(struct replay_gain_info *rgi,
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool
|
||||
flac_find_string_comment(const FLAC__StreamMetadata *block,
|
||||
const char *cmnt, char **str)
|
||||
{
|
||||
int offset;
|
||||
size_t pos;
|
||||
int len;
|
||||
unsigned char tmp, *p;
|
||||
|
||||
*str = NULL;
|
||||
offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0,
|
||||
cmnt);
|
||||
if (offset < 0)
|
||||
return false;
|
||||
|
||||
pos = strlen(cmnt) + 1; /* 1 is for '=' */
|
||||
len = block->data.vorbis_comment.comments[offset].length - pos;
|
||||
if (len <= 0)
|
||||
return false;
|
||||
|
||||
p = &block->data.vorbis_comment.comments[offset].entry[pos];
|
||||
tmp = p[len];
|
||||
p[len] = '\0';
|
||||
*str = strdup((char *)p);
|
||||
p[len] = tmp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
flac_parse_mixramp(char **mixramp_start, char **mixramp_end,
|
||||
const FLAC__StreamMetadata *block)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (flac_find_string_comment(block, "mixramp_start", mixramp_start))
|
||||
found = true;
|
||||
if (flac_find_string_comment(block, "mixramp_end", mixramp_end))
|
||||
found = true;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified name matches the entry's name, and if yes,
|
||||
* returns the comment value (not null-temrinated).
|
||||
|
@@ -37,6 +37,10 @@ bool
|
||||
flac_parse_replay_gain(struct replay_gain_info *rgi,
|
||||
const FLAC__StreamMetadata *block);
|
||||
|
||||
bool
|
||||
flac_parse_mixramp(char **mixramp_start, char **mixramp_end,
|
||||
const FLAC__StreamMetadata *block);
|
||||
|
||||
void
|
||||
flac_vorbis_comments_to_tag(struct tag *tag, const char *char_tnum,
|
||||
const FLAC__StreamMetadata_VorbisComment *comment);
|
||||
|
@@ -347,6 +347,47 @@ parse_id3_replay_gain_info(struct replay_gain_info *replay_gain_info,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ID3TAG
|
||||
static bool
|
||||
parse_id3_mixramp(char **mixramp_start, char **mixramp_end,
|
||||
struct id3_tag *tag)
|
||||
{
|
||||
int i;
|
||||
char *key;
|
||||
char *value;
|
||||
struct id3_frame *frame;
|
||||
bool found = false;
|
||||
|
||||
*mixramp_start = NULL;
|
||||
*mixramp_end = NULL;
|
||||
|
||||
for (i = 0; (frame = id3_tag_findframe(tag, "TXXX", i)); i++) {
|
||||
if (frame->nfields < 3)
|
||||
continue;
|
||||
|
||||
key = (char *)
|
||||
id3_ucs4_latin1duplicate(id3_field_getstring
|
||||
(&frame->fields[1]));
|
||||
value = (char *)
|
||||
id3_ucs4_latin1duplicate(id3_field_getstring
|
||||
(&frame->fields[2]));
|
||||
|
||||
if (g_ascii_strcasecmp(key, "mixramp_start") == 0) {
|
||||
*mixramp_start = strdup(value);
|
||||
found = true;
|
||||
} else if (g_ascii_strcasecmp(key, "mixramp_end") == 0) {
|
||||
*mixramp_end = strdup(value);
|
||||
found = true;
|
||||
}
|
||||
|
||||
free(key);
|
||||
free(value);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
|
||||
struct tag **mpd_tag)
|
||||
{
|
||||
@@ -403,10 +444,16 @@ static void mp3_parse_id3(struct mp3_data *data, size_t tagsize,
|
||||
|
||||
if (data->decoder != NULL) {
|
||||
struct replay_gain_info rgi;
|
||||
char *mixramp_start;
|
||||
char *mixramp_end;
|
||||
if (parse_id3_replay_gain_info(&rgi, id3_tag)) {
|
||||
decoder_replay_gain(data->decoder, &rgi);
|
||||
data->found_replay_gain = true;
|
||||
}
|
||||
if (parse_id3_mixramp(&mixramp_start, &mixramp_end, id3_tag)) {
|
||||
g_debug("setting mixramp_tags");
|
||||
decoder_mixramp(data->decoder, mixramp_start, mixramp_end);
|
||||
}
|
||||
}
|
||||
|
||||
id3_tag_delete(id3_tag);
|
||||
|
Reference in New Issue
Block a user