From 224400074c61f667fb6d0d89d7170a4d04ba39b4 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 22 Sep 2018 19:24:34 +0200 Subject: [PATCH] player/CrossFade: use std::chrono::duration --- src/command/PlayerCommands.cxx | 14 +++++------ src/player/Control.cxx | 10 ++++---- src/player/Control.hxx | 8 +++---- src/player/CrossFade.cxx | 43 ++++++++++++++++++---------------- src/player/CrossFade.hxx | 5 ++-- src/player/Thread.cxx | 2 +- src/queue/PlaylistState.cxx | 10 ++++---- test/test_mixramp.cxx | 18 +++++++------- 8 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx index 27147f373..136baeb10 100644 --- a/src/command/PlayerCommands.cxx +++ b/src/command/PlayerCommands.cxx @@ -152,13 +152,13 @@ handle_status(Client &client, gcc_unused Request args, Response &r) pc.GetMixRampDb(), state); - if (pc.GetCrossFade() > 0) + if (pc.GetCrossFade() > FloatDuration::zero()) r.Format(COMMAND_STATUS_CROSSFADE ": %lu\n", - std::lround(pc.GetCrossFade())); + std::lround(pc.GetCrossFade().count())); - if (pc.GetMixRampDelay() > 0) + if (pc.GetMixRampDelay() > FloatDuration::zero()) r.Format(COMMAND_STATUS_MIXRAMPDELAY ": %f\n", - pc.GetMixRampDelay()); + pc.GetMixRampDelay().count()); song = playlist.GetCurrentPosition(); if (song >= 0) { @@ -316,8 +316,8 @@ handle_seekcur(Client &client, Request args, gcc_unused Response &r) CommandResult handle_crossfade(Client &client, Request args, gcc_unused Response &r) { - unsigned xfade_time = args.ParseUnsigned(0); - client.GetPlayerControl().SetCrossFade(xfade_time); + FloatDuration duration{args.ParseUnsigned(0)}; + client.GetPlayerControl().SetCrossFade(duration); return CommandResult::OK; } @@ -332,7 +332,7 @@ handle_mixrampdb(Client &client, Request args, gcc_unused Response &r) CommandResult handle_mixrampdelay(Client &client, Request args, gcc_unused Response &r) { - float delay_secs = args.ParseFloat(0); + FloatDuration delay_secs{args.ParseFloat(0)}; client.GetPlayerControl().SetMixRampDelay(delay_secs); return CommandResult::OK; } diff --git a/src/player/Control.cxx b/src/player/Control.cxx index 296b9c431..0b8a695e7 100644 --- a/src/player/Control.cxx +++ b/src/player/Control.cxx @@ -283,11 +283,9 @@ PlayerControl::LockSeek(std::unique_ptr song, SongTime t) } void -PlayerControl::SetCrossFade(float _cross_fade_seconds) noexcept +PlayerControl::SetCrossFade(FloatDuration duration) noexcept { - if (_cross_fade_seconds < 0) - _cross_fade_seconds = 0; - cross_fade.duration = _cross_fade_seconds; + cross_fade.duration = std::max(duration, FloatDuration::zero()); idle_add(IDLE_OPTIONS); } @@ -301,9 +299,9 @@ PlayerControl::SetMixRampDb(float _mixramp_db) noexcept } void -PlayerControl::SetMixRampDelay(float _mixramp_delay_seconds) noexcept +PlayerControl::SetMixRampDelay(FloatDuration _mixramp_delay) noexcept { - cross_fade.mixramp_delay = _mixramp_delay_seconds; + cross_fade.mixramp_delay = _mixramp_delay; idle_add(IDLE_OPTIONS); } diff --git a/src/player/Control.hxx b/src/player/Control.hxx index f2a85ce2a..3bcb05d58 100644 --- a/src/player/Control.hxx +++ b/src/player/Control.hxx @@ -557,9 +557,9 @@ private: } public: - void SetCrossFade(float cross_fade_seconds) noexcept; + void SetCrossFade(FloatDuration duration) noexcept; - float GetCrossFade() const noexcept { + auto GetCrossFade() const noexcept { return cross_fade.duration; } @@ -569,9 +569,9 @@ public: return cross_fade.mixramp_db; } - void SetMixRampDelay(float mixramp_delay_seconds) noexcept; + void SetMixRampDelay(FloatDuration mixramp_delay) noexcept; - float GetMixRampDelay() const noexcept { + auto GetMixRampDelay() const noexcept { return cross_fade.mixramp_delay; } diff --git a/src/player/CrossFade.cxx b/src/player/CrossFade.cxx index 82c11223c..b7c5787c4 100644 --- a/src/player/CrossFade.cxx +++ b/src/player/CrossFade.cxx @@ -33,10 +33,11 @@ static constexpr Domain cross_fade_domain("cross_fade"); gcc_pure -static float +static FloatDuration mixramp_interpolate(const char *ramp_list, float required_db) noexcept { - float last_db = 0, last_secs = 0; + float last_db = 0; + FloatDuration last_duration = FloatDuration::zero(); bool have_last = false; /* ramp_list is a string of pairs of dBs and seconds that describe the @@ -54,7 +55,7 @@ mixramp_interpolate(const char *ramp_list, float required_db) noexcept ramp_list = endptr + 1; /* Parse the time. */ - float secs = ParseFloat(ramp_list, &endptr); + FloatDuration duration{ParseFloat(ramp_list, &endptr)}; if (endptr == ramp_list || (*endptr != ';' && *endptr != 0)) break; @@ -64,27 +65,27 @@ mixramp_interpolate(const char *ramp_list, float required_db) noexcept /* Check for exact match. */ if (db == required_db) { - return secs; + return duration; } /* Save if too quiet. */ if (db < required_db) { last_db = db; - last_secs = secs; + last_duration = duration; have_last = true; continue; } /* If required db < any stored value, use the least. */ if (!have_last) - return secs; + return duration; /* Finally, interpolate linearly. */ - secs = last_secs + (required_db - last_db) * (secs - last_secs) / (db - last_db); - return secs; + duration = last_duration + (required_db - last_db) * (duration - last_duration) / (db - last_db); + return duration; } - return -1; + return FloatDuration(-1); } unsigned @@ -99,36 +100,38 @@ CrossFadeSettings::Calculate(SignedSongTime total_time, float chunks_f; if (total_time.IsNegative() || - duration < 0 || duration >= total_time.ToDoubleS() || + duration <= FloatDuration::zero() || + duration >= std::chrono::duration_cast(total_time) || /* we can't crossfade when the audio formats are different */ af != old_format) return 0; - assert(duration >= 0); + assert(duration > FloatDuration::zero()); assert(af.IsValid()); chunks_f = (float)af.GetTimeToSize() / (float)sizeof(MusicChunk::data); - if (mixramp_delay <= 0 || !mixramp_start || !mixramp_prev_end) { - chunks = std::lround(chunks_f * duration); + if (mixramp_delay <= FloatDuration::zero() || + !mixramp_start || !mixramp_prev_end) { + chunks = std::lround(chunks_f * duration.count()); } else { /* Calculate mixramp overlap. */ - const float mixramp_overlap_current = + const auto mixramp_overlap_current = mixramp_interpolate(mixramp_start, mixramp_db - replay_gain_db); - const float mixramp_overlap_prev = + const auto mixramp_overlap_prev = mixramp_interpolate(mixramp_prev_end, mixramp_db - replay_gain_prev_db); - const float mixramp_overlap = + const auto mixramp_overlap = mixramp_overlap_current + mixramp_overlap_prev; - if (mixramp_overlap_current >= 0 && - mixramp_overlap_prev >= 0 && + if (mixramp_overlap_current >= FloatDuration::zero() && + mixramp_overlap_prev >= FloatDuration::zero() && mixramp_delay <= mixramp_overlap) { - chunks = (chunks_f * (mixramp_overlap - mixramp_delay)); + chunks = (chunks_f * (mixramp_overlap - mixramp_delay).count()); FormatDebug(cross_fade_domain, "will overlap %d chunks, %fs", chunks, - mixramp_overlap - mixramp_delay); + (mixramp_overlap - mixramp_delay).count()); } } diff --git a/src/player/CrossFade.hxx b/src/player/CrossFade.hxx index 2bdd3f0a0..67effd1f0 100644 --- a/src/player/CrossFade.hxx +++ b/src/player/CrossFade.hxx @@ -20,6 +20,7 @@ #ifndef MPD_CROSSFADE_HXX #define MPD_CROSSFADE_HXX +#include "Chrono.hxx" #include "util/Compiler.h" struct AudioFormat; @@ -29,7 +30,7 @@ struct CrossFadeSettings { /** * The configured cross fade duration [s]. */ - float duration; + FloatDuration duration; float mixramp_db; @@ -37,7 +38,7 @@ struct CrossFadeSettings { * The configured MixRapm delay [s]. A non-positive value * disables MixRamp. */ - float mixramp_delay; + FloatDuration mixramp_delay; CrossFadeSettings() :duration(0), diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx index 9c8af5e90..ab0a35141 100644 --- a/src/player/Thread.cxx +++ b/src/player/Thread.cxx @@ -809,7 +809,7 @@ Player::PlayNextChunk() noexcept cross_fade_tag = Tag::Merge(std::move(cross_fade_tag), std::move(other_chunk->tag)); - if (pc.cross_fade.mixramp_delay <= 0) { + if (pc.cross_fade.mixramp_delay <= FloatDuration::zero()) { chunk->mix_ratio = ((float)cross_fade_position) / cross_fade_chunks; } else { diff --git a/src/queue/PlaylistState.cxx b/src/queue/PlaylistState.cxx index 33e701aca..f4b7bdef6 100644 --- a/src/queue/PlaylistState.cxx +++ b/src/queue/PlaylistState.cxx @@ -92,10 +92,10 @@ playlist_state_save(BufferedOutputStream &os, const struct playlist &playlist, (int)playlist.queue.single); os.Format(PLAYLIST_STATE_FILE_CONSUME "%i\n", playlist.queue.consume); os.Format(PLAYLIST_STATE_FILE_CROSSFADE "%i\n", - (int)pc.GetCrossFade()); + (int)pc.GetCrossFade().count()); os.Format(PLAYLIST_STATE_FILE_MIXRAMPDB "%f\n", pc.GetMixRampDb()); os.Format(PLAYLIST_STATE_FILE_MIXRAMPDELAY "%f\n", - pc.GetMixRampDelay()); + pc.GetMixRampDelay().count()); os.Write(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "\n"); queue_save(os, playlist.queue); os.Write(PLAYLIST_STATE_FILE_PLAYLIST_END "\n"); @@ -159,14 +159,14 @@ playlist_state_restore(const StateFileConfig &config, } else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_CONSUME))) { playlist.SetConsume(StringIsEqual(p, "1")); } else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_CROSSFADE))) { - pc.SetCrossFade(atoi(p)); + pc.SetCrossFade(FloatDuration(atoi(p))); } else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB))) { pc.SetMixRampDb(ParseFloat(p)); } else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY))) { /* this check discards "nan" which was used prior to MPD 0.18 */ if (IsDigitASCII(*p)) - pc.SetMixRampDelay(ParseFloat(p)); + pc.SetMixRampDelay(FloatDuration(ParseFloat(p))); } else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_RANDOM))) { random_mode = StringIsEqual(p, "1"); } else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_CURRENT))) { @@ -232,7 +232,7 @@ playlist_state_get_hash(const playlist &playlist, (playlist.current >= 0 ? (playlist.queue.OrderToPosition(playlist.current) << 16) : 0) ^ - ((int)pc.GetCrossFade() << 20) ^ + ((int)pc.GetCrossFade().count() << 20) ^ (unsigned(player_status.state) << 24) ^ /* note that this takes 2 bits */ ((int)playlist.queue.single << 25) ^ diff --git a/test/test_mixramp.cxx b/test/test_mixramp.cxx index ea245f72f..898452c89 100644 --- a/test/test_mixramp.cxx +++ b/test/test_mixramp.cxx @@ -23,53 +23,53 @@ public: char *foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(double(0), - mixramp_interpolate(foo, 0), + mixramp_interpolate(foo, 0).count(), 0.05); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(0), - mixramp_interpolate(foo, 1), + mixramp_interpolate(foo, 1).count(), 0.005); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(0.1), - mixramp_interpolate(foo, 3), + mixramp_interpolate(foo, 3).count(), 0.005); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(2.5), - mixramp_interpolate(foo, 6), + mixramp_interpolate(foo, 6).count(), 0.01); free(foo); foo = strdup(input); - CPPUNIT_ASSERT(mixramp_interpolate(foo, 6.1) < 0); + CPPUNIT_ASSERT(mixramp_interpolate(foo, 6.1) < FloatDuration::zero()); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(0.05), - mixramp_interpolate(foo, 2), + mixramp_interpolate(foo, 2).count(), 0.05); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(1.3), - mixramp_interpolate(foo, 4.5), + mixramp_interpolate(foo, 4.5).count(), 0.05); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(0.9), - mixramp_interpolate(foo, 4), + mixramp_interpolate(foo, 4).count(), 0.05); free(foo); foo = strdup(input); CPPUNIT_ASSERT_DOUBLES_EQUAL(float(1.7), - mixramp_interpolate(foo, 5), + mixramp_interpolate(foo, 5).count(), 0.05); free(foo); }