Ala*_*art 18 algorithm audio signal-processing sample-rate
iOS通过某些USB音频设备录制问题.它无法可靠地再现(分批发生在每2000个〜2000-3000个记录中并且无声地消失),我们目前手动检查我们的音频是否有任何录音问题.它导致少量样本(1-20)被移动了一小部分,听起来像是一种"噼啪声".
它们看起来像这样:

接近:

接近:

另一个,同一音频文件中其他地方的单个样本错误:

问题是,如何在算法上检测这些(假设直接访问样本),同时不会触发高频音频的误报,如下所示:

奖励积分:在确定尽可能多的错误后,如何"修复"音频?
更多奖励积分:在iOS USB音频驱动程序/硬件中可能导致此问题的原因(假设它在那里).
use*_*905 13
我不认为有一个开箱即用的解决方案来找到干扰,但这是一种(非标准的)解决问题的方法.使用这个,我可以找到大多数间隔,我只得到少量的误报,但算法当然可以使用一些微调.
我的想法是找到偏离样本的起点和终点.第一步应该是让这些要点更加突出.这可以通过获取数据的对数并获取连续值之间的差异来完成.
在MATLAB中我加载数据(在本例中我使用dirty-sample-other.wav)
y1 = wavread('dirty-sample-pictured.wav');
y2 = wavread('dirty-sample-other.wav');
y3 = wavread('clean-highfreq.wav');
data = y2;
Run Code Online (Sandbox Code Playgroud)
并使用以下代码:
logdata = log(1+data);
difflogdata = diff(logdata);
Run Code Online (Sandbox Code Playgroud)
因此,而不是原始数据的这个图:

我们得到:

我们寻找的区间突出显示为正和负的峰值.例如,放大对数差异图中的最大正值,我们得到以下两个数字.一个用于原始数据:

和一个对数的差异:

该图可以帮助手动查找区域,但理想情况下我们希望使用算法找到它们.我这样做的方法是采用大小为6的移动窗口,计算窗口的平均值(除了最小值之外的所有点),并将其与最大值进行比较.如果最大点是高于平均值的唯一点并且至少是平均值的两倍,则将其计为正极值.
然后我使用了一个计数阈值,至少有一半的窗口移动到该值时应将其检测为极值以便接受它.
将所有点乘以(-1),然后再次运行该算法以检测最小值.
用"o"标记正极值,用"*"标记负极值,我们得到以下两个图.一个用于对数的差异:

和一个原始数据:

放大显示对数差异的图的左侧部分,我们可以看到找到了最极端的值:

似乎找到了大多数间隔,并且只有少量误报.例如,在'clean-highfreq.wav'I 上运行算法只能找到一个正极值和一个负极值.
错误地归类为极值的单个值也许可以通过匹配起点和终点来消除.如果你想要替换丢失的数据,你可以使用周围的数据点进行某种插值,甚至线性插值也许就足够了.
这是我使用的MATLAB代码:
function test20()
clc
clear all
y1 = wavread('dirty-sample-pictured.wav');
y2 = wavread('dirty-sample-other.wav');
y3 = wavread('clean-highfreq.wav');
data = y2;
logdata = log(1+data);
difflogdata = diff(logdata);
figure,plot(data),hold on,plot(data,'.')
figure,plot(difflogdata),hold on,plot(difflogdata,'.')
figure,plot(data),hold on,plot(data,'.'),xlim([68000,68200])
figure,plot(difflogdata),hold on,plot(difflogdata,'.'),xlim([68000,68200])
k = 6;
myData = difflogdata;
myPoints = findPoints(myData,k);
myData2 = -difflogdata;
myPoints2 = findPoints(myData2,k);
figure
plotterFunction(difflogdata,myPoints>=k,'or')
hold on
plotterFunction(difflogdata,myPoints2>=k,'*r')
figure
plotterFunction(data,myPoints>=k,'or')
hold on
plotterFunction(data,myPoints2>=k,'*r')
end
function myPoints = findPoints(myData,k)
iterationVector = k+1:length(myData);
myPoints = zeros(size(myData));
for i = iterationVector
subVector = myData(i-k:i);
meanSubVector = mean(subVector(subVector>min(subVector)));
[maxSubVector, maxIndex] = max(subVector);
if (sum(subVector>meanSubVector) == 1 && maxSubVector>2*meanSubVector)
myPoints(i-k-1+maxIndex) = myPoints(i-k-1+maxIndex) +1;
end
end
end
function plotterFunction(allPoints,extremeIndices,markerType)
extremePoints = NaN(size(allPoints));
extremePoints(extremeIndices) = allPoints(extremeIndices);
plot(extremePoints,markerType,'MarkerSize',15),
hold on
plot(allPoints,'.')
plot(allPoints)
end
Run Code Online (Sandbox Code Playgroud)
编辑 - 有关恢复原始数据的注释
以下是上图3的略微缩小视图:(干扰介于6.8和6.82之间)

当我检查这些值时,关于被反映为负值的数据的理论似乎并不完全符合模式.但无论如何,我想要消除差异当然是不正确的.由于干扰似乎没有改变周围的点,我可能会回到最初的想法,即不信任受影响区域内的点,而是使用周围数据进行某种插值.在大多数情况下,似乎简单的线性插值将是一个非常好的近似.
要回答为什么会发生的问题 -
USB音频设备和主机不是时钟同步的 - 也就是说主机无法准确恢复主机本地时钟与音频接口上ADC/DAC的字时钟之间的关系.存在各种技术用于具有不同程度有效性的时钟恢复.为了解决这个问题,总线时钟可能与两个音频时钟中的任何一个无关.
虽然您可能想象这对于音频接收并不是太过关注 - 音频捕获回调可能在有数据时发生 - 音频接口通常是双向的,主机将定期渲染音频,另一端是潜在消费的速度略有不同.
中间是几组缓冲区,可以运行过度或欠运行,这就是这里发生的事情; 它发生的间隔肯定是正确的.
您可能会发现将USB音频设备更改为围绕不同芯片组(或简称为不同的本地振荡器)构建的设备会有所帮助.
另外,IEEE1394音频和MPEG传输流都具有相同的时钟恢复要求.它们都以一种非常可预测的方式将本地时钟参考数据包嵌入到串行比特流中,从而在另一端实现精确的时钟恢复,从而解决了这个问题.