From f6660bc51fe8c02ff7c3b6188e8437c67712bddf Mon Sep 17 00:00:00 2001 From: Sander Vocke Date: Fri, 26 Jul 2024 21:57:32 +0200 Subject: Rename Powermap to CurveMap, bugfix, unit tests --- plugin/Makefile.mingw32.in | 2 +- plugingui/powerwidget.cc | 1 - plugingui/powerwidget.h | 4 +- src/Makefile.am | 4 +- src/curvemap.cc | 277 +++++++++++++++++++++++++++++++++++++++++++++ src/curvemap.h | 94 +++++++++++++++ src/powermap.cc | 251 ---------------------------------------- src/powermap.h | 76 ------------- src/powermapfilter.h | 4 +- test/Makefile.am | 14 +-- test/curvemaptest.cc | 267 +++++++++++++++++++++++++++++++++++++++++++ test/powermaptest.cc | 51 --------- tools/add_file | 4 + 13 files changed, 656 insertions(+), 393 deletions(-) create mode 100644 src/curvemap.cc create mode 100644 src/curvemap.h delete mode 100644 src/powermap.cc delete mode 100644 src/powermap.h create mode 100644 test/curvemaptest.cc delete mode 100644 test/powermaptest.cc diff --git a/plugin/Makefile.mingw32.in b/plugin/Makefile.mingw32.in index ad47bcc..9cfcc9e 100644 --- a/plugin/Makefile.mingw32.in +++ b/plugin/Makefile.mingw32.in @@ -39,7 +39,7 @@ DG_SRC = \ @top_srcdir@/src/midimapper.cc \ @top_srcdir@/src/path.cc \ @top_srcdir@/src/powerlist.cc \ - @top_srcdir@/src/powermap.cc \ + @top_srcdir@/src/curvemap.cc \ @top_srcdir@/src/powermapfilter.cc \ @top_srcdir@/src/random.cc \ @top_srcdir@/src/sample.cc \ diff --git a/plugingui/powerwidget.cc b/plugingui/powerwidget.cc index 9be0c48..db37561 100644 --- a/plugingui/powerwidget.cc +++ b/plugingui/powerwidget.cc @@ -31,7 +31,6 @@ #include #include -#include #include #include diff --git a/plugingui/powerwidget.h b/plugingui/powerwidget.h index 3a7bb8e..3d09e6b 100644 --- a/plugingui/powerwidget.h +++ b/plugingui/powerwidget.h @@ -34,7 +34,7 @@ #include #include -#include +#include struct Settings; class SettingsNotifier; @@ -75,7 +75,7 @@ private: virtual void mouseLeaveEvent() override; private: - Powermap power_map; + CurveMap power_map; void parameterChangedFloat(float); void parameterChangedBool(bool); diff --git a/src/Makefile.am b/src/Makefile.am index a8bdb59..e2a2583 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,7 +67,7 @@ libdg_la_SOURCES = \ $(top_srcdir)/src/midimapper.cc \ $(top_srcdir)/src/path.cc \ $(top_srcdir)/src/powerlist.cc \ - $(top_srcdir)/src/powermap.cc \ + $(top_srcdir)/src/curvemap.cc \ $(top_srcdir)/src/powermapfilter.cc \ $(top_srcdir)/src/random.cc \ $(top_srcdir)/src/sample.cc \ @@ -126,7 +126,7 @@ EXTRA_DIST = \ path.h \ platform.h \ powerlist.h \ - powermap.h \ + curvemap.h \ powermapfilter.h \ random.h \ range.h \ diff --git a/src/curvemap.cc b/src/curvemap.cc new file mode 100644 index 0000000..073dde4 --- /dev/null +++ b/src/curvemap.cc @@ -0,0 +1,277 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + * powermap.cc + * + * Fri Apr 17 23:06:12 CEST 2020 + * Copyright 2020 André Nusser + * andre.nusser@googlemail.com + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * DrumGizmo 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "curvemap.h" + +#include +#include + +namespace +{ + +using CurveValue = CurveMap::CurveValue; +using CurveValuePair = CurveMap::CurveValuePair; + +CurveValue h00(CurveValue x) +{ + return (1 + 2 * x) * pow(1 - x, 2); +} + +CurveValue h10(CurveValue x) +{ + return x * pow(1 - x, 2); +} + +CurveValue h01(CurveValue x) +{ + return x * x * (3 - 2 * x); +} + +CurveValue h11(CurveValue x) +{ + return x * x * (x - 1); +} + +CurveValue computeValue(const CurveValue x, const CurveValuePair& P0, const CurveValuePair& P1, + const CurveValue m0, const CurveValue m1) +{ + const auto x0 = P0.in; + const auto x1 = P1.in; + const auto y0 = P0.out; + const auto y1 = P1.out; + const auto dx = x1 - x0; + const auto x_prime = (x - x0)/dx; + + return + h00(x_prime) * y0 + + h10(x_prime) * dx * m0 + + h01(x_prime) * y1 + + h11(x_prime) * dx * m1; +} + +} // end anonymous namespace + +constexpr std::array CurveMap::default_fixed; + +CurveValue CurveMap::map(CurveValue in) +{ + assert(in >= 0. && in <= 1.); + if (invert) + { + in = 1.0 - in; + } + + if (spline_needs_update) + { + updateSpline(); + } + + CurveValue out; + if (in < fixed[0].in) + { + out = shelf ? fixed[0].out + : computeValue(in, {0.,0.}, fixed[0], m[0], m[1]); + } + else if (in < fixed[1].in) + { + out = computeValue(in, fixed[0], fixed[1], m[1], m[2]); + } + else if (in < fixed[2].in) + { + out = computeValue(in, fixed[1], fixed[2], m[2], m[3]); + } + else + { + // in >= fixed[2].in + out = shelf ? fixed[2].out + : computeValue(in, fixed[2], {1.,1.}, m[3], m[4]); + } + + assert(out >= 0. && out <= 1.); + return out; +} + +void CurveMap::reset() +{ + *this = CurveMap{}; + + updateSpline(); +} + +void CurveMap::setFixed0(CurveValuePair new_value) +{ + auto prev = fixed[0]; + fixed[0].in = clamp(new_value.in, eps, fixed[1].in - eps); + fixed[0].out = clamp(new_value.out, eps, fixed[1].out - eps); + if (fixed[0] != prev) + { + spline_needs_update = true; + } +} + +void CurveMap::setFixed1(CurveValuePair new_value) +{ + auto prev = fixed[1]; + fixed[1].in = clamp(new_value.in, fixed[0].in + eps, fixed[2].in - eps); + fixed[1].out = clamp(new_value.out, fixed[0].out + eps, fixed[2].out - eps); + if (fixed[1] != prev) + { + spline_needs_update = true; + } +} + +void CurveMap::setFixed2(CurveValuePair new_value) +{ + auto prev = fixed[2]; + fixed[2].in = clamp(new_value.in, fixed[1].in + eps, 1 - eps); + fixed[2].out = clamp(new_value.out, fixed[1].out + eps, 1 - eps); + if (fixed[2] != prev) + { + spline_needs_update = true; + } +} + +void CurveMap::setInvert(bool enable) +{ + if (invert != enable) + { + spline_needs_update = true; + invert = enable; + } +} + +void CurveMap::setShelf(bool enable) +{ + if (shelf != enable) + { + spline_needs_update = true; + shelf = enable; + } +} + +CurveValuePair CurveMap::getFixed0() const +{ + return fixed[0]; +} + +CurveValuePair CurveMap::getFixed1() const +{ + return fixed[1]; +} + +CurveValuePair CurveMap::getFixed2() const +{ + return fixed[2]; +} + +bool CurveMap::getInvert() const { + return invert; +} + +bool CurveMap::getShelf() const { + return shelf; +} + +// This mostly followes the wikipedia article for monotone cubic splines: +// https://en.wikipedia.org/wiki/Monotone_cubic_interpolation +void CurveMap::updateSpline() +{ + assert(0. <= fixed[0].in && fixed[0].in < fixed[1].in && + fixed[1].in < fixed[2].in && fixed[2].in <= 1.); + assert(0. <= fixed[0].out && fixed[0].out <= fixed[1].out && + fixed[1].out <= fixed[2].out && fixed[2].out <= 1.); + + CurveValues X = shelf ? CurveValues{fixed[0].in, fixed[1].in, fixed[2].in} + : CurveValues{0., fixed[0].in, fixed[1].in, fixed[2].in, 1.}; + CurveValues Y = shelf ? CurveValues{fixed[0].out, fixed[1].out, fixed[2].out} + : CurveValues{0., fixed[0].out, fixed[1].out, fixed[2].out, 1.}; + + auto slopes = calcSlopes(X, Y); + + if (shelf) + { + assert(slopes.size() == 3); + this->m[1] = slopes[0]; + this->m[2] = slopes[1]; + this->m[3] = slopes[2]; + } + else + { + assert(slopes.size() == 5); + for (std::size_t i = 0; i < m.size(); ++i) + { + this->m[i] = slopes[i]; + } + } + + spline_needs_update = false; +} + +// This follows the monotone cubic spline algorithm of Steffen, from: +// "A Simple Method for Monotonic Interpolation in One Dimension" +std::vector CurveMap::calcSlopes(const CurveValues& X, const CurveValues& Y) +{ + CurveValues m(X.size()); + + CurveValues d(X.size() - 1); + CurveValues h(X.size() - 1); + for (std::size_t i = 0; i < d.size(); ++i) + { + h[i] = X[i + 1] - X[i]; + d[i] = (Y[i + 1] - Y[i]) / h[i]; + } + + m.front() = d.front(); + for (std::size_t i = 1; i < m.size() - 1; ++i) + { + m[i] = (d[i - 1] + d[i]) / 2.; + } + m.back() = d.back(); + + for (std::size_t i = 1; i < m.size() - 1; ++i) + { + const auto min_d = 2*std::min(d[i - 1], d[i]); + m[i] = + std::min(min_d, + (h[i] * d[i - 1] + h[i - 1] * d[i]) / (h[i - 1] + h[i])); + } + + return m; +} + +CurveValue CurveMap::clamp(CurveValue in, CurveValue min, CurveValue max) const +{ + return std::max(min, std::min(in, max)); +} + +bool CurveMap::operator==(const CurveMap& other) const +{ + return getFixed0() == other.getFixed0() && + getFixed1() == other.getFixed1() && + getFixed2() == other.getFixed2() && + getShelf() == other.getShelf() && + getInvert() == other.getInvert(); +} diff --git a/src/curvemap.h b/src/curvemap.h new file mode 100644 index 0000000..926543d --- /dev/null +++ b/src/curvemap.h @@ -0,0 +1,94 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + * curvemap.h + * + * Fri Apr 17 23:06:12 CEST 2020 + * Copyright 2020 André Nusser + * andre.nusser@googlemail.com + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * DrumGizmo 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#pragma once + +#include +#include + +class CurveMap +{ +public: + using CurveValue = float; + using CurveValues = std::vector; + + bool operator==(const CurveMap& other) const; + + struct CurveValuePair + { + CurveValue in; + CurveValue out; + + bool operator==(const CurveValuePair& other) + { + return in == other.in || out == other.out; + } + bool operator!=(const CurveValuePair& other) + { + return !(*this == other); + } + }; + + CurveValue map(CurveValue in); + void reset(); + + void setFixed0(CurveValuePair new_value); + void setFixed1(CurveValuePair new_value); + void setFixed2(CurveValuePair new_value); + void setShelf(bool enable); + + //! If enabled, inversion inverts (1 - x) the input value before mapping + //! it through the curve. + void setInvert(bool enable); + + CurveValuePair getFixed0() const; + CurveValuePair getFixed1() const; + CurveValuePair getFixed2() const; + bool getShelf() const; + bool getInvert() const; + +private: + static constexpr CurveValue eps = 1e-4; + static constexpr std::array default_fixed { + CurveValuePair {eps, eps}, + CurveValuePair {.5, .5}, + CurveValuePair {1 - eps, 1 - eps} + }; + + // input parameters (state of this class) + std::array fixed { default_fixed }; + bool shelf { true }; + bool invert { false }; + + // spline parameters (deterministically computed from the input parameters) + bool spline_needs_update { true }; + std::array m { 0, 0, 0, 0, 0 }; + + void updateSpline(); + std::vector calcSlopes(const CurveValues& X, const CurveValues& P); + + CurveValue clamp(CurveValue in, CurveValue min, CurveValue max) const; +}; \ No newline at end of file diff --git a/src/powermap.cc b/src/powermap.cc deleted file mode 100644 index 2bb45b7..0000000 --- a/src/powermap.cc +++ /dev/null @@ -1,251 +0,0 @@ -/* -*- Mode: c++ -*- */ -/*************************************************************************** - * powermap.cc - * - * Fri Apr 17 23:06:12 CEST 2020 - * Copyright 2020 André Nusser - * andre.nusser@googlemail.com - ****************************************************************************/ - -/* - * This file is part of DrumGizmo. - * - * DrumGizmo is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * DrumGizmo 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with DrumGizmo; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ -#include "powermap.h" - -#include -#include - -namespace -{ - -using Power = Powermap::Power; -using PowerPair = Powermap::PowerPair; - -Power h00(Power x) -{ - return (1 + 2 * x) * pow(1 - x, 2); -} - -Power h10(Power x) -{ - return x * pow(1 - x, 2); -} - -Power h01(Power x) -{ - return x * x * (3 - 2 * x); -} - -Power h11(Power x) -{ - return x * x * (x - 1); -} - -Power computeValue(const Power x, const PowerPair& P0, const PowerPair& P1, - const Power m0, const Power m1) -{ - const auto x0 = P0.in; - const auto x1 = P1.in; - const auto y0 = P0.out; - const auto y1 = P1.out; - const auto dx = x1 - x0; - const auto x_prime = (x - x0)/dx; - - return - h00(x_prime) * y0 + - h10(x_prime) * dx * m0 + - h01(x_prime) * y1 + - h11(x_prime) * dx * m1; -} - -} // end anonymous namespace - -Powermap::Powermap() -{ - reset(); -} - -Power Powermap::map(Power in) -{ - assert(in >= 0. && in <= 1.); - - if (spline_needs_update) - { - updateSpline(); - } - - Power out; - if (in < fixed[0].in) - { - out = shelf ? fixed[0].out - : computeValue(in, {0.,0.}, fixed[0], m[0], m[1]); - } - else if (in < fixed[1].in) - { - out = computeValue(in, fixed[0], fixed[1], m[1], m[2]); - } - else if (in < fixed[2].in) - { - out = computeValue(in, fixed[1], fixed[2], m[2], m[3]); - } - else - { - // in >= fixed[2].in - out = shelf ? fixed[2].out - : computeValue(in, fixed[2], {1.,1.}, m[3], m[4]); - } - - assert(out >= 0. && out <= 1.); - return out; -} - -void Powermap::reset() -{ - setFixed0({eps, eps}); - setFixed1({.5, .5}); - setFixed2({1 - eps, 1 - eps}); - // FIXME: better false? - shelf = true; - - updateSpline(); -} - -void Powermap::setFixed0(PowerPair new_value) -{ - if (fixed[0] != new_value) - { - spline_needs_update = true; - fixed[0].in = clamp(new_value.in, eps, fixed[1].in - eps); - fixed[0].out = clamp(new_value.out, eps, fixed[1].out - eps); - } -} - -void Powermap::setFixed1(PowerPair new_value) -{ - if (fixed[1] != new_value) - { - spline_needs_update = true; - fixed[1].in = clamp(new_value.in, fixed[0].in + eps, fixed[2].in - eps); - fixed[1].out = clamp(new_value.out, fixed[0].out + eps, fixed[2].out - eps); - } -} - -void Powermap::setFixed2(PowerPair new_value) -{ - if (fixed[2] != new_value) - { - spline_needs_update = true; - fixed[2].in = clamp(new_value.in, fixed[1].in + eps, 1 - eps); - fixed[2].out = clamp(new_value.out, fixed[1].out + eps, 1 - eps); - } -} - -void Powermap::setShelf(bool enable) -{ - if (shelf != enable) - { - spline_needs_update = true; - this->shelf = enable; - } -} - -PowerPair Powermap::getFixed0() const -{ - return fixed[0]; -} - -PowerPair Powermap::getFixed1() const -{ - return fixed[1]; -} - -PowerPair Powermap::getFixed2() const -{ - return fixed[2]; -} - -// This mostly followes the wikipedia article for monotone cubic splines: -// https://en.wikipedia.org/wiki/Monotone_cubic_interpolation -void Powermap::updateSpline() -{ - assert(0. <= fixed[0].in && fixed[0].in < fixed[1].in && - fixed[1].in < fixed[2].in && fixed[2].in <= 1.); - assert(0. <= fixed[0].out && fixed[0].out <= fixed[1].out && - fixed[1].out <= fixed[2].out && fixed[2].out <= 1.); - - Powers X = shelf ? Powers{fixed[0].in, fixed[1].in, fixed[2].in} - : Powers{0., fixed[0].in, fixed[1].in, fixed[2].in, 1.}; - Powers Y = shelf ? Powers{fixed[0].out, fixed[1].out, fixed[2].out} - : Powers{0., fixed[0].out, fixed[1].out, fixed[2].out, 1.}; - - auto slopes = calcSlopes(X, Y); - - if (shelf) - { - assert(slopes.size() == 3); - this->m[1] = slopes[0]; - this->m[2] = slopes[1]; - this->m[3] = slopes[2]; - } - else - { - assert(slopes.size() == 5); - for (std::size_t i = 0; i < m.size(); ++i) - { - this->m[i] = slopes[i]; - } - } - - spline_needs_update = false; -} - -// This follows the monotone cubic spline algorithm of Steffen, from: -// "A Simple Method for Monotonic Interpolation in One Dimension" -std::vector Powermap::calcSlopes(const Powers& X, const Powers& Y) -{ - Powers m(X.size()); - - Powers d(X.size() - 1); - Powers h(X.size() - 1); - for (std::size_t i = 0; i < d.size(); ++i) - { - h[i] = X[i + 1] - X[i]; - d[i] = (Y[i + 1] - Y[i]) / h[i]; - } - - m.front() = d.front(); - for (std::size_t i = 1; i < m.size() - 1; ++i) - { - m[i] = (d[i - 1] + d[i]) / 2.; - } - m.back() = d.back(); - - for (std::size_t i = 1; i < m.size() - 1; ++i) - { - const auto min_d = 2*std::min(d[i - 1], d[i]); - m[i] = - std::min(min_d, - (h[i] * d[i - 1] + h[i - 1] * d[i]) / (h[i - 1] + h[i])); - } - - return m; -} - -Power Powermap::clamp(Power in, Power min, Power max) const -{ - return std::max(min, std::min(in, max)); -} diff --git a/src/powermap.h b/src/powermap.h deleted file mode 100644 index 3a406cc..0000000 --- a/src/powermap.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: c++ -*- */ -/*************************************************************************** - * powermap.h - * - * Fri Apr 17 23:06:12 CEST 2020 - * Copyright 2020 André Nusser - * andre.nusser@googlemail.com - ****************************************************************************/ - -/* - * This file is part of DrumGizmo. - * - * DrumGizmo is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * DrumGizmo 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with DrumGizmo; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ -#pragma once - -#include -#include - -class Powermap -{ -public: - using Power = float; - using Powers = std::vector; - struct PowerPair - { - Power in; - Power out; - - bool operator!=(const PowerPair& other) - { - return in != other.in || out != other.out; - } - }; - - Powermap(); - - Power map(Power in); - void reset(); - - void setFixed0(PowerPair new_value); - void setFixed1(PowerPair new_value); - void setFixed2(PowerPair new_value); - void setShelf(bool enable); - - PowerPair getFixed0() const; - PowerPair getFixed1() const; - PowerPair getFixed2() const; - -private: - // input parameters (state of this class) - std::array fixed; - bool shelf; - - // spline parameters (deterministically computed from the input parameters) - bool spline_needs_update; - std::array m; - const Power eps = 1e-4; - - void updateSpline(); - std::vector calcSlopes(const Powers& X, const Powers& P); - - Power clamp(Power in, Power min, Power max) const; -}; diff --git a/src/powermapfilter.h b/src/powermapfilter.h index 263f809..b9dfe5b 100644 --- a/src/powermapfilter.h +++ b/src/powermapfilter.h @@ -27,7 +27,7 @@ #pragma once #include "inputfilter.h" -#include "powermap.h" +#include "curvemap.h" struct Settings; @@ -43,5 +43,5 @@ public: private: Settings& settings; - Powermap powermap; + CurveMap powermap; }; diff --git a/test/Makefile.am b/test/Makefile.am index 15ceb7d..0827cae 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -8,7 +8,7 @@ TESTS = resource enginetest paintertest configfile audiocache \ randomtest atomictest syncedsettingstest imagecachetest \ semaphoretest drumkitcreatortest bytesizeparsertest notifiertest \ dgxmlparsertest domloadertest configparsertest midimapparsertest \ - eventsdstest powermaptest midimappertest + eventsdstest curvemaptest midimappertest if WITH_NLS TESTS += translationtest @@ -329,14 +329,14 @@ eventsdstest_SOURCES = \ eventsdstest.cc \ uunit/uunit.cc -powermaptest_CXXFLAGS = \ - -I$(top_srcdir)/test/uunit -DOUTPUT=\"powermaptest\" \ +curvemaptest_CXXFLAGS = \ + -I$(top_srcdir)/test/uunit -DOUTPUT=\"curvemaptest\" \ $(DEBUG_FLAGS) \ -I$(top_srcdir)/src -powermaptest_LDFLAGS = -powermaptest_SOURCES = \ - $(top_srcdir)/src/powermap.cc \ - powermaptest.cc \ +curvemaptest_LDFLAGS = +curvemaptest_SOURCES = \ + $(top_srcdir)/src/curvemap.cc \ + curvemaptest.cc \ uunit/uunit.cc midimappertest_CXXFLAGS = \ diff --git a/test/curvemaptest.cc b/test/curvemaptest.cc new file mode 100644 index 0000000..cb90d1b --- /dev/null +++ b/test/curvemaptest.cc @@ -0,0 +1,267 @@ +/* -*- Mode: c++ -*- */ +/*************************************************************************** + * curvemaptest.cc + * + * Fri Jul 26 19:43:32 CEST 2024 + * Copyright 2024 Sander Vocke + * sandervocke@gmail.com + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * DrumGizmo 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include +#include + +#include "../src/curvemap.h" +#include +#include + +class test_curvemaptest + : public uUnit +{ +public: + test_curvemaptest() + { + uUNIT_TEST(test_curvemaptest::check_default); + uUNIT_TEST(test_curvemaptest::check_default_invert); + uUNIT_TEST(test_curvemaptest::check_default_disabled_shelf); + uUNIT_TEST(test_curvemaptest::check_default_disabled_shelf_invert); + uUNIT_TEST(test_curvemaptest::check_fixed1_075_025); + uUNIT_TEST(test_curvemaptest::check_fixed1_075_025_invert); + uUNIT_TEST(test_curvemaptest::check_shelf_060); + uUNIT_TEST(test_curvemaptest::check_shelf_060_invert); + uUNIT_TEST(test_curvemaptest::check_reset); + } + + const std::map default_map = { + {0.0, 1e-4}, + {1e-4, 1e-4}, + {0.1, 0.1}, + {0.2, 0.2}, + {0.3, 0.3}, + {0.4, 0.4}, + {0.5, 0.5}, + {0.6, 0.6}, + {0.7, 0.7}, + {0.8, 0.8}, + {0.9, 0.9}, + {1.0 - 1e-4, 1.0 - 1e-4}, + {1.0, 1.0 - 1e-4} + }; + + const std::map identity_map = { + {0.0, 0.0}, + {0.1, 0.1}, + {0.2, 0.2}, + {0.3, 0.3}, + {0.4, 0.4}, + {0.5, 0.5}, + {0.6, 0.6}, + {0.7, 0.7}, + {0.8, 0.8}, + {0.9, 0.9}, + {1.0, 1.0} + }; + + const std::map fixed1_075_025_map = { + {0.0, 1e-4}, + {1e-4, 1e-4}, + {0, 0.0001}, + {0.1, 0.0295469705015421}, + {0.2, 0.0536915548145771}, + {0.3, 0.0760560110211372}, + {0.4, 0.100195862352848}, + {0.5, 0.129666686058044}, + {0.6, 0.168024003505707}, + {0.7, 0.218823373317719}, + {0.8, 0.325357049703598}, + {0.9, 0.64416378736496}, + {1.0 - 1e-4, 1.0 - 1e-4}, + {1.0, 1.0 - 1e-4} + }; + + const std::map shelf_060_map = { + {0.0, 1e-4}, + {1e-4, 1e-4}, + {0.1, 0.1}, + {0.2, 0.2}, + {0.3, 0.3}, + {0.4, 0.4}, + {0.5, 0.5}, + {0.6, 0.6}, + {0.7, 0.6}, + {0.8, 0.6}, + {0.9, 0.6}, + {1.0, 0.6} + }; + + void check_default() + { + auto dataset = this->default_map; + + CurveMap map; + + for (auto& entry : dataset) { + auto in = entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_reset() + { + auto dataset = this->default_map; + + CurveMap map; + map.setFixed0({0.1, 0.2}); + map.setFixed1({0.2, 0.3}); + map.setFixed2({0.3, 0.4}); + map.setInvert(!map.getInvert()); + map.setShelf(!map.getShelf()); + + bool any_difference = false; + for (auto& entry : dataset) { + auto in = entry.first; + auto expect = entry.second; + if (expect != map.map(in)) { + any_difference = true; + break; + } + } + + uASSERT(any_difference); + + map.reset(); + + for (auto& entry : dataset) { + auto in = entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_default_invert() + { + auto dataset = this->default_map; + + CurveMap map; + map.setInvert(true); + + for (auto& entry : dataset) { + auto in = 1.0 - entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_default_disabled_shelf() + { + auto dataset = this->identity_map; + + CurveMap map; + map.setShelf(false); + map.setFixed2({0.6, 0.6}); + + for (auto& entry : dataset) { + auto in = entry.first; + auto expect = entry.second; + // std::cout << "{" << in << ", " << std::setprecision (15) << map.map(in) << "}," << std::endl; // FIXME + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_default_disabled_shelf_invert() + { + auto dataset = this->identity_map; + + CurveMap map; + map.setShelf(false); + map.setFixed2({0.6, 0.6}); + map.setInvert(true); + + for (auto& entry : dataset) { + auto in = 1.0 - entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_fixed1_075_025() + { + auto dataset = this->fixed1_075_025_map; + + CurveMap map; + map.setFixed1({0.75, 0.25}); + + for (auto& entry : dataset) { + auto in = entry.first; + auto expect = entry.second; + // std::cout << "{" << in << ", " << std::setprecision (15) << map.map(in) << "}," << std::endl; // FIXME + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_fixed1_075_025_invert() + { + auto dataset = this->fixed1_075_025_map; + + CurveMap map; + map.setFixed1({0.75, 0.25}); + map.setInvert(true); + + for (auto& entry : dataset) { + auto in = 1.0 - entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_shelf_060() + { + auto dataset = this->shelf_060_map; + + CurveMap map; + map.setFixed2({0.6, 0.6}); + map.setShelf(true); + + for (auto& entry : dataset) { + auto in = entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } + + void check_shelf_060_invert() + { + auto dataset = this->shelf_060_map; + + CurveMap map; + map.setFixed2({0.6, 0.6}); + map.setShelf(true); + map.setInvert(true); + + for (auto& entry : dataset) { + auto in = 1.0 - entry.first; + auto expect = entry.second; + uASSERT_EQUAL(expect, map.map(in)); + } + } +}; + +// Registers the fixture into the 'registry' +static test_curvemaptest test; diff --git a/test/powermaptest.cc b/test/powermaptest.cc deleted file mode 100644 index bef5bdc..0000000 --- a/test/powermaptest.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- Mode: c++ -*- */ -/*************************************************************************** - * powermaptest.cc - * - * Sun Apr 19 23:23:37 CEST 2020 - * Copyright 2020 André Nusser - * andre.nusser@googlemail.com - ****************************************************************************/ - -/* - * This file is part of DrumGizmo. - * - * DrumGizmo is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * DrumGizmo 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with DrumGizmo; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ -#include - -#include "../src/powermap.h" - -class test_powermaptest - : public uUnit -{ -public: - test_powermaptest() - { - uUNIT_TEST(test_powermaptest::check_values); - } - - void check_values() - { - Powermap powermap; - - // TODO - // std::cout << powermap.map(.8) << std::endl; - // uUNIT_ASSERT_EQUAL(powermap.map(.8), .8); - } -}; - -// Registers the fixture into the 'registry' -static test_powermaptest test; diff --git a/tools/add_file b/tools/add_file index a704029..51d50b4 100755 --- a/tools/add_file +++ b/tools/add_file @@ -26,6 +26,10 @@ function allfile() { then NAME="Goran Mekić"; EMAIL="meka@tilda.center" fi + if [ "$USER" == "sander" ] + then + NAME="Sander Vocke"; EMAIL="sandervocke@gmail.com" + fi echo "/* -*- Mode: c++ -*- */" > $1; echo "/***************************************************************************" >> $1; -- cgit v1.2.3