Fork me on GitHub

原理

  在现在的喊麦上,人声消除是常用的一个功能,笔者测试过几款喊麦的系统,发现就人声消除这块,可以说效果是参差不齐。由于自己产品上也要有这个功能,就花了一些时间来研究了一下。下面就把研究的心得体会做个总结。
人声的声波波形在歌曲的两个声道是相同或者相似的,因此,我们可以采取两个声道相减的办法来消除立体声歌曲中的人声。
一个标准的人声消除过程如下:
步骤一:高通滤波器(High-pass filter)
步骤二:声道混合(Channel Mixer)
步骤三:低通滤波器(Low-pass filter)
其实,高通和通过滤波器的作用就是尽量让音乐的声音保留。在实际的操作中,有些简单的做法直接使用步骤2,省略到了步骤1和3,这样做的好处是操作简单,问题是人声音消除的不是很干净的。
我们一般把声道混合分成四个参数,分别为:

  1. 新左声道里原左声道所占的百分数a1;
  2. 新左声道里原右声道所占的百分数a2;
  3. 新右声道里原左声道所占的百分数b1;
  4. 新右声道里原右声道所占的百分数b2;
    a1,a2,a3,a4这四个数的数值在-100到100之间。则新左声道采样值newLeft=a1Left/100+a2Right/100,新右声道采样值newRight=b1Left/100+b2Right/100。
    如果想消除80%的人声,那么就将声道混合的数值设定如下:
    100,-80, -80, 100;
    如果想消除50%的人声,那么声道混合的四个数值为:
    100, -50, -50, 100。
    如果想消除100%的人声,那么声道混合的四个数值为:
    100, -100, -100, 100。
    这样,人声消除就很清楚了,接下来就是算法实现了。

python源码

  在这里,我用python做了一个简单的仿真代码,可以实现简单的消除人声的效果。具体代码如下:

 1 import numpy as np
 2 from scipy.io import wavfile
 3 from scipy import signal
 4 
 5 def splitChannel(srcMusicFile):
 6    # read wav file
 7    sampleRate, musicData = wavfile.read(srcMusicFile)
 8 
 9    left = []
10    right = []
11    for item in musicData:
12        left.append(item[0])
13        right.append(item[1])
14 
15    mixed_data = np.array(left) - np.array(right)
16    wavfile.write('mixed_b.wav', sampleRate, mixed_data)
17 
18 splitChannel("test.wav")

通过播放原始音乐和处理后的音乐,发现人声消除的效果还不错。笔者发现,这个消除的效果要和音乐有关系,对于那些立体声比较对称的音乐来说,这种方法效果还是非常不错的。针对有些特殊的音乐,这个就不那么好用了。市面上基本上使用的都是这种方法。
对于那些本想把音频直接挂到博客园上,没想到遇到了一些技术问题,只能把它们连同代码一同放到github上了,有需要的朋友可以进去看一下。github地址:GitHub - DyLanCao/CoolAdudio: my open source audio edit software
输出音频:

方案实现

仅仅有仿真是远远不够的,还要把方案做出了,笔者在国内一家蓝牙芯片上,实现了该功能,效果初步测试和上面的仿真的基本能够吻合。不过,要把效果做的更好,还要加一些料的。针对消不掉的人声音,直接加vad检测,针对检测到的人声做一下衰减,再过一下这个,效果那就是杠杠的了。案子涉及到产品保密,就不往网上挂了。有兴趣的朋友可以通过QQ交流。

参考文档

posted on 2019-10-14 18:03  音频大牛  阅读(5751)  评论(0编辑  收藏  举报