From d3d1d37782952e9b1142a4735635aac3dd2db466 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Fri, 21 Sep 2018 19:32:35 +0200
Subject: [PATCH] AudioFormat: add TimeToSize(), SizeToTime()

---
 src/AudioFormat.hxx                           | 24 +++++++++++++++++++
 src/decoder/Bridge.cxx                        |  3 +--
 .../plugins/HybridDsdDecoderPlugin.cxx        |  2 +-
 src/decoder/plugins/Mpg123DecoderPlugin.cxx   |  3 +--
 src/player/Thread.cxx                         |  2 +-
 5 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/src/AudioFormat.hxx b/src/AudioFormat.hxx
index 8b0ffb557..8c9cda3e3 100644
--- a/src/AudioFormat.hxx
+++ b/src/AudioFormat.hxx
@@ -23,6 +23,8 @@
 #include "pcm/SampleFormat.hxx"
 #include "util/Compiler.h"
 
+#include <chrono>
+
 #include <stdint.h>
 #include <stddef.h>
 
@@ -152,6 +154,28 @@ struct AudioFormat {
 	 * span to a storage size in bytes.
 	 */
 	double GetTimeToSize() const;
+
+	template<typename D>
+	constexpr auto TimeToFrames(D t) const noexcept {
+		using Period = typename D::period;
+		return ((t.count() * sample_rate) / Period::den) * Period::num;
+	}
+
+	template<typename D>
+	constexpr size_t TimeToSize(D t) const noexcept {
+		return size_t(size_t(TimeToFrames(t)) * GetFrameSize());
+	}
+
+	template<typename D>
+	constexpr D FramesToTime(std::uintmax_t size) const noexcept {
+		using Period = typename D::period;
+		return D(((size / Period::num) * Period::den) / sample_rate);
+	}
+
+	template<typename D>
+	constexpr D SizeToTime(std::uintmax_t size) const noexcept {
+		return FramesToTime<D>(size / GetFrameSize());
+	}
 };
 
 /**
diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx
index 08a3c51d5..4df66553b 100644
--- a/src/decoder/Bridge.cxx
+++ b/src/decoder/Bridge.cxx
@@ -532,8 +532,7 @@ DecoderBridge::SubmitData(InputStream *is,
 		data = (const uint8_t *)data + nbytes;
 		length -= nbytes;
 
-		timestamp += FloatDuration((double)nbytes /
-					   dc.out_audio_format.GetTimeToSize());
+		timestamp += dc.out_audio_format.SizeToTime<FloatDuration>(nbytes);
 	}
 
 	absolute_frame += data_frames;
diff --git a/src/decoder/plugins/HybridDsdDecoderPlugin.cxx b/src/decoder/plugins/HybridDsdDecoderPlugin.cxx
index ec04aee9d..3cad55470 100644
--- a/src/decoder/plugins/HybridDsdDecoderPlugin.cxx
+++ b/src/decoder/plugins/HybridDsdDecoderPlugin.cxx
@@ -183,7 +183,7 @@ HybridDsdDecode(DecoderClient &client, InputStream &input)
 
 	try {
 		auto result = FindHybridDsdData(client, input);
-		auto duration = SignedSongTime::FromS(result.second / result.first.GetTimeToSize());
+		auto duration = result.first.SizeToTime<SignedSongTime>(result.second);
 		client.Ready(result.first, true, duration);
 		frame_size = result.first.GetFrameSize();
 		kbit_rate = frame_size * result.first.sample_rate /
diff --git a/src/decoder/plugins/Mpg123DecoderPlugin.cxx b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
index 3a51f616a..0fd63b068 100644
--- a/src/decoder/plugins/Mpg123DecoderPlugin.cxx
+++ b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
@@ -264,8 +264,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
 				client.SeekError();
 			else {
 				client.CommandFinished();
-				client.SubmitTimestamp(FloatDuration(c)
-						       / audio_format.sample_rate);
+				client.SubmitTimestamp(audio_format.FramesToTime<FloatDuration>(c));
 			}
 
 			cmd = DecoderCommand::NONE;
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 9be121cb7..9c8af5e90 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -766,7 +766,7 @@ PlayerControl::PlayChunk(DetachedSong &song, MusicChunkPtr chunk,
 	const double chunk_length(chunk->length);
 
 	outputs.Play(std::move(chunk));
-	total_play_time += FloatDuration(chunk_length / format.GetTimeToSize());
+	total_play_time += format.SizeToTime<decltype(total_play_time)>(chunk_length);
 }
 
 inline bool