openMSX
WavImage.cc
Go to the documentation of this file.
1 #include "WavImage.hh"
2 #include "File.hh"
3 #include "Filename.hh"
4 #include "FilePool.hh"
5 #include "Math.hh"
6 #include "xrange.hh"
7 
8 namespace openmsx {
9 
10 // DC-removal filter
11 // y(n) = x(n) - x(n-1) + R * y(n-1)
12 // see comments in MSXMixer.cc for more details
13 class DCFilter {
14 public:
15  void setFreq(unsigned sampleFreq) {
16  const float cuttOffFreq = 800.0f; // trial-and-error
17  R = 1.0f - ((float(2 * M_PI) * cuttOffFreq) / sampleFreq);
18  }
19  int16_t operator()(int16_t x) {
20  float t1 = R * t0 + x;
21  int16_t y = Math::clipIntToShort(t1 - t0);
22  t0 = t1;
23  return y;
24  }
25 private:
26  float R;
27  float t0 = 0.0f;
28 };
29 
30 // Note: type detection not implemented yet for WAV images
32  : clock(EmuTime::zero())
33 {
34  File file(filename);
35  setSha1Sum(filePool.getSha1Sum(file));
36 
37  wav = WavData(std::move(file), DCFilter{});
38  clock.setFreq(wav.getFreq());
39 }
40 
41 int16_t WavImage::getSampleAt(EmuTime::param time)
42 {
43  // The WAV file is typically sampled at 44kHz, but the MSX may sample
44  // the signal at arbitrary moments in time. Initially we would simply
45  // returned the closest older sample point (sample-and-hold
46  // resampling). Now we perform cubic interpolation between the 4
47  // surrounding sample points. Presumably this results in more accurately
48  // timed zero-crossings of the signal.
49  //
50  // Thanks to 'p_gimeno' for figuring out that cubic resampling makes
51  // the tape "Ingrid's back" sha1:9493e8851e9f173b67670a9a3de4645918ef436f
52  // work in openMSX (with sample-and-hold it didn't work).
53  auto [sample, x] = clock.getTicksTillAsIntFloat(time);
54  float p[4] = {
55  float(wav.getSample(unsigned(sample) - 1)), // intentional: underflow wraps to UINT_MAX
56  float(wav.getSample(sample + 0)),
57  float(wav.getSample(sample + 1)),
58  float(wav.getSample(sample + 2))
59  };
60  return Math::clipIntToShort(int(Math::cubicHermite(p + 1, x)));
61 }
62 
63 EmuTime WavImage::getEndTime() const
64 {
65  DynamicClock clk(clock);
66  clk += wav.getSize();
67  return clk.getTime();
68 }
69 
70 unsigned WavImage::getFrequency() const
71 {
72  return clock.getFreq();
73 }
74 
75 void WavImage::fillBuffer(unsigned pos, float** bufs, unsigned num) const
76 {
77  if (pos < wav.getSize()) {
78  for (auto i : xrange(num)) {
79  bufs[0][i] = wav.getSample(pos + i);
80  }
81  } else {
82  bufs[0] = nullptr;
83  }
84 }
85 
87 {
88  return 1.0f / 32768;
89 }
90 
91 } // namespace openmsx
WavImage.hh
openmsx::WavImage::getEndTime
EmuTime getEndTime() const override
Definition: WavImage.cc:63
xrange
auto xrange(T e)
Definition: xrange.hh:170
openmsx::DynamicClock::setFreq
void setFreq(unsigned freq)
Change the frequency at which this clock ticks.
Definition: DynamicClock.hh:103
openmsx::WavData::getSample
int16_t getSample(unsigned pos) const
Definition: WavData.hh:35
openmsx::WavData
Definition: WavData.hh:15
openmsx::WavData::getFreq
unsigned getFreq() const
Definition: WavData.hh:33
openmsx::WavData::getSize
unsigned getSize() const
Definition: WavData.hh:34
Math::cubicHermite
float cubicHermite(const float *y, float x)
Definition: Math.hh:288
openmsx::DynamicClock::getFreq
unsigned getFreq() const
Returns the frequency (in Hz) at which this clock ticks.
Definition: DynamicClock.hh:123
Filename.hh
openmsx::DCFilter::operator()
int16_t operator()(int16_t x)
Definition: WavImage.cc:19
M_PI
#define M_PI
Definition: Math.hh:27
openmsx::DynamicClock
Represents a clock with a variable frequency.
Definition: DynamicClock.hh:17
openmsx::FilePool::getSha1Sum
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
Definition: FilePool.cc:550
openmsx::DCFilter::setFreq
void setFreq(unsigned sampleFreq)
Definition: WavImage.cc:15
openmsx::CassetteImage::setSha1Sum
void setSha1Sum(const Sha1Sum &sha1sum)
Definition: CassetteImage.cc:19
File.hh
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
openmsx::WavImage::fillBuffer
void fillBuffer(unsigned pos, float **bufs, unsigned num) const override
Definition: WavImage.cc:75
openmsx::DCFilter
Definition: WavImage.cc:13
FilePool.hh
openmsx::WavImage::getAmplificationFactorImpl
float getAmplificationFactorImpl() const override
Definition: WavImage.cc:86
openmsx::x
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:1419
openmsx::WavImage::getFrequency
unsigned getFrequency() const override
Definition: WavImage.cc:70
openmsx::File
Definition: File.hh:16
Math::clipIntToShort
int16_t clipIntToShort(int x)
Clip x to range [-32768,32767].
Definition: Math.hh:111
openmsx::DynamicClock::getTime
EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
Definition: DynamicClock.hh:38
openmsx::FilePool
Definition: FilePool.hh:26
openmsx::DynamicClock::getTicksTillAsIntFloat
std::pair< unsigned, float > getTicksTillAsIntFloat(EmuTime::param e) const
Like getTicksTill(), but also returns the fractional part (in range [0, 1)).
Definition: DynamicClock.hh:64
openmsx::Filename
This class represents a filename.
Definition: Filename.hh:18
Math.hh
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
xrange.hh
openmsx::WavImage::getSampleAt
int16_t getSampleAt(EmuTime::param time) override
Definition: WavImage.cc:41
openmsx::WavImage::WavImage
WavImage(const Filename &filename, FilePool &filePool)
Definition: WavImage.cc:31