-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathResampler.h
182 lines (148 loc) · 6.38 KB
/
Resampler.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/** Derive from this class to design a resampling system of your choosing! */
class Resampler
{
public:
/** Constructor. */
Resampler() noexcept = default;
/** Destructor. */
virtual ~Resampler() noexcept = default;
//==============================================================================
/** */
virtual void prepare (int numChannels, double sampleRate, int numSamples) = 0;
/** Configures the give audio buffers with the appropriate channels and samples.
@param numResultingSamples This is the destination number of samples.
@param numChannels The number of channels you plan on processing.
@param source The source audio buffer to configure.
@param destination The destination audio buffer to configure.
*/
virtual void configure (int numResultingSamples, int numChannels,
juce::AudioBuffer<float>& source,
juce::AudioBuffer<float>& destination)
{
const auto numSamples = roundToIntAccurate (getRatio() * numResultingSamples);
source.setSize (numChannels, numSamples, false, false, true);
source.clear();
destination.setSize (numChannels, numResultingSamples, false, false, true);
destination.clear();
}
/** Resamples a stream of samples.
@param source The source data to read from. This must contain at
least (speedRatio * numOutputSamplesToProduce) samples.
@param destination The buffer to write the results into.
@returns the actual number of input samples that were used.
*/
virtual int process (juce::AudioBuffer<float>& source,
juce::AudioBuffer<float>& destination) = 0;
//==============================================================================
/** Sets the ratio directly. */
void setRatio (double newRatio)
{
if (! approximatelyEqual (ratio.load(), newRatio) && newRatio > 0.0)
{
ratio = newRatio;
updateRatio();
}
}
/** Set the ratio via sampling rates; the source rate, and the destination rate to correct to. */
void setRatio (double sourceRate, double destinationRate)
{
if (sourceRate > 0.0 && destinationRate > 0.0)
setRatio (sourceRate / destinationRate);
}
/** If the ratio has changed, you might need to override this to update your subclass. */
virtual void updateRatio() {}
/** @returns the current resampling ratio. */
[[nodiscard]] double getRatio() const noexcept { return ratio.load(); }
/** @returns the inverse resampling ratio. */
[[nodiscard]] double getInverseRatio() const noexcept { return 1.0 / getRatio(); }
private:
//==============================================================================
std::atomic<double> ratio { 1.0 };
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Resampler)
};
//==============================================================================
/** */
template<typename ResamplerType>
class TemplatedResampler final : public Resampler
{
public:
/** Default Constructor. */
TemplatedResampler() = default;
/** Call this to prepare this fairly straightforward resampler. */
void prepare (int numChannels)
{
resamplers.ensureStorageAllocated (numChannels);
for (int i = 0; i < numChannels; ++i)
{
if (auto* r = resamplers[i])
r->reset();
else
resamplers.add (new ResamplerType());
}
}
/** @internal */
void prepare (int numChannels, double sampleRate, int numSamples) override
{
ignoreUnused (sampleRate, numSamples);
prepare (numChannels);
}
/** @internal */
int process (juce::AudioBuffer<float>& source, juce::AudioBuffer<float>& dest) override
{
const auto localRatio = getRatio();
if (approximatelyEqual (localRatio, 1.0) || source.hasBeenCleared())
{
dest = source;
return source.getNumSamples();
}
int numSamplesUsed = 0;
const auto numOutSamples = dest.getNumSamples();
const auto numChans = std::min (source.getNumChannels(), dest.getNumChannels(), resamplers.size());
if (numChans <= 0)
dest.clear();
for (int i = numChans; --i >= 0;)
numSamplesUsed = std::max (numSamplesUsed,
resamplers.getUnchecked (i)->process (localRatio,
source.getReadPointer (i),
dest.getWritePointer (i),
numOutSamples));
return numSamplesUsed;
}
private:
//==============================================================================
OwnedArray<ResamplerType> resamplers; // Need to have one resampler per channel.
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemplatedResampler)
};
//==============================================================================
/** */
using WindowedSincResampler = TemplatedResampler<WindowedSincInterpolator>;
/** */
using LagrangeResampler = TemplatedResampler<LagrangeInterpolator>;
/** */
using CatmullRomResampler = TemplatedResampler<CatmullRomInterpolator>;
/** */
using LinearResampler = TemplatedResampler<LinearInterpolator>;
/** */
using ZeroOrderHoldResampler = TemplatedResampler<ZeroOrderHoldInterpolator>;
//==============================================================================
#if SQUAREPINE_USE_R8BRAIN
/** */
class R8brainResampler final : public Resampler
{
public:
/** Constructor. */
R8brainResampler() noexcept = default;
/** @internal */
void prepare (int numChannels, int numSamples, double sampleRate) override;
/** @internal */
int process (juce::AudioBuffer<float>& source, juce::AudioBuffer<float>& dest) override;
/** @internal */
void updateRatio() override;
private:
OwnedArray<r8b::CDSPResampler24> resamplers;
int numChannels = 0, blockSize = 0;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (R8brainResampler)
};
#endif //SQUAREPINE_USE_R8BRAIN