在实际业务场景中,遇到了需要将双声道的音频文件分割成两个单声道音频文件的问题。
网上常规的操作是,使用 wavfile 包,然后利用 for 循环去逐帧进行拆分。
import wavfile
def split_stereo(input_path, output_path):
# default stereo
samplerate, data = wavfile.read(input_path)
left = []
right = []
for item in data:
left.append(item[0])
right.append(item[1])
file_name = input_path.split('\\')[-1]
file_name = file_name.split('.')[0]
outfile_name = file_name + '_1ch_left.wav'
out_path_file = os.path.join(output_path, outfile_name)
wavfile.write(out_path_file, samplerate, np.array(left))
经过测试后,该方法基本不可用,对于长音频的输入,for 循环的时间过长。因此我们寻求使用万能的 ffmpeg 去处理这个问题。
首先我们区分以下几个不同的场景:
stereo → mono stream
将单个立体声流混合为单声道流。立体声流的两个通道都将被缩混到一个流中:
ffmpeg -i stereo.flac -ac 1 mono.flac
也可以只选择某个仅包含右通道:
ffmpeg -i Stereo.wav -filter_complex "[0:a]channelsplit=channel_layout=stereo:channels=FR[right]" -map "[right]" front_right.wav
stereo → 2 × mono files
这个就是我们所需要的功能,将双声道立体声,分割为 2 个独立的单声道文件。
ffmpeg -i stereo.wav -filter_complex "[0:a]channelsplit=channel_layout=stereo[left][right]" -map "[left]" left.wav -map "[right]" right.wav
或使用以下 -map_channel 选项:
ffmpeg -i stereo.wav -map_channel 0.0.0 left.wav -map_channel 0.0.1 right.wav
以上两个方法亲测都能够成功实现我们所需要的功能,并且在性能也满足。
stereo → 2 × mono streams
使用 channelsplit 音频过滤器将立体声输入中的每个通道输出到一个输出文件中的各个单声道流:
ffmpeg -i in.mp3 -filter_complex "[0:a]channelsplit=channel_layout=stereo" output.mka
2 × mono → stereo
除了拆分之外,我们也可以进行合并。从两个单声道输入创建立体声输出:
ffmpeg -i left.mp3 -i right.mp3 -filter_complex "[0:a][1:a]join=inputs=2:channel_layout=stereo[a]" -map "[a]" output.mp3
或者使用另一种方法:
ffmpeg -i left.mp3 -i right.mp3 -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map "[a]" output.mka
以上基本是我们所需要的一些基础操作,但是除此之外,我们还可以扩展一些常用到的 5.1 声道的处理方法。
6 × mono → 5.1
使用连接音频滤波器 将 6 个单声道输入合并为一个 5.1(6 通道)输出:
ffmpeg -i front_left.wav -i front_right.wav -i front_center.wav -i lfe.wav -i back_left.wav -i back_right.wav \
-filter_complex "[0:a][1:a][2:a][3:a][4:a][5:a]join=inputs=6:channel_layout=5.1[a]" -map "[a]" output.wav
连接音频过滤器还允许您手动选择布局:
ffmpeg -i front_left.wav -i front_right.wav -i front_center.wav -i lfe.wav -i back_left.wav -i back_right.wav \
-filter_complex "[0:a][1:a][2:a][3:a][4:a][5:a]join=inputs=6:channel_layout=5.1:map=0.0-FL|1.0-FR|2.0-FC|3.0-LFE|4.0-BL|5.0-BR[a]" -map "[a]" output.wav
另一种使用合并音频过滤器的方法,其灵活性比上面显示的连接过滤器稍差:
ffmpeg -i front_left.wav -i front_right.wav -i front_center.wav -i lfe.wav -i back_left.wav -i back_right.wav \
-filter_complex "[0:a][1:a][2:a][3:a][4:a][5:a]amerge=inputs=6[a]" -map "[a]" output.wav
使用合并时,所有输入必须具有相同的采样率和格式。如果输入的持续时间不同,则输出将以最短的时间停止。
5.1 → 6 × mono
使用 Channelsplit 音频过滤器 将 5.1 通道输入拆分为单独的每通道文件:
ffmpeg -i in.wav \
-filter_complex "channelsplit=channel_layout=5.1[FL][FR][FC][LFE][BL][BR]" \
-map "[FL]" front_left.wav \
-map "[FR]" front_right.wav \
-map "[FC]" front_center.wav \
-map“[LFE]”lfe.wav \
-map "[BL]" back_left.wav \
-map“[BR]”back_right.wav
5.1 → stereo
将 5.1 声道的文件要缩混成双通道的立体声,可以简单地使用-ac 2:
ffmpeg -i 6channels.wav -ac 2 stereo.wav
以上就是一些常用的做法进行了总结,目前网上没有相关的资料去汇总这方面的信息,所以记录下来还是比较有帮助的。