Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2026 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #pragma once
23 :
24 : #include <algorithm>
25 : #include <variant>
26 :
27 : #include "global/types/secs.h"
28 : #include "global/types/number.h"
29 :
30 : #include "mpe/automationpoint.h"
31 :
32 : namespace muse::audio {
33 : using AutomationEnvelope = mpe::AutomationCurve<muse::secs_t>;
34 :
35 : //! NOTE: a parameter that is either a fixed value, or driven by an AutomationEnvelope over time
36 : template<typename T>
37 : class AutomatableValue
38 : {
39 : public:
40 4 : AutomatableValue() = default;
41 6 : AutomatableValue(const T& value)
42 6 : : m_value(value) {}
43 4 : AutomatableValue(const AutomationEnvelope& envelope)
44 4 : : m_value(envelope) {}
45 :
46 14 : bool hasAutomation() const noexcept { return std::holds_alternative<AutomationEnvelope>(m_value); }
47 :
48 0 : T evaluateAt(muse::secs_t pos, T min, T max) const noexcept
49 : {
50 0 : if (const T* v = std::get_if<T>(&m_value)) {
51 0 : return std::clamp(*v, min, max);
52 : }
53 :
54 0 : const AutomationEnvelope& envelope = std::get<AutomationEnvelope>(m_value);
55 0 : if (envelope.empty()) {
56 0 : return T {};
57 : }
58 :
59 0 : const real_t normalized = mpe::evaluateCurveAt(envelope, pos);
60 0 : const T mapped = min + static_cast<T>(normalized.raw()) * (max - min);
61 0 : return std::clamp(mapped, min, max);
62 : }
63 :
64 6 : const std::variant<T, AutomationEnvelope>& value() const noexcept { return m_value; }
65 :
66 6 : bool operator==(const AutomatableValue& other) const noexcept { return m_value == other.m_value; }
67 :
68 : private:
69 : std::variant<T, AutomationEnvelope> m_value;
70 : };
71 : }
|