峰值滤波器出现了杂音和爆破声

5
OSStatus MusicPlayerCallback ( 
                       void *                     inRefCon, 
                       AudioUnitRenderActionFlags *   ioActionFlags, 
                       const AudioTimeStamp *         inTimeStamp, 
                       UInt32                     inBusNumber, 
                       UInt32                     inNumberFrames, 
                       AudioBufferList *            ioData) { 


MusicPlaybackState *musicPlaybackState = (MusicPlaybackState*) inRefCon; 

double sampleinp; 

double A,omega,sn,cs,alpha,Bandwidth; 

double dbGain; 

double   a0,a1,a2,b0,b1,b2; 

dbGain = 1.0; 

A=pow(10.0,dbGain/40.0); 

Bandwidth = 2.0; 

omega=2 * M_PI * 800.0/44100.0; 

sn=sin(omega); 

cs=cos(omega); 

alpha=sn*sinh(((M_LN2/2)*Bandwidth*omega)/sn); 


//Peak Filter Biquad 

b0 =1.0 + alpha * A; 

b1 = (-2.0 * cs); 

b2 = 1.0 - alpha * A; 

a0 = 1.0 + (alpha /A); 

a1 = -2.0 * cs; 

a2 = 1.0 - (alpha /A); 



double b0a0, b1a0, b2a0, a1a0, a2a0; 

double static x1; 

double static x2; 

double static y1; 

double static y2; 


b0a0=b0/a0;   

b1a0=b1/a0; 

b2a0=b2/a0; 

a1a0=a1/a0; 

a2a0=a2/a0; 


for (int i = 0 ; i < ioData->mNumberBuffers; i++){ 


  AudioBuffer buffer = ioData->mBuffers[i]; 
  AudioSampleType *outSample = buffer.mData; 

  for (int j = 0; j < inNumberFrames*2; j++){ 

     sampleinp = *musicPlaybackState->samplePtr++; 

     outSample[j] =  b0a0 * sampleinp + 
     b1a0 * x1 + 
     b2a0 * x2 - 
     a1a0 * y1 - 
     a2a0 * y2; 


     x2=x1; 
     x1=sampleinp; 

     y2=y1; 
     y1=outSample[j]; 

  }} 





return noErr; 
} 

拥有点击/爆裂问题。请有人帮忙...我不知道我做错了什么。这是在Xcode中使用C语言的Objective-C。我尝试将Coeff设置为全局和静态,但没有运气。音频文件是一个.caf格式,我尝试过.wav,但仍然不行...

谢谢,抱歉向大家求助。我是这个网站的新手...我正在尝试在我的应用程序中添加峰值滤波器,但每次我使用滑块或只是将增益保留在1时,都会出现砰砰声和点击声。似乎一切都在那里,并且像持有先前的样本等方面都正常工作。当更改频率或带宽时,我也会得到某种相位。我很困惑,已经学习dsp几个月了,我认为这与Objective-C有关,也有一点用户错误。当将样本更改为SInt32时,它似乎消失了,但当更改频率时左声道消失。

Dsp.h

typedef struct { 

  void* audioData; 

   UInt32 audioDataByteCount; 

   SInt16 *samplePtr; 

} MusicPlaybackState; 

1
我无法想象为什么有人投票关闭这个。 - ocodo
@Slomojo:我认为这个问题不应该被关闭,但是它的表述并不是很清晰,我可以理解为什么会有人投票关闭。@Cocell:你可能需要改进这个问题,以避免进一步的关闭投票-尝试更详细地描述问题和你所尝试的内容,并将其变成一个具体的问题,而不是一个泛泛的“求助”。 - Paul R
1
@Paul R - 我同意问题应该更有效地提出,但完全无声的关闭投票是不合适的。很明显,Cocell是SO的新用户,只是想解决一个棘手的问题。少于2k rep的人无法投票关闭,所以当这种情况发生时,非常令人失望。这是武断、没有帮助和粗鲁的,如果需要更多信息,只需要请求更多信息的评论即可,而不是“走开,你的问题不受欢迎”,这正是关闭投票所传达的。 - ocodo
@eryksun 数据类型是SInt16,希望这是你需要的。我还没有测试过正弦波。我一直在测试不同的立体声歌曲,以为滤波器会起作用。这让我疯了。我一直在使用MATLab创建滤波器,然后尝试在我的应用程序中实现它们,但即使有静态系数也没有运气。 - Cocell
@Paul R - 是的,它相当"粗鄙"。 - ocodo
显示剩余2条评论
4个回答

4
根据hotpaw2的回答,这是您的滤波器响应的图表:
from pylab import *
import scipy.signal as signal

def biquad_peak(omega, gain_db, bandwidth):
    sn = sin(omega)
    cs = cos(omega)
    alpha = sn * sinh(log(2) / 2 * bandwidth * omega / sn)
    gain_sqrt = 10.0 ** (gain_db / 40.0)

    # feed-forward coefficients
    b0 = 1.0 + alpha * gain_sqrt
    b1 = -2.0 * cs
    b2 = 1.0 - alpha * gain_sqrt
    # feedback coefficients
    a0 = 1.0 + (alpha / gain_sqrt)
    a1 = -2.0 * cs
    a2 = 1.0 - (alpha / gain_sqrt)
    # normalize by a0
    B = array([b0, b1, b2]) / a0
    A = array([a0, a1, a2]) / a0
    return B, A

