diff options
author | Tim Phipps <mpd@phipps-hutton.freeserve.co.uk> | 2010-03-21 18:21:47 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2010-03-21 18:21:47 +0100 |
commit | e7a515c8b11c643332406d60a13ab1fe06d2b226 (patch) | |
tree | aa7179b453b6fe7b163d1b4b807157359cb436cf /src/decoder | |
parent | e9b75d462c4d0ffee3b3b26582800ec4f657a333 (diff) | |
download | mpd-e7a515c8b11c643332406d60a13ab1fe06d2b226.tar.gz mpd-e7a515c8b11c643332406d60a13ab1fe06d2b226.tar.xz mpd-e7a515c8b11c643332406d60a13ab1fe06d2b226.zip |
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.
Diffstat (limited to '')
-rw-r--r-- | src/decoder/_flac_common.c | 11 | ||||
-rw-r--r-- | src/decoder/flac_decoder_plugin.c | 7 | ||||
-rw-r--r-- | src/decoder/flac_metadata.c | 43 | ||||
-rw-r--r-- | src/decoder/flac_metadata.h | 4 | ||||
-rw-r--r-- | src/decoder/mad_decoder_plugin.c | 47 | ||||
-rw-r--r-- | src/decoder_api.c | 12 | ||||
-rw-r--r-- | src/decoder_api.h | 11 | ||||
-rw-r--r-- | src/decoder_control.c | 50 | ||||
-rw-r--r-- | src/decoder_control.h | 13 | ||||
-rw-r--r-- | src/decoder_thread.c | 11 |
10 files changed, 203 insertions, 6 deletions
diff --git a/src/decoder/_flac_common.c b/src/decoder/_flac_common.c index b642121ba..6f6d33f05 100644 --- a/src/decoder/_flac_common.c +++ b/src/decoder/_flac_common.c @@ -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, diff --git a/src/decoder/flac_decoder_plugin.c b/src/decoder/flac_decoder_plugin.c index 022ee7045..e89e2ea11 100644 --- a/src/decoder/flac_decoder_plugin.c +++ b/src/decoder/flac_decoder_plugin.c @@ -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 diff --git a/src/decoder/flac_metadata.c b/src/decoder/flac_metadata.c index 926cd3af7..68d15f6d4 100644 --- a/src/decoder/flac_metadata.c +++ b/src/decoder/flac_metadata.c @@ -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). diff --git a/src/decoder/flac_metadata.h b/src/decoder/flac_metadata.h index 3cc333617..06e691d1d 100644 --- a/src/decoder/flac_metadata.h +++ b/src/decoder/flac_metadata.h @@ -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); diff --git a/src/decoder/mad_decoder_plugin.c b/src/decoder/mad_decoder_plugin.c index 379cb9b8a..6f6ee8fa4 100644 --- a/src/decoder/mad_decoder_plugin.c +++ b/src/decoder/mad_decoder_plugin.c @@ -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); diff --git a/src/decoder_api.c b/src/decoder_api.c index fc7ed3900..948ccb567 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -427,3 +427,15 @@ decoder_replay_gain(struct decoder *decoder, } else decoder->replay_gain_serial = 0; } + +void +decoder_mixramp(struct decoder *decoder, + char *mixramp_start, char *mixramp_end) +{ + assert(decoder != NULL); + struct decoder_control *dc = decoder->dc; + assert(dc != NULL); + + dc_mixramp_start(dc, mixramp_start); + dc_mixramp_end(dc, mixramp_end); +} diff --git a/src/decoder_api.h b/src/decoder_api.h index 8c7133251..e2b645f6d 100644 --- a/src/decoder_api.h +++ b/src/decoder_api.h @@ -157,4 +157,15 @@ void decoder_replay_gain(struct decoder *decoder, const struct replay_gain_info *replay_gain_info); +/** + * Store MixRamp tags. + * + * @param decoder the decoder object + * @param mixramp_start the mixramp_start tag; may be NULL to invalidate + * @param mixramp_end the mixramp_end tag; may be NULL to invalidate + */ +void +decoder_mixramp(struct decoder *decoder, + char *mixramp_start, char *mixramp_end); + #endif diff --git a/src/decoder_control.c b/src/decoder_control.c index eeb4670a0..7388d307f 100644 --- a/src/decoder_control.c +++ b/src/decoder_control.c @@ -22,6 +22,10 @@ #include "player_control.h" #include <assert.h> +#include <malloc.h> + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "decoder_control" void dc_init(struct decoder_control *dc) @@ -33,6 +37,10 @@ dc_init(struct decoder_control *dc) dc->state = DECODE_STATE_STOP; dc->command = DECODE_COMMAND_NONE; + + dc->mixramp_start = NULL; + dc->mixramp_end = NULL; + dc->mixramp_prev_end = NULL; } void @@ -40,6 +48,15 @@ dc_deinit(struct decoder_control *dc) { g_cond_free(dc->cond); g_mutex_free(dc->mutex); + if (dc->mixramp_start) + free(dc->mixramp_start); + if (dc->mixramp_end) + free(dc->mixramp_end); + if (dc->mixramp_prev_end) + free(dc->mixramp_prev_end); + dc->mixramp_start = NULL; + dc->mixramp_end = NULL; + dc->mixramp_prev_end = NULL; } static void @@ -147,3 +164,36 @@ dc_quit(struct decoder_control *dc) g_thread_join(dc->thread); dc->thread = NULL; } + +void +dc_mixramp_start(struct decoder_control *dc, char *mixramp_start) +{ + assert(dc != NULL); + + if (dc->mixramp_start) + free(dc->mixramp_start); + dc->mixramp_start = mixramp_start; + g_debug("mixramp_start = %s", mixramp_start ? mixramp_start : "NULL"); +} + +void +dc_mixramp_end(struct decoder_control *dc, char *mixramp_end) +{ + assert(dc != NULL); + + if (dc->mixramp_end) + free(dc->mixramp_end); + dc->mixramp_end = mixramp_end; + g_debug("mixramp_end = %s", mixramp_end ? mixramp_end : "NULL"); +} + +void +dc_mixramp_prev_end(struct decoder_control *dc, char *mixramp_prev_end) +{ + assert(dc != NULL); + + if (dc->mixramp_prev_end) + free(dc->mixramp_prev_end); + dc->mixramp_prev_end = mixramp_prev_end; + g_debug("mixramp_prev_end = %s", mixramp_prev_end ? mixramp_prev_end : "NULL"); +} diff --git a/src/decoder_control.h b/src/decoder_control.h index 9c6f6e88c..7794258c9 100644 --- a/src/decoder_control.h +++ b/src/decoder_control.h @@ -89,6 +89,10 @@ struct decoder_control { * owns this object, and is responsible for freeing it. */ struct music_pipe *pipe; + + char *mixramp_start; + char *mixramp_end; + char *mixramp_prev_end; }; void @@ -235,4 +239,13 @@ dc_seek(struct decoder_control *dc, double where); void dc_quit(struct decoder_control *dc); +void +dc_mixramp_start(struct decoder_control *dc, char *mixramp_start); + +void +dc_mixramp_end(struct decoder_control *dc, char *mixramp_end); + +void +dc_mixramp_prev_end(struct decoder_control *dc, char *mixramp_prev_end); + #endif diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 99fa2c7e2..3eab61295 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -23,6 +23,7 @@ #include "decoder_internal.h" #include "decoder_list.h" #include "decoder_plugin.h" +#include "decoder_api.h" #include "input_stream.h" #include "player_control.h" #include "pipe.h" @@ -36,6 +37,9 @@ #include <unistd.h> +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "decoder_thread" + static enum decoder_command decoder_lock_get_command(struct decoder_control *dc) { @@ -430,6 +434,13 @@ decoder_task(gpointer arg) switch (dc->command) { case DECODE_COMMAND_START: + g_debug("clearing mixramp tags"); + dc_mixramp_start(dc, NULL); + dc_mixramp_prev_end(dc, dc->mixramp_end); + dc->mixramp_end = NULL; /* Don't free, it's copied above. */ + + /* fall through */ + case DECODE_COMMAND_SEEK: decoder_run(dc); |