void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) { const SpinLock::ScopedLockType sl (ratioLock); const int scaledBlockSize = roundToInt (samplesPerBlockExpected * ratio); input->prepareToPlay (scaledBlockSize, sampleRate * ratio); buffer.setSize (numChannels, scaledBlockSize + 32); filterStates.calloc ((size_t) numChannels); srcBuffers.calloc ((size_t) numChannels); destBuffers.calloc ((size_t) numChannels); createLowPass (ratio); flushBuffers(); }
void ResamplingAudioSource::prepareToPlay (int samplesPerBlockExpected, double sampleRate) { const SpinLock::ScopedLockType sl (ratioLock); input->prepareToPlay (samplesPerBlockExpected, sampleRate); buffer.setSize (numChannels, roundToInt (samplesPerBlockExpected * ratio) + 32); buffer.clear(); sampsInBuffer = 0; bufferPos = 0; subSampleOffset = 0.0; filterStates.calloc ((size_t) numChannels); srcBuffers.calloc ((size_t) numChannels); destBuffers.calloc ((size_t) numChannels); createLowPass (ratio); resetFilters(); }
void ResamplingAudioSource::getNextAudioBlock (const AudioSourceChannelInfo& info) { double localRatio; { const SpinLock::ScopedLockType sl (ratioLock); localRatio = ratio; } if (lastRatio != localRatio) { createLowPass (localRatio); lastRatio = localRatio; } const int sampsNeeded = roundToInt (info.numSamples * localRatio) + 3; int bufferSize = buffer.getNumSamples(); if (bufferSize < sampsNeeded + 8) { bufferPos %= bufferSize; bufferSize = sampsNeeded + 32; buffer.setSize (buffer.getNumChannels(), bufferSize, true, true); } bufferPos %= bufferSize; int endOfBufferPos = bufferPos + sampsInBuffer; const int channelsToProcess = jmin (numChannels, info.buffer->getNumChannels()); while (sampsNeeded > sampsInBuffer) { endOfBufferPos %= bufferSize; int numToDo = jmin (sampsNeeded - sampsInBuffer, bufferSize - endOfBufferPos); AudioSourceChannelInfo readInfo (&buffer, endOfBufferPos, numToDo); input->getNextAudioBlock (readInfo); if (localRatio > 1.0001) { // for down-sampling, pre-apply the filter.. for (int i = channelsToProcess; --i >= 0;) applyFilter (buffer.getWritePointer (i, endOfBufferPos), numToDo, filterStates[i]); } sampsInBuffer += numToDo; endOfBufferPos += numToDo; } for (int channel = 0; channel < channelsToProcess; ++channel) { destBuffers[channel] = info.buffer->getWritePointer (channel, info.startSample); srcBuffers[channel] = buffer.getReadPointer (channel); } int nextPos = (bufferPos + 1) % bufferSize; for (int m = info.numSamples; --m >= 0;) { jassert (sampsInBuffer > 0 && nextPos != endOfBufferPos); const float alpha = (float) subSampleOffset; for (int channel = 0; channel < channelsToProcess; ++channel) *destBuffers[channel]++ = srcBuffers[channel][bufferPos] + alpha * (srcBuffers[channel][nextPos] - srcBuffers[channel][bufferPos]); subSampleOffset += localRatio; while (subSampleOffset >= 1.0) { if (++bufferPos >= bufferSize) bufferPos = 0; --sampsInBuffer; nextPos = (bufferPos + 1) % bufferSize; subSampleOffset -= 1.0; } } if (localRatio < 0.9999) { // for up-sampling, apply the filter after transposing.. for (int i = channelsToProcess; --i >= 0;) applyFilter (info.buffer->getWritePointer (i, info.startSample), info.numSamples, filterStates[i]); } else if (localRatio <= 1.0001 && info.numSamples > 0) { // if the filter's not currently being applied, keep it stoked with the last couple of samples to avoid discontinuities for (int i = channelsToProcess; --i >= 0;) { const float* const endOfBuffer = info.buffer->getReadPointer (i, info.startSample + info.numSamples - 1); FilterState& fs = filterStates[i]; if (info.numSamples > 1) { fs.y2 = fs.x2 = *(endOfBuffer - 1); } else { fs.y2 = fs.y1; fs.x2 = fs.x1; } fs.y1 = fs.x1 = *endOfBuffer; } } jassert (sampsInBuffer >= 0); }