19template <
typename T>
class DSPBase;
20template <
typename T>
class SignalBase;
25template <
typename SampleType>
33 AudioBuffer (size_t numChannels = 0, size_t numFrames = 0,
double sampleRateHz =
nan<double>()) :
34 m_numChannels (numChannels),
35 m_numFrames (numFrames),
36 m_sampleRateHz (sampleRateHz),
37 m_frames (m_numChannels * m_numFrames),
38 m_channelPointers (m_numChannels)
40 updateChannelPointers();
45 m_numChannels (other.m_numChannels),
46 m_numFrames (other.m_numFrames),
47 m_sampleRateHz (other.m_sampleRateHz),
48 m_frames (other.m_frames),
49 m_channelPointers (m_numChannels)
51 updateChannelPointers();
56 m_numChannels (other.m_numChannels),
57 m_numFrames (other.m_numFrames),
58 m_sampleRateHz (other.m_sampleRateHz),
59 m_frames (std::move (other.m_frames)),
60 m_channelPointers (std::move (other.m_channelPointers))
74 if (m_numChannels != other.m_numChannels)
77 m_numFrames = other.m_numFrames;
78 m_sampleRateHz = other.m_sampleRateHz;
79 m_frames = other.m_frames;
80 m_channelPointers.resize (m_numChannels);
81 updateChannelPointers();
92 m_numChannels = other.m_numChannels;
93 m_numFrames = other.m_numFrames;
94 m_sampleRateHz = other.m_sampleRateHz;
95 m_frames = std::move (other.m_frames);
96 m_channelPointers = std::move (other.m_channelPointers);
107 return static_cast<
const SampleType*
const*> (m_channelPointers.data());
115 return m_channelPointers.data();
123 return other.hasSampleRate()
124 ?
AudioBuffer (other.getNumChannels(), other.getNumFrames(), other.getSampleRateHz())
125 :
AudioBuffer (other.getNumChannels(), other.getNumFrames());
146 if (newNumFrames == m_numFrames)
149 const size_t oldTotalSamples = m_frames.size();
150 const size_t newTotalSamples = m_numChannels * newNumFrames;
152 if (newNumFrames < m_numFrames)
154 m_frames.resize (newTotalSamples);
155 m_numFrames = newNumFrames;
156 updateChannelPointers();
160 if (newTotalSamples > oldTotalSamples)
162 m_frames.resize (newTotalSamples);
164 m_frames.begin() + oldTotalSamples,
170 m_numFrames = newNumFrames;
171 updateChannelPointers();
179 return ! std::isnan (m_sampleRateHz);
187 hassert (! std::isnan (m_sampleRateHz));
188 return m_sampleRateHz;
196 if (m_numFrames == 0)
199 hassert (! std::isnan (m_sampleRateHz));
201 return static_cast <
double> (m_numFrames) / m_sampleRateHz;
209 return m_channelPointers[channel];
215 const SampleType*
operator[] (size_t channel)
const
217 return m_channelPointers[channel];
231 if (m_numChannels != other.m_numChannels || m_numFrames != other.m_numFrames)
234 if (
hasSampleRate() && other.hasSampleRate() && ! floatsEqual (m_sampleRateHz, other.m_sampleRateHz))
237 const SampleType* thisRawData = m_frames.data();
238 const SampleType* otherRawData = other.m_frames.data();
239 const size_t numFlattenedSamples = m_frames.size();
241 for (size_t sample = 0; sample < numFlattenedSamples; ++sample)
242 if (std::abs (thisRawData[sample] - otherRawData[sample]) > toleranceLinear)
272 if (otherBuffer.getNumChannels() != m_numChannels)
278 const size_t thisNumFrames = m_numFrames;
279 const size_t otherNumFrames = otherBuffer.getNumFrames();
281 std::vector<SampleType> combinedFrames (m_numChannels * (thisNumFrames + otherNumFrames));
283 for (size_t channel = 0; channel < m_numChannels; ++channel)
285 SampleType* newChannelStart = &combinedFrames[channel * (thisNumFrames + otherNumFrames)];
286 std::copy (m_channelPointers[channel], m_channelPointers[channel] + thisNumFrames, newChannelStart);
287 std::copy (otherBuffer[channel], otherBuffer[channel] + otherNumFrames, newChannelStart + thisNumFrames);
290 m_frames = std::move (combinedFrames);
291 m_numFrames += otherNumFrames;
293 updateChannelPointers();
306 if (m_channelPointers.size() != m_numChannels)
307 m_channelPointers.resize (m_numChannels);
309 updateChannelPointers();
317 SampleType
getMagnitude (size_t channel, size_t startFrame, size_t numFrames)
const
319 if (channel >= m_numChannels)
322 if (startFrame + numFrames > m_numFrames || numFrames == 0)
325 const SampleType* start = m_channelPointers[channel] + startFrame;
326 const SampleType* peakSample = std::max_element (
329 [] (SampleType a, SampleType b) {
return std::abs (a) < std::abs (b); }
332 return std::abs (*peakSample);
341 if (startFrame + numFrames > m_numFrames || numFrames == 0)
344 SampleType peakSampleAcrossAllChannels = (SampleType) 0;
346 for (size_t channel = 0; channel < m_numChannels; ++channel)
348 const SampleType* start = m_channelPointers[channel] + startFrame;
349 const SampleType* peakSample = std::max_element (
352 [] (SampleType a, SampleType b) {
return std::abs (a) < std::abs (b); }
354 peakSampleAcrossAllChannels = std::max (peakSampleAcrossAllChannels, std::abs (*peakSample));
357 return peakSampleAcrossAllChannels;
367 void copyFrom (size_t destChannel, size_t destStartFrame,
const AudioBuffer& source, size_t sourceChannel, size_t sourceStartFrame, size_t numFrames)
369 if (destChannel >= m_numChannels || sourceChannel >= source.m_numChannels)
372 if (destStartFrame + numFrames > m_numFrames || sourceStartFrame + numFrames > source.m_numFrames)
379 source.m_channelPointers[sourceChannel] + sourceStartFrame,
380 source.m_channelPointers[sourceChannel] + sourceStartFrame + numFrames,
381 m_channelPointers[destChannel] + destStartFrame
390 void copyFrom (size_t destChannel, size_t destStartFrame,
const SampleType* source, size_t numFrames)
392 if (destChannel >= m_numChannels)
395 if (destStartFrame + numFrames > m_numFrames)
398 std::copy (source, source + numFrames, m_channelPointers[destChannel] + destStartFrame);
405 std::fill (m_frames.begin(), m_frames.end(), (SampleType) 0);
413 void clear (size_t channel, size_t startFrame, size_t numFrames)
415 if (channel >= m_numChannels)
418 if (startFrame + numFrames > m_numFrames)
421 std::fill (m_channelPointers[channel], m_channelPointers[channel] + numFrames, (SampleType) 0);
428 stream <<
"AudioBuffer (" << m_numChannels <<
", " << m_numFrames;
431 stream <<
", " <<
hzPrecision << m_sampleRateHz <<
"_Hz)";
433 stream <<
", nan())";
456 _fillWith (signal, blockSizeFrames, signalPreparation);
479 _fillWith (signal, blockSizeFrames, signalPreparation);
503 _fillWith (signal, blockSizeFrames, signalPreparation);
504 return std::move (*
this);
526 _fillWith (signal, blockSizeFrames, signalPreparation);
527 return std::move (*
this);
550 _processWith (dsp, blockSizeFrames, dspPreparation);
573 _processWith (dsp, blockSizeFrames, dspPreparation);
597 _processWith (dsp, blockSizeFrames, dspPreparation);
598 return std::move (*
this);
620 _processWith (dsp, blockSizeFrames, dspPreparation);
621 return std::move (*
this);
637 return {0, numFrames};
642 const size_t startFrame =
static_cast<size_t> (slice
.start);
643 const size_t stopFrame =
static_cast<size_t> (slice
.stop);
646 std::min (startFrame, numFrames),
647 std::min (stopFrame, numFrames)
658 std::min (startFrame, numFrames),
659 std::min (stopFrame, numFrames)
671 size_t m_numChannels = 0;
672 size_t m_numFrames = 0;
673 double m_sampleRateHz =
nan<double>();
674 std::vector<SampleType> m_frames;
675 std::vector<SampleType*> m_channelPointers;
677 void updateChannelPointers()
679 for (size_t channel = 0; channel < m_numChannels; ++channel)
680 m_channelPointers[channel] = m_numFrames > 0 ? &m_frames[channel * m_numFrames] :
nullptr;
685 friend std::ostream& operator<< (std::ostream& stream,
const AudioBuffer& audioBuffer)
687 audioBuffer.represent (stream);
691 void _processWith (
DSPBase<SampleType>& dsp, size_t blockSizeFrames,
Preparation dspPreparation);
692 void _fillWith (SignalBase<SampleType>& signal, size_t blockSizeFrames,
Preparation signalPreparation);
Container for audio data.
void clear(size_t channel, size_t startFrame, size_t numFrames)
Clears a specific section of a given channel.
AudioBuffer< SampleType > && processWith(DSPBase< SampleType > &dsp, size_t blockSizeFrames=0, Preparation dspPreparation=Preparation::resetAndPrepare) &&
Processes this AudioBuffer by rendering its audio through a provided DSP.
AudioBuffer< SampleType > & fillWith(SignalBase< SampleType > &signal, size_t blockSizeFrames=0, Preparation signalPreparation=Preparation::resetAndPrepare) &
Fills this AudioBuffer by rendering audio from a Signal.
SampleType * operator[](size_t channel)
Get a raw pointer to a specific channel's mutable audio data.
static AudioBuffer emptyLike(const AudioBuffer &other)
Creates an empty audio buffer with the same number of channels, frames and sample rate as the other b...
size_t getNumFrames() const
Get number of frames (samples)
AudioBuffer & operator=(const AudioBuffer &other)
Creates an audio buffer by copy-assigning.
AudioBuffer(size_t numChannels=0, size_t numFrames=0, double sampleRateHz=nan< double >())
Creates an audio buffer.
void appendFrom(const AudioBuffer< SampleType > &otherBuffer)
Appends data from another buffer.
AudioBuffer(AudioBuffer &&other) noexcept
Creates an audio buffer by moving.
double getLengthSeconds() const
Get a duration of the audio buffer.
bool hasSampleRate() const
Check if a specific sample rate was assigned to the audio buffer.
void setNumFrames(size_t newNumFrames)
Resizes the buffer to hold a new number of frames per channel.
void copyFrom(size_t destChannel, size_t destStartFrame, const SampleType *source, size_t numFrames)
Copies audio from another generic audio buffer.
void copyFrom(size_t destChannel, size_t destStartFrame, const AudioBuffer &source, size_t sourceChannel, size_t sourceStartFrame, size_t numFrames)
Copies audio from another buffer.
double getSampleRateHz() const
Get a sample rate metadata.
std::pair< size_t, size_t > getFrameIndices(const Slice &slice) const
Returns a pair of indices representing a provided slice.
AudioBuffer< SampleType > & processWith(DSPBase< SampleType > &&dsp, size_t blockSizeFrames=0, Preparation dspPreparation=Preparation::resetAndPrepare) &
Processes this AudioBuffer by rendering its audio through a provided DSP.
AudioBuffer< SampleType > && processWith(DSPBase< SampleType > &&dsp, size_t blockSizeFrames=0, Preparation dspPreparation=Preparation::resetAndPrepare) &&
Processes this AudioBuffer by rendering its audio through a provided DSP.
AudioBuffer< SampleType > & fillWith(SignalBase< SampleType > &&signal, size_t blockSizeFrames=0, Preparation signalPreparation=Preparation::resetAndPrepare) &
Fills this AudioBuffer by rendering audio from a Signal.
const SampleType *const * getArrayOfReadPointers() const
Gets a raw pointer to the read-only audio data.
bool operator!=(const AudioBuffer &other) const
Checks whether two buffers differ beyond the default comparison tolerance.
SampleType getMagnitude(size_t startFrame, size_t numFrames) const
Get the maximum absolute value in the buffer across all channels.
AudioBuffer & operator=(AudioBuffer &&other) noexcept
Creates an audio buffer by move-assigning.
SampleType *const * getArrayOfWritePointers()
Gets a raw pointer to the mutable audio data.
AudioBuffer(const AudioBuffer &other)
Creates an audio buffer by copying.
~AudioBuffer()=default
The destructor.
const SampleType * operator[](size_t channel) const
Get a raw pointer to a specific channel's read-only audio data.
AudioBuffer< SampleType > && fillWith(SignalBase< SampleType > &&signal, size_t blockSizeFrames=0, Preparation signalPreparation=Preparation::resetAndPrepare) &&
Fills this AudioBuffer by rendering audio from a Signal.
AudioBuffer< SampleType > && fillWith(SignalBase< SampleType > &signal, size_t blockSizeFrames=0, Preparation signalPreparation=Preparation::resetAndPrepare) &&
Fills this AudioBuffer by rendering audio from a Signal.
AudioBuffer< SampleType > & processWith(DSPBase< SampleType > &dsp, size_t blockSizeFrames=0, Preparation dspPreparation=Preparation::resetAndPrepare) &
Processes this AudioBuffer by rendering its audio through a provided DSP.
void represent(std::ostream &stream) const
Prints readable representation of the audio buffer.
SampleType getMagnitude(size_t channel, size_t startFrame, size_t numFrames) const
Get the maximum absolute value in the buffer in a specific channel.
void clear()
Clears the entire buffer.
size_t getNumChannels() const
Get number of channels.
void erase()
Clears the buffer.
bool equalsTo(const AudioBuffer &other, SampleType toleranceLinear=(SampleType) 1e-6) const
Checks whether this buffer contains approximately the same audio as another buffer.
bool operator==(const AudioBuffer &other) const
Checks whether two buffers contain approximately the same audio.
Thrown when a numbers of channels is mismatched.
Polymorphic base for all DSP.
Thrown when a container index is out of range.
Thrown when some metric is requested to return a value in an unsupported unit.
#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 HART_THROW_OR_RETURN(ExceptionType, message, returnValue)
Throws an exception if HART_DO_NOT_THROW_EXCEPTIONS is set, prints a message and returns a specified ...
std::ostream & hzPrecision(std::ostream &stream)
Sets number of decimal places for values in hertz.
FloatType nan()
Returns a quiet NaN value for the given floating-point type.
static size_t roundToSizeT(SampleType x)
Rounds a floating point value to a size_t value.
static SampleType floatsEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.
Preparation
Describes whether to call reset() and/or prepare() before rendering through DSP or a Signal.
Represents a slice of analysis data.