HART  0.2.0
High level Audio Regression and Testing
Loading...
Searching...
No Matches
hart_resample.hpp
Go to the documentation of this file.
1#pragma once
2
3// Config for r8brain
4#define R8B_IPP 0 // Don't want extra dependencies it comes with
5#define R8B_PFFFT 0 // Don't want this extra dependency
6#define R8B_PFFFT_DOUBLE 0 // Don't want this extra dependency
7#define R8B_FASTTIMING 0 // On the fence here, but doesn't seem to have much of an impact either way
8#define R8B_EXTFFT 1 // We don't mind extra latency
9
10#include "dependencies/r8brain-free-src/CDSPResampler.h"
12#include "hart_utils.hpp" // roundToSizeT(), floatsEqual()
13
14namespace hart
15{
16
17/// @brief Resamples audio buffers
18/// @details Uses r8brain under the hood, a sample rate converter designed by Aleksey Vaneev of Voxengo
19/// @note Intended to be used internally by containers like AudioBuffer or ImpulseResponse, but you can use
20/// it too, if you really want to. But it's encouraged to use those containers' methods, whenever appropriate.
21/// @ingroup Utilities
22template <typename SampleType>
23static void resample (const SampleType* sourceData, size_t sourceSizeFrames, double sourceSampleRateHz, SampleType* destinationData, size_t destinationCapacityFrames, double destinationSampleRateHz)
24{
25 if (sourceData == nullptr)
26 HART_THROW_OR_RETURN_VOID (NullPointerError, "sourceData pointer is nullptr");
27
28 if (destinationData == nullptr)
29 HART_THROW_OR_RETURN_VOID (NullPointerError, "destinationData pointer is nullptr");
30
31 if (sourceSizeFrames == 0)
32 HART_THROW_OR_RETURN_VOID (SizeError, "Source data length is zero");
33
34 if (destinationCapacityFrames == 0)
35 HART_THROW_OR_RETURN_VOID (SizeError, "Destination data capacity is zero");
36
37 if (sourceSampleRateHz < 0.0 || floatsEqual (sourceSampleRateHz, 0.0) || std::isnan (sourceSampleRateHz))
38 HART_THROW_OR_RETURN_VOID (hart::SampleRateError, "Invalid source sample rate");
39
40 if (destinationSampleRateHz < 0.0 || floatsEqual (destinationSampleRateHz, 0.0) || std::isnan (destinationSampleRateHz))
41 HART_THROW_OR_RETURN_VOID (hart::SampleRateError, "Invalid destination sample rate");
42
43 const double sampleRatesRatio = destinationSampleRateHz / sourceSampleRateHz;
44 const double minDestinationCapacityFrames = roundToSizeT (static_cast<double> (sourceSizeFrames) * destinationSampleRateHz / sourceSampleRateHz);
45
46 if (destinationCapacityFrames < minDestinationCapacityFrames)
47 HART_THROW_OR_RETURN_VOID (SizeError, "Destination buffer doesn't have sufficient capacity");
48
49 // It can also be r8b::CDSPResampler instead of r8b::CDSPResampler24, for even better fidelity
50 r8b::CDSPResampler24 resampler (sourceSampleRateHz, destinationSampleRateHz, sourceSizeFrames);
51 hassert (floatsEqual (resampler.getLatencyFrac(), 0.0)); // We don't want SRC filters to introduce latency without us knowiung
52
53 resampler.oneshot (const_cast<SampleType*> (sourceData), static_cast<int> (sourceSizeFrames), destinationData, static_cast<int> (destinationCapacityFrames));
54}
55
56} // namespace hart
Thrown when a nullptr could be handled gracefully.
Thrown when sample rate is mismatched or invalid.
Thrown when an unexpected container size is encountered.
#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
static size_t roundToSizeT(SampleType x)
Rounds a floating point value to a size_t value.
static void resample(const SampleType *sourceData, size_t sourceSizeFrames, double sourceSampleRateHz, SampleType *destinationData, size_t destinationCapacityFrames, double destinationSampleRateHz)
Resamples audio buffers.
static SampleType floatsEqual(SampleType a, SampleType b, SampleType epsilon=(SampleType) 1e-8)
Compares two floating point numbers within a given tolerance.