Coverage Report

Created: 2025-03-04 07:22

/src/serenity/Userland/Libraries/LibAudio/Resampler.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>.
3
 *
4
 * SPDX-License-Identifier: BSD-2-Clause
5
 */
6
7
#pragma once
8
9
#include <AK/Concepts.h>
10
#include <AK/Types.h>
11
#include <AK/Vector.h>
12
13
namespace Audio {
14
15
// Small helper to resample from one playback rate to another
16
// This isn't really "smart", in that we just insert (or drop) samples.
17
// Should do better...
18
template<typename SampleType>
19
class ResampleHelper {
20
public:
21
    ResampleHelper(u32 source, u32 target)
22
63.9k
        : m_source(source)
23
63.9k
        , m_target(target)
24
63.9k
    {
25
63.9k
        VERIFY(source > 0);
26
63.9k
        VERIFY(target > 0);
27
63.9k
    }
28
29
    // To be used as follows:
30
    // while the resampler doesn't need a new sample, read_sample(current) and store the resulting samples.
31
    // as long as the resampler needs a new sample, process_sample(current)
32
33
    // Stores a new sample
34
    void process_sample(SampleType sample_l, SampleType sample_r)
35
185M
    {
36
185M
        m_last_sample_l = sample_l;
37
185M
        m_last_sample_r = sample_r;
38
185M
        m_current_ratio += m_target;
39
185M
    }
40
41
    // Assigns the given sample to its correct value and returns false if there is a new sample required
42
    bool read_sample(SampleType& next_l, SampleType& next_r)
43
192M
    {
44
192M
        if (m_current_ratio >= m_source) {
45
7.71M
            m_current_ratio -= m_source;
46
7.71M
            next_l = m_last_sample_l;
47
7.71M
            next_r = m_last_sample_r;
48
7.71M
            return true;
49
7.71M
        }
50
51
185M
        return false;
52
192M
    }
53
54
    template<ArrayLike<SampleType> Samples>
55
    ErrorOr<Vector<SampleType>> try_resample(Samples&& to_resample)
56
63.9k
    {
57
63.9k
        Vector<SampleType> resampled;
58
63.9k
        TRY(try_resample_into_end(resampled, forward<Samples>(to_resample)));
59
0
        return resampled;
60
63.9k
    }
61
62
    template<ArrayLike<SampleType> Samples, size_t vector_inline_capacity = 0>
63
    ErrorOr<void> try_resample_into_end(Vector<SampleType, vector_inline_capacity>& destination, Samples&& to_resample)
64
63.9k
    {
65
63.9k
        float ratio = (m_source > m_target) ? static_cast<float>(m_source) / m_target : static_cast<float>(m_target) / m_source;
66
63.9k
        TRY(destination.try_ensure_capacity(destination.size() + to_resample.size() * ratio));
67
185M
        for (auto sample : to_resample) {
68
185M
            process_sample(sample, sample);
69
70
192M
            while (read_sample(sample, sample))
71
7.71M
                destination.unchecked_append(sample);
72
185M
        }
73
63.9k
        return {};
74
63.9k
    }
75
76
    template<ArrayLike<SampleType> Samples>
77
    Vector<SampleType> resample(Samples&& to_resample)
78
63.9k
    {
79
63.9k
        return MUST(try_resample(forward<Samples>(to_resample)));
80
63.9k
    }
81
82
    void reset()
83
    {
84
        m_current_ratio = 0;
85
        m_last_sample_l = {};
86
        m_last_sample_r = {};
87
    }
88
89
    u32 source() const { return m_source; }
90
    u32 target() const { return m_target; }
91
92
private:
93
    u32 const m_source;
94
    u32 const m_target;
95
    u32 m_current_ratio { 0 };
96
    SampleType m_last_sample_l {};
97
    SampleType m_last_sample_r {};
98
};
99
100
}