Last active
June 15, 2020 17:22
-
-
Save jpcima/3f8272bf70e19db24850e5dca18c888f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: BSD-2-Clause | |
// This code is part of the sfizz library and is licensed under a BSD 2-clause | |
// license. You should have receive a LICENSE.md file along with the code. | |
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz | |
#pragma once | |
#include <elements.hpp> | |
#include <infra/support.hpp> | |
namespace el = cycfi::elements; | |
/** | |
* @brief Common base of ranged elements | |
*/ | |
class range_element_base : public el::receiver<double> { | |
public: | |
virtual ~range_element_base() {} | |
typedef std::pair<double, double> range_type; | |
explicit range_element_base(range_type r) | |
: range_(r) | |
{ | |
} | |
range_type range() const | |
{ | |
return range_; | |
} | |
void range(range_type r) | |
{ | |
double v = value(); | |
range_ = r; | |
value(v); | |
} | |
std::function<void(double)> on_change; | |
protected: | |
double clamp(double x) const | |
{ | |
return std::max(range_.first, std::min(range_.second, x)); | |
} | |
double normalize(double x) const | |
{ | |
return (x - range_.first) / (range_.second - range_.first); | |
} | |
double denormalize(double x) const | |
{ | |
return range_.first + x * (range_.second - range_.first); | |
} | |
private: | |
range_type range_ { 0.0, 1.0 }; | |
}; | |
/** | |
* @brief Specialized base of ranged elements | |
*/ | |
template <class Subject, class Base = range_element_base> | |
class basic_range_element : public Base, public el::proxy<Subject> { | |
public: | |
using range_type = typename Base::range_type; | |
basic_range_element(Subject&& subject_, range_type init_range) | |
: Base(init_range), el::proxy<Subject>(std::move(subject_)) | |
{ | |
auto& e = static_cast<Subject&>(this->subject()); | |
e.on_change = [this](double v) { | |
if (this->on_change) | |
this->on_change(this->denormalize(v)); | |
}; | |
} | |
double value() const override | |
{ | |
auto& e = static_cast<const Subject&>(this->subject()); | |
return this->denormalize(e.value()); | |
} | |
void value(double v) override | |
{ | |
auto& e = static_cast<Subject&>(this->subject()); | |
e.value(this->normalize(v)); | |
} | |
}; | |
/** | |
* @brief Create a ranged proxy for a valued element, | |
* | |
* @param element the element to wrap. | |
* @param init_value the initial value. (optional, default 0) | |
* @param init_range the initial range. (optional, default 0-1) | |
*/ | |
template <class Element> | |
inline basic_range_element<cycfi::remove_cvref_t<Element>> | |
ranged(Element&& element, double init_value = 0.0, std::pair<double, double> init_range = { 0.0, 1.0 }) | |
{ | |
basic_range_element<cycfi::remove_cvref_t<Element>> e { | |
std::forward<Element>(element), init_range | |
}; | |
e.value(init_value); | |
return e; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment