27 const bool deleteInputWhenDeleted,
29 : input (inputSource, deleteInputWhenDeleted),
35 numChannels (channels)
37 jassert (input !=
nullptr);
38 zeromem (coefficients,
sizeof (coefficients));
45 jassert (samplesInPerOutputSample > 0);
48 ratio = jmax (0.0, samplesInPerOutputSample);
55 auto scaledBlockSize = roundToInt (samplesPerBlockExpected * ratio);
56 input->prepareToPlay (scaledBlockSize, sampleRate * ratio);
58 buffer.
setSize (numChannels, scaledBlockSize + 32);
60 filterStates.
calloc (numChannels);
61 srcBuffers.
calloc (numChannels);
62 destBuffers.
calloc (numChannels);
63 createLowPass (ratio);
73 subSampleOffset = 0.0;
79 input->releaseResources();
80 buffer.
setSize (numChannels, 0);
92 if (lastRatio != localRatio)
94 createLowPass (localRatio);
95 lastRatio = localRatio;
98 const int sampsNeeded = roundToInt (info.
numSamples * localRatio) + 3;
102 if (bufferSize < sampsNeeded + 8)
104 bufferPos %= bufferSize;
105 bufferSize = sampsNeeded + 32;
109 bufferPos %= bufferSize;
111 int endOfBufferPos = bufferPos + sampsInBuffer;
114 while (sampsNeeded > sampsInBuffer)
116 endOfBufferPos %= bufferSize;
118 int numToDo = jmin (sampsNeeded - sampsInBuffer,
119 bufferSize - endOfBufferPos);
122 input->getNextAudioBlock (readInfo);
124 if (localRatio > 1.0001)
128 for (
int i = channelsToProcess; --i >= 0;)
129 applyFilter (buffer.
getWritePointer (i, endOfBufferPos), numToDo, filterStates[i]);
132 sampsInBuffer += numToDo;
133 endOfBufferPos += numToDo;
136 for (
int channel = 0; channel < channelsToProcess; ++channel)
142 int nextPos = (bufferPos + 1) % bufferSize;
146 jassert (sampsInBuffer > 0 && nextPos != endOfBufferPos);
148 const float alpha = (float) subSampleOffset;
150 for (
int channel = 0; channel < channelsToProcess; ++channel)
151 *destBuffers[channel]++ = srcBuffers[channel][bufferPos]
152 + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]);
154 subSampleOffset += localRatio;
156 while (subSampleOffset >= 1.0)
158 if (++bufferPos >= bufferSize)
163 nextPos = (bufferPos + 1) % bufferSize;
164 subSampleOffset -= 1.0;
168 if (localRatio < 0.9999)
171 for (
int i = channelsToProcess; --i >= 0;)
174 else if (localRatio <= 1.0001 && info.numSamples > 0)
177 for (
int i = channelsToProcess; --i >= 0;)
180 FilterState& fs = filterStates[i];
184 fs.y2 = fs.x2 = *(endOfBuffer - 1);
192 fs.y1 = fs.x1 = *endOfBuffer;
196 jassert (sampsInBuffer >= 0);
199 void ResamplingAudioSource::createLowPass (
const double frequencyRatio)
201 const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio
202 : 0.5 * frequencyRatio;
205 const double nSquared = n * n;
208 setFilterCoefficients (c1,
212 c1 * 2.0 * (1.0 - nSquared),
216 void ResamplingAudioSource::setFilterCoefficients (
double c1,
double c2,
double c3,
double c4,
double c5,
double c6)
218 const double a = 1.0 / c4;
226 coefficients[0] = c1;
227 coefficients[1] = c2;
228 coefficients[2] = c3;
229 coefficients[3] = c4;
230 coefficients[4] = c5;
231 coefficients[5] = c6;
234 void ResamplingAudioSource::resetFilters()
236 if (filterStates !=
nullptr)
237 filterStates.
clear ((
size_t) numChannels);
240 void ResamplingAudioSource::applyFilter (
float* samples,
int num, FilterState& fs)
244 const double in = *samples;
246 double out = coefficients[0] * in
247 + coefficients[1] * fs.x1
248 + coefficients[2] * fs.x2
249 - coefficients[4] * fs.y1
250 - coefficients[5] * fs.y2;
253 if (! (out < -1.0e-8 || out > 1.0e-8))
262 *samples++ = (float) out;
void prepareToPlay(int samplesPerBlockExpected, double sampleRate) override
Tells the source to prepare for playing.
int numSamples
The number of samples in the buffer which the callback is expected to fill with data.
void getNextAudioBlock(const AudioSourceChannelInfo &) override
Called repeatedly to fetch subsequent blocks of audio data.
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
Changes the buffer's size or number of channels.
void releaseResources() override
Allows the source to release anything it no longer needs after playback has stopped.
const Type * getReadPointer(int channelNumber) const noexcept
Returns a pointer to an array of read-only samples in one of the buffer's channels.
void calloc(SizeType newNumElements, const size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory and clears it.
void flushBuffers()
Clears any buffers and filters that the resampler is using.
Base class for objects that can produce a continuous stream of audio.
int getNumChannels() const noexcept
Returns the number of channels of audio data that this buffer contains.
~ResamplingAudioSource() override
Destructor.
void clear(SizeType numElements) noexcept
This fills the block with zeros, up to the number of elements specified.
ResamplingAudioSource(AudioSource *inputSource, bool deleteInputWhenDeleted, int numChannels=2)
Creates a ResamplingAudioSource for a given input source.
int startSample
The first sample in the buffer from which the callback is expected to write data. ...
AudioBuffer< float > * buffer
The destination buffer to fill with audio data.
void setResamplingRatio(double samplesInPerOutputSample)
Changes the resampling ratio.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer's channels.
Commonly used mathematical constants.
Used by AudioSource::getNextAudioBlock().
Automatically locks and unlocks a mutex object.
void clear() noexcept
Clears all the samples in all channels.