From 53def9a6824fdf6f4aea969fd3b28eff563dceec Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Mon, 27 Nov 2017 22:32:55 +0100
Subject: [PATCH 1/9] increment version number to 0.20.13

---
 NEWS         | 2 ++
 configure.ac | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index bac45976d..266c11e38 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+ver 0.20.13 (not yet released)
+
 ver 0.20.12 (2017/11/25)
 * database
   - upnp: adapt to libupnp 1.8 API changes
diff --git a/configure.ac b/configure.ac
index 5249044f0..b6baaf5f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
 AC_PREREQ(2.60)
 
-AC_INIT(mpd, 0.20.12, musicpd-dev-team@lists.sourceforge.net)
+AC_INIT(mpd, 0.20.13, musicpd-dev-team@lists.sourceforge.net)
 
 VERSION_MAJOR=0
 VERSION_MINOR=20
-VERSION_REVISION=12
+VERSION_REVISION=13
 VERSION_EXTRA=0
 
 AC_CONFIG_SRCDIR([src/Main.cxx])

From 63fc98591d9be2ee4f1ef11965f7eb0717689d68 Mon Sep 17 00:00:00 2001
From: FlashSystems <developer@flashsystems.de>
Date: Sat, 25 Nov 2017 12:24:27 +0100
Subject: [PATCH 2/9] Fix for "Mount-Points are purged from database on
 update/rescan."

Signed-off-by: FlashSystems <developer@flashsystems.de>
---
 NEWS                                | 2 ++
 src/db/plugins/simple/Directory.cxx | 2 +-
 src/db/update/Walk.cxx              | 2 +-
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index 266c11e38..d82e2b19d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.20.13 (not yet released)
+* database
+  - simple: don't purge mount points on update/rescan
 
 ver 0.20.12 (2017/11/25)
 * database
diff --git a/src/db/plugins/simple/Directory.cxx b/src/db/plugins/simple/Directory.cxx
index 655778b99..30b044b1f 100644
--- a/src/db/plugins/simple/Directory.cxx
+++ b/src/db/plugins/simple/Directory.cxx
@@ -109,7 +109,7 @@ Directory::PruneEmpty() noexcept
 	     child != end;) {
 		child->PruneEmpty();
 
-		if (child->IsEmpty())
+		if (child->IsEmpty() && !child->IsMount())
 			child = children.erase_and_dispose(child,
 							   DeleteDisposer());
 		else
diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index c3af3f789..1ef37e4d1 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -104,7 +104,7 @@ inline void
 UpdateWalk::PurgeDeletedFromDirectory(Directory &directory)
 {
 	directory.ForEachChildSafe([&](Directory &child){
-			if (DirectoryExists(storage, child))
+			if (child.IsMount() || DirectoryExists(storage, child))
 				return;
 
 			editor.LockDeleteDirectory(&child);

From 78728138a04c2493c6bfadee98060043eca204bf Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 2 Dec 2017 14:47:27 +0100
Subject: [PATCH 3/9] lib/upnp/Compat: disable the 1.8 API emulation with
 libupnp 1.6.24

libupnp 1.6.24 added a few badly designed macros which break the MPD
build:

 https://sourceforge.net/p/pupnp/code/ci/8177a4195a4d4a5d6cb095eaf4ca5b65ac446381/

To work around this, we disable our emulation functions (from
714011c81ed6053f7a35812071499356f337dd70) on this libupnp version.

Closes #163
---
 NEWS                    | 1 +
 src/lib/upnp/Compat.hxx | 7 +++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index d82e2b19d..998836c38 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 ver 0.20.13 (not yet released)
 * database
   - simple: don't purge mount points on update/rescan
+  - upnp: work around libupnp 1.6.24 API breakage
 
 ver 0.20.12 (2017/11/25)
 * database
diff --git a/src/lib/upnp/Compat.hxx b/src/lib/upnp/Compat.hxx
index 2e2d2f1de..c9f1cc47f 100644
--- a/src/lib/upnp/Compat.hxx
+++ b/src/lib/upnp/Compat.hxx
@@ -23,12 +23,15 @@
 #include <upnp/upnp.h>
 
 #if UPNP_VERSION < 10800
-#include "Compiler.h"
-
 /* emulate the libupnp 1.8 API with older versions */
 
 using UpnpDiscovery = Upnp_Discovery;
 
+#endif
+
+#if UPNP_VERSION < 10624
+#include "Compiler.h"
+
 gcc_pure
 static inline int
 UpnpDiscovery_get_Expires(const UpnpDiscovery *disco) noexcept

From 4a3059f50969fd84ad6d1a0a51b46cd1e86db928 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 2 Dec 2017 16:25:32 +0100
Subject: [PATCH 4/9] queue/PlaylistControl: don't skip highest priority song
 on "play"

When starting playback with a specific song which does not have the
highest priority, the previous highest priority song was skipped
completely because its order was "swapped".  This commit changes to a
more expensive operation which inserts the selected song into the
order list.

This fixes a small part of #165
---
 src/queue/PlaylistControl.cxx | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/queue/PlaylistControl.cxx b/src/queue/PlaylistControl.cxx
index 4b17386ae..018ddcbb7 100644
--- a/src/queue/PlaylistControl.cxx
+++ b/src/queue/PlaylistControl.cxx
@@ -75,8 +75,7 @@ playlist::MoveOrderToCurrent(unsigned old_order)
 	} else {
 		/* not playing anything: move the specified song to
 		   the front */
-		queue.SwapOrders(old_order, 0);
-		return 0;
+		return queue.MoveOrderBefore(old_order, 0);
 	}
 }
 

From 478180ebe4e44c30721783db47be6829cd3376e8 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sat, 2 Dec 2017 17:08:20 +0100
Subject: [PATCH 5/9] queue/PlaylistEdit: shuffle appended songs only within
 its priority group

Fixes #165.
---
 NEWS                       |  1 +
 src/queue/PlaylistEdit.cxx |  2 +-
 src/queue/Queue.cxx        | 14 +++++++++++++-
 src/queue/Queue.hxx        |  9 +++++----
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index 998836c38..c8969c55d 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ ver 0.20.13 (not yet released)
 * database
   - simple: don't purge mount points on update/rescan
   - upnp: work around libupnp 1.6.24 API breakage
+* queue: fix spuriously misplaced prioritized songs
 
 ver 0.20.12 (2017/11/25)
 * database
diff --git a/src/queue/PlaylistEdit.cxx b/src/queue/PlaylistEdit.cxx
index 67675680c..8d7429e27 100644
--- a/src/queue/PlaylistEdit.cxx
+++ b/src/queue/PlaylistEdit.cxx
@@ -112,7 +112,7 @@ playlist::AppendSong(PlayerControl &pc, DetachedSong &&song)
 		else
 			start = current + 1;
 		if (start < queue.GetLength())
-			queue.ShuffleOrderLast(start, queue.GetLength());
+			queue.ShuffleOrderLastWithPriority(start, queue.GetLength());
 	}
 
 	UpdateQueuedSong(pc, queued_song);
diff --git a/src/queue/Queue.cxx b/src/queue/Queue.cxx
index 720778099..0997e91e3 100644
--- a/src/queue/Queue.cxx
+++ b/src/queue/Queue.cxx
@@ -364,8 +364,20 @@ Queue::ShuffleOrderFirst(unsigned start, unsigned end)
 }
 
 void
