Real-time 与 FFTW 的脉冲响应卷积——结果听起来 IR 是对称的
Real-time impulse response convolution with FFTW -- result sounds like IR is symmetrical
出于研究目的,我正在使用 FFTW(以及用于声音传输的 PortAudio)和 overlap-add 卷积方法在 C++ 中构建一个 real-time 混响卷积引擎。它的大部分都在工作,但出现了一个非常奇特的效果。虽然我不明白为什么,但听起来脉冲响应变得非常对称:h[n]
变成了 h[n] + h[-n]
。有谁知道按照我下面描述的方式执行 FFT 是否会产生这种效果?
基本上我的流程是这样的:
提前知道:
h
,脉冲响应 m
样本长
x
,声音 n
采样长
FFT_SIZE
,一个分区size/window大小
n > m
大约是 3 倍,但 FFT_SIZE
小得多(目前为 1024)
音频开始前在离线阶段完成的工作:
我将 x
分成 FFT_SIZE
长度的部分。因为我会将每个 window 与 h
进行卷积,所以我将每个 n+m - 1
样本复制到长度为 0 的填充缓冲区中,并执行前向 FFT,保存生成的复杂数组。 (我有 n/FFT_SIZE
个复杂的数组。)现在我正在使用没有重叠的矩形 windowing,一旦我解决了这个问题,如果它改进了,我将实施 Hamming。
我还在 0 填充到长度 n+m - 1
之后执行 h
的单个前向 FFT,并存储与其他大小相同的单个复数数组。
实时阶段
PortAudio 与大多数音频引擎一样,调用回调以定期用声音数据填充缓冲区 out
。在我的回调中(根据设计要求 FFT_SIZE
音频样本,我每次 select 表示下一个 window 的复杂数组(因为一个回调调用对应于与一个相同的声音长度 window 用于 FFT)。
我将该数组与 FFT-ing h
生成的数组逐点相乘,然后执行 IFFT。生成的声音缓冲区 n+m-1
长,比 FFT_SIZE
大得多,所以我只将开头复制到 out
缓冲区并将其余部分添加到 overlap/carry 缓冲区(累积混响在将进位缓冲区的开头移动到 out
之后(因此 out
现在包含一个 window 的新 IFFT 数据添加到一个 window 之前计算的衰变尾巴的价值)。
关注现在
就像我之前提到的,这听起来好像脉冲响应没有被正确地进行 FFT,并且导致表现得好像它是对称的 - 反转然后添加到自身。我不确定我做错了什么,但我看不出这种影响是如何由我的携带问题产生的——尽管如果我是,我很高兴找到了这个错误!
我最好的猜测是我也应该以某种方式执行 h
的 windowing。但是,根据我读过的文献,您只需将 x
的每个 window 与整个 h
进行卷积并进行进位。也许这是错误的?
感谢您的帮助!
当 point-wise 乘以 2 个 FFT 向量时,您的算术似乎是错误的。复向量乘法必须考虑实部和虚部之间的叉积。例如re = re1*re2 - im1*im2; im = re1*im2 + re2*im1 等
出于研究目的,我正在使用 FFTW(以及用于声音传输的 PortAudio)和 overlap-add 卷积方法在 C++ 中构建一个 real-time 混响卷积引擎。它的大部分都在工作,但出现了一个非常奇特的效果。虽然我不明白为什么,但听起来脉冲响应变得非常对称:h[n]
变成了 h[n] + h[-n]
。有谁知道按照我下面描述的方式执行 FFT 是否会产生这种效果?
基本上我的流程是这样的:
提前知道:
h
,脉冲响应m
样本长x
,声音n
采样长FFT_SIZE
,一个分区size/window大小
n > m
大约是 3 倍,但 FFT_SIZE
小得多(目前为 1024)
音频开始前在离线阶段完成的工作:
我将 x
分成 FFT_SIZE
长度的部分。因为我会将每个 window 与 h
进行卷积,所以我将每个 n+m - 1
样本复制到长度为 0 的填充缓冲区中,并执行前向 FFT,保存生成的复杂数组。 (我有 n/FFT_SIZE
个复杂的数组。)现在我正在使用没有重叠的矩形 windowing,一旦我解决了这个问题,如果它改进了,我将实施 Hamming。
我还在 0 填充到长度 n+m - 1
之后执行 h
的单个前向 FFT,并存储与其他大小相同的单个复数数组。
实时阶段
PortAudio 与大多数音频引擎一样,调用回调以定期用声音数据填充缓冲区 out
。在我的回调中(根据设计要求 FFT_SIZE
音频样本,我每次 select 表示下一个 window 的复杂数组(因为一个回调调用对应于与一个相同的声音长度 window 用于 FFT)。
我将该数组与 FFT-ing h
生成的数组逐点相乘,然后执行 IFFT。生成的声音缓冲区 n+m-1
长,比 FFT_SIZE
大得多,所以我只将开头复制到 out
缓冲区并将其余部分添加到 overlap/carry 缓冲区(累积混响在将进位缓冲区的开头移动到 out
之后(因此 out
现在包含一个 window 的新 IFFT 数据添加到一个 window 之前计算的衰变尾巴的价值)。
关注现在
就像我之前提到的,这听起来好像脉冲响应没有被正确地进行 FFT,并且导致表现得好像它是对称的 - 反转然后添加到自身。我不确定我做错了什么,但我看不出这种影响是如何由我的携带问题产生的——尽管如果我是,我很高兴找到了这个错误!
我最好的猜测是我也应该以某种方式执行 h
的 windowing。但是,根据我读过的文献,您只需将 x
的每个 window 与整个 h
进行卷积并进行进位。也许这是错误的?
感谢您的帮助!
当 point-wise 乘以 2 个 FFT 向量时,您的算术似乎是错误的。复向量乘法必须考虑实部和虚部之间的叉积。例如re = re1*re2 - im1*im2; im = re1*im2 + re2*im1 等