我正在设置一个简单的音频 IO 系统,它通过从已存储在内存中的文件一次调用一个 block 来模拟“实时 block 处理”。
此刻,我有一个简单的脚本,它从文件中检索数据,然后进入 while 循环,一次提取一个 block ,并提供 600 Hz 的一阶巴特沃斯低通滤波器(用于测试的框架设置).然后将每个 block 处理并添加到另一个声明在 while 循环范围之外的数组中,以便处理后的数据可以在完成后写入 wave 文件。
为了过滤数据,我使用 Octave signal pkg 生成系数 ( butter ),然后内置 filter应用 IIR 滤波器的函数。
问题是,如果我不应用过滤器影响,即输入 = 输出,音频听起来完全一样。但是,如果我每次调用一个 block 时都应用一个滤波器,则会产生一个振铃,使信号在数字上严重失真。
请参阅以下设置脚本(目前仅处理单声道音频)。
# Reset
close all; clear all;
# Audio file path
fileName = 'test.wav';
# Init routines
[x,fs] = audioread(fileName);
xlen = length(x);
[dim1,dim2] = size(x);
y = zeros(dim1,dim2);
[b,a] = butter(1, (600./(fs*0.5)));
index = 1;
blockSize = 256;
# Enter process loop
while(index + blockSize < xlen)
# Extract one block
audioBlock(:,1) = x(index : index + blockSize - 1, 1);
# Do process
outAudioBlock = filter(b,a,audioBlock);
# Store output block
y(index : index + blockSize - 1, 1) = outAudioBlock(:);
# Update index
index += blockSize;
endwhile
# Write to outputs
audiowrite('processed.wav', y, fs);
audiowrite('processed1.wav', filter(b,a,y), fs);
第二个 audiowrite 只是一个例子,它确认在一个调用中过滤整个音频数据不会产生失真,而 block 过滤会产生明显的数字失真。
作为旁注:
我还尝试使用不同的滤波技术,包括带窗口的频域乘法,然后 ifft 返回(使用 Octave fftfilt 并仅使用 fft)以及时域卷积并创建重叠相加方法。当应用 FIR 滤波器而不是使用 IIR 系数时,也会出现同样的效果。
我也知道这个例子忽略了最后一个 block 左右的音频,但对于这个用例,我不关心最后一个 block 的零填充。
我不确定我错过了什么;有什么想法吗?
编辑 1:我的想法是尽可能不使用频域处理(只是时域 IIR/FIR 滤波),但我调查了频域乘法以查看是否出现了类似的失真结果(确实如此) ).
最佳答案
这很可能是边缘效应。您将因果 IIR 滤波器应用于 audioBlock
.为了计算第一个样本,状态被初始化为全零。如果我没记错的话,这相当于假设第一个样本之前的信号全为零。这可能会产生不连续性,这将影响 block 开头的一定数量的样本。因为您使用 IIR 滤波器,所以这种影响可能会持续很长时间。在这方面使用 FIR 滤波器更安全。
让我们假设 margin
sample 受到影响。您可以按如下方式修改代码以将信号扩展该数量并防止失真:
while(index + blockSize < xlen)
% Extract one block
if index==1
audioBlock = x(index : index + blockSize - 1);
else
audioBlock = x(index - margin : index + blockSize - 1);
end
% Do process
outAudioBlock = filter(b,a,audioBlock);
% Store output block
if index==1
y(index : index + blockSize - 1) = outAudioBlock;
else
y(index : index + blockSize - 1) = outAudioBlock(margin+1:end);
end
% Update index
index += blockSize;
end
(免责声明:我这里没有安装octave,而且我的MATLAB副本没有信号处理工具箱,所以我无法测试上面的代码。)
不请自来的建议:
你的数据都是一维的,使用一维(线性)索引。它效率更高,输入时间更短。 (见我上面的代码。)
不要做
audioBlock(:,1) =
当提取一个新的信号位时。只需将结果分配给变量即可。它的速度多,并且如果信号大小发生变化并且您忘记重置变量也不会出现问题。不要以
close all; clear all;
开头.相反,写function <filename>
在脚本的顶部。这会将脚本转换为一个函数,这意味着它有自己的工作区。这是一种更安全的工作方式,因为您不会不小心在脚本中使用现有变量,也不会不小心删除基础工作区中的任何内容。我使用了
end
而不是endwhile
.这是一样的,但也适用于 MATLAB。没有理由不使用最便携的选项。我使用了
%
而不是#
.同样,相同但便携。请注意 SO 语法突出显示如何与%
一起使用但不是#
! :)
关于matlab - 阻止从文件流式传输时的音频失真( Octave ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49275088/