我正在移植一个过滤器库,该过滤器库目前使用Apple特定的(加速)vDSP功能vDSP_deq22到Android(其中Accelerate不可用).滤波器组是一组带通滤波器,每个滤波器滤波器返回其各自频带的RMS幅度.目前代码(ObjectiveC++,改编自NVDSP)如下所示:
- (float) filterContiguousData: (float *)data numFrames:(UInt32)numFrames channel:(UInt32)channel { // Init float to store RMS volume float rmsVolume = 0.0f; // Provide buffer for processing float tInputBuffer[numFrames + 2]; float tOutputBuffer[numFrames + 2]; // Copy the two frames we stored into the start of the inputBuffer, filling the rest with the current buffer data memcpy(tInputBuffer, gInputKeepBuffer[channel], 2 * sizeof(float)); memcpy(tOutputBuffer, gOutputKeepBuffer[channel], 2 * sizeof(float)); memcpy(&(tInputBuffer[2]), data, numFrames * sizeof(float)); // Do the processing vDSP_deq22(tInputBuffer, 1, coefficients, tOutputBuffer, 1, numFrames); vDSP_rmsqv(tOutputBuffer, 1, &rmsVolume, numFrames); // Copy the last two data points of each array to be put at the start of the next buffer. memcpy(gInputKeepBuffer[channel], &(tInputBuffer[numFrames]), 2 * sizeof(float)); memcpy(gOutputKeepBuffer[channel], &(tOutputBuffer[numFrames]), 2 * sizeof(float)); return rmsVolume; }
如所看到的在这里,deq22实现通过递归函数上一个给定的输入矢量双二阶滤波器.这是文档中函数的描述:
A =:单精度实输入向量
IA =:迈向A.
B =:5个单精度输入(滤波器系数),步长为1.
C =:单精度实数输出向量.
IC =:C的步伐
N =:要生成的新输出元素的数量.
这是我到目前为止(它在Swift中,就像我已在Android上运行的其余代码库):
// N is fixed on init to be the same size as buffer.count, below // 'input' and 'output' are initialised with (N+2) length and filled with 0s func getFilteredRMSMagnitudeFromBuffer(var buffer: [Float]) -> Float { let inputStride = 1 // hardcoded for now let outputStride = 1 input[0] = input[N] input[1] = input[N+1] output[0] = output[N] output[1] = output[N+1] // copy the current buffer into input input[2 ... N+1] = buffer[0 ..< N] // Not sure if this is neccessary, just here to duplicate NVDSP behaviour: output[2 ... N+1] = [Float](count: N, repeatedValue: 0)[0 ..< N] // Again duplicating NVDSP behaviour, can probably just start at 0: var sumOfSquares = (input[0] * input[0]) + (input[1] * input[1]) for n in (2 ... N+1) { let sumG = (0...2).reduce(Float(0)) { total, p in return total + input[(n - p) * inputStride] * coefficients[p] } let sumH = (3...4).reduce(Float(0)) { total, p in return total + output[(n - p + 2) * outputStride] * coefficients[p] } let filteredFrame = sumG - sumH output[n] = filteredFrame sumOfSquares = filteredFrame * filteredFrame } let meanSquare = sumOfSquares / Float(N + 2) // we added 2 values by hand, before the loop let rootMeanSquare = sqrt(meanSquare) return rootMeanSquare }
滤波器给deq22提供了不同的幅度输出,并且似乎在其中具有循环波动的圆形"噪声"(具有恒定的输入音调,该频率的幅度上下泵送).
我已经检查过以确保每个实现之间的系数数组是相同的.每个滤波器实际上似乎"工作",因为它拾取正确的频率(并且只有那个频率),它只是这个泵浦,并且RMS幅度输出比vDSP更安静,通常是几个数量级:
Naive | vDSP 3.24305e-06 0.000108608 1.57104e-06 5.53645e-05 1.96445e-06 4.33506e-05 2.05422e-06 2.09781e-05 1.44778e-06 1.8729e-05 4.28997e-07 2.72648e-05
任何人都可以看到我的逻辑问题吗?
编辑:这是一个结果的gif视频,具有恒定的440Hz音调.各种绿色条是各个滤带.第3频段(此处显示)是调谐到440Hz的频段.
正如预期的那样,NVDSP版本只显示与输入音量成比例的恒定(非波动)幅度读数.