summaryrefslogtreecommitdiff
path: root/Userland/Services/AudioServer/FadingProperty.h
blob: 5df78fe79cddc77132eb67e2e912c4b012524049 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
 * Copyright (c) 2021, kleines Filmröllchen <malu.bertsch@gmail.com>.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include "Mixer.h"
#include <compare>

namespace AudioServer {

// This is in buffer counts.
// As each buffer is approx 1/40 of a second, this means about 1/4 of a second of fade time.
constexpr int DEFAULT_FADE_TIME = 10;

// A property of an audio system that needs to fade briefly whenever changed.
template<typename T>
class FadingProperty {
public:
    FadingProperty(T const value)
        : FadingProperty(value, DEFAULT_FADE_TIME)
    {
    }
    FadingProperty(T const value, int const fade_time)
        : m_old_value(value)
        , m_new_value(move(value))
        , m_fade_time(fade_time)
    {
    }
    virtual ~FadingProperty()
    {
        m_old_value.~T();
        m_new_value.~T();
    }

    FadingProperty<T>& operator=(T const& new_value)
    {
        // The origin of the fade is wherever we're right now.
        m_old_value = static_cast<T>(*this);
        m_new_value = new_value;
        m_current_fade = 0;
        return *this;
    }
    FadingProperty<T>& operator=(FadingProperty<T> const&) = delete;

    operator T() const
    {
        if (!is_fading())
            return m_new_value;
        return m_old_value * (1 - m_current_fade) + m_new_value * (m_current_fade);
    }

    auto operator<=>(FadingProperty<T> const& other) const
    {
        return static_cast<T>(this) <=> static_cast<T>(other);
    }

    auto operator<=>(T const& other) const
    {
        return static_cast<T>(*this) <=> other;
    }

    void advance_time()
    {
        m_current_fade += 1.0 / static_cast<double>(m_fade_time);
        m_current_fade = clamp(m_current_fade, 0.0, 1.0);
    }

    bool is_fading() const
    {
        return m_current_fade < 1;
    }

    T target() const { return m_new_value; }

private:
    T m_old_value {};
    T m_new_value {};
    double m_current_fade { 0 };
    int const m_fade_time;
};

}