openMSX
ResampleBlip.cc
Go to the documentation of this file.
1 #include "ResampleBlip.hh"
3 #include "likely.hh"
4 #include "one_of.hh"
5 #include "ranges.hh"
6 #include "vla.hh"
7 #include "xrange.hh"
8 #include <cassert>
9 
10 namespace openmsx {
11 
12 template<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 
28 template<unsigned CHANNELS>
29 bool ResampleBlip<CHANNELS>::generateOutputImpl(float* dataOut, unsigned 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, 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 (unlikely(delta != 0)) {
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  bool results[CHANNELS];
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.
110 template class ResampleBlip<1>;
111 template class ResampleBlip<2>;
112 
113 } // namespace openmsx
constexpr unsigned CHANNELS
Definition: YM2413Test.cc:20
Definition: one_of.hh:7
Represents a clock with a variable frequency.
Definition: DynamicClock.hh:17
EmuDuration getPeriod() const
Returns the length of one clock-cycle.
constexpr uint64_t length() const
Definition: EmuDuration.hh:50
static constexpr FixedPoint roundRatioDown(unsigned n, unsigned d)
Definition: FixedPoint.hh:59
ResampleBlip(ResampledSoundDevice &input, const DynamicClock &hostClock)
Definition: ResampleBlip.cc:13
bool generateOutputImpl(float *dataOut, unsigned num, EmuTime::param time) override
Definition: ResampleBlip.cc:29
constexpr auto step
Definition: eeprom.cc:9
#define unlikely(x)
Definition: likely.hh:15
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
This file implemented 3 utility functions:
Definition: Autofire.cc:5
void fill(ForwardRange &&range, const T &value)
Definition: ranges.hh:197
#define VLA_SSE_ALIGNED(TYPE, NAME, LENGTH)
Definition: vla.hh:44
constexpr auto xrange(T e)
Definition: xrange.hh:155