diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2017-09-13 19:31:42 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2017-09-18 11:40:54 -0400 |
commit | cba53a20233531ef3e6c3692993eac8f74e991a1 (patch) | |
tree | dc5655c4bfe367842804200bfef0b2dcc57d770b /libs/evoral | |
parent | e37558502eabc54768b0858fb611aeba40d1fc9e (diff) |
add _locked() variants to new tempo experiment
Diffstat (limited to 'libs/evoral')
-rw-r--r-- | libs/evoral/evoral/Beats.hpp.orig | 247 | ||||
-rw-r--r-- | libs/evoral/test/BeatsTest.cpp | 170 | ||||
-rw-r--r-- | libs/evoral/test/BeatsTest.hpp | 22 | ||||
-rw-r--r-- | libs/evoral/wscript.orig | 168 |
4 files changed, 607 insertions, 0 deletions
diff --git a/libs/evoral/evoral/Beats.hpp.orig b/libs/evoral/evoral/Beats.hpp.orig new file mode 100644 index 0000000000..e0277c4b3d --- /dev/null +++ b/libs/evoral/evoral/Beats.hpp.orig @@ -0,0 +1,247 @@ +/* This file is part of Evoral. + * Copyright (C) 2008-2015 David Robillard <http://drobilla.net> + * Copyright (C) 2000-2008 Paul Davis + * + * Evoral is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef EVORAL_BEATS_HPP +#define EVORAL_BEATS_HPP + +#include <float.h> +#include <math.h> +#include <stdint.h> + +#include <iostream> +#include <limits> + +#include "evoral/visibility.h" + +namespace Evoral { + +/** Musical time in beats. */ +class /*LIBEVORAL_API*/ Beats { +public: + LIBEVORAL_API static const double PPQN; + + Beats() : _time(0.0) {} + + /** Create from a real number of beats. */ + explicit Beats(double time) : _time(time) {} + + /** Create from an integer number of beats. */ + static Beats beats(int32_t beats) { + return Beats((double)beats); + } + + /** Create from ticks at the standard PPQN. */ + static Beats ticks(uint32_t ticks) { + return Beats(ticks / PPQN); + } + + /** Create from ticks at a given rate. + * + * Note this can also be used to create from frames by setting ppqn to the + * number of samples per beat. + */ + static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn) { + return Beats((double)ticks / (double)ppqn); + } + + Beats& operator=(const Beats& other) { + _time = other._time; + return *this; + } + + Beats round_up_to_beat() const { + return Evoral::Beats(ceil(_time)); + } + + Beats round_down_to_beat() const { + return Evoral::Beats(floor(_time)); + } + + Beats snap_to(const Evoral::Beats& snap) const { + return Beats(ceil(_time / snap._time) * snap._time); + } + + inline bool operator==(const Beats& b) const { + /* Acceptable tolerance is 1 tick. */ + return fabs(_time - b._time) <= (1.0 / PPQN); + } + + inline bool operator==(double t) const { + /* Acceptable tolerance is 1 tick. */ + return fabs(_time - t) <= (1.0 / PPQN); + } + + inline bool operator==(int beats) const { + /* Acceptable tolerance is 1 tick. */ + return fabs(_time - beats) <= (1.0 / PPQN); + } + + inline bool operator!=(const Beats& b) const { + return !operator==(b); + } + + inline bool operator<(const Beats& b) const { + /* Acceptable tolerance is 1 tick. */ + if (fabs(_time - b._time) <= (1.0 / PPQN)) { + return false; /* Effectively identical. */ + } else { + return _time < b._time; + } + } + + inline bool operator<=(const Beats& b) const { + return operator==(b) || operator<(b); + } + + inline bool operator>(const Beats& b) const { + /* Acceptable tolerance is 1 tick. */ + if (fabs(_time - b._time) <= (1.0 / PPQN)) { + return false; /* Effectively identical. */ + } else { + return _time > b._time; + } + } + + inline bool operator>=(const Beats& b) const { + return operator==(b) || operator>(b); + } + + inline bool operator<(double b) const { + /* Acceptable tolerance is 1 tick. */ + if (fabs(_time - b) <= (1.0 / PPQN)) { + return false; /* Effectively identical. */ + } else { + return _time < b; + } + } + + inline bool operator<=(double b) const { + return operator==(b) || operator<(b); + } + + inline bool operator>(double b) const { + /* Acceptable tolerance is 1 tick. */ + if (fabs(_time - b) <= (1.0 / PPQN)) { + return false; /* Effectively identical. */ + } else { + return _time > b; + } + } + + inline bool operator>=(double b) const { + return operator==(b) || operator>(b); + } + + Beats operator+(const Beats& b) const { + return Beats(_time + b._time); + } + + Beats operator-(const Beats& b) const { + return Beats(_time - b._time); + } + + Beats operator+(double d) const { + return Beats(_time + d); + } + + Beats operator-(double d) const { + return Beats(_time - d); + } + + Beats operator-() const { + return Beats(-_time); + } + + template<typename Number> + Beats operator*(Number factor) const { + return Beats(_time * factor); + } + + Beats& operator+=(const Beats& b) { + _time += b._time; + return *this; + } + + Beats& operator-=(const Beats& b) { + _time -= b._time; + return *this; + } + + double to_double() const { return _time; } + uint64_t to_ticks() const { return lrint(_time * PPQN); } + uint64_t to_ticks(uint32_t ppqn) const { return lrint(_time * ppqn); } + + uint32_t get_beats() const { return floor(_time); } + uint32_t get_ticks() const { return (uint32_t)lrint(fmod(_time, 1.0) * PPQN); } + + bool operator!() const { return _time == 0; } + + static Beats min() { return Beats(DBL_MIN); } + static Beats max() { return Beats(DBL_MAX); } + static Beats tick() { return Beats(1.0 / PPQN); } + +private: + double _time; +}; + +extern LIBEVORAL_API const Beats MaxBeats; +extern LIBEVORAL_API const Beats MinBeats; + +/* + TIL, several horrible hours later, that sometimes the compiler looks in the + namespace of a type (Evoral::Beats in this case) for an operator, and + does *NOT* look in the global namespace. + + C++ is proof that hell exists and we are living in it. In any case, move + these to the global namespace and PBD::Property's loopy + virtual-method-in-a-template will bite you. +*/ + +inline std::ostream& +operator<<(std::ostream& os, const Beats& t) +{ + os << t.to_double(); + return os; +} + +inline std::istream& +operator>>(std::istream& is, Beats& t) +{ + double beats; + is >> beats; + t = Beats(beats); + return is; +} + +} // namespace Evoral + +namespace PBD { + namespace DEBUG { + LIBEVORAL_API extern uint64_t Beats; + } +} + +namespace std { + template<> + struct numeric_limits<Evoral::Beats> { + static Evoral::Beats min() { return Evoral::Beats::min(); } + static Evoral::Beats max() { return Evoral::Beats::max(); } + }; +} + +#endif // EVORAL_BEATS_HPP diff --git a/libs/evoral/test/BeatsTest.cpp b/libs/evoral/test/BeatsTest.cpp new file mode 100644 index 0000000000..0e3d29a6c6 --- /dev/null +++ b/libs/evoral/test/BeatsTest.cpp @@ -0,0 +1,170 @@ +#include <stdlib.h> + +#include "BeatsTest.hpp" +#include "evoral/Beats.hpp" + +CPPUNIT_TEST_SUITE_REGISTRATION(BeatsTest); + +using namespace Evoral; + +static const double delta = 1.5 / (double)Beats::PPQN; + +void +BeatsTest::createTest() +{ + const Beats a(1, 2); + CPPUNIT_ASSERT_EQUAL(1, a.get_beats()); + CPPUNIT_ASSERT_EQUAL(2, a.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1 + 2 / (double)Beats::PPQN, a.to_double(), delta); + + const Beats b(1.5); + CPPUNIT_ASSERT_EQUAL(1, b.get_beats()); + CPPUNIT_ASSERT_EQUAL(Beats::PPQN / 2, b.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.5, b.to_double(), delta); + + const Beats c = Beats::beats(6); + CPPUNIT_ASSERT_EQUAL(6, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(0, c.get_ticks()); + + const Beats d = Beats::ticks(7); + CPPUNIT_ASSERT_EQUAL(0, d.get_beats()); + CPPUNIT_ASSERT_EQUAL(7, d.get_ticks()); + + Beats e(8, 9); + e = d; + CPPUNIT_ASSERT_EQUAL(d, e); + + + // const Beats diff = n2 - n1; + // CPPUNIT_ASSERT_EQUAL(-44, diff.get_beats()); + // CPPUNIT_ASSERT_EQUAL(44 / Beats::PPQN, diff.get_ticks()); + // CPPUNIT_ASSERT_DOUBLES_EQUAL(diff.to_double(), -44.44, delta); +} + +void +BeatsTest::addTest() +{ + const Beats a(1, 2); + const Beats b(3, 4); + + // Positive + positive + const Beats c = a + b; + CPPUNIT_ASSERT_EQUAL(4, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(6, c.get_ticks()); + + const Beats n1(-12.34); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-12.34, n1.to_double(), delta); + + const Beats n2(-56.78); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-56.78, n2.to_double(), delta); + + // Positive + negative + const Beats p1(1.0); + const Beats p_n = p1 + n1; + CPPUNIT_ASSERT_EQUAL(-11, p_n.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.34), p_n.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.34, p_n.to_double(), delta); + + // Negative + positive + const Beats n_p = n1 + p1; + CPPUNIT_ASSERT_EQUAL(-11, n_p.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.34), n_p.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-11.34, n_p.to_double(), delta); + + // Negative + negative + const Beats sum = n1 + n2; + CPPUNIT_ASSERT_EQUAL(-69, sum.get_beats()); + //CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.12), n_p.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-69.12, sum.to_double(), delta); +} + +void +BeatsTest::subtractTest() +{ + const Beats a(1, 2); + const Beats b(3, 4); + + // Positive - positive + const Beats c = b - a; + CPPUNIT_ASSERT_EQUAL(2, c.get_beats()); + CPPUNIT_ASSERT_EQUAL(2, c.get_ticks()); + + const Beats n1(-12.34); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-12.34, n1.to_double(), delta); + + const Beats n2(-56.78); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-56.78, n2.to_double(), delta); + + // Positive - negative + const Beats p1(1.0); + const Beats p_n = p1 - n1; + CPPUNIT_ASSERT_EQUAL(13, p_n.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * 0.34), p_n.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(13.34, p_n.to_double(), delta); + + // Negative - positive + const Beats n_p = n1 - p1; + CPPUNIT_ASSERT_EQUAL(-13, n_p.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)(Beats::PPQN * -0.34), n_p.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-13.34, n_p.to_double(), delta); + + // Negative - negative + const Beats diff = n1 - n2; + CPPUNIT_ASSERT_EQUAL(44, diff.get_beats()); + CPPUNIT_ASSERT_EQUAL((int32_t)lrint(Beats::PPQN * 0.44), diff.get_ticks()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(44.44, diff.to_double(), delta); +} + +void +BeatsTest::multiplyTest() +{ + CPPUNIT_ASSERT_DOUBLES_EQUAL(3.0, (Beats(1.5) * 2.0).to_double(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-10.0, (Beats(5.0) * -2.0).to_double(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-10.0, (Beats(-5.0) * 2.0).to_double(), delta); +} + +void +BeatsTest::roundTest() +{ + Beats a(1, 1); + + // Round a up + const Beats au = a.round_up_to_beat(); + CPPUNIT_ASSERT_EQUAL(au.get_beats(), 2); + CPPUNIT_ASSERT_EQUAL(au.get_ticks(), 0); + + // Round a down + const Beats ad = a.round_down_to_beat(); + CPPUNIT_ASSERT_EQUAL(ad.get_beats(), 1); + CPPUNIT_ASSERT_EQUAL(ad.get_ticks(), 0); + + // Round result down again + const Beats add = ad.round_down_to_beat(); + CPPUNIT_ASSERT_EQUAL(ad, add); + + // Round result up + const Beats adu = ad.round_up_to_beat(); + CPPUNIT_ASSERT_EQUAL(ad, adu); + + // Snap to 1.5 + const Beats snapped = a.snap_to(Beats(1.5)); + CPPUNIT_ASSERT_EQUAL(snapped.get_beats(), 1); + CPPUNIT_ASSERT_EQUAL(snapped.get_ticks(), Beats::PPQN / 2); +} + +void +BeatsTest::convertTest() +{ + const Beats a = Beats::ticks_at_rate(72000, 48000); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1, a.get_beats(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(Beats::PPQN / 2, a.get_ticks(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(1.5, a.to_double(), delta); + + const Beats b = Beats::ticks_at_rate(8, 48000); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0, b.get_beats(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL(Beats::PPQN * 8 / 48000, b.get_ticks(), delta); + CPPUNIT_ASSERT_DOUBLES_EQUAL((8 / 48000.0), b.to_double(), delta); + + CPPUNIT_ASSERT_EQUAL(int64_t(1.5 * Beats::PPQN), a.to_ticks()); + CPPUNIT_ASSERT_EQUAL(int64_t(1.5 * 192), a.to_ticks(192)); +} diff --git a/libs/evoral/test/BeatsTest.hpp b/libs/evoral/test/BeatsTest.hpp new file mode 100644 index 0000000000..0db3831b49 --- /dev/null +++ b/libs/evoral/test/BeatsTest.hpp @@ -0,0 +1,22 @@ +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +class BeatsTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(BeatsTest); + CPPUNIT_TEST(createTest); + CPPUNIT_TEST(addTest); + CPPUNIT_TEST(subtractTest); + CPPUNIT_TEST(multiplyTest); + CPPUNIT_TEST(convertTest); + CPPUNIT_TEST(roundTest); + CPPUNIT_TEST_SUITE_END(); + +public: + void createTest(); + void addTest(); + void subtractTest(); + void multiplyTest(); + void convertTest(); + void roundTest(); +}; diff --git a/libs/evoral/wscript.orig b/libs/evoral/wscript.orig new file mode 100644 index 0000000000..9ceab182a5 --- /dev/null +++ b/libs/evoral/wscript.orig @@ -0,0 +1,168 @@ +#!/usr/bin/env python +from waflib.extras import autowaf as autowaf +from waflib import Options +import os + +# Version of this package (even if built as a child) +EVORAL_VERSION = '0.0.0' + +# Library version (UNIX style major, minor, micro) +# major increment <=> incompatible changes +# minor increment <=> compatible changes (additions) +# micro increment <=> no interface changes +# Version history: +# 0.0.0 = 0,0,0 +EVORAL_LIB_VERSION = '0.0.0' + +# Variables for 'waf dist' +APPNAME = 'evoral' +VERSION = EVORAL_VERSION + +# Mandatory variables +top = '.' +out = 'build' + +def options(opt): + opt.load('compiler_c') + opt.load('compiler_cxx') + autowaf.set_options(opt) + opt.add_option('--test', action='store_true', default=False, dest='build_tests', + help="Build unit tests") + opt.add_option('--test-coverage', action='store_true', default=False, dest='test_coverage', + help="Use gcov to test for code coverage") + opt.add_option('--internal-shared-libs', action='store_true', default=True, dest='internal_shared_libs', + help='Build internal libs as shared libraries') + +def configure(conf): + conf.load('compiler_c') + conf.load('compiler_cxx') + autowaf.configure(conf) + #autowaf.display_header('Evoral Configuration') + + autowaf.check_pkg(conf, 'cppunit', uselib_store='CPPUNIT', atleast_version='1.12.0', mandatory=False) + autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.2') + autowaf.check_pkg(conf, 'glibmm-2.4', uselib_store='GLIBMM', atleast_version='2.14.0') + autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD', atleast_version='2.14.0') + if not autowaf.is_child(): + autowaf.check_pkg(conf, 'libpbd-4', uselib_store='LIBPBD', atleast_version='4.0.0', mandatory=True) + + # Boost headers + autowaf.check_header(conf, 'cxx', 'boost/shared_ptr.hpp') + autowaf.check_header(conf, 'cxx', 'boost/weak_ptr.hpp') + + conf.env['BUILD_TESTS'] = Options.options.build_tests + conf.env['TEST_COVERAGE'] = Options.options.test_coverage + + if Options.options.internal_shared_libs: + conf.define('INTERNAL_SHARED_LIBS', 1) + #autowaf.display_msg(conf, "Unit tests", str(conf.env['BUILD_TESTS'])) + #print + +def build(bld): + # Headers + #bld.install_files('${INCLUDEDIR}/evoral', 'evoral/*.h') + #bld.install_files('${INCLUDEDIR}/evoral', 'evoral/*.hpp') + + # Pkgconfig file + #autowaf.build_pc(bld, 'EVORAL', EVORAL_VERSION, 'GLIBMM GTHREAD') + + libsmf = bld(features = 'c cstlib') + libsmf.source = ''' + src/libsmf/smf.c + src/libsmf/smf_decode.c + src/libsmf/smf_load.c + src/libsmf/smf_save.c + src/libsmf/smf_tempo.c + ''' + libsmf.export_includes = ['./src/libsmf'] + libsmf.defines = ['SMF_VERSION="1.2"', 'LIBSMF_DLL_EXPORTS'] + libsmf.includes = ['./src'] + libsmf.name = 'libsmf' + libsmf.target = 'smf' + libsmf.uselib = 'GLIB' + libsmf.install_path = None + if bld.env['build_target'] != 'mingw': + libsmf.cxxflags = [ '-fPIC' ] + libsmf.cflags = [ '-fPIC' ] + + lib_source = ''' + src/Control.cpp + src/ControlList.cpp + src/ControlSet.cpp + src/Curve.cpp + src/Event.cpp + src/Note.cpp + src/SMF.cpp + src/Sequence.cpp + src/TimeConverter.cpp + src/debug.cpp + src/types.cpp + ''' + + # Library + if bld.is_defined ('INTERNAL_SHARED_LIBS'): + obj = bld.shlib(features = 'c cxx cshlib cxxshlib', source=lib_source) + # DLL exports for this library + obj.defines = [ 'LIBEVORAL_DLL_EXPORTS' ] + else: + obj = bld.stlib(features = 'c cxx cstlib cxxstlib', source=lib_source) + obj.cxxflags = [ '-fPIC' ] + obj.cflags = [ '-fPIC' ] + obj.defines = [ ] + + obj.export_includes = ['.'] + obj.includes = ['.', './src'] + obj.name = 'libevoral' + obj.target = 'evoral' + obj.uselib = 'GLIBMM GTHREAD SMF XML LIBPBD' + obj.use = 'libsmf libpbd' + obj.vnum = EVORAL_LIB_VERSION + obj.install_path = bld.env['LIBDIR'] + obj.defines += [ 'PACKAGE="libevoral"' ] + + if bld.env['BUILD_TESTS'] and bld.is_defined('HAVE_CPPUNIT'): + # Static library (for unit test code coverage) + obj = bld(features = 'cxx cstlib') + obj.source = lib_source + obj.export_includes = ['.'] + obj.includes = ['.', './src'] + obj.name = 'libevoral_static' + obj.target = 'evoral_static' + obj.uselib = 'GLIBMM GTHREAD SMF XML LIBPBD' + obj.use = 'libsmf libpbd' + obj.vnum = EVORAL_LIB_VERSION + obj.install_path = '' + if bld.env['TEST_COVERAGE']: + obj.linkflags = ['--coverage'] + obj.cflags = ['--coverage'] + obj.cxxflags = ['--coverage'] + obj.defines = ['PACKAGE="libevoral"'] + + # Unit tests + obj = bld(features = 'cxx cxxprogram') + obj.source = ''' + test/SequenceTest.cpp + test/SMFTest.cpp + test/RangeTest.cpp + test/NoteTest.cpp + test/CurveTest.cpp + test/testrunner.cpp + ''' + obj.includes = ['.', './src'] + obj.use = 'libevoral_static' + obj.uselib = 'CPPUNIT SNDFILE LIBPBD' + obj.target = 'run-tests' + obj.name = 'libevoral-tests' + obj.install_path = '' + obj.defines = ['PACKAGE="libevoraltest"'] + if bld.env['TEST_COVERAGE']: + obj.linkflags = ['--coverage'] + obj.cflags = ['--coverage'] + obj.cxxflags = ['--coverage'] + +def test(ctx): + autowaf.pre_test(ctx, APPNAME) + print(os.getcwd()) + os.environ['EVORAL_TEST_PATH'] = os.path.abspath('../test/testdata/') + autowaf.run_tests(ctx, APPNAME, ['./run-tests']) + autowaf.post_test(ctx, APPNAME) |