Fix non-frame-aligned trims when using trim-to-playhead.
authorCarl Hetherington <cth@carlh.net>
Wed, 4 Jan 2017 21:41:07 +0000 (21:41 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 4 Jan 2017 21:41:07 +0000 (21:41 +0000)
Reimplement Time::ceil and add a corresponding Time::floor with tests.
ceil returns slightly different results to previously with non-integer
frame rates.

Then use floor to round the playhead position when trimming.

ChangeLog
src/lib/dcpomatic_time.h
src/wx/film_viewer.h
src/wx/timing_panel.cc
test/util_test.cc

index efc8f7d..3b631c2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-01-04  Carl Hetherington  <cth@carlh.net>
+
+       * Fix non frame-aligned trims when using the to-playhead
+       buttons.
+
 2016-12-25  Carl Hetherington  <cth@carlh.net>
 
        * Updated fr_FR translation from Thierry Journet.
index 6834ee0..16d93ca 100644 (file)
@@ -119,9 +119,11 @@ public:
         *  @param r Sampling rate.
         */
        Time<S, O> ceil (float r) const {
-               Type const n = llrintf (HZ / r);
-               Type const a = _t + n - 1;
-               return Time<S, O> (a - (a % n));
+               return Time<S, O> (llrint (HZ * frames_ceil(r) / double(r)));
+       }
+
+       Time<S, O> floor (float r) const {
+               return Time<S, O> (llrint (HZ * frames_floor(r) / double(r)));
        }
 
        double seconds () const {
@@ -143,7 +145,7 @@ public:
 
        template <typename T>
        int64_t frames_floor (T r) const {
-               return floor (_t * r / HZ);
+               return ::floor (_t * r / HZ);
        }
 
        template <typename T>
@@ -212,6 +214,7 @@ public:
 
 private:
        friend struct dcptime_ceil_test;
+       friend struct dcptime_floor_test;
 
        Type _t;
        static const int HZ = 96000;
index a67820a..aa588b9 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -41,6 +41,7 @@ public:
 
        void set_film (boost::shared_ptr<Film>);
 
+       /** @return our `playhead' position; this may not lie exactly on a frame boundary */
        DCPTime position () const {
                return _position;
        }
index bd4177f..d7ed46f 100644 (file)
@@ -441,14 +441,15 @@ TimingPanel::film_changed (Film::Property p)
 void
 TimingPanel::trim_start_to_playhead_clicked ()
 {
-       DCPTime const ph = _viewer->position ();
+       shared_ptr<const Film> film = _parent->film ();
+       DCPTime const ph = _viewer->position().floor (film->video_frame_rate ());
        optional<DCPTime> new_ph;
 
        _viewer->set_coalesce_player_changes (true);
 
        BOOST_FOREACH (shared_ptr<Content> i, _parent->selected ()) {
                if (i->position() < ph && ph < i->end ()) {
-                       FrameRateChange const frc = _parent->film()->active_frame_rate_change (i->position ());
+                       FrameRateChange const frc = film->active_frame_rate_change (i->position ());
                        i->set_trim_start (i->trim_start() + ContentTime (ph - i->position (), frc));
                        new_ph = i->position ();
                }
@@ -464,10 +465,11 @@ TimingPanel::trim_start_to_playhead_clicked ()
 void
 TimingPanel::trim_end_to_playhead_clicked ()
 {
-       DCPTime const ph = _viewer->position ();
+       shared_ptr<const Film> film = _parent->film ();
+       DCPTime const ph = _viewer->position().floor (film->video_frame_rate ());
        BOOST_FOREACH (shared_ptr<Content> i, _parent->selected ()) {
                if (i->position() < ph && ph < i->end ()) {
-                       FrameRateChange const frc = _parent->film()->active_frame_rate_change (i->position ());
+                       FrameRateChange const frc = film->active_frame_rate_change (i->position ());
                        i->set_trim_end (ContentTime (i->position() + i->full_length() - ph - DCPTime::from_frames (1, frc.dcp), frc) - i->trim_start());
                }
        }
index c7bf994..334811c 100644 (file)
@@ -65,7 +65,24 @@ BOOST_AUTO_TEST_CASE (dcptime_ceil_test)
        BOOST_CHECK_EQUAL (DCPTime(43).ceil(DCPTime::HZ / 42).get(), 84);
 
        /* Check that rounding up to non-integer frame rates works */
-       BOOST_CHECK_EQUAL (DCPTime(45312).ceil(29.976).get(), 48045);
+       BOOST_CHECK_EQUAL (DCPTime(45312).ceil(29.976).get(), 48038);
+}
+
+/* Straightforward test of DCPTime::floor */
+BOOST_AUTO_TEST_CASE (dcptime_floor_test)
+{
+       BOOST_CHECK_EQUAL (DCPTime(0).floor(DCPTime::HZ / 2).get(), 0);
+       BOOST_CHECK_EQUAL (DCPTime(1).floor(DCPTime::HZ / 2).get(), 0);
+       BOOST_CHECK_EQUAL (DCPTime(2).floor(DCPTime::HZ / 2).get(), 2);
+       BOOST_CHECK_EQUAL (DCPTime(3).floor(DCPTime::HZ / 2).get(), 2);
+
+       BOOST_CHECK_EQUAL (DCPTime(0).floor(DCPTime::HZ / 42).get(), 0);
+       BOOST_CHECK_EQUAL (DCPTime(1).floor(DCPTime::HZ / 42).get(), 0);
+       BOOST_CHECK_EQUAL (DCPTime(42).floor(DCPTime::HZ / 42.0).get(), 42);
+       BOOST_CHECK_EQUAL (DCPTime(43).floor(DCPTime::HZ / 42.0).get(), 42);
+
+       /* Check that rounding down to non-integer frame rates works */
+       BOOST_CHECK_EQUAL (DCPTime(45312).floor(29.976).get(), 44836);
 }
 
 BOOST_AUTO_TEST_CASE (timecode_test)