extend/fix/improve operator overloads and methods for Timecode::BBT_Time
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 13 Sep 2017 21:12:51 +0000 (17:12 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 18 Sep 2017 15:40:53 +0000 (11:40 -0400)
libs/timecode/src/bbt_time.cc
libs/timecode/timecode/bbt_time.h

index 826f0cd91f9233487ec925f9b56f3bddb76f3c67..8ee6d1a3137ae4624e5241aa6082133ebb9e2b38 100644 (file)
@@ -29,15 +29,17 @@ using namespace Timecode;
    1/Nth divisions are integer numbers of ticks.
 
    1920 has many factors, though going up to 3840 gets a couple more.
    1/Nth divisions are integer numbers of ticks.
 
    1920 has many factors, though going up to 3840 gets a couple more.
+
+   This needs to match Evoral::Beats::PPQN
 */
 
 const double BBT_Time::ticks_per_beat = 1920.0;
 
 */
 
 const double BBT_Time::ticks_per_beat = 1920.0;
 
-BBT_Time::BBT_Time (double dbeats)
+BBT_Offset::BBT_Offset (double dbeats)
 {
        /* NOTE: this does not construct a BBT time in a canonical form,
           in that beats may be a very large number, and bars will
 {
        /* NOTE: this does not construct a BBT time in a canonical form,
           in that beats may be a very large number, and bars will
-          always be zero.
+          always be zero. Hence ... it's a BBT_Offset
        */
 
        assert (dbeats >= 0);
        */
 
        assert (dbeats >= 0);
index b3ba3a6b571c50d0b9b4571463298dd337be1180..b42ccf741e518a3950af37047f4f11fcc740ca66 100644 (file)
 #include <ostream>
 #include <stdint.h>
 #include <iomanip>
 #include <ostream>
 #include <stdint.h>
 #include <iomanip>
+#include <exception>
 
 #include "timecode/visibility.h"
 
 namespace Timecode {
 
 /** Bar, Beat, Tick Time (i.e. Tempo-Based Time) */
 
 #include "timecode/visibility.h"
 
 namespace Timecode {
 
 /** Bar, Beat, Tick Time (i.e. Tempo-Based Time) */
-struct LIBTIMECODE_API BBT_Time {
+struct LIBTIMECODE_API BBT_Time
+{
        static const double ticks_per_beat;
 
        static const double ticks_per_beat;
 
-       uint32_t bars;
-       uint32_t beats;
-       uint32_t ticks;
+       /* note that it is illegal for BBT_Time to have bars==0 or
+        * beats==0. The "neutral" or "default" value is 1|1|0
+        */
 
 
-       BBT_Time ()
-               : bars (1), beats (1), ticks (0) {}
+       int32_t bars;
+       int32_t beats;
+       int32_t ticks;
 
 
-       BBT_Time (uint32_t ba, uint32_t be, uint32_t t)
-               : bars (ba), beats (be), ticks (t) {}
+       struct IllegalBBTTimeException : public std::exception {
+               virtual const char* what() const throw() { return "illegal BBT time (bars or beats were zero)"; }
+       };
 
 
-       BBT_Time (double beats);
+       BBT_Time () : bars (1), beats (1), ticks (0) {}
+       BBT_Time (int32_t ba, uint32_t be, uint32_t t) : bars (ba), beats (be), ticks (t) { if (!bars || !beats) { throw IllegalBBTTimeException(); } }
 
        bool operator< (const BBT_Time& other) const {
                return bars < other.bars ||
 
        bool operator< (const BBT_Time& other) const {
                return bars < other.bars ||
@@ -74,6 +79,37 @@ struct LIBTIMECODE_API BBT_Time {
        bool operator!= (const BBT_Time& other) const {
                return bars != other.bars || beats != other.beats || ticks != other.ticks;
        }
        bool operator!= (const BBT_Time& other) const {
                return bars != other.bars || beats != other.beats || ticks != other.ticks;
        }
+
+       /* it would be nice to provide operator+(BBT_Time const&) and
+        * operator-(BBT_Time const&) but this math requires knowledge of the
+        * meter (time signature) used to define 1 bar, and so cannot be
+        * carried out with only two BBT_Time values.
+        */
+
+       BBT_Time round_to_beat () const { return ticks >= (ticks_per_beat/2) ? BBT_Time (bars, beats+1, 0) : BBT_Time (bars, beats, 0); }
+       BBT_Time round_down_to_beat () const { return BBT_Time (bars, beats, 0); }
+       BBT_Time round_up_to_beat () const { return ticks ? BBT_Time (bars, beats+1, 0) : *this; }
+
+       /* cannot implement round_to_bar() without knowing meter (time
+        * signature) information.
+        */
+};
+
+struct LIBTIMECODE_API BBT_Offset
+{
+       int32_t bars;
+       int32_t beats;
+       int32_t ticks;
+
+       /* this is a variant for which bars==0 and/or beats==0 is legal. It
+        * represents an offset from a given BBT_Time and is used when doing
+        * add/subtract operations on a BBT_Time.
+        */
+
+       BBT_Offset () : bars (0), beats (0), ticks (0) {}
+       BBT_Offset (int32_t ba, uint32_t be, uint32_t t) : bars (ba), beats (be), ticks (t) {}
+       BBT_Offset (BBT_Time const & bbt) : bars (bbt.bars), beats (bbt.beats), ticks (bbt.ticks) {}
+       BBT_Offset (double beats);
 };
 
 }
 };
 
 }
@@ -85,6 +121,13 @@ operator<< (std::ostream& o, const Timecode::BBT_Time& bbt)
        return o;
 }
 
        return o;
 }
 
+inline std::ostream&
+operator<< (std::ostream& o, const Timecode::BBT_Offset& bbt)
+{
+       o << bbt.bars << '|' << bbt.beats << '|' << bbt.ticks;
+       return o;
+}
+
 inline std::ostream&
 print_padded (std::ostream& o, const Timecode::BBT_Time& bbt)
 {
 inline std::ostream&
 print_padded (std::ostream& o, const Timecode::BBT_Time& bbt)
 {