diff --git a/src/MusicPipe.cxx b/src/MusicPipe.cxx
index 9dd2a7a8f..35a79edc5 100644
--- a/src/MusicPipe.cxx
+++ b/src/MusicPipe.cxx
@@ -73,7 +73,7 @@ MusicPipe::Shift() noexcept
 }
 
 void
-MusicPipe::Clear(MusicBuffer &buffer) noexcept
+MusicPipe::Clear() noexcept
 {
 	MusicChunk *chunk;
 
diff --git a/src/MusicPipe.hxx b/src/MusicPipe.hxx
index ecb923431..b3e28a656 100644
--- a/src/MusicPipe.hxx
+++ b/src/MusicPipe.hxx
@@ -37,6 +37,11 @@ class MusicBuffer;
  * tail, and the other consumes them from the head.
  */
 class MusicPipe {
+	/**
+	 * The #MusicBuffer where all chunks must be returned.
+	 */
+	MusicBuffer &buffer;
+
 	/** the first chunk */
 	MusicChunk *head = nullptr;
 
@@ -57,7 +62,8 @@ public:
 	/**
 	 * Creates a new #MusicPipe object.  It is empty.
 	 */
-	MusicPipe() = default;
+	explicit MusicPipe(MusicBuffer &_buffer) noexcept
+		:buffer(_buffer) {}
 
 	MusicPipe(const MusicPipe &) = delete;
 
@@ -71,6 +77,10 @@ public:
 
 	MusicPipe &operator=(const MusicPipe &) = delete;
 
+	MusicBuffer &GetBuffer() noexcept {
+		return buffer;
+	}
+
 #ifndef NDEBUG
 	/**
 	 * Checks if the audio format if the chunk is equal to the specified
@@ -106,10 +116,8 @@ public:
 
 	/**
 	 * Clears the whole pipe and returns the chunks to the buffer.
-	 *
-	 * @param buffer the buffer object to return the chunks to
 	 */
-	void Clear(MusicBuffer &buffer) noexcept;
+	void Clear() noexcept;
 
 	/**
 	 * Pushes a chunk to the tail of the pipe.
diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx
index 0dbaf49af..87d2e3a8a 100644
--- a/src/decoder/Bridge.cxx
+++ b/src/decoder/Bridge.cxx
@@ -98,7 +98,7 @@ DecoderBridge::GetChunk() noexcept
 		return current_chunk;
 
 	do {
-		current_chunk = dc.buffer->Allocate();
+		current_chunk = dc.pipe->GetBuffer().Allocate();
 		if (current_chunk != nullptr) {
 			current_chunk->replay_gain_serial = replay_gain_serial;
 			if (replay_gain_serial != 0)
@@ -123,7 +123,7 @@ DecoderBridge::FlushChunk()
 
 	auto *chunk = std::exchange(current_chunk, nullptr);
 	if (chunk->IsEmpty())
-		dc.buffer->Return(chunk);
+		dc.pipe->GetBuffer().Return(chunk);
 	else
 		dc.pipe->Push(chunk);
 
@@ -303,11 +303,11 @@ DecoderBridge::CommandFinished()
 		/* delete frames from the old song position */
 
 		if (current_chunk != nullptr) {
-			dc.buffer->Return(current_chunk);
+			dc.pipe->GetBuffer().Return(current_chunk);
 			current_chunk = nullptr;
 		}
 
-		dc.pipe->Clear(*dc.buffer);
+		dc.pipe->Clear();
 
 		if (convert != nullptr)
 			convert->Reset();
diff --git a/src/decoder/DecoderControl.cxx b/src/decoder/DecoderControl.cxx
index aa2721e86..d121b60b0 100644
--- a/src/decoder/DecoderControl.cxx
+++ b/src/decoder/DecoderControl.cxx
@@ -92,7 +92,7 @@ DecoderControl::IsCurrentSong(const DetachedSong &_song) const noexcept
 void
 DecoderControl::Start(std::unique_ptr<DetachedSong> _song,
 		      SongTime _start_time, SongTime _end_time,
-		      MusicBuffer &_buffer, MusicPipe &_pipe) noexcept
+		      MusicPipe &_pipe) noexcept
 {
 	assert(_song != nullptr);
 	assert(_pipe.IsEmpty());
@@ -100,7 +100,6 @@ DecoderControl::Start(std::unique_ptr<DetachedSong> _song,
 	song = std::move(_song);
 	start_time = _start_time;
 	end_time = _end_time;
-	buffer = &_buffer;
 	pipe = &_pipe;
 
 	ClearError();
diff --git a/src/decoder/DecoderControl.hxx b/src/decoder/DecoderControl.hxx
index e77237481..da3472e04 100644
--- a/src/decoder/DecoderControl.hxx
+++ b/src/decoder/DecoderControl.hxx
@@ -44,7 +44,6 @@
 #endif
 
 class DetachedSong;
-class MusicBuffer;
 class MusicPipe;
 
 enum class DecoderState : uint8_t {
@@ -152,9 +151,6 @@ struct DecoderControl final : InputStreamHandler {
 
 	SignedSongTime total_time;
 
-	/** the #MusicChunk allocator */
-	MusicBuffer *buffer;
-
 	/**
 	 * The destination pipe for decoded chunks.  The caller thread
 	 * owns this object, and is responsible for freeing it.
@@ -383,7 +379,7 @@ public:
 	 */
 	void Start(std::unique_ptr<DetachedSong> song,
 		   SongTime start_time, SongTime end_time,
-		   MusicBuffer &buffer, MusicPipe &pipe) noexcept;
+		   MusicPipe &pipe) noexcept;
 
 	/**
 	 * Caller must lock the object.
diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx
index 7b5b764cb..6a0d9d152 100644
--- a/src/decoder/DecoderThread.cxx
+++ b/src/decoder/DecoderThread.cxx
@@ -551,7 +551,7 @@ DecoderControl::RunThread() noexcept
 			/* we need to clear the pipe here; usually the
 			   PlayerThread is responsible, but it is not
 			   aware that the decoder has finished */
-			pipe->Clear(*buffer);
+			pipe->Clear();
 
 			decoder_run(*this);
 			break;
diff --git a/src/output/MultipleOutputs.cxx b/src/output/MultipleOutputs.cxx
index bc59b283a..b5c3e0e0b 100644
--- a/src/output/MultipleOutputs.cxx
+++ b/src/output/MultipleOutputs.cxx
@@ -207,7 +207,6 @@ MultipleOutputs::SetReplayGainMode(ReplayGainMode mode) noexcept
 void
 MultipleOutputs::Play(MusicChunk *chunk)
 {
-	assert(buffer != nullptr);
 	assert(pipe != nullptr);
 	assert(chunk != nullptr);
 	assert(chunk->CheckFormat(input_audio_format));
@@ -224,21 +223,18 @@ MultipleOutputs::Play(MusicChunk *chunk)
 
 void
 MultipleOutputs::Open(const AudioFormat audio_format,
-		      MusicBuffer &_buffer)
+		      MusicBuffer &buffer)
 {
 	bool ret = false, enabled = false;
 
-	assert(buffer == nullptr || buffer == &_buffer);
-	assert((pipe == nullptr) == (buffer == nullptr));
-
-	buffer = &_buffer;
+	assert(pipe == nullptr || &pipe->GetBuffer() == &buffer);
 
 	/* the audio format must be the same as existing chunks in the
 	   pipe */
 	assert(pipe == nullptr || pipe->CheckFormat(audio_format));
 
 	if (pipe == nullptr)
-		pipe = new MusicPipe();
+		pipe = new MusicPipe(buffer);
 	else
 		/* if the pipe hasn't been cleared, the the audio
 		   format must not have changed */
@@ -321,7 +317,6 @@ MultipleOutputs::CheckPipe() noexcept
 	MusicChunk *shifted;
 	bool locked[outputs.size()];
 
-	assert(buffer != nullptr);
 	assert(pipe != nullptr);
 
 	while ((chunk = pipe->Peek()) != nullptr) {
@@ -355,7 +350,7 @@ MultipleOutputs::CheckPipe() noexcept
 					outputs[i]->mutex.unlock();
 
 		/* return the chunk to the buffer */
-		buffer->Return(shifted);
+		pipe->GetBuffer().Return(shifted);
 	}
 
 	return 0;
@@ -394,7 +389,7 @@ MultipleOutputs::Cancel() noexcept
 	/* clear the music pipe and return all chunks to the buffer */
 
 	if (pipe != nullptr)
-		pipe->Clear(*buffer);
+		pipe->Clear();
 
 	/* the audio outputs are now waiting for a signal, to
 	   synchronize the cleared music pipe */
@@ -413,15 +408,11 @@ MultipleOutputs::Close() noexcept
 		ao->LockCloseWait();
 
 	if (pipe != nullptr) {
-		assert(buffer != nullptr);
-
-		pipe->Clear(*buffer);
+		pipe->Clear();
 		delete pipe;
 		pipe = nullptr;
 	}
 
-	buffer = nullptr;
-
 	input_audio_format.Clear();
 
 	elapsed_time = SignedSongTime::Negative();
@@ -434,15 +425,11 @@ MultipleOutputs::Release() noexcept
 		ao->LockRelease();
 
 	if (pipe != nullptr) {
-		assert(buffer != nullptr);
-
-		pipe->Clear(*buffer);
+		pipe->Clear();
 		delete pipe;
 		pipe = nullptr;
 	}
 
-	buffer = nullptr;
-
 	input_audio_format.Clear();
 
 	elapsed_time = SignedSongTime::Negative();
diff --git a/src/output/MultipleOutputs.hxx b/src/output/MultipleOutputs.hxx
index c0a2f5c52..3048a81f5 100644
--- a/src/output/MultipleOutputs.hxx
+++ b/src/output/MultipleOutputs.hxx
@@ -52,11 +52,6 @@ class MultipleOutputs final : public PlayerOutputs {
 
 	AudioFormat input_audio_format = AudioFormat::Undefined();
 
-	/**
-	 * The #MusicBuffer object where consumed chunks are returned.
-	 */
-	MusicBuffer *buffer = nullptr;
-
 	/**
 	 * The #MusicPipe object which feeds all audio outputs.  It is
 	 * filled by Play().
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 80be00b9a..e20b9b3a9 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -170,7 +170,7 @@ private:
 	}
 
 	void ClearAndDeletePipe() noexcept {
-		pipe->Clear(buffer);
+		pipe->Clear();
 		delete pipe;
 	}
 
@@ -348,7 +348,7 @@ Player::StartDecoder(MusicPipe &_pipe) noexcept
 
 	dc.Start(std::make_unique<DetachedSong>(*pc.next_song),
 		 start_time, pc.next_song->GetEndTime(),
-		 buffer, _pipe);
+		 _pipe);
 }
 
 void
@@ -361,7 +361,7 @@ Player::StopDecoder() noexcept
 	if (dc.pipe != nullptr) {
 		/* clear and free the decoder pipe */
 
-		dc.pipe->Clear(buffer);
+		dc.pipe->Clear();
 
 		if (dc.pipe != pipe)
 			delete dc.pipe;
@@ -585,7 +585,7 @@ Player::SeekDecoder() noexcept
 
 		/* clear music chunks which might still reside in the
 		   pipe */
-		pipe->Clear(buffer);
+		pipe->Clear();
 
 		/* re-start the decoder */
 		StartDecoder(*pipe);
@@ -666,7 +666,7 @@ Player::ProcessCommand() noexcept
 		pc.CommandFinished();
 
 		if (dc.IsIdle())
-			StartDecoder(*new MusicPipe());
+			StartDecoder(*new MusicPipe(buffer));
 
 		break;
 
@@ -939,7 +939,7 @@ Player::SongBorder() noexcept
 inline void
 Player::Run() noexcept
 {
-	pipe = new MusicPipe();
+	pipe = new MusicPipe(buffer);
 
 	const std::lock_guard<Mutex> lock(pc.mutex);
 
@@ -986,7 +986,7 @@ Player::Run() noexcept
 
 			assert(dc.pipe == nullptr || dc.pipe == pipe);
 
-			StartDecoder(*new MusicPipe());
+			StartDecoder(*new MusicPipe(buffer));
 		}
 
 		if (/* no cross-fading if MPD is going to pause at the