当前位置:  开发笔记 > 人工智能 > 正文

混合声音的算法

如何解决《混合声音的算法》经验,为你挑选了7个好方法。

我有两个原始声音流,我需要加在一起.出于这个问题的目的,我们可以假设它们具有相同的比特率和比特深度(例如16比特样本,44.1khz采样率).

显然,如果我只是将它们加在一起,我将溢出并下溢我的16位空间.如果我将它们加在一起并除以2,那么每个的体积减半,这是不正确的声音 - 如果两个人在一个房间里说话,他们的声音不会变得安静一半,麦克风可以选择它们两者都没有击中限制器.

那么在我的软件混音器中将这些声音组合在一起的正确方法是什么?

我错了,正确的方法是将每个的体积减少一半?

我是否需要添加压缩器/限制器或其他处理阶段以获得我正在尝试的音量和混音效果?

-亚当



1> Roddy..:

您应该将它们一起添加,但将结果剪切到允许的范围以防止上溢/下溢.

如果发生剪辑,您在音频中引入失真,但这是不可避免的.您可以使用裁剪代码"检测"这种情况并将其报告给用户/操作员(相当于混音器上的红色"剪辑"灯......)

你可以实现一个更"适当"的压缩器/限制器,但不知道你的确切应用,很难说它是否值得.

如果您正在进行大量的音频处理,您可能希望将音频级别表示为浮点值,并且只在该过程结束时返回到16位空间.高端数字音频系统通常以这种方式工作.


这个答案如何?真的不回答任何事情......
@Kyberias That doesn't make sense; the first sentence literally explains exactly what to do.

2> podperson..:

我更愿意评论两个排名很高的回复之一,但由于我的声誉微薄(我猜)我不能.

"勾选"答案:加在一起并且剪辑是正确的,但如果你想避免剪裁则不是.

链接的答案从[0,1]中两个正信号的可行巫术算法开始,然后应用一些非常错误的代数来导出一个完全不正确的有符号值和8位值的算法.该算法也不会扩展到三个或更多输入(信号的乘积将在总和增加时下降).

因此 - 将输入信号转换为浮点数,将它们缩放到[0,1](例如,有符号的16位值将变为
float v = ( s + 32767.0 ) / 65536.0 (close enough...))
然后求和.

要缩放输入信号,您应该做一些实际工作,而不是乘以或减去巫毒值.我建议保持一个运行平均音量,然后如果它开始漂移高(高于0.25说)或低(低于0.01说)开始应用基于音量的缩放值.这基本上成为一个自动级别的实现,它可以随任意数量的输入进行扩展.最重要的是,在大多数情况下,它根本不会弄乱您的信号.



3> 小智..:

有一个关于混合的文章在这里.我有兴趣知道其他人对此的看法.


这篇文章具有误导性(请参阅下面的答案).如果你将示例值提供给他的最终公式,你会得到不好的输出(他的代数很糟糕).例如,静音输入为您提供-1输出.无论如何,它不会扩展到两个以上的输入,它是一个没有现实依据的巫毒算法.
+1该文章似乎比所选答案更好

4> Mark Heath..:

大多数音频混合应用程序将使用浮点数进行混合(32位足以混合少量流).将16位样本转换为浮点数,范围-1.0到1.0表示16位世界中的满量程.然后将样本汇总在一起 - 你现在有足够的空间.最后,如果你得到任何值超过满量程的样本,你可以衰减整个信号或使用硬限制(削波值为1.0).

与将16位样本相加并让它们溢出相比,这将产生更好的声音效果.这是一个非常简单的代码示例,展示了如何将两个16位样本相加:

short sample1 = ...;
short sample2 = ...;
float samplef1 = sample1 / 32768.0f;
float samplef2 = sample2 / 32768.0f;
float mixed = samplef1 + sample2f;
// reduce the volume a bit:
mixed *= 0.8;
// hard clipping
if (mixed > 1.0f) mixed = 1.0f;
if (mixed < -1.0f) mixed = -1.0f;
short outputSample = (short)(mixed * 32768.0f)



5> Mark Ransom..:

"安静一半"并不完全正确.由于耳朵的对数响应,将样本分成两半会使6-db更安静 - 当然明显,但不是灾难性的.

您可能希望通过乘以0.75来妥协.这将使3-db更安静,但是会减少溢出的可能性,并且当它确实发生时也会减少失真.



6> 小智..:

我无法相信没有人知道正确的答案.每个人都足够接近,但仍然是一种纯粹的哲学.最近的,即最好的是:(s1 + s2) - (s1*s2).这是一种非常好的方法,特别是对于MCU.

所以,算法是:

    找出您想要输出声音的音量.它可以是其中一个信号的平均值或最大值.
    factor = average(s1) 您假设两个信号都已正常,而不是溢出32767.0

    使用此因子标准化两个信号:
    s1 = (s1/max(s1))*factor
    s2 = (s2/max(s2))*factor

    将它们添加到一起并使用相同的因子对结果进行标准化
    output = ((s1+s2)/max(s1+s2))*factor

请注意,在步骤1之后,您实际上不需要返回到整数,您可以使用-1.0到1.0间隔的浮点数,并使用先前选择的功率因数将返回值应用于最后的整数.我希望我现在没有弄错,因为我很着急.



7> Glenn Barnet..:

您还可以为自己购买一些头部空间,如曲线y = 1.1x - 0.2x ^ 3,顶部和底部都有一个帽子.当玩家一起演奏多个音符时(最多6个音符),我在Hexaphone中使用了它.

float waveshape_distort( float in ) {
  if(in <= -1.25f) {
    return -0.984375;
  } else if(in >= 1.25f) {
    return 0.984375;
  } else {    
    return 1.1f * in - 0.2f * in * in * in;
  }
}

它不是防弹 - 但会让你达到1.25级别,并使剪辑平滑到一个漂亮的曲线.产生谐波失真,听起来比削波更好,在某些情况下可能是理想的.


记录:这是压缩(和一点扩展).
推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有