Fixes to the resampler wrapper, such that it will survive some close encounters with the edge of the buffer, if necessary. Also so it will obey the buffer size limit for the output buffer. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
150 lines
4.2 KiB
C
150 lines
4.2 KiB
C
//
|
|
// r8bstate.h
|
|
// CogAudio Framework
|
|
//
|
|
// Created by Christopher Snowhill on 3/3/22.
|
|
//
|
|
|
|
#ifndef r8bstate_h
|
|
#define r8bstate_h
|
|
|
|
#include <Accelerate/Accelerate.h>
|
|
|
|
#include "r8bbase.h"
|
|
|
|
#include "CDSPResampler.h"
|
|
|
|
struct r8bstate {
|
|
int channelCount;
|
|
int bufferCapacity;
|
|
size_t remainder;
|
|
uint64_t inProcessed;
|
|
uint64_t outProcessed;
|
|
double sampleRatio;
|
|
r8b::CFixedBuffer<double> InBuf;
|
|
r8b::CFixedBuffer<double> *OutBufs;
|
|
r8b::CDSPResampler24 **Resamps;
|
|
r8bstate(int _channelCount, int _bufferCapacity, double srcRate, double dstRate)
|
|
: channelCount(_channelCount), bufferCapacity(_bufferCapacity), inProcessed(0), outProcessed(0), remainder(0) {
|
|
InBuf.alloc(bufferCapacity);
|
|
OutBufs = new r8b::CFixedBuffer<double>[channelCount];
|
|
Resamps = new r8b::CDSPResampler24 *[channelCount];
|
|
for(int i = 0; i < channelCount; ++i) {
|
|
Resamps[i] = new r8b::CDSPResampler24(srcRate, dstRate, bufferCapacity);
|
|
}
|
|
sampleRatio = dstRate / srcRate;
|
|
}
|
|
|
|
~r8bstate() {
|
|
delete[] OutBufs;
|
|
for(int i = 0; i < channelCount; ++i) {
|
|
delete Resamps[i];
|
|
}
|
|
delete[] Resamps;
|
|
}
|
|
|
|
int resample(const float *input, size_t inCount, size_t *inDone, float *output, size_t outMax) {
|
|
int ret = 0;
|
|
int i;
|
|
if(inDone) *inDone = 0;
|
|
while(remainder > 0) {
|
|
size_t blockCount = remainder;
|
|
if(blockCount > outMax)
|
|
blockCount = outMax;
|
|
for(i = 0; i < channelCount; ++i) {
|
|
vDSP_vdpsp(&OutBufs[i][0], 1, output + i, channelCount, blockCount);
|
|
}
|
|
remainder -= blockCount;
|
|
output += channelCount * blockCount;
|
|
outProcessed += blockCount;
|
|
outMax -= blockCount;
|
|
ret += blockCount;
|
|
if(!outMax)
|
|
return ret;
|
|
}
|
|
while(inCount > 0) {
|
|
size_t blockCount = inCount;
|
|
if(blockCount > bufferCapacity)
|
|
blockCount = bufferCapacity;
|
|
int outputDone;
|
|
for(i = 0; i < channelCount; ++i) {
|
|
double *outputPointer;
|
|
vDSP_vspdp(input + i, channelCount, &InBuf[0], 1, blockCount);
|
|
outputDone = Resamps[i]->process(InBuf, (int)blockCount, outputPointer);
|
|
if(outputDone) {
|
|
if(outputDone > outMax) {
|
|
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outMax);
|
|
remainder = outputDone - outMax;
|
|
OutBufs[i].alloc((int)remainder);
|
|
memcpy(&OutBufs[i][0], outputPointer + outMax, remainder);
|
|
} else {
|
|
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outputDone);
|
|
}
|
|
}
|
|
}
|
|
size_t outputActual = outputDone - remainder;
|
|
input += channelCount * blockCount;
|
|
output += channelCount * outputActual;
|
|
inCount -= blockCount;
|
|
if(inDone) *inDone += blockCount;
|
|
inProcessed += blockCount;
|
|
outProcessed += outputActual;
|
|
outMax -= outputActual;
|
|
ret += outputActual;
|
|
if(remainder)
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int flush(float *output, size_t outMax) {
|
|
int ret = 0;
|
|
int i;
|
|
if(remainder > 0) {
|
|
size_t blockCount = remainder;
|
|
if(blockCount > outMax)
|
|
blockCount = outMax;
|
|
for(i = 0; i < channelCount; ++i) {
|
|
vDSP_vdpsp(&OutBufs[i][0], 1, output + i, channelCount, blockCount);
|
|
}
|
|
remainder -= blockCount;
|
|
output += channelCount * blockCount;
|
|
outProcessed += blockCount;
|
|
outMax -= blockCount;
|
|
ret += blockCount;
|
|
if(!outMax)
|
|
return ret;
|
|
}
|
|
uint64_t outputWanted = ceil(inProcessed * sampleRatio);
|
|
memset(&InBuf[0], 0, sizeof(double) * bufferCapacity);
|
|
while(outProcessed < outputWanted) {
|
|
int outputDone = 0;
|
|
for(int i = 0; i < channelCount; ++i) {
|
|
double *outputPointer;
|
|
outputDone = Resamps[i]->process(InBuf, bufferCapacity, outputPointer);
|
|
if(outputDone) {
|
|
if(outputDone > (outputWanted - outProcessed))
|
|
outputDone = (int)(outputWanted - outProcessed);
|
|
if(outputDone > outMax) {
|
|
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outMax);
|
|
remainder = outputDone - outMax;
|
|
OutBufs[i].alloc((int)remainder);
|
|
memcpy(&OutBufs[i][0], outputPointer + outMax, remainder);
|
|
} else {
|
|
vDSP_vdpsp(outputPointer, 1, output + i, channelCount, outputDone);
|
|
}
|
|
}
|
|
}
|
|
size_t outputActual = outputDone - remainder;
|
|
outProcessed += outputActual;
|
|
output += channelCount * outputActual;
|
|
outMax -= outputActual;
|
|
ret += outputActual;
|
|
if(remainder)
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
#endif /* r8bstate_h */
|