13static std::vector<float> bufferStorage;
14static size_t bufferSize = 0;
15static float* aBuffer =
nullptr;
19template<
unsigned CHANNELS>
23 std::unique_ptr<ResampleLQ<CHANNELS>> result;
25 result = std::make_unique<ResampleLQUp <CHANNELS>>(input, hostClock);
27 result = std::make_unique<ResampleLQDown<CHANNELS>>(input, hostClock);
32template<
unsigned CHANNELS>
36 , hostClock(hostClock_)
41 narrow<unsigned>(emuPeriod));
47[[nodiscard]]
static bool isSilent(
float x)
49 constexpr float threshold = 1.0f / 32768;
50 return std::abs(x) < threshold;
53template<
unsigned CHANNELS>
56 auto& emuClk = getEmuClock();
57 unsigned emuNum = emuClk.getTicksTill(time);
60 unsigned required = emuNum + 4;
61 if (required > bufferSize) [[unlikely]] {
63 bufferStorage.resize(required + 3);
65 auto p =
reinterpret_cast<uintptr_t
>(bufferStorage.data());
66 aBuffer =
reinterpret_cast<float*
>((p + 15) & ~15);
68 bufferSize = (bufferStorage.data() + bufferStorage.size()) - aBuffer;
69 assert(bufferSize >= required);
74 auto* buffer = &aBuffer[4 - 2 * CHANNELS];
75 assert((uintptr_t(&buffer[2 * CHANNELS]) & 15) == 0);
77 if (!input.generateInput(&buffer[2 * CHANNELS], emuNum)) {
79 if (
ranges::all_of(lastInput, [](
auto& l) {
return isSilent(l); })) {
84 ranges::fill(std::span{&buffer[CHANNELS], emuNum * CHANNELS}, 0);
86 for (
auto j :
xrange(2 * CHANNELS)) {
87 buffer[j] = lastInput[j];
88 lastInput[j] = buffer[emuNum * CHANNELS + j];
95template<
unsigned CHANNELS>
103template<
unsigned CHANNELS>
105 float* __restrict dataOut,
size_t hostNum, EmuTime::param time)
107 auto& emuClk = this->getEmuClock();
108 EmuTime host1 = this->hostClock.getFastAdd(1);
109 assert(host1 > emuClk.getTime());
111 emuClk.getTicksTill(host1, pos);
112 assert(pos.toInt() < 2);
115 if (!this->fetchData(time, valid))
return false;
120 auto* buffer = &aBuffer[4 - 2 * CHANNELS];
121 for (
auto i :
xrange(hostNum)) {
122 unsigned p = pos.toInt();
124 for (
auto j :
xrange(CHANNELS)) {
125 dataOut[i * CHANNELS + j] = buffer[p * CHANNELS + j];
135template<
unsigned CHANNELS>
143template<
unsigned CHANNELS>
145 float* __restrict dataOut,
size_t hostNum, EmuTime::param time)
147 auto& emuClk = this->getEmuClock();
148 EmuTime host1 = this->hostClock.getFastAdd(1);
149 assert(host1 > emuClk.getTime());
151 emuClk.getTicksTill(host1, pos);
154 if (!this->fetchData(time, valid))
return false;
156 auto* buffer = &aBuffer[4 - 2 * CHANNELS];
157 for (
auto i :
xrange(hostNum)) {
158 unsigned p = pos.toInt();
159 assert((p + 1) < valid);
160 FP fract = pos.fract();
161 for (
auto j :
xrange(CHANNELS)) {
162 auto s0 = buffer[(p + 0) * CHANNELS + j];
163 auto s1 = buffer[(p + 1) * CHANNELS + j];
164 auto out = s0 + (fract.toFloat() * (s1 - s0));
165 dataOut[i * CHANNELS + j] = out;
174template class ResampleLQ<1>;
175template 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:
bool all_of(InputRange &&range, UnaryPredicate pred)
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto xrange(T e)