我试图将2个16位线性PCM音频流混合在一起,但我似乎无法克服噪音问题。我认为将样品混合在一起时,它们会溢出。
我有以下功能...
short int mix_sample(short int sample1, short int sample2)
{
return #mixing_algorithm#;
}
......以及我作为#mixing_algorithm#
尝试的内容sample1/2 + sample2/2
2*(sample1 + sample2) - 2*(sample1*sample2) - 65535
(sample1 + sample2) - sample1*sample2
(sample1 + sample2) - sample1*sample2 - 65535
(sample1 + sample2) - ((sample1*sample2) >> 0x10) // same as divide by 65535
其中一些产生了比其他产品更好的效果,但即使最好的结果也包含了很多噪音。
任何想法如何解决?
答案 0 :(得分:10)
我找到的最佳解决方案是given by Viktor Toth。他为8位无符号PCM提供了解决方案,并为16位带符号PCM改变了这一点,产生了这样的结果:
int a = 111; // first sample (-32768..32767)
int b = 222; // second sample
int m; // mixed result will go here
// Make both samples unsigned (0..65535)
a += 32768;
b += 32768;
// Pick the equation
if ((a < 32768) || (b < 32768)) {
// Viktor's first equation when both sources are "quiet"
// (i.e. less than middle of the dynamic range)
m = a * b / 32768;
} else {
// Viktor's second equation when one or both sources are loud
m = 2 * (a + b) - (a * b) / 32768 - 65536;
}
// Output is unsigned (0..65536) so convert back to signed (-32768..32767)
if (m == 65536) m = 65535;
m -= 32768;
使用此算法意味着几乎不需要剪切输出,因为它只是一个不在范围内的值。与直线平均不同,即使另一个源静音,也不会减少一个源的音量。
答案 1 :(得分:8)
这是一个描述性的实现:
short int mix_sample(short int sample1, short int sample2) {
const int32_t result(static_cast<int32_t>(sample1) + static_cast<int32_t>(sample2));
typedef std::numeric_limits<short int> Range;
if (Range::max() < result)
return Range::max();
else if (Range::min() > result)
return Range::min();
else
return result;
}
混合,它只是添加和剪辑!
为了避免剪切伪像,您需要使用饱和度或限制器。理想情况下,您将拥有一个带有少量前瞻的小int32_t
缓冲区。这将引入延迟。
比限制所有地方更常见的是在信号中留下一些“净空”值。
答案 2 :(得分:2)
这是我在最近的合成器项目中所做的。
int* unfiltered = (int *)malloc(lengthOfLongPcmInShorts*4);
int i;
for(i = 0; i < lengthOfShortPcmInShorts; i++){
unfiltered[i] = shortPcm[i] + longPcm[i];
}
for(; i < lengthOfLongPcmInShorts; i++){
unfiltered[i] = longPcm[i];
}
int max = 0;
for(int i = 0; i < lengthOfLongPcmInShorts; i++){
int val = unfiltered[i];
if(abs(val) > max)
max = val;
}
short int *newPcm = (short int *)malloc(lengthOfLongPcmInShorts*2);
for(int i = 0; i < lengthOfLongPcmInShorts; i++){
newPcm[i] = (unfilted[i]/max) * MAX_SHRT;
}
我将所有PCM数据添加到整数数组中,这样我就可以得到所有未经过滤的数据。
在这之后我在整数数组中查找绝对最大值。
最后,我取整数数组并将其放入一个短的int数组中,将每个元素除以该最大值,然后乘以max short int值。
通过这种方式,您可以获得满足数据所需的最小“净空”量。
您可以对整数数组进行一些统计并整合一些剪辑,但是对于我需要的最小量的余量对我来说已经足够了。
答案 3 :(得分:1)
这里有一个讨论:https://dsp.stackexchange.com/questions/3581/algorithms-to-mix-audio-signals-without-clipping,为什么A + B-A * B解决方案不理想。在此讨论的评论中,隐藏了一项建议,即对这些值求和并除以信号数量的平方根。额外的裁剪检查不会受到伤害。这似乎是一个合理的(简单而快速的)中间立场。
答案 4 :(得分:0)
我认为它们应该是映射[MIN_SHORT, MAX_SHORT] -> [MIN_SHORT, MAX_SHORT]
的函数,它们显然不是(除了第一个),所以会发生溢出。
如果unwind的命题不起作用,你也可以尝试:
((long int)(sample1) + sample2) / 2
答案 5 :(得分:-1)
由于您在时域中,频率信息在连续样本之间的差异中,当您除以2时会损坏该信息。这就是为什么添加和剪辑效果更好的原因。剪切当然会增加非常高的频率噪声,可能会过滤掉。