diff --git a/src/SongPrint.cxx b/src/SongPrint.cxx
index 207aa7b13..235b6a943 100644
--- a/src/SongPrint.cxx
+++ b/src/SongPrint.cxx
@@ -30,14 +30,14 @@ song_print_uri(Response &r, const char *uri, bool base) noexcept
 			uri = allocated.c_str();
 	}
 
-	r.Fmt(FMT_STRING(SONG_FILE "{}\n"), uri);
+	r.Fmt(SONG_FILE "{}\n", uri);
 }
 
 void
 song_print_uri(Response &r, const LightSong &song, bool base) noexcept
 {
 	if (!base && song.directory != nullptr)
-		r.Fmt(FMT_STRING(SONG_FILE "{}/{}\n"),
+		r.Fmt(SONG_FILE "{}/{}\n",
 		      song.directory, song.uri);
 	else
 		song_print_uri(r, song.uri, base);
@@ -56,13 +56,13 @@ PrintRange(Response &r, SongTime start_time, SongTime end_time) noexcept
 	const unsigned end_ms = end_time.ToMS();
 
 	if (end_ms > 0)
-		r.Fmt(FMT_STRING("Range: {}.{:03}-{}.{:03}\n"),
+		r.Fmt("Range: {}.{:03}-{}.{:03}\n",
 		      start_ms / 1000,
 		      start_ms % 1000,
 		      end_ms / 1000,
 		      end_ms % 1000);
 	else if (start_ms > 0)
-		r.Fmt(FMT_STRING("Range: {}.{:03}-\n"),
+		r.Fmt("Range: {}.{:03}-\n",
 		      start_ms / 1000,
 		      start_ms % 1000);
 }
@@ -81,14 +81,14 @@ song_print_info(Response &r, const LightSong &song, bool base) noexcept
 		time_print(r, "Added", song.added);
 
 	if (song.audio_format.IsDefined())
-		r.Fmt(FMT_STRING("Format: {}\n"), song.audio_format);
+		r.Fmt("Format: {}\n", song.audio_format);
 
 	tag_print_values(r, song.tag);
 
 	const auto duration = song.GetDuration();
 	if (!duration.IsNegative())
-		r.Fmt(FMT_STRING("Time: {}\n"
-				 "duration: {:1.3f}\n"),
+		r.Fmt("Time: {}\n"
+		      "duration: {:1.3f}\n",
 		      duration.RoundS(),
 		      duration.ToDoubleS());
 }
@@ -107,14 +107,14 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
 		time_print(r, "Added", song.GetAdded());
 
 	if (const auto &f = song.GetAudioFormat(); f.IsDefined())
-		r.Fmt(FMT_STRING("Format: {}\n"), f);
+		r.Fmt("Format: {}\n", f);
 
 	tag_print_values(r, song.GetTag());
 
 	const auto duration = song.GetDuration();
 	if (!duration.IsNegative())
-		r.Fmt(FMT_STRING("Time: {}\n"
-				 "duration: {:1.3f}\n"),
+		r.Fmt("Time: {}\n"
+		      "duration: {:1.3f}\n",
 		      duration.RoundS(),
 		      duration.ToDoubleS());
 }
diff --git a/src/Stats.cxx b/src/Stats.cxx
index b7e52ede8..80956a297 100644
--- a/src/Stats.cxx
+++ b/src/Stats.cxx
@@ -83,10 +83,10 @@ db_stats_print(Response &r, const Database &db)
 	unsigned total_duration_s =
 		std::chrono::duration_cast<std::chrono::seconds>(stats.total_duration).count();
 
-	r.Fmt(FMT_STRING("artists: {}\n"
-			 "albums: {}\n"
-			 "songs: {}\n"
-			 "db_playtime: {}\n"),
+	r.Fmt("artists: {}\n"
+	      "albums: {}\n"
+	      "songs: {}\n"
+	      "db_playtime: {}\n",
 	      stats.artist_count,
 	      stats.album_count,
 	      stats.song_count,
@@ -94,7 +94,7 @@ db_stats_print(Response &r, const Database &db)
 
 	const auto update_stamp = db.GetUpdateStamp();
 	if (!IsNegative(update_stamp))
-		r.Fmt(FMT_STRING("db_update: {}\n"),
+		r.Fmt("db_update: {}\n",
 		      std::chrono::system_clock::to_time_t(update_stamp));
 }
 
@@ -109,8 +109,8 @@ stats_print(Response &r, const Partition &partition)
 	const auto uptime = std::chrono::steady_clock::now() - start_time;
 #endif
 
-	r.Fmt(FMT_STRING("uptime: {}\n"
-			 "playtime: {}\n"),
+	r.Fmt("uptime: {}\n"
+	      "playtime: {}\n",
 	      std::chrono::duration_cast<std::chrono::seconds>(uptime).count(),
 	      lround(partition.pc.GetTotalPlayTime().count()));
 
diff --git a/src/TagPrint.cxx b/src/TagPrint.cxx
index fa638405a..9b1257bff 100644
--- a/src/TagPrint.cxx
+++ b/src/TagPrint.cxx
@@ -15,7 +15,7 @@ tag_print_types(Response &r) noexcept
 	const auto tag_mask = global_tag_mask & r.GetTagMask();
 	for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++)
 		if (tag_mask.Test(TagType(i)))
-			r.Fmt(FMT_STRING("tagtype: {}\n"), tag_item_names[i]);
+			r.Fmt("tagtype: {}\n", tag_item_names[i]);
 }
 
 void
@@ -29,13 +29,14 @@ tag_print_types_available(Response &r) noexcept
 void
 tag_print(Response &r, TagType type, std::string_view value) noexcept
 {
-	r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
+	const std::string_view value{_value};
+	r.Fmt("{}: {}\n", tag_item_names[type], value);
 }
 
 void
 tag_print(Response &r, TagType type, const char *value) noexcept
 {
-	r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
+	r.Fmt("{}: {}\n", tag_item_names[type], value);
 }
 
 void
@@ -51,8 +52,8 @@ void
 tag_print(Response &r, const Tag &tag) noexcept
 {
 	if (!tag.duration.IsNegative())
-		r.Fmt(FMT_STRING("Time: {}\n"
-				 "duration: {:1.3f}\n"),
+		r.Fmt("Time: {}\n"
+		      "duration: {:1.3f}\n",
 		      tag.duration.RoundS(),
 		      tag.duration.ToDoubleS());
 
diff --git a/src/TimePrint.cxx b/src/TimePrint.cxx
index d47f3178b..36852a948 100644
--- a/src/TimePrint.cxx
+++ b/src/TimePrint.cxx
@@ -20,5 +20,5 @@ time_print(Response &r, const char *name,
 		return;
 	}
 
-	r.Fmt(FMT_STRING("{}: {}\n"), name, s.c_str());
+	r.Fmt("{}: {}\n", name, s.c_str());
 }
diff --git a/src/client/Idle.cxx b/src/client/Idle.cxx
index a3ae757b3..d04cab2e2 100644
--- a/src/client/Idle.cxx
+++ b/src/client/Idle.cxx
@@ -16,7 +16,7 @@ WriteIdleResponse(Response &r, unsigned flags) noexcept
 	const char *const*idle_names = idle_get_names();
 	for (unsigned i = 0; idle_names[i]; ++i) {
 		if (flags & (1 << i))
-			r.Fmt(FMT_STRING("changed: {}\n"), idle_names[i]);
+			r.Fmt("changed: {}\n", idle_names[i]);
 	}
 
 	r.Write("OK\n");
diff --git a/src/client/Response.cxx b/src/client/Response.cxx
index e2db07309..42085e6ab 100644
--- a/src/client/Response.cxx
+++ b/src/client/Response.cxx
@@ -46,7 +46,7 @@ Response::WriteBinary(std::span<const std::byte> payload) noexcept
 void
 Response::Error(enum ack code, const char *msg) noexcept
 {
-	Fmt(FMT_STRING("ACK [{}@{}] {{{}}} "),
+	Fmt("ACK [{}@{}] {{{}}} ",
 	    (int)code, list_index, command);
 
 	Write(msg);
@@ -57,7 +57,7 @@ void
 Response::VFmtError(enum ack code,
 		    fmt::string_view format_str, fmt::format_args args) noexcept
 {
-	Fmt(FMT_STRING("ACK [{}@{}] {{{}}} "),
+	Fmt("ACK [{}@{}] {{{}}} ",
 	    (int)code, list_index, command);
 
 	VFmt(format_str, args);
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index cfc4c29c1..0292e8393 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -254,7 +254,7 @@ PrintAvailableCommands(Response &r, const Partition &partition,
 
 		if (cmd->permission == (permission & cmd->permission) &&
 		    command_available(partition, cmd))
-			r.Fmt(FMT_STRING("command: {}\n"), cmd->cmd);
+			r.Fmt("command: {}\n", cmd->cmd);
 	}
 
 	return CommandResult::OK;
@@ -267,7 +267,7 @@ PrintUnavailableCommands(Response &r, unsigned permission) noexcept
 		const struct command *cmd = &i;
 
 		if (cmd->permission != (permission & cmd->permission))
-			r.Fmt(FMT_STRING("command: {}\n"), cmd->cmd);
+			r.Fmt("command: {}\n", cmd->cmd);
 	}
 
 	return CommandResult::OK;
@@ -325,7 +325,7 @@ command_check_request(const struct command *cmd, Response &r,
 {
 	if (cmd->permission != (permission & cmd->permission)) {
 		r.FmtError(ACK_ERROR_PERMISSION,
-			   FMT_STRING("you don't have permission for {:?}"),
+			   "you don't have permission for {:?}",
 			   cmd->cmd);
 		return false;
 	}
@@ -338,17 +338,17 @@ command_check_request(const struct command *cmd, Response &r,
 
 	if (min == max && unsigned(max) != args.size()) {
 		r.FmtError(ACK_ERROR_ARG,
-			   FMT_STRING("wrong number of arguments for {:?}"),
+			   "wrong number of arguments for {:?}",
 			   cmd->cmd);
 		return false;
 	} else if (args.size() < unsigned(min)) {
 		r.FmtError(ACK_ERROR_ARG,
-			   FMT_STRING("too few arguments for {:?}"),
+			   "too few arguments for {:?}",
 			   cmd->cmd);
 		return false;
 	} else if (max >= 0 && args.size() > unsigned(max)) {
 		r.FmtError(ACK_ERROR_ARG,
-			   FMT_STRING("too many arguments for {:?}"),
+			   "too many arguments for {:?}",
 			   cmd->cmd);
 		return false;
 	} else
@@ -362,7 +362,7 @@ command_checked_lookup(Response &r, unsigned permission,
 	const struct command *cmd = command_lookup(cmd_name);
 	if (cmd == nullptr) {
 		r.FmtError(ACK_ERROR_UNKNOWN,
-			   FMT_STRING("unknown command {:?}"), cmd_name);
+			   "unknown command {:?}", cmd_name);
 		return nullptr;
 	}
 
diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx
index ea028ef92..930e6fd37 100644
--- a/src/command/DatabaseCommands.cxx
+++ b/src/command/DatabaseCommands.cxx
@@ -230,7 +230,7 @@ handle_count_internal(Client &client, Request args, Response &r, bool fold_case)
 		group = tag_name_parse_i(s);
 		if (group == TAG_NUM_OF_ITEM_TYPES) {
 			r.FmtError(ACK_ERROR_ARG,
-				   FMT_STRING("Unknown tag type: {}"), s);
+				   "Unknown tag type: {}", s);
 			return CommandResult::ERROR;
 		}
 
@@ -311,7 +311,7 @@ handle_list(Client &client, Request args, Response &r)
 	const auto tagType = tag_name_parse_i(tag_name);
 	if (tagType == TAG_NUM_OF_ITEM_TYPES) {
 		r.FmtError(ACK_ERROR_ARG,
-			   FMT_STRING("Unknown tag type: {}"), tag_name);
+			   "Unknown tag type: {}", tag_name);
 		return CommandResult::ERROR;
 	}
 
@@ -325,7 +325,7 @@ handle_list(Client &client, Request args, Response &r)
 		/* for compatibility with < 0.12.0 */
 		if (tagType != TAG_ALBUM) {
 			r.FmtError(ACK_ERROR_ARG,
-				   FMT_STRING("should be {:?} for 3 arguments"),
+				   "should be {:?} for 3 arguments",
 				   tag_item_names[TAG_ALBUM]);
 			return CommandResult::ERROR;
 		}
@@ -340,7 +340,7 @@ handle_list(Client &client, Request args, Response &r)
 		const auto group = tag_name_parse_i(s);
 		if (group == TAG_NUM_OF_ITEM_TYPES) {
 			r.FmtError(ACK_ERROR_ARG,
-				   FMT_STRING("Unknown tag type: {}"), s);
+				   "Unknown tag type: {}", s);
 			return CommandResult::ERROR;
 		}
 
diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx
index 08ab31d39..9b9ed90fd 100644
--- a/src/command/FileCommands.cxx
+++ b/src/command/FileCommands.cxx
@@ -68,12 +68,12 @@ handle_listfiles_local(Response &r, Path path_fs)
 			continue;
 
 		if (fi.IsRegular())
-			r.Fmt(FMT_STRING("file: {}\n"
-					 "size: {}\n"),
+			r.Fmt("file: {}\n"
+			      "size: {}\n",
 			      name_utf8,
 			      fi.GetSize());
 		else if (fi.IsDirectory())
-			r.Fmt(FMT_STRING("directory: {}\n"), name_utf8);
+			r.Fmt("directory: {}\n", name_utf8);
 		else
 			continue;
 
@@ -111,7 +111,7 @@ public:
 
 	void OnPair(std::string_view key, std::string_view value) noexcept override {
 		if (IsValidName(key) && IsValidValue(value))
-			response.Fmt(FMT_STRING("{}: {}\n"), key, value);
+			response.Fmt("{}: {}\n", key, value);
 	}
 };
 
@@ -200,7 +200,7 @@ read_stream_art(Response &r, const std::string_view art_directory,
 		read_size = is->Read(lock, {buffer.get(), buffer_size});
 	}
 
-	r.Fmt(FMT_STRING("size: {}\n"), art_file_size);
+	r.Fmt("size: {}\n", art_file_size);
 
 	r.WriteBinary({buffer.get(), read_size});
 
@@ -330,10 +330,10 @@ public:
 			return;
 		}
 
-		response.Fmt(FMT_STRING("size: {}\n"), buffer.size());
+		    response.Fmt("size: {}\n", buffer.size());
 
 		if (mime_type != nullptr)
-			response.Fmt(FMT_STRING("type: {}\n"), mime_type);
+			response.Fmt("type: {}\n", mime_type);
 
 		buffer = buffer.subspan(offset);
 
diff --git a/src/command/FingerprintCommands.cxx b/src/command/FingerprintCommands.cxx
index e029d795f..c6f46600b 100644
--- a/src/command/FingerprintCommands.cxx
+++ b/src/command/FingerprintCommands.cxx
@@ -46,7 +46,7 @@ protected:
 	void Run() override;
 
 	void SendResponse(Response &r) noexcept override {
-		r.Fmt(FMT_STRING("chromaprint: {}\n"),
+		r.Fmt("chromaprint: {}\n",
 		      GetFingerprint());
 	}
 
diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx
index b3d1b9673..44f0938ea 100644
--- a/src/command/MessageCommands.cxx
+++ b/src/command/MessageCommands.cxx
@@ -70,7 +70,7 @@ handle_channels(Client &client, [[maybe_unused]] Request args, Response &r)
 	}
 
 	for (const auto &channel : channels)
-		r.Fmt(FMT_STRING("channel: {}\n"), channel);
+		r.Fmt("channel: {}\n", channel);
 
 	return CommandResult::OK;
 }
@@ -82,7 +82,7 @@ handle_read_messages(Client &client,
 	assert(args.empty());
 
 	client.ConsumeMessages([&r](const auto &msg){
-		r.Fmt(FMT_STRING("channel: {}\nmessage: {}\n"),
+		r.Fmt("channel: {}\nmessage: {}\n",
 		      msg.GetChannel(), msg.GetMessage());
 	});
 
diff --git a/src/command/NeighborCommands.cxx b/src/command/NeighborCommands.cxx
index f824573a3..7f6d2260f 100644
--- a/src/command/NeighborCommands.cxx
+++ b/src/command/NeighborCommands.cxx
@@ -30,8 +30,8 @@ handle_listneighbors(Client &client, [[maybe_unused]] Request args, Response &r)
 	}
 
 	for (const auto &i : neighbors->GetList())
-		r.Fmt(FMT_STRING("neighbor: {}\n"
-				 "name: {}\n"),
+		r.Fmt("neighbor: {}\n"
+		      "name: {}\n",
 		      i.uri,
 		      i.display_name);
 	return CommandResult::OK;
diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx
index 58aa38410..a1664308c 100644
--- a/src/command/OtherCommands.cxx
+++ b/src/command/OtherCommands.cxx
@@ -46,7 +46,7 @@ static void
 print_spl_list(Response &r, const PlaylistVector &list)
 {
 	for (const auto &i : list) {
-		r.Fmt(FMT_STRING("playlist: {}\n"), i.name);
+		r.Fmt("playlist: {}\n", i.name);
 
 		if (!IsNegative(i.mtime))
 			time_print(r, "Last-Modified", i.mtime);
@@ -233,7 +233,7 @@ handle_update(Response &r, UpdateService &update,
 	      const char *uri_utf8, bool discard)
 {
 	unsigned ret = update.Enqueue(uri_utf8, discard);
-	r.Fmt(FMT_STRING("updating_db: {}\n"), ret);
+	r.Fmt("updating_db: {}\n", ret);
 	return CommandResult::OK;
 }
 
@@ -243,7 +243,7 @@ handle_update(Response &r, Database &db,
 {
 	unsigned id = db.Update(uri_utf8, discard);
 	if (id > 0) {
-		r.Fmt(FMT_STRING("updating_db: {}\n"), id);
+		r.Fmt("updating_db: {}\n", id);
 		return CommandResult::OK;
 	} else {
 		/* Database::Update() has returned 0 without setting
@@ -308,7 +308,7 @@ handle_getvol(Client &client, Request, Response &r)
 
 	const auto volume = partition.mixer_memento.GetVolume(partition.outputs);
 	if (volume >= 0)
-		r.Fmt(FMT_STRING("volume: {}\n"), volume);
+		r.Fmt("volume: {}\n", volume);
 
 	return CommandResult::OK;
 }
@@ -372,7 +372,7 @@ handle_config(Client &client, [[maybe_unused]] Request args, Response &r)
 #ifdef ENABLE_DATABASE
 	if (const Storage *storage = client.GetStorage()) {
 		const auto path = storage->MapUTF8("");
-		r.Fmt(FMT_STRING("music_directory: {}\n"), path);
+		r.Fmt("music_directory: {}\n", path);
 	}
 #endif
 
@@ -394,7 +394,7 @@ handle_idle(Client &client, Request args, Response &r)
 		unsigned event = idle_parse_name(i);
 		if (event == 0) {
 			r.FmtError(ACK_ERROR_ARG,
-				   FMT_STRING("Unrecognized idle event: {}"),
+				   "Unrecognized idle event: {}",
 				   i);
 			return CommandResult::ERROR;
 		}
diff --git a/src/command/PartitionCommands.cxx b/src/command/PartitionCommands.cxx
index 722f53aa3..a21f8bcff 100644
--- a/src/command/PartitionCommands.cxx
+++ b/src/command/PartitionCommands.cxx
@@ -33,7 +33,7 @@ CommandResult
 handle_listpartitions(Client &client, Request, Response &r)
 {
 	for (const auto &partition : client.GetInstance().partitions) {
-		r.Fmt(FMT_STRING("partition: {}\n"), partition.name);
+		r.Fmt("partition: {}\n", partition.name);
 	}
 
 	return CommandResult::OK;
diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx
index 5ae7441f8..d7486f053 100644
--- a/src/command/PlayerCommands.cxx
+++ b/src/command/PlayerCommands.cxx
@@ -119,18 +119,18 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
 
 	const auto volume = partition.mixer_memento.GetVolume(partition.outputs);
 	if (volume >= 0)
-		r.Fmt(FMT_STRING("volume: {}\n"), volume);
+		r.Fmt("volume: {}\n", volume);
 
-	r.Fmt(FMT_STRING(COMMAND_STATUS_REPEAT ": {}\n"
-			 COMMAND_STATUS_RANDOM ": {}\n"
-			 COMMAND_STATUS_SINGLE ": {}\n"
-			 COMMAND_STATUS_CONSUME ": {}\n"
-			 "partition: {}\n"
-			 COMMAND_STATUS_PLAYLIST ": {}\n"
-			 COMMAND_STATUS_PLAYLIST_LENGTH ": {}\n"
-			 COMMAND_STATUS_MIXRAMPDB ": {}\n"
-			 COMMAND_STATUS_STATE ": {}\n"
-			 COMMAND_STATUS_LOADED_PLAYLIST ": {}\n"),
+	r.Fmt(COMMAND_STATUS_REPEAT ": {}\n"
+	      COMMAND_STATUS_RANDOM ": {}\n"
+	      COMMAND_STATUS_SINGLE ": {}\n"
+	      COMMAND_STATUS_CONSUME ": {}\n"
+	      "partition: {}\n"
+	      COMMAND_STATUS_PLAYLIST ": {}\n"
+	      COMMAND_STATUS_PLAYLIST_LENGTH ": {}\n"
+	      COMMAND_STATUS_MIXRAMPDB ": {}\n"
+	      COMMAND_STATUS_STATE ": {}\n",
+	      COMMAND_STATUS_LOADED_PLAYLIST ": {}\n",
 	      (unsigned)playlist.GetRepeat(),
 	      (unsigned)playlist.GetRandom(),
 	      SingleToString(playlist.GetSingle()),
@@ -143,24 +143,24 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
 	      playlist.GetLastLoadedPlaylist());
 
 	if (pc.GetCrossFade() > FloatDuration::zero())
-		r.Fmt(FMT_STRING(COMMAND_STATUS_CROSSFADE ": {}\n"),
+		r.Fmt(COMMAND_STATUS_CROSSFADE ": {}\n",
 		      lround(pc.GetCrossFade().count()));
 
 	if (pc.GetMixRampDelay() > FloatDuration::zero())
-		r.Fmt(FMT_STRING(COMMAND_STATUS_MIXRAMPDELAY ": {}\n"),
+		r.Fmt(COMMAND_STATUS_MIXRAMPDELAY ": {}\n",
 		      pc.GetMixRampDelay().count());
 
 	song = playlist.GetCurrentPosition();
 	if (song >= 0) {
-		r.Fmt(FMT_STRING(COMMAND_STATUS_SONG ": {}\n"
-				 COMMAND_STATUS_SONGID ": {}\n"),
+		r.Fmt(COMMAND_STATUS_SONG ": {}\n"
+		      COMMAND_STATUS_SONGID ": {}\n",
 		      song, playlist.PositionToId(song));
 	}
 
 	if (player_status.state != PlayerState::STOP) {
-		r.Fmt(FMT_STRING(COMMAND_STATUS_TIME ": {}:{}\n"
-				 "elapsed: {:1.3f}\n"
-				 COMMAND_STATUS_BITRATE ": {}\n"),
+		r.Fmt(COMMAND_STATUS_TIME ": {}:{}\n"
+		      "elapsed: {:1.3f}\n"
+		      COMMAND_STATUS_BITRATE ": {}\n",
 		      player_status.elapsed_time.RoundS(),
 		      player_status.total_time.IsNegative()
 		      ? 0U
@@ -169,11 +169,11 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
 		      player_status.bit_rate);
 
 		if (!player_status.total_time.IsNegative())
-			r.Fmt(FMT_STRING("duration: {:1.3f}\n"),
+			r.Fmt("duration: {:1.3f}\n",
 				 player_status.total_time.ToDoubleS());
 
 		if (player_status.audio_format.IsDefined())
-			r.Fmt(FMT_STRING(COMMAND_STATUS_AUDIO ": {}\n"),
+			r.Fmt(COMMAND_STATUS_AUDIO ": {}\n",
 			      player_status.audio_format);
 	}
 
@@ -183,7 +183,7 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
 		? update_service->GetId()
 		: 0;
 	if (updateJobId != 0) {
-		r.Fmt(FMT_STRING(COMMAND_STATUS_UPDATING_DB ": {}\n"),
+		r.Fmt(COMMAND_STATUS_UPDATING_DB ": {}\n",
 		      updateJobId);
 	}
 #endif
@@ -191,14 +191,14 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
 	try {
 		pc.LockCheckRethrowError();
 	} catch (...) {
-		r.Fmt(FMT_STRING(COMMAND_STATUS_ERROR ": {}\n"),
+		r.Fmt(COMMAND_STATUS_ERROR ": {}\n",
 		      GetFullMessage(std::current_exception()));
 	}
 
 	song = playlist.GetNextPosition();
 	if (song >= 0)
-		r.Fmt(FMT_STRING(COMMAND_STATUS_NEXTSONG ": {}\n"
-				 COMMAND_STATUS_NEXTSONGID ": {}\n"),
+		r.Fmt(COMMAND_STATUS_NEXTSONG ": {}\n"
+		      COMMAND_STATUS_NEXTSONGID ": {}\n",
 		      song, playlist.PositionToId(song));
 
 	return CommandResult::OK;
@@ -341,7 +341,7 @@ CommandResult
 handle_replay_gain_status(Client &client, [[maybe_unused]] Request args,
 			  Response &r)
 {
-	r.Fmt(FMT_STRING("replay_gain_mode: {}\n"),
+	r.Fmt("replay_gain_mode: {}\n",
 	      ToString(client.GetPartition().replay_gain_mode));
 	return CommandResult::OK;
 }
diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx
index 83f4b0952..8b54e23d5 100644
--- a/src/command/PlaylistCommands.cxx
+++ b/src/command/PlaylistCommands.cxx
@@ -43,7 +43,7 @@ static void
 print_spl_list(Response &r, const PlaylistVector &list)
 {
 	for (const auto &i : list) {
-		r.Fmt(FMT_STRING("playlist: {}\n"), i.name);
+		r.Fmt("playlist: {}\n", i.name);
 
 		if (!IsNegative(i.mtime))
 			time_print(r, "Last-Modified", i.mtime);
diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx
index 9812b3b89..4fc00520e 100644
--- a/src/command/QueueCommands.cxx
+++ b/src/command/QueueCommands.cxx
@@ -140,7 +140,7 @@ handle_addid(Client &client, Request args, Response &r)
 
 	partition.instance.LookupRemoteTag(uri);
 
-	r.Fmt(FMT_STRING("Id: {}\n"), added_id);
+	r.Fmt("Id: {}\n", added_id);
 	return CommandResult::OK;
 }
 
diff --git a/src/command/StorageCommands.cxx b/src/command/StorageCommands.cxx
index 3cce0eb5c..3f4d56629 100644
--- a/src/command/StorageCommands.cxx
+++ b/src/command/StorageCommands.cxx
@@ -50,14 +50,14 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader)
 			continue;
 
 		case StorageFileInfo::Type::REGULAR:
-			r.Fmt(FMT_STRING("file: {}\n"
-					 "size: {}\n"),
+			r.Fmt("file: {}\n"
+			      "size: {}\n",
 			      name_utf8,
 			      info.size);
 			break;
 
 		case StorageFileInfo::Type::DIRECTORY:
-			r.Fmt(FMT_STRING("directory: {}\n"), name_utf8);
+			r.Fmt("directory: {}\n", name_utf8);
 			break;
 		}
 
@@ -110,7 +110,7 @@ print_storage_uri(Client &client, Response &r, const Storage &storage)
 			uri = std::move(allocated);
 	}
 
-	r.Fmt(FMT_STRING("storage: {}\n"), uri);
+	r.Fmt("storage: {}\n", uri);
 }
 
 CommandResult
@@ -126,7 +126,7 @@ handle_listmounts(Client &client, [[maybe_unused]] Request args, Response &r)
 
 	const auto visitor = [&client, &r](const char *mount_uri,
 					   const Storage &storage){
-		r.Fmt(FMT_STRING("mount: {}\n"), mount_uri);
+		r.Fmt("mount: {}\n", mount_uri);
 		print_storage_uri(client, r, storage);
 	};
 
diff --git a/src/command/TagCommands.cxx b/src/command/TagCommands.cxx
index 170904ff5..8e60b75e0 100644
--- a/src/command/TagCommands.cxx
+++ b/src/command/TagCommands.cxx
@@ -19,7 +19,7 @@ handle_addtagid(Client &client, Request args, Response &r)
 	const char *const tag_name = args[1];
 	const TagType tag_type = tag_name_parse_i(tag_name);
 	if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
-		r.FmtError(ACK_ERROR_ARG, FMT_STRING("Unknown tag type: {}"),
+		r.FmtError(ACK_ERROR_ARG, "Unknown tag type: {}",
 			   tag_name);
 		return CommandResult::ERROR;
 	}
@@ -41,7 +41,7 @@ handle_cleartagid(Client &client, Request args, Response &r)
 		tag_type = tag_name_parse_i(tag_name);
 		if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
 			r.FmtError(ACK_ERROR_ARG,
-				   FMT_STRING("Unknown tag type: {}"),
+				   "Unknown tag type: {}",
 				   tag_name);
 			return CommandResult::ERROR;
 		}
diff --git a/src/db/Count.cxx b/src/db/Count.cxx
index b1b574ded..a83276628 100644
--- a/src/db/Count.cxx
+++ b/src/db/Count.cxx
@@ -33,8 +33,8 @@ PrintSearchStats(Response &r, const SearchStats &stats) noexcept
 	unsigned total_duration_s =
 		std::chrono::duration_cast<std::chrono::seconds>(stats.total_duration).count();
 
-	r.Fmt(FMT_STRING("songs: {}\n"
-			 "playtime: {}\n"),
+	r.Fmt("songs: {}\n"
+	      "playtime: {}\n",
 	      stats.n_songs, total_duration_s);
 }
 
diff --git a/src/db/DatabasePrint.cxx b/src/db/DatabasePrint.cxx
index 7e31bf1da..bc86fc9c6 100644
--- a/src/db/DatabasePrint.cxx
+++ b/src/db/DatabasePrint.cxx
@@ -34,7 +34,7 @@ static void
 PrintDirectoryURI(Response &r, bool base,
 		  const LightDirectory &directory) noexcept
 {
-	r.Fmt(FMT_STRING("directory: {}\n"),
+	r.Fmt("directory: {}\n",
 	      ApplyBaseFlag(directory.GetPath(), base));
 }
 
@@ -64,10 +64,10 @@ print_playlist_in_directory(Response &r, bool base,
 			    const char *name_utf8) noexcept
 {
 	if (base || directory == nullptr)
-		r.Fmt(FMT_STRING("playlist: {}\n"),
+		r.Fmt("playlist: {}\n",
 		      ApplyBaseFlag(name_utf8, base));
 	else
-		r.Fmt(FMT_STRING("playlist: {}/{}\n"),
+		r.Fmt("playlist: {}/{}\n",
 		      directory, name_utf8);
 }
 
@@ -77,9 +77,9 @@ print_playlist_in_directory(Response &r, bool base,
 			    const char *name_utf8) noexcept
 {
 	if (base || directory == nullptr || directory->IsRoot())
-		r.Fmt(FMT_STRING("playlist: {}\n"), name_utf8);
+		r.Fmt("playlist: {}\n", name_utf8);
 	else
-		r.Fmt(FMT_STRING("playlist: {}/{}\n"),
+		r.Fmt("playlist: {}/{}\n",
 		      directory->GetPath(), name_utf8);
 }
 
@@ -183,7 +183,7 @@ PrintUniqueTags(Response &r, std::span<const TagType> tag_types,
 	tag_types = tag_types.subspan(1);
 
 	for (const auto &[key, tag] : map) {
-		r.Fmt(FMT_STRING("{}: {}\n"), name, key);
+		r.Fmt("{}: {}\n", name, key);
 
 		if (!tag_types.empty())
 			PrintUniqueTags(r, tag_types, tag);
diff --git a/src/decoder/DecoderPrint.cxx b/src/decoder/DecoderPrint.cxx
index 8015ab145..ea5d3ffa6 100644
--- a/src/decoder/DecoderPrint.cxx
+++ b/src/decoder/DecoderPrint.cxx
@@ -19,11 +19,11 @@ decoder_plugin_print(Response &r,
 
 	assert(plugin.name != nullptr);
 
-	r.Fmt(FMT_STRING("plugin: {}\n"), plugin.name);
+	r.Fmt("plugin: {}\n", plugin.name);
 
 	if (plugin.suffixes != nullptr)
 		for (p = plugin.suffixes; *p != nullptr; ++p)
-			r.Fmt(FMT_STRING("suffix: {}\n"), *p);
+			r.Fmt("suffix: {}\n", *p);
 
 	if (plugin.suffixes_function != nullptr)
 		for (const auto &i : plugin.suffixes_function())
@@ -31,7 +31,7 @@ decoder_plugin_print(Response &r,
 
 	if (plugin.mime_types != nullptr)
 		for (p = plugin.mime_types; *p != nullptr; ++p)
-			r.Fmt(FMT_STRING("mime_type: {}\n"), *p);
+			r.Fmt("mime_type: {}\n", *p);
 }
 
 void
diff --git a/src/ls.cxx b/src/ls.cxx
index f56816172..8f5a7418f 100644
--- a/src/ls.cxx
+++ b/src/ls.cxx
@@ -56,7 +56,7 @@ print_supported_uri_schemes(Response &r)
 	}
 
 	for (const auto& protocol : protocols) {
-		r.Fmt(FMT_STRING("handler: {}\n"), protocol);
+		r.Fmt("handler: {}\n", protocol);
 	}
 }
 
diff --git a/src/output/Print.cxx b/src/output/Print.cxx
index 9c6dbea33..bc32b535c 100644
--- a/src/output/Print.cxx
+++ b/src/output/Print.cxx
@@ -18,16 +18,16 @@ printAudioDevices(Response &r, const MultipleOutputs &outputs)
 	for (unsigned i = 0, n = outputs.Size(); i != n; ++i) {
 		const auto &ao = outputs.Get(i);
 
-		r.Fmt(FMT_STRING("outputid: {}\n"
-				 "outputname: {}\n"
-				 "plugin: {}\n"
-				 "outputenabled: {}\n"),
+		r.Fmt("outputid: {}\n"
+		       "outputname: {}\n"
+		       "plugin: {}\n"
+		       "outputenabled: {}\n",
 		      i,
 		      ao.GetName(), ao.GetPluginName(),
 		      (unsigned)ao.IsEnabled());
 
 		for (const auto &[attribute, value] : ao.GetAttributes())
-			r.Fmt(FMT_STRING("attribute: {}={}\n"),
+			r.Fmt("attribute: {}={}\n",
 			      attribute, value);
 	}
 }
diff --git a/src/output/plugins/PipeWireOutputPlugin.cxx b/src/output/plugins/PipeWireOutputPlugin.cxx
index 6c093ba05..8d391ba8d 100644
--- a/src/output/plugins/PipeWireOutputPlugin.cxx
+++ b/src/output/plugins/PipeWireOutputPlugin.cxx
@@ -666,7 +666,7 @@ PipeWireOutput::ParamChanged([[maybe_unused]] uint32_t id,
 				::SetVolume(*stream, channels, volume);
 			} catch (...) {
 				FmtError(pipewire_output_domain,
-					 FMT_STRING("Failed to restore volume: {}"),
+					 "Failed to restore volume: {}",
 					 std::current_exception());
 			}
 		}
diff --git a/src/queue/QueuePrint.cxx b/src/queue/QueuePrint.cxx
new file mode 100644
index 000000000..0ed6d1313
--- /dev/null
+++ b/src/queue/QueuePrint.cxx
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2003-2021 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 "QueuePrint.hxx"
+#include "Queue.hxx"
+#include "song/Filter.hxx"
+#include "SongPrint.hxx"
+#include "song/DetachedSong.hxx"
+#include "song/LightSong.hxx"
+#include "client/Response.hxx"
+
+#include <fmt/format.h>
+
+/**
+ * Send detailed information about a range of songs in the queue to a
+ * client.
+ *
+ * @param client the client which has requested information
+ * @param start the index of the first song (including)
+ * @param end the index of the last song (excluding)
+ */
+static void
+queue_print_song_info(Response &r, const Queue &queue,
+		      unsigned position)
+{
+	song_print_info(r, queue.Get(position));
+	r.Fmt("Pos: {}\nId: {}\n",
+	      position, queue.PositionToId(position));
+
+	uint8_t priority = queue.GetPriorityAtPosition(position);
+	if (priority != 0)
+		r.Fmt("Prio: {}\n", priority);
+}
+
+void
+queue_print_info(Response &r, const Queue &queue,
+		 unsigned start, unsigned end)
+{
+	assert(start <= end);
+	assert(end <= queue.GetLength());
+
+	for (unsigned i = start; i < end; ++i)
+		queue_print_song_info(r, queue, i);
+}
+
+void
+queue_print_uris(Response &r, const Queue &queue,
+		 unsigned start, unsigned end)
+{
+	assert(start <= end);
+	assert(end <= queue.GetLength());
+
+	for (unsigned i = start; i < end; ++i) {
+		r.Fmt("{}:", i);
+		song_print_uri(r, queue.Get(i));
+	}
+}
+
+void
+queue_print_changes_info(Response &r, const Queue &queue,
+			 uint32_t version,
+			 unsigned start, unsigned end)
+{
+	assert(start <= end);
+	assert(end <= queue.GetLength());
+
+	for (unsigned i = start; i < end; i++)
+		if (queue.IsNewerAtPosition(i, version))
+			queue_print_song_info(r, queue, i);
+}
+
+void
+queue_print_changes_position(Response &r, const Queue &queue,
+			     uint32_t version,
+			     unsigned start, unsigned end)
+{
+	assert(start <= end);
+	assert(end <= queue.GetLength());
+
+	for (unsigned i = start; i < end; i++)
+		if (queue.IsNewerAtPosition(i, version))
+			r.Fmt("cpos: {}\nId: {}\n",
+			      i, queue.PositionToId(i));
+}
+
+void
+queue_find(Response &r, const Queue &queue,
+	   const SongFilter &filter)
+{
+	for (unsigned i = 0; i < queue.GetLength(); i++) {
+		const LightSong song{queue.Get(i)};
+
+		if (filter.Match(song))
+			queue_print_song_info(r, queue, i);
+	}
+}
diff --git a/src/sticker/Print.cxx b/src/sticker/Print.cxx
index 31bb488d7..d40649efd 100644
--- a/src/sticker/Print.cxx
+++ b/src/sticker/Print.cxx
@@ -11,7 +11,7 @@ void
 sticker_print_value(Response &r,
 		    const char *name, const char *value)
 {
-	r.Fmt(FMT_STRING("sticker: {}={}\n"), name, value);
+	r.Fmt("sticker: {}={}\n", name, value);
 }
 
 void