原理
在現在的喊麥上,人聲消除是常用的一個功能,筆者測試過幾款喊麥的系統,發現就人聲消除這塊,可以說效果是參差不齊。由於自己產品上也要有這個功能,就花了一些時間來研究了一下。下面就把研究的心得體會做個總結。
人聲的聲波波形在歌曲的兩個聲道是相同或者相似的,因此,我們可以采取兩個聲道相減的辦法來消除立體聲歌曲中的人聲。
一個標准的人聲消除過程如下:
步驟一:高通濾波器(High-pass filter)
步驟二:聲道混合(Channel Mixer)
步驟三:低通濾波器(Low-pass filter)
其實,高通和通過濾波器的作用就是盡量讓音樂的聲音保留。在實際的操作中,有些簡單的做法直接使用步驟2,省略到了步驟1和3,這樣做的好處是操作簡單,問題是人聲音消除的不是很干凈的。
我們一般把聲道混合分成四個參數,分別為:
- 新左聲道里原左聲道所占的百分數a1;
- 新左聲道里原右聲道所占的百分數a2;
- 新右聲道里原左聲道所占的百分數b1;
- 新右聲道里原右聲道所占的百分數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交流。