diff --git a/Makefile.am b/Makefile.am
index 0cbfffd49..ddb27a689 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,7 @@ mpd_headers = \
 	src/filter/autoconvert_filter_plugin.h \
 	src/filter/chain_filter_plugin.h \
 	src/filter/convert_filter_plugin.h \
+	src/filter/replay_gain_filter_plugin.h \
 	src/filter/volume_filter_plugin.h \
 	src/command.h \
 	src/idle.h \
@@ -175,7 +176,6 @@ mpd_headers = \
 	src/queue_save.h \
 	src/replay_gain_config.h \
 	src/replay_gain_info.h \
-	src/replay_gain_state.h \
 	src/sig_handlers.h \
 	src/song.h \
 	src/song_print.h \
@@ -306,7 +306,6 @@ src_mpd_SOURCES = \
 	src/queue_save.c \
 	src/replay_gain_config.c \
 	src/replay_gain_info.c \
-	src/replay_gain_state.c \
 	src/sig_handlers.c \
 	src/song.c \
 	src/song_update.c \
@@ -744,6 +743,7 @@ FILTER_SRC = \
 	src/filter/convert_filter_plugin.c \
 	src/filter/route_filter_plugin.c \
 	src/filter/normalize_filter_plugin.c \
+	src/filter/replay_gain_filter_plugin.c \
 	src/filter/volume_filter_plugin.c
 
 
@@ -900,6 +900,8 @@ test_run_filter_SOURCES = test/run_filter.c \
 	src/audio_check.c \
 	src/audio_format.c \
 	src/audio_parser.c \
+	src/replay_gain_config.c \
+	src/replay_gain_info.c \
 	src/AudioCompress/compress.c \
 	$(FILTER_SRC)
 
@@ -985,10 +987,13 @@ test_run_output_SOURCES = test/run_output.c \
 	src/filter_config.c \
 	src/filter/autoconvert_filter_plugin.c \
 	src/filter/convert_filter_plugin.c \
+	src/filter/replay_gain_filter_plugin.c \
 	src/filter/normalize_filter_plugin.c \
 	src/filter/volume_filter_plugin.c \
 	src/pcm_volume.c \
 	src/AudioCompress/compress.c \
+	src/replay_gain_info.c \
+	src/replay_gain_config.c \
 	src/fd_util.c \
 	$(OUTPUT_SRC)
 
diff --git a/NEWS b/NEWS
index 7cc25808e..4000a1933 100644
--- a/NEWS
+++ b/NEWS
@@ -70,6 +70,8 @@ ver 0.16 (20??/??/??)
   - rescan after metadata_to_use change
 * normalize: upgraded to AudioCompress 2.0
   - automatically convert to 16 bit samples
+* replay gain:
+  - reimplemented as a filter plugin
 * log unused/unknown block parameters
 * removed the deprecated "error_file" option
 * save state when stopped
diff --git a/src/chunk.c b/src/chunk.c
index 8fff3c7dd..5418b6cda 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -29,6 +29,7 @@ music_chunk_init(struct music_chunk *chunk)
 {
 	chunk->length = 0;
 	chunk->tag = NULL;
+	chunk->replay_gain_serial = 0;
 }
 
 void
diff --git a/src/chunk.h b/src/chunk.h
index 58bab3dc2..23f6321fb 100644
--- a/src/chunk.h
+++ b/src/chunk.h
@@ -20,6 +20,8 @@
 #ifndef MPD_CHUNK_H
 #define MPD_CHUNK_H
 
+#include "replay_gain_info.h"
+
 #ifndef NDEBUG
 #include "audio_format.h"
 #endif
