基于 librosa和soundfile对音频进行重采样 (Bert-VITS2 必备)

基于 librosa和soundfile对音频进行重采样

一、前言

在玩bert-vits2的时候有对音频进行重采样的需求,故写了一下批量对音频进行重采样的脚本。
优化点:

  1. 根据机器自适应线程数为最多,保证充分利用机器资源,提高速度>30%。
  2. 支持多级文件夹结构的处理

运行结果如下·:

基于 librosa和soundfile对音频进行重采样 (Bert-VITS2 必备)_第1张图片
输出文件夹:
基于 librosa和soundfile对音频进行重采样 (Bert-VITS2 必备)_第2张图片

二、具体代码

1、单采样

具体代码如下:

import os
import time
import librosa
import soundfile as sf
import concurrent.futures
from tqdm import tqdm
def resampleAudio(params):
    '''
    Parameters
    ----------
    params
audioPath, outpath,target_sr #音频地址,重采样后的输出地址,目标音频的采样率
    Returns
    -------
    '''
    audioPath, outpath,target_sr=params
    try:
        src_sig,sr = sf.read(audioPath)  #name是要 输入的wav 返回 src_sig:音频数据  sr:原采样频率
        dst_sig = librosa.resample(src_sig,orig_sr=sr,target_sr=target_sr)  #resample 入参三个 音频数据 原采样频率 和目标采样频率
        sf.write(outpath,dst_sig,target_sr) #写出数据  参数三个 :  目标地址  更改后的音频数据  目标采样数据
        return True
    except Exception as e:
        print(e)
        return False

def Getsr(audioPath):
    '''
    查询音频的采样率是否更改
    Returns
    -------
    '''

    src_sig, sr = sf.read(audioPath)  # name是要 输入的wav 返回 src_sig:音频数据  sr:原采样频率
    return sr

def main(dirpath,target_sr):
    '''

    Parameters
    ----------
    dirpath :包含要修改采样率的音频文件夹地址
    target_sr:目标采样率

    Returns
    -------

    '''
    outdir=dirpath+'_'+str(target_sr)
    if not os.path.exists(outdir):
        os.mkdir(outdir)
    cpuNum=min(1,os.cpu_count()-2)
    with concurrent.futures.ThreadPoolExecutor(max_workers=cpuNum) as excutor:
        futures=[]
        for ret,dirs,files in os.walk(dirpath):
            for fileName in files:
                filepath=os.path.join(ret,fileName)
                outfile=filepath.replace(dirpath,outdir)
                if not os.path.exists(os.path.dirname(outfile)): #如果没有输出的这个文件夹则新建一个
                    os.mkdir(os.path.dirname(outfile))

                params=filepath,outfile,target_sr
                task=excutor.submit(resampleAudio,params)
                futures.append(task)
        prad=tqdm(total=len(futures))
        for future in concurrent.futures.as_completed(futures):
            res=future.result()
            prad.update(1)
        prad.close()

if __name__=="__main__":
    dirpath = r'I:\audioData\UVR\test9' #更改为你的文件夹
    target_sr=44100
    preTime=time.time()
    audioNum=len(os.listdir(dirpath))
    isshow=True #是否显示过程

    if isshow:
        print('开始对文件夹:{}下的{}个音频的采样率都更改为:{}HZ'.format(dirpath,audioNum,target_sr))
    main(dirpath,target_sr)
    if isshow:
        print('重采样完成,保存地址:{}\n耗费时间:{:.2f} min'.format(dirpath+'_'+str(target_sr),(time.time()-preTime)/60))
        try:
            audioPath = dirpath+'_'+str(target_sr)+'/'+os.listdir(dirpath)[0]
            sr=Getsr(audioPath)  #查询音频的采样率是否更改
            print('抽样查询更改后输出文件:{}的采样率'.format(audioPath))
            if sr==target_sr:
                print('该音频更改成功')
        except Exception as e:
            print(e)

2、采样44100+通道数为1+音频类型为wav+编码格式pcm16

