Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HW/GranularMixer.h
3658 views
1
// Copyright 2009 Dolphin Emulator Project
2
// SPDX-License-Identifier: GPL-2.0-or-later
3
4
#pragma once
5
6
#include <algorithm>
7
#include <array>
8
#include <atomic>
9
#include <cmath>
10
11
#include "Common/CommonTypes.h"
12
#include "Core/Config.h"
13
14
class PointerWrap;
15
16
// Replacement for std::countr_one from a later version of C++
17
constexpr u32 countr_one_replacement(u32 x) {
18
u32 count = 0;
19
while (x & 1) {
20
++count;
21
x >>= 1;
22
}
23
return count;
24
}
25
26
struct GranularStats {
27
int queuedGranulesMin;
28
int queuedGranulesMax;
29
int queuedSamplesTarget;
30
float smoothedQueuedGranules;
31
int targetQueueSize;
32
int maxQueuedGranules;
33
float fadeVolume;
34
bool looping;
35
int overruns;
36
int underruns;
37
float smoothedReadSize;
38
float frameTimeEstimate;
39
};
40
41
class GranularMixer final {
42
public:
43
explicit GranularMixer();
44
45
// Called from audio threads
46
void Mix(s16 *samples, u32 numSamples, int outSampleRate, float vpsEstimate);
47
48
// Called from emulation thread
49
void PushSamples(const s32 *samples, u32 num_samples, float volume);
50
51
void GetStats(GranularStats *stats);
52
53
static constexpr u32 GRANULE_SIZE = 256;
54
55
private:
56
static constexpr std::size_t MAX_GRANULE_QUEUE_SIZE = 128;
57
static constexpr std::size_t GRANULE_QUEUE_MASK = MAX_GRANULE_QUEUE_SIZE - 1;
58
59
struct StereoPair final {
60
float l = 0.f;
61
float r = 0.f;
62
63
constexpr StereoPair() = default;
64
constexpr StereoPair(const StereoPair&) = default;
65
constexpr StereoPair& operator=(const StereoPair&) = default;
66
constexpr StereoPair(StereoPair&&) = default;
67
constexpr StereoPair& operator=(StereoPair&&) = default;
68
69
constexpr StereoPair(float mono) : l(mono), r(mono) {}
70
constexpr StereoPair(float left, float right) : l(left), r(right) {}
71
constexpr StereoPair(s16 left, s16 right) : l(left), r(right) {}
72
73
StereoPair operator+(const StereoPair& other) const {
74
return StereoPair(l + other.l, r + other.r);
75
}
76
77
StereoPair operator*(float f) const {
78
return StereoPair(l * f, r * f);
79
}
80
};
81
82
static constexpr u32 GRANULE_OVERLAP = GRANULE_SIZE / 2;
83
static constexpr u32 GRANULE_MASK = GRANULE_SIZE - 1;
84
static constexpr u32 GRANULE_BITS = countr_one_replacement(GRANULE_MASK);
85
static constexpr u32 GRANULE_FRAC_BITS = 32 - GRANULE_BITS;
86
87
using Granule = std::array<StereoPair, GRANULE_SIZE>;
88
89
Granule m_next_buffer{};
90
u32 m_next_buffer_index = 0;
91
92
u32 m_current_index = 0;
93
Granule m_front;
94
Granule m_back;
95
96
std::atomic<u32> m_granule_queue_size{ 20 };
97
float smoothedQueueSize_ = 0.0f;
98
Granule m_queue[MAX_GRANULE_QUEUE_SIZE];
99
100
// These are permitted to grow indefinitely and masked on use.
101
std::atomic<u32> m_queue_head{};
102
std::atomic<u32> m_queue_tail{};
103
std::atomic<bool> m_queue_looping{};
104
105
float m_fade_volume = 1.0;
106
int underruns_ = 0;
107
int overruns_ = 0;
108
int queuedGranulesMin_ = 10000;
109
int queuedGranulesMax_ = 0;
110
int queuedSamplesTarget_ = 0;
111
float smoothedReadSize_ = 0.0f;
112
float frameTimeEstimate_ = 0.0f;
113
114
void Enqueue();
115
void Dequeue(Granule* granule);
116
};
117
118