#include "config.h"
#if ENABLE(WEB_AUDIO)
#include "SincResampler.h"
#include <wtf/MathExtras.h>
using namespace std;
namespace WebCore {
SincResampler::SincResampler(double scaleFactor, unsigned kernelSize, unsigned numberOfKernelOffsets)
: m_scaleFactor(scaleFactor)
, m_kernelSize(kernelSize)
, m_numberOfKernelOffsets(numberOfKernelOffsets)
, m_kernelStorage(m_kernelSize * (m_numberOfKernelOffsets + 1))
, m_virtualSourceIndex(0.0)
, m_blockSize(512)
, m_inputBuffer(m_blockSize + m_kernelSize) , m_source(0)
, m_sourceFramesAvailable(0)
{
initializeKernel();
}
void SincResampler::initializeKernel()
{
double alpha = 0.16;
double a0 = 0.5 * (1.0 - alpha);
double a1 = 0.5;
double a2 = 0.5 * alpha;
double sincScaleFactor = m_scaleFactor > 1.0 ? 1.0 / m_scaleFactor : 1.0;
sincScaleFactor *= 0.9;
int n = m_kernelSize;
int halfSize = n / 2;
for (unsigned offsetIndex = 0; offsetIndex <= m_numberOfKernelOffsets; ++offsetIndex) {
double subsampleOffset = static_cast<double>(offsetIndex) / m_numberOfKernelOffsets;
for (int i = 0; i < n; ++i) {
double s = sincScaleFactor * piDouble * (i - halfSize - subsampleOffset);
double sinc = !s ? 1.0 : sin(s) / s;
sinc *= sincScaleFactor;
double x = (i - subsampleOffset) / n;
double window = a0 - a1 * cos(2.0 * piDouble * x) + a2 * cos(4.0 * piDouble * x);
m_kernelStorage[i + offsetIndex * m_kernelSize] = sinc * window;
}
}
}
void SincResampler::consumeSource(float* buffer, unsigned numberOfSourceFrames)
{
ASSERT(m_source);
if (!m_source)
return;
unsigned framesToCopy = min(m_sourceFramesAvailable, numberOfSourceFrames);
memcpy(buffer, m_source, sizeof(float) * framesToCopy);
if (framesToCopy < numberOfSourceFrames)
memset(buffer + framesToCopy, 0, sizeof(float) * (numberOfSourceFrames - framesToCopy));
m_sourceFramesAvailable -= framesToCopy;
m_source += numberOfSourceFrames;
}
void SincResampler::process(float* source, float* destination, unsigned numberOfSourceFrames)
{
ASSERT(m_blockSize > m_kernelSize);
ASSERT(m_inputBuffer.size() >= m_blockSize + m_kernelSize);
ASSERT(!(m_kernelSize % 2));
float* r0 = m_inputBuffer.data() + m_kernelSize / 2;
float* r1 = m_inputBuffer.data();
float* r2 = r0;
float* r3 = r0 + m_blockSize - m_kernelSize / 2;
float* r4 = r0 + m_blockSize;
float* r5 = r0 + m_kernelSize / 2;
m_source = source;
m_sourceFramesAvailable = numberOfSourceFrames;
unsigned numberOfDestinationFrames = static_cast<unsigned>(numberOfSourceFrames / m_scaleFactor);
consumeSource(r0, m_blockSize + m_kernelSize / 2);
m_virtualSourceIndex = 0;
while (numberOfDestinationFrames) {
while (m_virtualSourceIndex < m_blockSize) {
int sourceIndexI = static_cast<int>(m_virtualSourceIndex);
double subsampleRemainder = m_virtualSourceIndex - sourceIndexI;
double virtualOffsetIndex = subsampleRemainder * m_numberOfKernelOffsets;
int offsetIndex = static_cast<int>(virtualOffsetIndex);
float* k1 = m_kernelStorage.data() + offsetIndex * m_kernelSize;
float* k2 = k1 + m_kernelSize;
float* inputP = r1 + sourceIndexI;
float sum1 = 0;
float sum2 = 0;
double kernelInterpolationFactor = virtualOffsetIndex - offsetIndex;
int n = m_kernelSize;
#define CONVOLVE_ONE_SAMPLE \
input = *inputP++; \
sum1 += input * *k1; \
sum2 += input * *k2; \
++k1; \
++k2;
{
float input;
if (n == 32) {
CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE } else if (n == 64) {
CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE CONVOLVE_ONE_SAMPLE } else {
while (n--) {
CONVOLVE_ONE_SAMPLE
}
}
}
double result = (1.0 - kernelInterpolationFactor) * sum1 + kernelInterpolationFactor * sum2;
*destination++ = result;
--numberOfDestinationFrames;
if (!numberOfDestinationFrames)
return;
m_virtualSourceIndex += m_scaleFactor;
}
m_virtualSourceIndex -= m_blockSize;
memcpy(r1, r3, sizeof(float) * (m_kernelSize / 2));
memcpy(r2, r4, sizeof(float) * (m_kernelSize / 2));
consumeSource(r5, m_blockSize);
}
}
}
#endif // ENABLE(WEB_AUDIO)