有时候要对音频改为特定的格式比如Bert-VITS2要的,采样44100+通道数为1+音频类型为wav+编码格式pcm16
这时候就需要对批量程序进行一下修改,在这里由于有多种需求,我就直接使用ffmpeg进行转,提高转化的速度和转化能力。

import os
import time
import librosa
import soundfile as sf
import concurrent.futures
from tqdm import tqdm
import subprocess
import imageio_ffmpeg

def resampleAudio(params):
    '''
    Parameters
    ----------
    params
audioPath, outpath,target_sr #音频地址,重采样后的输出地址,目标音频的采样率
    Returns
    -------
    '''
    audioPath, outpath,target_sr=params
    try:
       # src_sig,sr = librosa.load(audioPath, sr=None)  #name是要 输入的wav 返回 src_sig:音频数据  sr:原采样频率
       # dst_sig = librosa.resample(src_sig,orig_sr=sr,target_sr=target_sr)  #resample 入参三个 音频数据 原采样频率 和目标采样频率
        #sf.write(outpath,dst_sig,target_sr) #写出数据  参数三个 :  目标地址  更改后的音频数据  目标采样数据
        compress = '{} -i "{}" -acodec pcm_f32le -ac 1 -ar {} "{}"'.format(imageio_ffmpeg.get_ffmpeg_exe(), audioPath,target_sr,outpath)
        f = subprocess.Popen(compress)
        return True
    except Exception as e:
        print(e)
        return False

def Getsr(audioPath):
    '''
    查询音频的采样率是否更改
    Returns
    -------
    '''

    src_sig, sr = sf.read(audioPath)  # name是要 输入的wav 返回 src_sig:音频数据  sr:原采样频率
    return sr

def main(dirpath,target_sr):
    '''

    Parameters
    ----------
    dirpath :包含要修改采样率的音频文件夹地址
    target_sr:目标采样率
    Returns
    -------
    '''
    outdir=dirpath+'_'+str(target_sr)
    if not os.path.exists(outdir):
        os.mkdir(outdir)
    cpuNum=min(1,os.cpu_count()-2)
    with concurrent.futures.ThreadPoolExecutor(max_workers=cpuNum) as excutor:
        futures=[]
        for ret,dirs,files in os.walk(dirpath):
            for fileName in files:
                if fileName.endswith(('wav','mp3','ogg','opus','flac','m4a')) :
                    filepath=os.path.join(ret,fileName)
                    outfile=filepath.replace(dirpath,outdir).replace(fileName.split('.')[-1],'wav')
                    if not os.path.exists(os.path.dirname(outfile)): #如果没有输出的这个文件夹则新建一个
                        os.mkdir(os.path.dirname(outfile))

                    params=filepath,outfile,target_sr
                    if not os.path.exists(outfile):
                        task=excutor.submit(resampleAudio,params)
                        futures.append(task)
        prad=tqdm(total=len(futures))
        for future in concurrent.futures.as_completed(futures):
            res=future.result()
            prad.update(1)
        prad.close()

def AudioHandle():

    dirpath = input('待更音频文件夹绝对地址:') #更改为你的文件夹
    target_sr=44100                     #更改为你的目标音频采样率
    preTime=time.time()
    audioNum=len(os.listdir(dirpath))
    isshow=True #是否显示过程

    if isshow:
        print('开始对文件夹:{}下的{}个音频的采样率都更改为:{}HZ'.format(dirpath,audioNum,target_sr))
    main(dirpath,target_sr)
    if isshow:
        print('重采样完成,保存地址:{}\n耗费时间:{:.2f} min'.format(dirpath+'_'+str(target_sr),(time.time()-preTime)/60))
        try:
            fileName=os.listdir(dirpath)[0]
            audioPath = os.path.join(dirpath+'_'+str(target_sr),fileName.replace(fileName.split('.')[-1],'wav'))
            sr=Getsr(audioPath)  #查询音频的采样率是否更改
            print('抽样查询更改后输出文件:{}的采样率'.format(audioPath))
            if sr==target_sr:
                print('该音频更改成功')
        except Exception as e:
            print(e)

if __name__ == "__main__":
    AudioHandle()

你可能感兴趣的:(python实践,音视频)