omega = 2 * pi * 800.0 / 44100.0
gain_db = 1.0
bandwidth = 2.0

B, A = biquad_peak(omega, gain_db, bandwidth)
w, H = signal.freqz(B, A)
f = w / pi * 22050.0
plot(f, abs(H), 'r')
gain = 10.0 ** (gain_db / 20.0)
print  "Gain:", gain
plot(f, gain*ones(len(f)), 'b--'); grid()

biquad peak filter response

峰值增益设置为1.1220184543(即1 dB)。您可以看到滤波器导致大多数可听范围具有大于1的增益。

编辑2: 如果这是用于可调EQ,则由用户设置避免失真的增益。此外,我怀疑您所描述的极端问题不会因为典型音频轨道的狭窄带上的轻微1 dB增益而引起。相反,它可能是因为您的音频具有交错立体声数据。每个通道都需要单独过滤。我尝试修改您的嵌套循环以实现此目的:

a0 = 1.0 + alpha / A; 
a1 = -2.0 * cs / a0;     
a2 = (1.0 - alpha / A) / a0; 
b0 = (1.0 + alpha * A) / a0; 
b1 = -2.0 * cs / a0; 
b2 = (1.0 - alpha * A) / a0;

double static x11, x12, x21, x22;
double static y11, y12, y21, y22;
double x0, y0;

for (int i = 0; i < ioData->mNumberBuffers; i++) {  

    AudioBuffer buffer = ioData->mBuffers[i]; 
    AudioSampleType *outSample = buffer.mData; 

    for (int j = 0; j < inNumberFrames*2; j++) { 

        /* x0 is in the range of SInt16: -32768 to 32767 */

        x0 = *musicPlaybackState->samplePtr++;

        y0 = b0 * x0 + 
             b1 * x11 + 
             b2 * x12 - 
             a1 * y11 - 
             a2 * y12; 

        outSample[j] = fmax(fmin(y0, 32767.0), -32768.0); 

        x12 = x11; 
        x11 = x0;
        y12 = y11;
        y11 = y0
        j++;          

        x0 = *musicPlaybackState->samplePtr++;

        y0 =  b0 * x0 + 
              b1 * x21 + 
              b2 * x22 - 
              a1 * y21 - 
              a2 * y22; 

        outSample[j] = fmax(fmin(y0, 32767.0), -32768.0); 

        x22 = x21; 
        x21 = x0;          
        y22 = y21; 
        y21 = y0; 
    }
}

那么,如果我想在10000kHz处提高频率,例如峰值为12dB,而又不出现点击和爆音,如果你说它必须小于1dB,该怎么办? - Cocell
@eryksun 不是只是举个例子。我只是在想,如果我想在某个频率上提高12dB,会不会引起同样的问题?感谢您的帮助。 - Cocell
@eryksun,是的,我已经添加了AGC,因为我仍然有一点削波。这就是我接下来要做的(SInt32)。所以对于我的输入和系数,我会改为SInt32,然后在处理时从inNumberFrames*2减去inNumberFrames,然后输出回SInt16,这是iPhone读取的格式。我之前尝试过这样做,但我的左声道丢失了,所以重新调整这种方式应该会减少很多削波。 - Cocell
不用在意最后的注释中提到的输入数据类型。更改系数数据类型不会有太大的影响。 - Cocell
@eryksun 一切都正常工作。我之前使用了一个if语句来处理AGC,但我喜欢你的方法更好。现在我可以超过1.0而不会削波。我认为这对于任何使用iPhone/iPad/iPod Touch进行DSP的人都是一个很好的参考。再次感谢! :) - Cocell
显示剩余3条评论

2

一个重要的问题是,你的过滤器状态必须存储在refcon状态内(至少,在典型情况下这是显而易见的最佳位置)。

如果没有这样做,你的过滤器将在每次回调时重新构建和初始化,这意味着状态将不会正确地被保留,且除第一次回调之外的每个回调边界都会出现故障。


1

看起来你正在使用RBJ的双二次滤波器配方。

一个平均增益为1.0的双二次峰值滤波器在某些频率上具有高于1.0的增益。如果您不想削波,您要么必须使用小于1.0的增益,要么在输入上使用衰减器或AGC,以使峰值频率增益永远不会达到会削波的水平。

没有AGC是一个问题,因为一些客户希望峰值或低音增强滤波器使事物更响亮,而您必须衰减平均电平以完全防止在峰值频率处削波。


好的,我会尝试添加一个AGC。所以你的意思是说它发出声音的原因是因为不同频率上的增益在幅度上超过了1.0,而不是像eryksun提到的分贝? - Cocell

1
除了已经给出的优秀答案,我要补充一条一般性建议 - 你应该将过滤程序从回调中分离出来(即把它作为一个独立函数,不依赖于你的 iOS 代码)。这样你就可以将其放入测试环境并更容易地进行调试(在非实时环境下),避免可能会使事情复杂化的任何与 iOS 相关的问题。

谢谢,我第二个版本就是这样做的,但问题仍然存在。我只是把它们放在一起以便更容易帮助解决。 - Cocell
@Cocell:好的-当你将例程单独实现后,请编写一个测试套件,可以生成输入信号,例如给定幅度和频率的正弦波,然后以可绘制的格式转储输出-这样可以更轻松地进行调试等。 - Paul R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接