6#include "dependencies/choc/platform/choc_DisableAllWarnings.h"
7#include "dependencies/dr_libs/dr_wav.h"
8#include "dependencies/choc/platform/choc_ReenableAllWarnings.h"
11#include "signals/hart_signal.hpp"
25template<
typename SampleType>
47 m_filePath (filePath),
56 drwav_uint64 numFrames;
57 unsigned int numChannels;
58 unsigned int wavSampleRateHz;
60 float* pcmFrames = drwav_open_file_and_read_pcm_frames_f32 (
61 fileAbsolutePath.c_str(),
68 if (pcmFrames ==
nullptr)
71 m_wavFramesOriginal = std::make_shared<AudioBuffer<SampleType>> (
72 static_cast<size_t> (numChannels),
73 static_cast<size_t> (numFrames),
74 static_cast<
double> (wavSampleRateHz)
77 for (size_t frame = 0; frame < numFrames; ++frame)
78 for (size_t channel = 0; channel < numChannels; ++channel)
79 (*m_wavFramesOriginal)[channel][frame] =
static_cast<SampleType> (pcmFrames[frame * numChannels + channel]);
81 drwav_free (pcmFrames,
nullptr);
90 if (m_wavFramesOriginal ==
nullptr)
96 return numChannels <= m_wavFramesOriginal->getNumChannels();
102 return sampleRateHz > 0.0;
106 if (m_wavFramesOriginal ==
nullptr)
112 return floatsEqual (sampleRateHz, m_wavFramesOriginal->getSampleRateHz(), m_sampleRateToleranceHz);
115 void prepare (
double sampleRateHz, size_t numOutputChannels, size_t )
override
117 if (m_wavFramesOriginal ==
nullptr)
124 if (numOutputChannels != m_wavFramesOriginal->getNumChannels())
127 hassert (m_wavFramesOriginal->hasSampleRate());
128 const bool needsResampling = floatsNotEqual (sampleRateHz, m_wavFramesOriginal->getSampleRateHz(), m_sampleRateToleranceHz);
135 if (m_wavFramesResampled ==
nullptr || floatsNotEqual (m_wavFramesResampled->getSampleRateHz(), sampleRateHz, m_sampleRateToleranceHz))
136 m_wavFramesResampled = std::make_shared<AudioBuffer<SampleType>> (m_wavFramesOriginal->resample (sampleRateHz));
138 m_wavFramesSource = m_wavFramesResampled;
142 m_wavFramesSource = m_wavFramesOriginal;
145 hassert (m_wavFramesSource !=
nullptr);
146 hassert (floatsEqual (m_wavFramesSource->getSampleRateHz(), sampleRateHz, m_sampleRateToleranceHz));
153 if (m_wavFramesSource ==
nullptr)
160 hassert (output.getNumChannels() == m_wavFramesSource->getNumChannels());
161 hassert (output.hasSampleRate());
162 hassert (m_wavFramesSource->hasSampleRate());
163 hassert (floatsEqual (output.getSampleRateHz(), m_wavFramesSource->getSampleRateHz(), m_sampleRateToleranceHz));
165 const size_t numFrames = output.getNumFrames();
166 const size_t numChannels = output.getNumChannels();
167 size_t frameInOutputBuffer = 0;
168 size_t frameInWavBuffer = m_wavOffsetFrames;
170 while (m_wavOffsetFrames < m_wavFramesSource->getNumFrames() && frameInOutputBuffer < numFrames)
172 for (size_t channel = 0; channel < m_wavFramesSource->getNumChannels(); ++channel)
173 output[channel][frameInOutputBuffer] = (*m_wavFramesSource)[channel][frameInWavBuffer];
175 ++frameInOutputBuffer;
180 m_wavOffsetFrames %= m_wavFramesSource->getNumFrames();
183 while (frameInOutputBuffer < numFrames)
187 for (size_t channel = 0; channel < m_wavFramesSource->getNumChannels(); ++channel)
188 output[channel][frameInOutputBuffer] = (SampleType) 0;
190 ++frameInOutputBuffer;
196 m_wavOffsetFrames = 0;
201 stream <<
"WavFile (\"" << m_filePath << (m_loop ==
Loop::yes ?
"\", Loop::yes)" :
"\", Loop::no)");
205 static constexpr double m_sampleRateToleranceHz = 1e-3;
206 const std::string m_filePath;
209 size_t m_wavOffsetFrames = 0;
210 std::shared_ptr<AudioBuffer<SampleType>> m_wavFramesOriginal;
211 std::shared_ptr<AudioBuffer<SampleType>> m_wavFramesResampled;
212 std::shared_ptr<AudioBuffer<SampleType>> m_wavFramesSource;
Thrown when a numbers of channels is mismatched.
Thrown when some I/O operation fails.
Produces audio from a wav file.
void renderNextBlock(AudioBuffer< SampleType > &output) override
Renders next block audio for the signal.
bool supportsSampleRate(double sampleRateHz) const override
Tells whether this Signal supports given sample rate.
Resample
Instructs WavFile whether to resample audio, if requested Sample Rate doesn't match original SR of th...
@ no
If sample of test runner doesn't match the wav file's SR, it will refuse to render audio.
@ yes
If sample of test runner doesn't match the wav file's SR, it will quietly re-sample.
void prepare(double sampleRateHz, size_t numOutputChannels, size_t) override
Prepare the signal for rendering.
void represent(std::ostream &stream) const override
Makes a text representation of this Signal for test failure outputs.
WavFile(const std::string &filePath, Loop loop=Loop::no, Resample resample=Resample::yes)
Creates a Signal that produces audio from a wav file.
bool supportsNumChannels(size_t numChannels) const override
Tells the host whether this Signal is capable of generating audio for a certain amount of channels.
void reset() override
Resets the Signal to initial state.
#define HART_THROW_OR_RETURN_VOID(ExceptionType, message)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns otherwise.
#define hassert(condition)
Triggers a HartAssertException if the condition is false
#define hassertfalse
Triggers a HartAssertException
static bool fileExistsAndReadable(const std::string &path)
static std::string toAbsolutePath(const std::string &path)
Converts path to absolute, if it's relative.
Loop
Helper values for something that could loop, like a Signal.
#define HART_SIGNAL_DECLARE_ALIASES_FOR(ClassName)