openMSX
ResampleBlip.cc
Go to the documentation of this file.
1#include "ResampleBlip.hh"
3#include "one_of.hh"
4#include "ranges.hh"
5#include "vla.hh"
6#include "xrange.hh"
7#include <array>
8#include <cassert>
9
10namespace openmsx {
11
12template<unsigned CHANNELS>
14 ResampledSoundDevice& input_, const DynamicClock& hostClock_)
15 : ResampleAlgo(input_)
16 , hostClock(hostClock_)
17 , step([&]{ // calculate 'hostClock.getFreq() / getEmuClock().getFreq()', but with less rounding errors
18 uint64_t emuPeriod = input_.getEmuClock().getPeriod().length(); // unknown units
19 uint64_t hostPeriod = hostClock.getPeriod().length(); // unknown units, but same as above
20 assert(unsigned( emuPeriod) == emuPeriod);
21 assert(unsigned(hostPeriod) == hostPeriod);
22 return FP::roundRatioDown(emuPeriod, hostPeriod);
23 }())
24{
25 ranges::fill(lastInput, 0.0f);
26}
27
28template<unsigned CHANNELS>
29bool ResampleBlip<CHANNELS>::generateOutputImpl(float* dataOut, size_t hostNum,
30 EmuTime::param time)
31{
32 auto& emuClk = getEmuClock();
33 unsigned emuNum = emuClk.getTicksTill(time);
34 if (emuNum > 0) {
35 // 3 extra for padding, CHANNELS extra for sentinel
36 // Clang will produce a link error if the length expression is put
37 // inside the macro.
38 const unsigned len = emuNum * CHANNELS + std::max(3u, CHANNELS);
39 VLA_SSE_ALIGNED(float, buf, len);
40 EmuTime emu1 = emuClk.getFastAdd(1); // time of 1st emu-sample
41 assert(emu1 > hostClock.getTime());
42 if (input.generateInput(buf.data(), emuNum)) {
43 FP pos1;
44 hostClock.getTicksTill(emu1, pos1);
45 for (auto ch : xrange(CHANNELS)) {
46 // In case of PSG (and to a lesser degree SCC) it happens
47 // very often that two consecutive samples have the same
48 // value. We can benefit from this by setting a sentinel
49 // at the end of the buffer and move the end-of-loop test
50 // into the 'samples differ' branch.
51 assert(emuNum > 0);
52 buf[CHANNELS * emuNum + ch] =
53 buf[CHANNELS * (emuNum - 1) + ch] + 1.0f;
54 FP pos = pos1;
55 auto last = lastInput[ch]; // local var is slightly faster
56 for (unsigned i = 0; ; ++i) {
57 auto delta = buf[CHANNELS * i + ch] - last;
58 if (delta != 0) [[unlikely]] {
59 if (i == emuNum) {
60 break;
61 }
62 last = buf[CHANNELS * i + ch];
63 blip[ch].addDelta(
65 delta);
66 }
67 pos += step;
68 }
69 lastInput[ch] = last;
70 }
71 } else {
72 // input all zero
74 hostClock.getTicksTill(emu1, pos);
75 for (auto ch : xrange(CHANNELS)) {
76 if (lastInput[ch] != 0.0f) {
77 auto delta = -lastInput[ch];
78 lastInput[ch] = 0.0f;
79 blip[ch].addDelta(pos, delta);
80 }
81 }
82 }
83 emuClk += emuNum;
84 }
85
86 std::array<bool, CHANNELS> results;
87 for (auto ch : xrange(CHANNELS)) {
88 results[ch] = blip[ch].template readSamples<CHANNELS>(dataOut + ch, hostNum);
89 }
90 static_assert(CHANNELS == one_of(1u, 2u), "either mono or stereo");
91 if constexpr (CHANNELS == 1) {
92 return results[0];
93 } else {
94 if (results[0] == results[1]) {
95 // Both muted or both unmuted
96 return results[0];
97 } else {
98 // One channel muted, the other not.
99 // We have to set the muted channel to all-zero.
100 unsigned offset = results[0] ? 1 : 0;
101 for (auto i : xrange(hostNum)) {
102 dataOut[2 * i + offset] = 0.0f;
103 }
104 return true;
105 }
106 }
107}
108
109// Force template instantiation.
110template class ResampleBlip<1>;
111template class ResampleBlip<2>;
112
113} // namespace openmsx
Definition: one_of.hh:7
Represents a clock with a variable frequency.
Definition: DynamicClock.hh:16
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
constexpr uint64_t length() const
Definition: EmuDuration.hh:52
static constexpr FixedPoint roundRatioDown(unsigned n, unsigned d)
Definition: FixedPoint.hh:59
bool generateOutputImpl(float *dataOut, size_t num, EmuTime::param time) override
Definition: ResampleBlip.cc:29
ResampleBlip(ResampledSoundDevice &input, const DynamicClock &hostClock)
Definition: ResampleBlip.cc:13
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:284
This file implemented 3 utility functions:
Definition: Autofire.cc:9
constexpr void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:287
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:50
constexpr auto xrange(T e)
Definition: xrange.hh:133