【问题标题】:Trying to mix two PCM audio sources尝试混合两个 PCM 音频源
【发布时间】:2015-04-25 21:20:26
【问题描述】:

我有两个使用 libsndfile 读取的音频文件。

SNDFILE* file1 = sf_open("D:\\audio1.wav", SFM_READ, &info);
SNDFILE* file2 = sf_open("D:\\audio2.wav", SFM_READ, &info2);

在完成前面的操作后,我采样了 x 个样本:

//Buffers that will hold the samples
short* buffer1 = new short[2 * sizeof(short) * 800000];
short* buffer2 = new short[2 * sizeof(short) * 800000];

// Read the samples using libsndfile
sf_readf_short(file1, buffer1, 800000);
sf_readf_short(file2, buffer2, 800000);

现在,我想混合这两者。我读到你需要分别得到左右声道,然后总结它们。我试过这样做:

short* mixdown = new short[channels * sizeof(short) * 800000];
for (int t = 0; t < 800000; ++t)
{
    mixdown[t] = buffer1[t] + buffer2[t] - ((buffer1[t]*buffer2[t]) / 65535);
    t++;
    mixdown[t] = buffer1[t] + buffer2[t] - ((buffer1[t]*buffer2[t]) / 65535);
}

之后我使用 ffmpeg 对新音频进行编码:

FILE* process2 = _popen("ffmpeg -y -f s16le -acodec pcm_s16le -ar 44100 -ac 2 -i - -f vob -ac 2 D:\\audioMixdown.wav", "wb");
fwrite(mixdown, 2 * sizeof(short) * 800000, 1, process2);

现在,问题是来自 buffer1 的音频在混音中听起来不错,但是当我将混音编码到文件时,唯一“添加”到新音频中的是噪音(就像它是旧的录音一样)。

如果我只将两者中的一个编码到一个文件中,它就可以完美地工作。

我不知道为什么会出错。我想这显然与混合有关,但我不知道我做错了什么。我得到了混合算法here,但它没有给我预期的结果。

我还阅读了关于 SO 的其他信息,关于人们有类似问题,但我无法用这些来弄清楚。

【问题讨论】:

  • 你在这里对立体声通道不小心 - 我希望这是因为这是一个简化的例子。
  • @Dries 您接受的答案是错误的,您链接的文章甚至解释了原因。您的代码看起来不错,但您应该划分32768,而不是65535。这可以解释一些失真。
  • @ElderBug 嗯...让我比较一下这两个想法。我认为“错误”有点苛刻。它确实适用于我的示例。
  • @Dries:不幸的是,对于混合问题没有完美的解决方案,假设您需要“即时”进行。如果您可以提前进行混音,则可以标准化输入样本并保持完整的动态范围,但否则您必须以一种或另一种方式妥协。多年来,关于这个主题的文章很多。
  • @PaulR 现在听起来不错。如果有一点质量损失也没关系。感谢您对该主题的洞察力,我确信我可以利用我获得的所有信息继续开发

标签: c++ audio ffmpeg libsndfile


【解决方案1】:

您的混音代码非常奇怪-您似乎添加了一个会导致失真的非线性项-这似乎是专门针对动态范围非常有限的 8 位 PCM 的黑客攻击,但您可能没有对于 16 位 PCM,无需担心这一点。对于基本的混音,你只需要这个:

for (int t = 0; t < 800000 * 2; ++t)
{
    mixdown[t] = (buffer1[t] + buffer2[t]) / 2;
}

请注意,当您有两个满量程信号时,必须除以 2 以防止失真。另请注意,我已删除 2x 循环展开。

【讨论】:

  • 编辑:nvm,修复了它!非常感谢
  • 那个hack可能不适合PCM。我认为这个 hack 是由不知道自己正在处理 uLaw 数据的人创建的,因此他尝试了一些简单的算术运算来解释 uLaw 值的整数解释。
  • @MSalters:啊哈 - 是的 - µLaw 是有道理的。
  • 该算法对 PCM 完全有效,而你的答案是错误的,因为它会导致幅度失真。 OP 的链接文章解释了原因。
  • @Elderbug:这取决于您是否要保持质量-通过引入非线性术语,您会引入失真。优点是您可以在一个样本安静时获得完整的动态范围,但代价是显着失真。对于低质量的音频(例如混合街机游戏声音),这可能没问题,但对于混合音乐等,人们可能更关心最小化失真。
【解决方案2】:

您的算法是正确的,但您错过了重要的一点:您的 PCM 的范围是从 -3276832767。因此,您必须除以32768,而不是65535

【讨论】:

  • 这应该是正确的答案。在许多情况下,下面建议的答案(除以 2)将使生成的音频音量减半(特别是如果输入之一是静音!)。
猜你喜欢
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-13
  • 2012-03-02
  • 1970-01-01
  • 2016-10-19
相关资源
最近更新 更多