17static std::vector<float> bufferStorage;
18static size_t bufferSize = 0;
19static float* aBuffer =
nullptr;
23template<
unsigned CHANNELS>
27 std::unique_ptr<ResampleLQ<CHANNELS>> result;
29 result = std::make_unique<ResampleLQUp <CHANNELS>>(input, hostClock);
31 result = std::make_unique<ResampleLQDown<CHANNELS>>(input, hostClock);
36template<
unsigned CHANNELS>
40 , hostClock(hostClock_)
45 narrow<unsigned>(emuPeriod));
51[[nodiscard]]
static bool isSilent(
float x)
53 constexpr float threshold = 1.0f / 32768;
54 return std::abs(x) < threshold;
57template<
unsigned CHANNELS>
60 auto& emuClk = getEmuClock();
61 unsigned emuNum = emuClk.getTicksTill(time);
64 unsigned required = emuNum + 4;
65 if (required > bufferSize) [[unlikely]] {
67 bufferStorage.resize(required + 3);
69 auto p = std::bit_cast<uintptr_t>(bufferStorage.data());
70 aBuffer = std::bit_cast<float*>((p + 15) & ~15);
72 bufferSize = (bufferStorage.data() + bufferStorage.size()) - aBuffer;
73 assert(bufferSize >= required);
78 auto* buffer = &aBuffer[4 - 2 * CHANNELS];
79 assert((uintptr_t(&buffer[2 * CHANNELS]) & 15) == 0);
81 if (!input.generateInput(&buffer[2 * CHANNELS], emuNum)) {
83 if (
ranges::all_of(lastInput, [](
auto& l) {
return isSilent(l); })) {
88 ranges::fill(std::span{&buffer[CHANNELS], emuNum * CHANNELS}, 0);
90 for (
auto j :
xrange(2 * CHANNELS)) {
91 buffer[j] = lastInput[j];
92 lastInput[j] = buffer[emuNum * CHANNELS + j];
99template<
unsigned CHANNELS>
107template<
unsigned CHANNELS>
109 float* __restrict dataOut,
size_t hostNum, EmuTime::param time)
111 auto& emuClk = this->getEmuClock();
112 EmuTime host1 = this->hostClock.getFastAdd(1);
113 assert(host1 > emuClk.getTime());
115 emuClk.getTicksTill(host1, pos);
116 assert(pos.toInt() < 2);
119 if (!this->fetchData(time, valid))
return false;
124 const auto* buffer = &aBuffer[4 - 2 * CHANNELS];
125 for (
auto i :
xrange(hostNum)) {
126 unsigned p = pos.toInt();
128 for (
auto j :
xrange(CHANNELS)) {
129 dataOut[i * CHANNELS + j] = buffer[p * CHANNELS + j];
139template<
unsigned CHANNELS>
147template<
unsigned CHANNELS>
149 float* __restrict dataOut,
size_t hostNum, EmuTime::param time)
151 auto& emuClk = this->getEmuClock();
152 EmuTime host1 = this->hostClock.getFastAdd(1);
153 assert(host1 > emuClk.getTime());
155 emuClk.getTicksTill(host1, pos);
158 if (!this->fetchData(time, valid))
return false;
160 const auto* buffer = &aBuffer[4 - 2 * CHANNELS];
161 for (
auto i :
xrange(hostNum)) {
162 unsigned p = pos.toInt();
163 assert((p + 1) < valid);
164 FP fract = pos.fract();
165 for (
auto j :
xrange(CHANNELS)) {
166 auto s0 = buffer[(p + 0) * CHANNELS + j];
167 auto s1 = buffer[(p + 1) * CHANNELS + j];
168 auto out = s0 + (fract.toFloat() * (s1 - s0));
169 dataOut[i * CHANNELS + j] = out;
178template class ResampleLQ<1>;
179template class ResampleLQ<2>;
Represents a clock with a variable frequency.
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
unsigned getFreq() const
Returns the frequency (in Hz) at which this clock ticks.
constexpr uint64_t length() const
static constexpr FixedPoint roundRatioDown(unsigned n, unsigned d)
ResampleLQDown(ResampledSoundDevice &input, const DynamicClock &hostClock)
ResampleLQUp(ResampledSoundDevice &input, const DynamicClock &hostClock)
ResampleLQ(ResampledSoundDevice &input, const DynamicClock &hostClock)
bool fetchData(EmuTime::param time, unsigned &valid)
static std::unique_ptr< ResampleLQ< CHANNELS > > create(ResampledSoundDevice &input, const DynamicClock &hostClock)
const DynamicClock & hostClock
DynamicClock & getEmuClock()
This file implemented 3 utility functions:
constexpr bool all_of(InputRange &&range, UnaryPredicate pred)
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto xrange(T e)