9

我试图将 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

其中一些产生了比其他更好的结果,但即使是最好的结果也包含相当多的噪音。

任何想法如何解决它?

4

6 回答 6

13

我找到的最佳解决方案是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;

使用这种算法意味着几乎不需要裁剪输出,因为它只有一个值在范围内。与直接平均不同,即使另一个源静音,一个源的音量也不会降低。

于 2014-08-03T06:44:03.547 回答
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带有少量前瞻的小缓冲区。这将引入延迟。

比到处限制更常见的是在你的信号中留下一些“余量”。

于 2012-08-23T11:24:25.287 回答
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 数据添加到一个整数数组中,这样我就可以得到所有未过滤的数据。

之后,我在整数数组中寻找绝对最大值。

最后,我将整数数组放入一个短整数数组中,方法是将每个元素除以该最大值,然后乘以最大短整数值。

通过这种方式,您可以获得适合数据所需的最小“净空”量。

您也许可以对整数数组进行一些统计并整合一些剪辑,但对于我需要的最小空间量对我来说已经足够了。

于 2014-11-18T17:28:05.803 回答
1

这里有一个讨论:https ://dsp.stackexchange.com/questions/3581/algorithms-to-mix-audio-signals-without-clipping关于为什么 A+B - A*B 解决方案不理想。隐藏在本次讨论的其中一条评论中的是建议将这些值相加并除以信号数量的平方根。额外的剪裁检查也无妨。这似乎是一个合理(简单而快速)的中间立场。

于 2020-04-02T13:50:23.173 回答
0

我认为它们应该是函数映射[MIN_SHORT, MAX_SHORT] -> [MIN_SHORT, MAX_SHORT],它们显然不是(除了第一个),所以会发生溢出。

如果 unwind 的提议不起作用,您也可以尝试:

((long int)(sample1) + sample2) / 2
于 2012-08-23T10:46:40.333 回答
-1

由于您处于时域中,因此频率信息位于连续样本之间的差异中,当您除以 2 时,您会损坏该信息。这就是为什么添加和剪辑效果更好的原因。削波当然会添加非常高频的噪声,可能会被过滤掉。

于 2013-04-23T00:43:55.987 回答