@@ -59,6 +61,19 @@ struct music_chunk {
 	 */
 	struct tag *tag;
 
+	/**
+	 * Replay gain information associated with this chunk.
+	 * Only valid if the serial is not 0.
+	 */
+	struct replay_gain_info replay_gain_info;
+
+	/**
+	 * A serial number for checking if replay gain info has
+	 * changed since the last chunk.  The magic value 0 indicates
+	 * that there is no replay gain info available.
+	 */
+	unsigned replay_gain_serial;
+
 	/** the data (probably PCM) */
 	char data[CHUNK_SIZE];
 
diff --git a/src/decoder_api.c b/src/decoder_api.c
index 7dfe84062..285e21a6b 100644
--- a/src/decoder_api.c
+++ b/src/decoder_api.c
@@ -27,8 +27,6 @@
 #include "buffer.h"
 #include "pipe.h"
 #include "chunk.h"
-#include "replay_gain_state.h"
-#include "replay_gain_config.h"
 
 #include <glib.h>
 
@@ -343,13 +341,6 @@ decoder_data(struct decoder *decoder,
 
 		memcpy(dest, data, nbytes);
 
-		/* apply replay gain or normalization */
-
-		replay_gain_state_set_mode(decoder->replay_gain,
-					   replay_gain_mode);
-		replay_gain_state_apply(decoder->replay_gain,
-					dest, nbytes, &dc->out_audio_format);
-
 		/* expand the music pipe chunk */
 
 		full = music_chunk_expand(chunk, &dc->out_audio_format, nbytes);
@@ -418,5 +409,21 @@ decoder_replay_gain(struct decoder *decoder,
 {
 	assert(decoder != NULL);
 
-	replay_gain_state_set_info(decoder->replay_gain, replay_gain_info);
+	if (replay_gain_info != NULL) {
+		static unsigned serial;
+		if (++serial == 0)
+			serial = 1;
+
+		decoder->replay_gain_info = *replay_gain_info;
+		decoder->replay_gain_serial = serial;
+
+		if (decoder->chunk != NULL) {
+			/* flush the current chunk because the new
+			   replay gain values affect the following
+			   samples */
+			decoder_flush_chunk(decoder);
+			player_lock_signal();
+		}
+	} else
+		decoder->replay_gain_serial = 0;
 }
diff --git a/src/decoder_internal.c b/src/decoder_internal.c
index 7829b4d76..990d728e9 100644
--- a/src/decoder_internal.c
+++ b/src/decoder_internal.c
@@ -86,8 +86,15 @@ decoder_get_chunk(struct decoder *decoder, struct input_stream *is)
 
 	do {
 		decoder->chunk = music_buffer_allocate(dc->buffer);
-		if (decoder->chunk != NULL)
+		if (decoder->chunk != NULL) {
+			decoder->chunk->replay_gain_serial =
+				decoder->replay_gain_serial;
+			if (decoder->replay_gain_serial != 0)
+				decoder->chunk->replay_gain_info =
+					decoder->replay_gain_info;
+
 			return decoder->chunk;
+		}
 
 		decoder_lock(dc);
 		cmd = need_chunks(dc, is, true);
diff --git a/src/decoder_internal.h b/src/decoder_internal.h
index 159b40b92..9e7e2037a 100644
--- a/src/decoder_internal.h
+++ b/src/decoder_internal.h
@@ -22,6 +22,7 @@
 
 #include "decoder_command.h"
 #include "pcm_convert.h"
+#include "replay_gain_info.h"
 
 struct input_stream;
 
@@ -53,7 +54,13 @@ struct decoder {
 	/** the chunk currently being written to */
 	struct music_chunk *chunk;
 
-	struct replay_gain_state *replay_gain;
+	struct replay_gain_info replay_gain_info;
+
+	/**
+	 * A positive serial number for checking if replay gain info
+	 * has changed since the last check.
+	 */
+	unsigned replay_gain_serial;
 };
 
 /**
diff --git a/src/decoder_thread.c b/src/decoder_thread.c
index 42a537ffe..99fa2c7e2 100644
--- a/src/decoder_thread.c
+++ b/src/decoder_thread.c
@@ -31,8 +31,6 @@
 #include "mapper.h"
 #include "path.h"
 #include "uri.h"
-#include "replay_gain_state.h"
-#include "replay_gain_config.h"
 
 #include <glib.h>
 
@@ -351,8 +349,6 @@ decoder_run_song(struct decoder_control *dc,
 {
 	struct decoder decoder = {
 		.dc = dc,
-		.replay_gain = replay_gain_state_new(replay_gain_preamp,
-						     replay_gain_missing_preamp),
 	};
 	int ret;
 
@@ -380,8 +376,6 @@ decoder_run_song(struct decoder_control *dc,
 	pcm_convert_deinit(&decoder.conv_state);
 
 	/* flush the last chunk */
-	if (decoder.replay_gain != NULL)
-		replay_gain_state_free(decoder.replay_gain);
 
 	if (decoder.chunk != NULL)
 		decoder_flush_chunk(&decoder);
diff --git a/src/filter/replay_gain_filter_plugin.c b/src/filter/replay_gain_filter_plugin.c
new file mode 100644
index 000000000..396f185cc
--- /dev/null
+++ b/src/filter/replay_gain_filter_plugin.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "filter/replay_gain_filter_plugin.h"
+#include "filter_plugin.h"
+#include "filter_internal.h"
+#include "filter_registry.h"
+#include "audio_format.h"
+#include "pcm_buffer.h"
+#include "pcm_volume.h"
+#include "replay_gain_info.h"
+#include "replay_gain_config.h"
+
+#include <string.h>
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "replay_gain"
+
+struct replay_gain_filter {
+	struct filter filter;
+
+	enum replay_gain_mode mode;
+
+	struct replay_gain_info info;
+
+	/**
+	 * The current volume, between 0 and #PCM_VOLUME_1 (both
+	 * including).
+	 */
+	unsigned volume;
+
+	struct audio_format audio_format;
+
+	struct pcm_buffer buffer;
+};
+
+static inline GQuark
+replay_gain_quark(void)
+{
+	return g_quark_from_static_string("replay_gain");
+}
+
+/**
+ * Recalculates the new volume after a property was changed.
+ */
+static void
+replay_gain_filter_update(struct replay_gain_filter *filter)
+{
+	if (filter->mode != REPLAY_GAIN_OFF) {
+		const struct replay_gain_tuple *tuple =
+			&filter->info.tuples[filter->mode];
+		float scale = replay_gain_tuple_defined(tuple)
+			? replay_gain_tuple_scale(tuple, replay_gain_preamp)
+			: replay_gain_missing_preamp;
+		g_debug("scale=%f\n", (double)scale);
+
+		filter->volume = pcm_float_to_volume(scale);
+	} else
+		filter->volume = PCM_VOLUME_1;
+}
+
+static struct filter *
+replay_gain_filter_init(G_GNUC_UNUSED const struct config_param *param,
+			G_GNUC_UNUSED GError **error_r)
+{
+	struct replay_gain_filter *filter = g_new(struct replay_gain_filter, 1);
+
+	filter_init(&filter->filter, &replay_gain_filter_plugin);
+
+	filter->mode = replay_gain_mode;
+	replay_gain_info_init(&filter->info);
+	filter->volume = PCM_VOLUME_1;
+
+	return &filter->filter;
+}
+
+static void
+replay_gain_filter_finish(struct filter *filter)
+{
+	g_free(filter);
+}
+
+static const struct audio_format *
+replay_gain_filter_open(struct filter *_filter,
+			struct audio_format *audio_format,
+			G_GNUC_UNUSED GError **error_r)
+{
+	struct replay_gain_filter *filter =
+		(struct replay_gain_filter *)_filter;
+
+	audio_format->reverse_endian = false;
+
+	filter->audio_format = *audio_format;
+	pcm_buffer_init(&filter->buffer);
+
+	return &filter->audio_format;
+}
+
+static void
+replay_gain_filter_close(struct filter *_filter)
+{
+	struct replay_gain_filter *filter =
+		(struct replay_gain_filter *)_filter;
+
+	pcm_buffer_deinit(&filter->buffer);
+}
+
+static const void *
+replay_gain_filter_filter(struct filter *_filter,
+			  const void *src, size_t src_size,
+			  size_t *dest_size_r, GError **error_r)
+{
+	struct replay_gain_filter *filter =
+		(struct replay_gain_filter *)_filter;
+	bool success;
+	void *dest;
+
+	/* check if the mode has been changed since the last call */
+	if (filter->mode != replay_gain_mode) {
+		filter->mode = replay_gain_mode;
+		replay_gain_filter_update(filter);
+	}
+
+	*dest_size_r = src_size;
+
+	if (filter->volume >= PCM_VOLUME_1)
+		/* optimized special case: 100% volume = no-op */
+		return src;
+
+	dest = pcm_buffer_get(&filter->buffer, src_size);
+	*dest_size_r = src_size;
+
+	if (filter->volume <= 0) {
+		/* optimized special case: 0% volume = memset(0) */
+		/* XXX is this valid for all sample formats? What
+		   about floating point? */
+		memset(dest, 0, src_size);
+		return dest;
+	}
+
+	memcpy(dest, src, src_size);
+
+	success = pcm_volume(dest, src_size, &filter->audio_format,
+			     filter->volume);
+	if (!success) {
+		g_set_error(error_r, replay_gain_quark(), 0,
+			    "pcm_volume() has failed");
+		return NULL;
+	}
+
+	return dest;
+}
+
+const struct filter_plugin replay_gain_filter_plugin = {
+	.name = "replay_gain",
+	.init = replay_gain_filter_init,
+	.finish = replay_gain_filter_finish,
+	.open = replay_gain_filter_open,
+	.close = replay_gain_filter_close,
+	.filter = replay_gain_filter_filter,
+};
+
+void
+replay_gain_filter_set_info(struct filter *_filter,
+			    const struct replay_gain_info *info)
+{
+	struct replay_gain_filter *filter =
+		(struct replay_gain_filter *)_filter;
+
+	if (info != NULL)
+		filter->info = *info;
+	else
+		replay_gain_info_init(&filter->info);
+
+	replay_gain_filter_update(filter);
+}
diff --git a/src/replay_gain_state.h b/src/filter/replay_gain_filter_plugin.h
similarity index 57%
rename from src/replay_gain_state.h
rename to src/filter/replay_gain_filter_plugin.h
index bf687aa05..4ab9f42a6 100644
--- a/src/replay_gain_state.h
+++ b/src/filter/replay_gain_filter_plugin.h
@@ -17,34 +17,21 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#ifndef MPD_REPLAY_GAIN_STATE_H
-#define MPD_REPLAY_GAIN_STATE_H
+#ifndef REPLAY_GAIN_FILTER_PLUGIN_H
+#define REPLAY_GAIN_FILTER_PLUGIN_H
 
-#include "check.h"
 #include "replay_gain_info.h"
 
-#include <stddef.h>
-
-struct replay_gain_state;
-struct audio_format;
-
-struct replay_gain_state *
-replay_gain_state_new(float preamp, float missing_preamp);
+struct filter;
 
+/**
+ * Sets a new #replay_gain_info at the beginning of a new song.
+ *
+ * @param info the new #replay_gain_info value, or NULL if no replay
+ * gain data is available for the current song
+ */
 void
-replay_gain_state_free(struct replay_gain_state *state);
-
-void
-replay_gain_state_set_mode(struct replay_gain_state *state,
-			   enum replay_gain_mode mode);
-
-void
-replay_gain_state_set_info(struct replay_gain_state *state,
-			   const struct replay_gain_info *info);
-
-void
-replay_gain_state_apply(const struct replay_gain_state *state,
-			void *buffer, size_t size,
-			const struct audio_format *format);
+replay_gain_filter_set_info(struct filter *filter,
+			    const struct replay_gain_info *info);
 
 #endif
diff --git a/src/filter_registry.c b/src/filter_registry.c
index 577e69bad..150043cc5 100644
--- a/src/filter_registry.c
+++ b/src/filter_registry.c
@@ -29,6 +29,7 @@ const struct filter_plugin *const filter_plugins[] = {
 	&route_filter_plugin,
 	&normalize_filter_plugin,
 	&volume_filter_plugin,
+	&replay_gain_filter_plugin,
 	NULL,
 };
 
diff --git a/src/filter_registry.h b/src/filter_registry.h
index 938afefb3..551a7afa1 100644
--- a/src/filter_registry.h
+++ b/src/filter_registry.h
@@ -32,6 +32,7 @@ extern const struct filter_plugin convert_filter_plugin;
 extern const struct filter_plugin route_filter_plugin;
 extern const struct filter_plugin normalize_filter_plugin;
 extern const struct filter_plugin volume_filter_plugin;
+extern const struct filter_plugin replay_gain_filter_plugin;
 
 const struct filter_plugin *
 filter_plugin_by_name(const char *name);
diff --git a/src/output_init.c b/src/output_init.c
index 2ce6b30f9..387915ddc 100644
--- a/src/output_init.c
+++ b/src/output_init.c
@@ -194,6 +194,17 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
 	ao->filter = filter_chain_new();
 	assert(ao->filter != NULL);
 
+	/* create the replay_gain filter */
+
+	ao->replay_gain_filter = filter_new(&replay_gain_filter_plugin,
+					    param, NULL);
+	assert(ao->replay_gain_filter != NULL);
+
+	filter_chain_append(ao->filter, ao->replay_gain_filter);
+	ao->replay_gain_serial = 0;
+
+	/* create the normalization filter (if configured) */
+
 	if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) {
 		struct filter *normalize_filter =
 			filter_new(&normalize_filter_plugin, NULL, NULL);
diff --git a/src/output_internal.h b/src/output_internal.h
index 804fd8cdc..2a438c62f 100644
--- a/src/output_internal.h
+++ b/src/output_internal.h
@@ -134,6 +134,18 @@ struct audio_output {
 	 */
 	struct filter *filter;
 
+	/**
+	 * The replay_gain_filter_plugin instance of this audio
+	 * output.
+	 */
+	struct filter *replay_gain_filter;
+
+	/**
+	 * The serial number of the last replay gain info.  0 means no
+	 * replay gain info was available.
+	 */
+	unsigned replay_gain_serial;
+
 	/**
 	 * The convert_filter_plugin instance of this audio output.
 	 * It is the last item in the filter chain, and is responsible
diff --git a/src/output_thread.c b/src/output_thread.c
index eb44d4c87..0e34c64b7 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -26,6 +26,7 @@
 #include "player_control.h"
 #include "filter_plugin.h"
 #include "filter/convert_filter_plugin.h"
+#include "filter/replay_gain_filter_plugin.h"
 
 #include <glib.h>
 
@@ -261,6 +262,16 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
 		g_mutex_lock(ao->mutex);
 	}
 
+	/* update replay gain */
+
+	if (chunk->replay_gain_serial != ao->replay_gain_serial) {
+		replay_gain_filter_set_info(ao->replay_gain_filter,
+					    chunk->replay_gain_serial != 0
+					    ? &chunk->replay_gain_info
+					    : NULL);
+		ao->replay_gain_serial = chunk->replay_gain_serial;
+	}
+
 	if (size == 0)
 		return true;
 
diff --git a/src/replay_gain_state.c b/src/replay_gain_state.c
deleted file mode 100644
index cfb2ce120..000000000
--- a/src/replay_gain_state.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "replay_gain_state.h"
-#include "pcm_volume.h"
-
-#include <glib.h>
-
-#include <assert.h>
-
-struct replay_gain_state {
-	float preamp, missing_preamp;
-
-	enum replay_gain_mode mode;
-
-	struct replay_gain_info info;
-
-	float scale;
-};
-
-struct replay_gain_state *
-replay_gain_state_new(float preamp, float missing_preamp)
-{
-	struct replay_gain_state *state = g_new(struct replay_gain_state, 1);
-
-	state->preamp = preamp;
-	state->scale = state->missing_preamp = missing_preamp;
-	state->mode = REPLAY_GAIN_OFF;
-	replay_gain_info_init(&state->info);
-
-	return state;
-}
-
-void
-replay_gain_state_free(struct replay_gain_state *state)
-{
-	assert(state != NULL);
-
-	g_free(state);
-}
-
-static void
-replay_gain_state_calc_scale(struct replay_gain_state *state)
-{
-	assert(state != NULL);
-
-	if (state->mode == REPLAY_GAIN_OFF)
-		return;
-
-	const struct replay_gain_tuple *tuple =
-		&state->info.tuples[state->mode];
-	if (replay_gain_tuple_defined(tuple)) {
-		g_debug("computing ReplayGain scale with gain %f, peak %f",
-			tuple->gain, tuple->peak);
-
-		state->scale = replay_gain_tuple_scale(tuple, state->preamp);
-	} else
-		state->scale = state->missing_preamp;
-}
-
-void
-replay_gain_state_set_mode(struct replay_gain_state *state,
-			   enum replay_gain_mode mode)
-{
-	assert(state != NULL);
-
-	if (mode == state->mode)
-		return;
-
-	state->mode = mode;
-
-	replay_gain_state_calc_scale(state);
-}
-
-void
-replay_gain_state_set_info(struct replay_gain_state *state,
-			   const struct replay_gain_info *info)
-{
-	assert(state != NULL);
-
-	if (info != NULL)
-		state->info = *info;
-	else
-		replay_gain_info_init(&state->info);
-
-	replay_gain_state_calc_scale(state);
-}
-
-void
-replay_gain_state_apply(const struct replay_gain_state *state,
-			void *buffer, size_t size,
-			const struct audio_format *format)
-{
-	assert(state != NULL);
-
-	if (state->mode == REPLAY_GAIN_OFF)
-		return;
-
-	pcm_volume(buffer, size, format, pcm_float_to_volume(state->scale));
-}
diff --git a/test/run_filter.c b/test/run_filter.c
index 9b4d79510..dd22312d5 100644
--- a/test/run_filter.c
+++ b/test/run_filter.c
@@ -23,6 +23,7 @@
 #include "audio_format.h"
 #include "filter_plugin.h"
 #include "pcm_volume.h"
+#include "idle.h"
 
 #include <glib.h>
 
@@ -31,6 +32,11 @@
 #include <errno.h>
 #include <unistd.h>
 
+void
+idle_add(G_GNUC_UNUSED unsigned flags)
+{
+}
+
 static void
 my_log_func(const gchar *log_domain, G_GNUC_UNUSED GLogLevelFlags log_level,
 	    const gchar *message, G_GNUC_UNUSED gpointer user_data)
diff --git a/test/run_output.c b/test/run_output.c
index 774ce99f9..6e0fffbd0 100644
--- a/test/run_output.c
+++ b/test/run_output.c
@@ -26,6 +26,7 @@
 #include "filter_registry.h"
 #include "pcm_convert.h"
 #include "event_pipe.h"
+#include "idle.h"
 
 #include <glib.h>
 
@@ -33,6 +34,11 @@
 #include <string.h>
 #include <unistd.h>
 
+void
+idle_add(G_GNUC_UNUSED unsigned flags)
+{
+}
+
 void
 event_pipe_emit(G_GNUC_UNUSED enum pipe_event event)
 {