aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chunk.h6
-rw-r--r--src/crossfade.c43
-rw-r--r--src/crossfade.h14
-rw-r--r--src/output_control.c2
-rw-r--r--src/output_init.c2
-rw-r--r--src/output_internal.h6
-rw-r--r--src/output_thread.c30
-rw-r--r--src/player_thread.c12
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 */