OpenShot Audio Library | OpenShotAudio: juce_ResamplingAudioSource.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.4.0 |

Loading...
Searching...
No Matches
juce_ResamplingAudioSource.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26ResamplingAudioSource::ResamplingAudioSource (AudioSource* const inputSource,
27 const bool deleteInputWhenDeleted,
28 const int channels)
29 : input (inputSource, deleteInputWhenDeleted),
30 numChannels (channels)
31{
32 jassert (input != nullptr);
33 zeromem (coefficients, sizeof (coefficients));
34}
35
36ResamplingAudioSource::~ResamplingAudioSource() {}
37
38 void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample)
39{
40 jassert (samplesInPerOutputSample > 0);
41
42 const SpinLock::ScopedLockType sl (ratioLock);
43 ratio = jmax (0.0, samplesInPerOutputSample);
44}
45
46 void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate)
47{
48 const SpinLock::ScopedLockType sl (ratioLock);
49
50 auto scaledBlockSize = roundToInt (samplesPerBlockExpected * ratio);
51 input->prepareToPlay (scaledBlockSize, sampleRate * ratio);
52
53 buffer.setSize (numChannels, scaledBlockSize + 32);
54
55 filterStates.calloc (numChannels);
56 srcBuffers.calloc (numChannels);
57 destBuffers.calloc (numChannels);
58 createLowPass (ratio);
59
60 flushBuffers();
61}
62
63 void ResamplingAudioSource::flushBuffers()
64{
65 const ScopedLock sl (callbackLock);
66
67 buffer.clear();
68 bufferPos = 0;
69 sampsInBuffer = 0;
70 subSampleOffset = 0.0;
71 resetFilters();
72}
73
74 void ResamplingAudioSource::releaseResources()
75{
76 input->releaseResources();
77 buffer.setSize (numChannels, 0);
78}
79
80 void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info)
81{
82 const ScopedLock sl (callbackLock);
83
84 double localRatio;
85
86 {
87 const SpinLock::ScopedLockType ratioSl (ratioLock);
88 localRatio = ratio;
89 }
90
91 if (! approximatelyEqual (lastRatio, localRatio))
92 {
93 createLowPass (localRatio);
94 lastRatio = localRatio;
95 }
96
97 const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 3;
98
99 int bufferSize = buffer.getNumSamples();
100
101 if (bufferSize < sampsNeeded + 8)
102 {
103 bufferPos %= bufferSize;
104 bufferSize = sampsNeeded + 32;
105 buffer.setSize (buffer.getNumChannels(), bufferSize, true, true);
106 }
107
108 bufferPos %= bufferSize;
109
110 int endOfBufferPos = bufferPos + sampsInBuffer;
111 const int channelsToProcess = jmin (numChannels, info.buffer->getNumChannels());
112
113 while (sampsNeeded > sampsInBuffer)
114 {
115 endOfBufferPos %= bufferSize;
116
117 int numToDo = jmin (sampsNeeded - sampsInBuffer,
118 bufferSize - endOfBufferPos);
119
120 AudioSourceChannelInfo readInfo (&buffer, endOfBufferPos, numToDo);
121 input->getNextAudioBlock (readInfo);
122
123 if (localRatio > 1.0001)
124 {
125 // for down-sampling, pre-apply the filter..
126
127 for (int i = channelsToProcess; --i >= 0;)
128 applyFilter (buffer.getWritePointer (i, endOfBufferPos), numToDo, filterStates[i]);
129 }
130
131 sampsInBuffer += numToDo;
132 endOfBufferPos += numToDo;
133 }
134
135 for (int channel = 0; channel < channelsToProcess; ++channel)
136 {
137 destBuffers[channel] = info.buffer->getWritePointer (channel, info.startSample);
138 srcBuffers[channel] = buffer.getReadPointer (channel);
139 }
140
141 int nextPos = (bufferPos + 1) % bufferSize;
142
143 for (int m = info.numSamples; --m >= 0;)
144 {
145 jassert (sampsInBuffer > 0 && nextPos != endOfBufferPos);
146
147 const float alpha = (float) subSampleOffset;
148
149 for (int channel = 0; channel < channelsToProcess; ++channel)
150 *destBuffers[channel]++ = srcBuffers[channel][bufferPos]
151 + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]);
152
153 subSampleOffset += localRatio;
154
155 while (subSampleOffset >= 1.0)
156 {
157 if (++bufferPos >= bufferSize)
158 bufferPos = 0;
159
160 --sampsInBuffer;
161
162 nextPos = (bufferPos + 1) % bufferSize;
163 subSampleOffset -= 1.0;
164 }
165 }
166
167 if (localRatio < 0.9999)
168 {
169 // for up-sampling, apply the filter after transposing..
170 for (int i = channelsToProcess; --i >= 0;)
171 applyFilter (info.buffer->getWritePointer (i, info.startSample), info.numSamples, filterStates[i]);
172 }
173 else if (localRatio <= 1.0001 && info.numSamples > 0)
174 {
175 // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
176 for (int i = channelsToProcess; --i >= 0;)
177 {
178 const float* const endOfBuffer = info.buffer->getReadPointer (i, info.startSample + info.numSamples - 1);
179 FilterState& fs = filterStates[i];
180
181 if (info.numSamples > 1)
182 {
183 fs.y2 = fs.x2 = *(endOfBuffer - 1);
184 }
185 else
186 {
187 fs.y2 = fs.y1;
188 fs.x2 = fs.x1;
189 }
190
191 fs.y1 = fs.x1 = *endOfBuffer;
192 }
193 }
194
195 jassert (sampsInBuffer >= 0);
196}
197
198void ResamplingAudioSource::createLowPass (const double frequencyRatio)
199{
200 const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio
201 : 0.5 * frequencyRatio;
202
203 const double n = 1.0 / std::tan (MathConstants<double>::pi * jmax (0.001, proportionalRate));
204 const double nSquared = n * n;
205 const double c1 = 1.0 / (1.0 + MathConstants<double>::sqrt2 * n + nSquared);
206
207 setFilterCoefficients (c1,
208 c1 * 2.0f,
209 c1,
210 1.0,
211 c1 * 2.0 * (1.0 - nSquared),
212 c1 * (1.0 - MathConstants<double>::sqrt2 * n + nSquared));
213}
214
215void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6)
216{
217 const double a = 1.0 / c4;
218
219 c1 *= a;
220 c2 *= a;
221 c3 *= a;
222 c5 *= a;
223 c6 *= a;
224
225 coefficients[0] = c1;
226 coefficients[1] = c2;
227 coefficients[2] = c3;
228 coefficients[3] = c4;
229 coefficients[4] = c5;
230 coefficients[5] = c6;
231}
232
233void ResamplingAudioSource::resetFilters()
234{
235 if (filterStates != nullptr)
236 filterStates.clear ((size_t) numChannels);
237}
238
239void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
240{
241 while (--num >= 0)
242 {
243 const double in = *samples;
244
245 double out = coefficients[0] * in
246 + coefficients[1] * fs.x1
247 + coefficients[2] * fs.x2
248 - coefficients[4] * fs.y1
249 - coefficients[5] * fs.y2;
250
251 #if JUCE_INTEL
252 if (! (out < -1.0e-8 || out > 1.0e-8))
253 out = 0;
254 #endif
255
256 fs.x2 = fs.x1;
257 fs.x1 = in;
258 fs.y2 = fs.y1;
259 fs.y1 = out;
260
261 *samples++ = (float) out;
262 }
263}
264
265} // namespace juce
juce::AudioBuffer::getWritePointer
Type * getWritePointer(int channelNumber) noexcept
Definition juce_AudioSampleBuffer.h:291
juce::AudioBuffer::getNumChannels
int getNumChannels() const noexcept
Definition juce_AudioSampleBuffer.h:236
juce::AudioBuffer::getReadPointer
const Type * getReadPointer(int channelNumber) const noexcept
Definition juce_AudioSampleBuffer.h:253
juce::AudioSource::AudioSource
AudioSource()=default
juce::ResamplingAudioSource::releaseResources
void releaseResources() override
Definition juce_ResamplingAudioSource.cpp:74
juce::ResamplingAudioSource::getNextAudioBlock
void getNextAudioBlock(const AudioSourceChannelInfo &) override
Definition juce_ResamplingAudioSource.cpp:80
juce::ResamplingAudioSource::prepareToPlay
void prepareToPlay(int samplesPerBlockExpected, double sampleRate) override
Definition juce_ResamplingAudioSource.cpp:46
juce::ResamplingAudioSource::flushBuffers
void flushBuffers()
Definition juce_ResamplingAudioSource.cpp:63
juce::ResamplingAudioSource::~ResamplingAudioSource
~ResamplingAudioSource() override
Definition juce_ResamplingAudioSource.cpp:36
juce::ResamplingAudioSource::setResamplingRatio
void setResamplingRatio(double samplesInPerOutputSample)
Definition juce_ResamplingAudioSource.cpp:38
juce::ResamplingAudioSource::ResamplingAudioSource
ResamplingAudioSource(AudioSource *inputSource, bool deleteInputWhenDeleted, int numChannels=2)
Definition juce_ResamplingAudioSource.cpp:26
juce::SpinLock::ScopedLockType
GenericScopedLock< SpinLock > ScopedLockType
Definition juce_SpinLock.h:73
juce::AudioSourceChannelInfo
Definition juce_AudioSource.h:33
juce::AudioSourceChannelInfo::numSamples
int numSamples
Definition juce_AudioSource.h:81
juce::AudioSourceChannelInfo::buffer
AudioBuffer< float > * buffer
Definition juce_AudioSource.h:73
juce::AudioSourceChannelInfo::startSample
int startSample
Definition juce_AudioSource.h:77
juce::MathConstants::sqrt2
static constexpr FloatType sqrt2
Definition juce_MathsFunctions.h:153
juce::MathConstants::pi
static constexpr FloatType pi
Definition juce_MathsFunctions.h:141