diff options
-rw-r--r-- | src/chunk.h | 6 | ||||
-rw-r--r-- | src/crossfade.c | 43 | ||||
-rw-r--r-- | src/crossfade.h | 14 | ||||
-rw-r--r-- | src/output_control.c | 2 | ||||
-rw-r--r-- | src/output_init.c | 2 | ||||
-rw-r--r-- | src/output_internal.h | 6 | ||||
-rw-r--r-- | src/output_thread.c | 30 | ||||
-rw-r--r-- | src/player_thread.c | 12 |
8 files changed, 50 insertions, 65 deletions
diff --git a/src/chunk.h b/src/chunk.h index a5fdda429..02e7b3650 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -50,6 +50,12 @@ struct music_chunk { */ struct music_chunk *other; + /** + * The current mix ratio for cross-fading: 1.0 means play 100% + * of this chunk, 0.0 means play 100% of the "other" chunk. + */ + float mix_ratio; + /** number of bytes stored in this chunk */ uint16_t length; diff --git a/src/crossfade.c b/src/crossfade.c index 7989b1dc9..b494b64b6 100644 --- a/src/crossfade.c +++ b/src/crossfade.c @@ -131,46 +131,3 @@ unsigned cross_fade_calc(float duration, float total_time, return chunks; } - -void cross_fade_apply(struct music_chunk *a, const struct music_chunk *b, - const struct audio_format *format, - float mix_ratio) -{ - size_t size; - - assert(a != NULL); - assert(b != NULL); - assert(a->length == 0 || b->length == 0 || - audio_format_equals(&a->audio_format, &b->audio_format)); - - if (a->tag == NULL && b->tag != NULL) - /* merge the tag into the destination chunk */ - a->tag = tag_dup(b->tag); - - size = b->length > a->length - ? a->length - : b->length; - - pcm_mix(a->data, - b->data, - size, - format, - mix_ratio); - - if (b->length > a->length) { - /* the second buffer is larger than the first one: - there is unmixed rest at the end. Copy it over. - The output buffer API guarantees that there is - enough room in a->data. */ - -#ifndef NDEBUG - if (a->length == 0) - a->audio_format = b->audio_format; -#endif - - memcpy(a->data + a->length, - b->data + a->length, - b->length - a->length); - a->length = b->length; - } -} diff --git a/src/crossfade.h b/src/crossfade.h index d313b4738..8e45ca72d 100644 --- a/src/crossfade.h +++ b/src/crossfade.h @@ -45,18 +45,4 @@ unsigned cross_fade_calc(float duration, float total_time, const struct audio_format *old_format, unsigned max_chunks); -/** - * Applies cross fading to two chunks, i.e. mixes these chunks. - * Internally, this calls pcm_mix(). - * - * @param a the chunk in the current song (and the destination chunk) - * @param b the according chunk in the new song - * @param format the audio format of both chunks (must be the same) - * @param current_chunk the relative index of the current chunk - * @param num_chunks the number of chunks used for cross fading - */ -void cross_fade_apply(struct music_chunk *a, const struct music_chunk *b, - const struct audio_format *format, - float mix_ratio); - #endif diff --git a/src/output_control.c b/src/output_control.c index 17edc3d72..bcedae247 100644 --- a/src/output_control.c +++ b/src/output_control.c @@ -301,4 +301,6 @@ void audio_output_finish(struct audio_output *ao) g_mutex_free(ao->mutex); filter_free(ao->filter); + + pcm_buffer_deinit(&ao->cross_fade_buffer); } diff --git a/src/output_init.c b/src/output_init.c index 6ee340edc..a091e749a 100644 --- a/src/output_init.c +++ b/src/output_init.c @@ -191,6 +191,8 @@ audio_output_init(struct audio_output *ao, const struct config_param *param, ao->pause = false; ao->fail_timer = NULL; + pcm_buffer_init(&ao->cross_fade_buffer); + /* set up the filter chain */ ao->filter = filter_chain_new(); diff --git a/src/output_internal.h b/src/output_internal.h index 06df9531b..06e209374 100644 --- a/src/output_internal.h +++ b/src/output_internal.h @@ -21,6 +21,7 @@ #define MPD_OUTPUT_INTERNAL_H #include "audio_format.h" +#include "pcm_buffer.h" #include <glib.h> @@ -135,6 +136,11 @@ struct audio_output { struct audio_format out_audio_format; /** + * The buffer used to allocate the cross-fading result. + */ + struct pcm_buffer cross_fade_buffer; + + /** * The filter object of this audio output. This is an * instance of chain_filter_plugin. */ diff --git a/src/output_thread.c b/src/output_thread.c index c3e064c3f..7f1e4935e 100644 --- a/src/output_thread.c +++ b/src/output_thread.c @@ -24,6 +24,7 @@ #include "chunk.h" #include "pipe.h" #include "player_control.h" +#include "pcm_mix.h" #include "filter_plugin.h" #include "filter/convert_filter_plugin.h" #include "filter/replay_gain_filter_plugin.h" @@ -299,6 +300,35 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk, ao->replay_gain_serial = chunk->replay_gain_serial; } + /* cross-fade */ + + if (chunk->other != NULL) { + size_t other_length; + const char *other_data = ao_chunk_data(ao, chunk->other, + &other_length); + if (other_length == 0) { + *length_r = 0; + return data; + } + + /* if the "other" chunk is longer, then that trailer + is used as-is, without mixing; it is part of the + "next" song being faded in, and if there's a rest, + it means cross-fading ends here */ + + if (length > other_length) + length = other_length; + + char *dest = pcm_buffer_get(&ao->cross_fade_buffer, + other_length); + memcpy(dest, other_data, other_length); + pcm_mix(dest, data, length, &ao->in_audio_format, + 1.0 - chunk->mix_ratio); + + data = dest; + length = other_length; + } + /* apply filter chain */ data = filter_filter(ao->filter, data, length, &length, &error); diff --git a/src/player_thread.c b/src/player_thread.c index 8fa089c1f..1a420a7fa 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -651,10 +651,9 @@ play_next_chunk(struct player *player) } if (other_chunk != NULL) { - float mix_ratio; - chunk = music_pipe_shift(player->pipe); assert(chunk != NULL); + assert(chunk->other == NULL); /* don't send the tags of the new song (which is being faded in) yet; postpone it until @@ -665,16 +664,13 @@ play_next_chunk(struct player *player) other_chunk->tag = NULL; if (isnan(pc.mixramp_delay_seconds)) { - mix_ratio = ((float)cross_fade_position) + chunk->mix_ratio = ((float)cross_fade_position) / player->cross_fade_chunks; } else { - mix_ratio = nan(""); + chunk->mix_ratio = nan(""); } - cross_fade_apply(chunk, other_chunk, - &dc->out_audio_format, - mix_ratio); - music_buffer_return(player_buffer, other_chunk); + chunk->other = other_chunk; } else { /* there are not enough decoded chunks yet */ |