Skip to content

Instantly share code, notes, and snippets.

@cjxgm
Created August 31, 2014 05:42
Show Gist options
  • Save cjxgm/6ccdcb1197cc6ef063f9 to your computer and use it in GitHub Desktop.
Save cjxgm/6ccdcb1197cc6ef063f9 to your computer and use it in GitHub Desktop.
bnd timecode: beat + numer/denom
#include <stdexcept>
#include <iostream>
#include <chrono>
using std::cout;
using std::endl;
// numer
// beat + ------- = beat (add) numer (over) denom -> band or bnd
// denom
// must NOT reduce!
struct bnd
{
using beat_type = int;
using numer_type = int;
using denom_type = numer_type;
beat_type b = 0;
numer_type n = 0;
denom_type d = 1;
bnd() = default;
bnd(beat_type b_, numer_type n_, denom_type d_)
: b{b_}, n{n_}, d{d_}
{
if (!d_) throw std::invalid_argument{"denominator cannot be zero."};
b += n / d;
n %= d;
}
explicit operator double() const { return b + double(n)/d; }
};
bool operator<(bnd const& a, bnd const& b)
{
if (a.b < b.b) return true;
if (a.b > b.b) return false;
return (a.n*b.d < b.n*a.d);
}
template <class T>
decltype(auto) operator*(bnd const& time, T b)
{
static_assert(std::is_integral<T>(),
"a bnd can only be mutiplied by an integral.");
return b*time.b + b*time.n / time.d;
}
bool operator==(bnd const& a, bnd const& b)
{
return (a.b == b.b && a.n*b.d == b.n*a.d);
}
std::ostream& operator<<(std::ostream& o, bnd const& time)
{
o << time.b << "+" << time.n << "/" << time.d;
return o;
}
template <class Duration>
Duration bnd_to_time(bnd const& b, int bpm)
{
using rep = typename Duration::rep;
using period = typename Duration::period;
return Duration((b * period::den) * 60 / period::num / bpm);
}
int main()
{
bnd a{1, 8, 6};
bnd b{1, 4, 3};
cout << a << " == " << b << " -> " << (a == b) << endl;
cout << a << " < " << b << " -> " << (a < b) << endl;
cout << double(a) << endl;
cout << double(b) << endl;
cout << a*2 << endl;
cout << a*3 << endl;
cout << a*4 << endl;
cout << a*5 << endl;
cout << a*6 << endl;
cout << a*10000 << endl;
cout << double(a)*1.2 << endl;
cout << a << "beat at 72bpm = "
<< bnd_to_time<std::chrono::milliseconds>(a, 72).count()
<< "ms" << endl;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment