2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../core/juce_StandardHeader.h"
30 #include "juce_ResamplingAudioSource.h"
33 //==============================================================================
34 ResamplingAudioSource::ResamplingAudioSource (AudioSource
* const inputSource
,
35 const bool deleteInputWhenDeleted
,
36 const int numChannels_
)
37 : input (inputSource
, deleteInputWhenDeleted
),
40 buffer (numChannels_
, 0),
42 numChannels (numChannels_
)
44 jassert (input
!= nullptr);
47 ResamplingAudioSource::~ResamplingAudioSource() {}
49 void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample
)
51 jassert (samplesInPerOutputSample
> 0);
53 const SpinLock::ScopedLockType
sl (ratioLock
);
54 ratio
= jmax (0.0, samplesInPerOutputSample
);
57 void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected
,
60 const SpinLock::ScopedLockType
sl (ratioLock
);
62 input
->prepareToPlay (samplesPerBlockExpected
, sampleRate
);
64 buffer
.setSize (numChannels
, roundToInt (samplesPerBlockExpected
* ratio
) + 32);
68 subSampleOffset
= 0.0;
70 filterStates
.calloc (numChannels
);
71 srcBuffers
.calloc (numChannels
);
72 destBuffers
.calloc (numChannels
);
73 createLowPass (ratio
);
77 void ResamplingAudioSource::releaseResources()
79 input
->releaseResources();
80 buffer
.setSize (numChannels
, 0);
83 void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo
& info
)
88 const SpinLock::ScopedLockType
sl (ratioLock
);
92 if (lastRatio
!= localRatio
)
94 createLowPass (localRatio
);
95 lastRatio
= localRatio
;
98 const int sampsNeeded
= roundToInt (info
.numSamples
* localRatio
) + 2;
100 int bufferSize
= buffer
.getNumSamples();
102 if (bufferSize
< sampsNeeded
+ 8)
104 bufferPos
%= bufferSize
;
105 bufferSize
= sampsNeeded
+ 32;
106 buffer
.setSize (buffer
.getNumChannels(), bufferSize
, true, true);
109 bufferPos
%= bufferSize
;
111 int endOfBufferPos
= bufferPos
+ sampsInBuffer
;
112 const int channelsToProcess
= jmin (numChannels
, info
.buffer
->getNumChannels());
114 while (sampsNeeded
> sampsInBuffer
)
116 endOfBufferPos
%= bufferSize
;
118 int numToDo
= jmin (sampsNeeded
- sampsInBuffer
,
119 bufferSize
- endOfBufferPos
);
121 AudioSourceChannelInfo readInfo
;
122 readInfo
.buffer
= &buffer
;
123 readInfo
.numSamples
= numToDo
;
124 readInfo
.startSample
= endOfBufferPos
;
126 input
->getNextAudioBlock (readInfo
);
128 if (localRatio
> 1.0001)
130 // for down-sampling, pre-apply the filter..
132 for (int i
= channelsToProcess
; --i
>= 0;)
133 applyFilter (buffer
.getSampleData (i
, endOfBufferPos
), numToDo
, filterStates
[i
]);
136 sampsInBuffer
+= numToDo
;
137 endOfBufferPos
+= numToDo
;
140 for (int channel
= 0; channel
< channelsToProcess
; ++channel
)
142 destBuffers
[channel
] = info
.buffer
->getSampleData (channel
, info
.startSample
);
143 srcBuffers
[channel
] = buffer
.getSampleData (channel
, 0);
146 int nextPos
= (bufferPos
+ 1) % bufferSize
;
147 for (int m
= info
.numSamples
; --m
>= 0;)
149 const float alpha
= (float) subSampleOffset
;
150 const float invAlpha
= 1.0f
- alpha
;
152 for (int channel
= 0; channel
< channelsToProcess
; ++channel
)
153 *destBuffers
[channel
]++ = srcBuffers
[channel
][bufferPos
] * invAlpha
+ srcBuffers
[channel
][nextPos
] * alpha
;
155 subSampleOffset
+= localRatio
;
157 jassert (sampsInBuffer
> 0);
159 while (subSampleOffset
>= 1.0)
161 if (++bufferPos
>= bufferSize
)
166 nextPos
= (bufferPos
+ 1) % bufferSize
;
167 subSampleOffset
-= 1.0;
171 if (localRatio
< 0.9999)
173 // for up-sampling, apply the filter after transposing..
174 for (int i
= channelsToProcess
; --i
>= 0;)
175 applyFilter (info
.buffer
->getSampleData (i
, info
.startSample
), info
.numSamples
, filterStates
[i
]);
177 else if (localRatio
<= 1.0001)
179 // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
180 for (int i
= channelsToProcess
; --i
>= 0;)
182 const float* const endOfBuffer
= info
.buffer
->getSampleData (i
, info
.startSample
+ info
.numSamples
- 1);
183 FilterState
& fs
= filterStates
[i
];
185 if (info
.numSamples
> 1)
187 fs
.y2
= fs
.x2
= *(endOfBuffer
- 1);
195 fs
.y1
= fs
.x1
= *endOfBuffer
;
199 jassert (sampsInBuffer
>= 0);
202 void ResamplingAudioSource::createLowPass (const double frequencyRatio
)
204 const double proportionalRate
= (frequencyRatio
> 1.0) ? 0.5 / frequencyRatio
205 : 0.5 * frequencyRatio
;
207 const double n
= 1.0 / std::tan (double_Pi
* jmax (0.001, proportionalRate
));
208 const double nSquared
= n
* n
;
209 const double c1
= 1.0 / (1.0 + std::sqrt (2.0) * n
+ nSquared
);
211 setFilterCoefficients (c1
,
215 c1
* 2.0 * (1.0 - nSquared
),
216 c1
* (1.0 - std::sqrt (2.0) * n
+ nSquared
));
219 void ResamplingAudioSource::setFilterCoefficients (double c1
, double c2
, double c3
, double c4
, double c5
, double c6
)
221 const double a
= 1.0 / c4
;
229 coefficients
[0] = c1
;
230 coefficients
[1] = c2
;
231 coefficients
[2] = c3
;
232 coefficients
[3] = c4
;
233 coefficients
[4] = c5
;
234 coefficients
[5] = c6
;
237 void ResamplingAudioSource::resetFilters()
239 filterStates
.clear (numChannels
);
242 void ResamplingAudioSource::applyFilter (float* samples
, int num
, FilterState
& fs
)
246 const double in
= *samples
;
248 double out
= coefficients
[0] * in
249 + coefficients
[1] * fs
.x1
250 + coefficients
[2] * fs
.x2
251 - coefficients
[4] * fs
.y1
252 - coefficients
[5] * fs
.y2
;
255 if (! (out
< -1.0e-8 || out
> 1.0e-8))
264 *samples
++ = (float) out
;