-Queue::ShuffleOrderLast(unsigned start, unsigned end)
+Queue::ShuffleOrderLastWithPriority(unsigned start, unsigned end)
 {
+	assert(end <= length);
+	assert(start < end);
+
+	/* skip all items at the start which have a higher priority,
+	   because the last item shall only be shuffled within its
+	   priority group */
+	const auto last_priority = items[OrderToPosition(end - 1)].priority;
+	while (items[OrderToPosition(start)].priority != last_priority) {
+		++start;
+		assert(start < end);
+	}
+
 	rand.AutoCreate();
 
 	std::uniform_int_distribution<unsigned> distribution(start, end - 1);
diff --git a/src/queue/Queue.hxx b/src/queue/Queue.hxx
index 06e800479..fb1d9c8b1 100644
--- a/src/queue/Queue.hxx
+++ b/src/queue/Queue.hxx
@@ -356,11 +356,12 @@ struct Queue {
 	void ShuffleOrderFirst(unsigned start, unsigned end);
 
 	/**
-	 * Shuffles the virtual order of the last song in the specified
-	 * (order) range.  This is used in random mode after a song has been
-	 * appended by queue_append().
+	 * Shuffles the virtual order of the last song in the
+	 * specified (order) range; only songs which match this song's
+	 * priority are considered.  This is used in random mode after
+	 * a song has been appended by Append().
 	 */
-	void ShuffleOrderLast(unsigned start, unsigned end);
+	void ShuffleOrderLastWithPriority(unsigned start, unsigned end);
 
 	/**
 	 * Shuffles a (position) range in the queue.  The songs are physically

From 18f350cd043b412328a2ccc31d230493fcc67be6 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sun, 3 Dec 2017 10:47:56 +0100
Subject: [PATCH 6/9] player/Thread: initialize MusicChunk::bit_rate in
 SendSilence()

This attribute is not particularly important, but it was
uninitialized.
---
 src/player/Thread.cxx | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index c06bd419f..7d3d18694 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -558,6 +558,7 @@ Player::SendSilence()
 	   partial frames */
 	unsigned num_frames = sizeof(chunk->data) / frame_size;
 
+	chunk->bit_rate = 0;
 	chunk->time = SignedSongTime::Negative(); /* undefined time stamp */
 	chunk->length = num_frames * frame_size;
 	PcmSilence({chunk->data, chunk->length}, play_audio_format.format);

From 396defaea920e8493252d647cbf640682c4603ed Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sun, 3 Dec 2017 11:39:07 +0100
Subject: [PATCH 7/9] MusicChunk: initialize replay_gain_serial on demand

---
 src/MusicChunk.hxx    | 2 +-
 src/player/Thread.cxx | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/MusicChunk.hxx b/src/MusicChunk.hxx
index c5be179a9..54c0c7753 100644
--- a/src/MusicChunk.hxx
+++ b/src/MusicChunk.hxx
@@ -84,7 +84,7 @@ struct MusicChunk {
 	 * changed since the last chunk.  The magic value 0 indicates
 	 * that there is no replay gain info available.
 	 */
-	unsigned replay_gain_serial = 0;
+	unsigned replay_gain_serial;
 
 	/** the data (probably PCM) */
 	uint8_t data[CHUNK_SIZE];
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 7d3d18694..be34d8af9 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -561,6 +561,7 @@ Player::SendSilence()
 	chunk->bit_rate = 0;
 	chunk->time = SignedSongTime::Negative(); /* undefined time stamp */
 	chunk->length = num_frames * frame_size;
+	chunk->replay_gain_serial = 0;
 	PcmSilence({chunk->data, chunk->length}, play_audio_format.format);
 
 	try {

From de90d401d290f69fb19bd1f8124ce43fcb932dc0 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Sun, 3 Dec 2017 11:15:11 +0100
Subject: [PATCH 8/9] MusicChunk: add magic value IGNORE_REPLAY_GAIN

This fixes spurious replay gain logs when the player inserts silence
chunks, because those silence chunks had no replay gain attached,
resetting the ReplayGainFilter state, flipping it forth and back.
---
 src/MusicChunk.hxx    | 8 ++++++++
 src/output/Source.cxx | 3 ++-
 src/player/Thread.cxx | 2 +-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/src/MusicChunk.hxx b/src/MusicChunk.hxx
index 54c0c7753..a730a0b2d 100644
--- a/src/MusicChunk.hxx
+++ b/src/MusicChunk.hxx
@@ -79,6 +79,14 @@ struct MusicChunk {
 	 */
 	ReplayGainInfo replay_gain_info;
 
+	/**
+	 * A magic value for #replay_gain_serial which omits updating
+	 * the #ReplayGainFilter.  This is used by "silence" chunks
+	 * (see PlayerThread::SendSilence()) so they don't affect the
+	 * replay gain.
+	 */
+	static constexpr unsigned IGNORE_REPLAY_GAIN = ~0u;
+
 	/**
 	 * A serial number for checking if replay gain info has
 	 * changed since the last chunk.  The magic value 0 indicates
diff --git a/src/output/Source.cxx b/src/output/Source.cxx
index de11595f5..73266687c 100644
--- a/src/output/Source.cxx
+++ b/src/output/Source.cxx
@@ -142,7 +142,8 @@ AudioOutputSource::GetChunkData(const MusicChunk &chunk,
 		replay_gain_filter_set_mode(*replay_gain_filter,
 					    replay_gain_mode);
 
-		if (chunk.replay_gain_serial != *replay_gain_serial_p) {
+		if (chunk.replay_gain_serial != *replay_gain_serial_p &&
+		    chunk.replay_gain_serial != MusicChunk::IGNORE_REPLAY_GAIN) {
 			replay_gain_filter_set_info(*replay_gain_filter,
 						    chunk.replay_gain_serial != 0
 						    ? &chunk.replay_gain_info
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index be34d8af9..913e541e1 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -561,7 +561,7 @@ Player::SendSilence()
 	chunk->bit_rate = 0;
 	chunk->time = SignedSongTime::Negative(); /* undefined time stamp */
 	chunk->length = num_frames * frame_size;
-	chunk->replay_gain_serial = 0;
+	chunk->replay_gain_serial = MusicChunk::IGNORE_REPLAY_GAIN;
 	PcmSilence({chunk->data, chunk->length}, play_audio_format.format);
 
 	try {

From 12085038881a4aba94c74b7104c5090bc777001e Mon Sep 17 00:00:00 2001
From: FlashSystems <developer@flashsystems.de>
Date: Tue, 28 Nov 2017 17:37:09 +0100
Subject: [PATCH 9/9] Removing gcc_malloc attribute from
 `Directory::CreateChild` to fix assignment of `mnt->mounted_database` in
 `SimpleDatabase::Mount`.

---
 NEWS                                | 1 +
 src/db/plugins/simple/Directory.hxx | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index c8969c55d..6cd9c76fc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 ver 0.20.13 (not yet released)
 * database
   - simple: don't purge mount points on update/rescan
+  - simple: fix "mount" bug caused by bad compiler optimization
   - upnp: work around libupnp 1.6.24 API breakage
 * queue: fix spuriously misplaced prioritized songs
 
diff --git a/src/db/plugins/simple/Directory.hxx b/src/db/plugins/simple/Directory.hxx
index 99572a4b4..8545ba092 100644
--- a/src/db/plugins/simple/Directory.hxx
+++ b/src/db/plugins/simple/Directory.hxx
@@ -127,7 +127,6 @@ public:
 	 *
 	 * @param name_utf8 the UTF-8 encoded name of the new sub directory
 	 */
-	gcc_malloc
 	Directory *CreateChild(const char *name_utf8);
 
 	/**