OpenShot Library | libopenshot-audio  0.1.9
juce_ResamplingAudioSource.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
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 
23 namespace juce
24 {
25 
27  const bool deleteInputWhenDeleted,
28  const int channels)
29  : input (inputSource, deleteInputWhenDeleted),
30  ratio (1.0),
31  lastRatio (1.0),
32  bufferPos (0),
33  sampsInBuffer (0),
34  subSampleOffset (0),
35  numChannels (channels)
36 {
37  jassert (input != nullptr);
38  zeromem (coefficients, sizeof (coefficients));
39 }
40 
42 
43 void ResamplingAudioSource::setResamplingRatio (const double samplesInPerOutputSample)
44 {
45  jassert (samplesInPerOutputSample > 0);
46 
47  const SpinLock::ScopedLockType sl (ratioLock);
48  ratio = jmax (0.0, samplesInPerOutputSample);
49 }
50 
51 void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate)
52 {
53  const SpinLock::ScopedLockType sl (ratioLock);
54 
55  auto scaledBlockSize = roundToInt (samplesPerBlockExpected * ratio);
56  input->prepareToPlay (scaledBlockSize, sampleRate * ratio);
57 
58  buffer.setSize (numChannels, scaledBlockSize + 32);
59 
60  filterStates.calloc (numChannels);
61  srcBuffers.calloc (numChannels);
62  destBuffers.calloc (numChannels);
63  createLowPass (ratio);
64 
65  flushBuffers();
66 }
67 
69 {
70  buffer.clear();
71  bufferPos = 0;
72  sampsInBuffer = 0;
73  subSampleOffset = 0.0;
74  resetFilters();
75 }
76 
78 {
79  input->releaseResources();
80  buffer.setSize (numChannels, 0);
81 }
82 
84 {
85  double localRatio;
86 
87  {
88  const SpinLock::ScopedLockType sl (ratioLock);
89  localRatio = ratio;
90  }
91 
92  if (lastRatio != localRatio)
93  {
94  createLowPass (localRatio);
95  lastRatio = localRatio;
96  }
97 
98  const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 3;
99 
100  int bufferSize = buffer.getNumSamples();
101 
102  if (bufferSize < sampsNeeded + 8)
103  {
104  bufferPos %= bufferSize;
105  bufferSize = sampsNeeded + 32;
106  buffer.setSize (buffer.getNumChannels(), bufferSize, true, true);
107  }
108 
109  bufferPos %= bufferSize;
110 
111  int endOfBufferPos = bufferPos + sampsInBuffer;
112  const int channelsToProcess = jmin (numChannels, info.buffer->getNumChannels());
113 
114  while (sampsNeeded > sampsInBuffer)
115  {
116  endOfBufferPos %= bufferSize;
117 
118  int numToDo = jmin (sampsNeeded - sampsInBuffer,
119  bufferSize - endOfBufferPos);
120 
121  AudioSourceChannelInfo readInfo (&buffer, endOfBufferPos, numToDo);
122  input->getNextAudioBlock (readInfo);
123 
124  if (localRatio > 1.0001)
125  {
126  // for down-sampling, pre-apply the filter..
127 
128  for (int i = channelsToProcess; --i >= 0;)
129  applyFilter (buffer.getWritePointer (i, endOfBufferPos), numToDo, filterStates[i]);
130  }
131 
132  sampsInBuffer += numToDo;
133  endOfBufferPos += numToDo;
134  }
135 
136  for (int channel = 0; channel < channelsToProcess; ++channel)
137  {
138  destBuffers[channel] = info.buffer->getWritePointer (channel, info.startSample);
139  srcBuffers[channel] = buffer.getReadPointer (channel);
140  }
141 
142  int nextPos = (bufferPos + 1) % bufferSize;
143 
144  for (int m = info.numSamples; --m >= 0;)
145  {
146  jassert (sampsInBuffer > 0 && nextPos != endOfBufferPos);
147 
148  const float alpha = (float) subSampleOffset;
149 
150  for (int channel = 0; channel < channelsToProcess; ++channel)
151  *destBuffers[channel]++ = srcBuffers[channel][bufferPos]
152  + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]);
153 
154  subSampleOffset += localRatio;
155 
156  while (subSampleOffset >= 1.0)
157  {
158  if (++bufferPos >= bufferSize)
159  bufferPos = 0;
160 
161  --sampsInBuffer;
162 
163  nextPos = (bufferPos + 1) % bufferSize;
164  subSampleOffset -= 1.0;
165  }
166  }
167 
168  if (localRatio < 0.9999)
169  {
170  // for up-sampling, apply the filter after transposing..
171  for (int i = channelsToProcess; --i >= 0;)
172  applyFilter (info.buffer->getWritePointer (i, info.startSample), info.numSamples, filterStates[i]);
173  }
174  else if (localRatio <= 1.0001 && info.numSamples > 0)
175  {
176  // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities
177  for (int i = channelsToProcess; --i >= 0;)
178  {
179  const float* const endOfBuffer = info.buffer->getReadPointer (i, info.startSample + info.numSamples - 1);
180  FilterState& fs = filterStates[i];
181 
182  if (info.numSamples > 1)
183  {
184  fs.y2 = fs.x2 = *(endOfBuffer - 1);
185  }
186  else
187  {
188  fs.y2 = fs.y1;
189  fs.x2 = fs.x1;
190  }
191 
192  fs.y1 = fs.x1 = *endOfBuffer;
193  }
194  }
195 
196  jassert (sampsInBuffer >= 0);
197 }
198 
199 void ResamplingAudioSource::createLowPass (const double frequencyRatio)
200 {
201  const double proportionalRate = (frequencyRatio > 1.0) ? 0.5 / frequencyRatio
202  : 0.5 * frequencyRatio;
203 
204  const double n = 1.0 / std::tan (MathConstants<double>::pi * jmax (0.001, proportionalRate));
205  const double nSquared = n * n;
206  const double c1 = 1.0 / (1.0 + MathConstants<double>::sqrt2 * n + nSquared);
207 
208  setFilterCoefficients (c1,
209  c1 * 2.0f,
210  c1,
211  1.0,
212  c1 * 2.0 * (1.0 - nSquared),
213  c1 * (1.0 - MathConstants<double>::sqrt2 * n + nSquared));
214 }
215 
216 void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6)
217 {
218  const double a = 1.0 / c4;
219 
220  c1 *= a;
221  c2 *= a;
222  c3 *= a;
223  c5 *= a;
224  c6 *= a;
225 
226  coefficients[0] = c1;
227  coefficients[1] = c2;
228  coefficients[2] = c3;
229  coefficients[3] = c4;
230  coefficients[4] = c5;
231  coefficients[5] = c6;
232 }
233 
234 void ResamplingAudioSource::resetFilters()
235 {
236  if (filterStates != nullptr)
237  filterStates.clear ((size_t) numChannels);
238 }
239 
240 void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)
241 {
242  while (--num >= 0)
243  {
244  const double in = *samples;
245 
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;
251 
252  #if JUCE_INTEL
253  if (! (out < -1.0e-8 || out > 1.0e-8))
254  out = 0;
255  #endif
256 
257  fs.x2 = fs.x1;
258  fs.x1 = in;
259  fs.y2 = fs.y1;
260  fs.y1 = out;
261 
262  *samples++ = (float) out;
263  }
264 }
265 
266 } // namespace juce
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&#39;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&#39;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&#39;s channels.
int getNumSamples() const noexcept
Returns the number of samples allocated in each of the buffer&#39;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.