六种python读取语音文件的方法

发布时间 2023-08-23 19:10:18作者: glowwormss

该文主要记录一下常用的python读取wav文件的常用三方库以及优缺点对比,以一段采样率16k,4.99秒单声道的测试语音为例子,音频文件读取后主要有以下几种形式

#格式一:列表 [-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259] float32
#格式二:列表 [-5, -7, -7, -9, -5] int16
#格式三:字节流 b'\xfb\xff\xf9\xff\xf9'   pcm编码格式
#格式四:字节流带文件头 b'RIFF\xb2\xbb\x00\x00WAVEfmt \x12\x00\x0 pcm编码格式
#格式五:字符串 'UklGRhIdAwBXQVZFZm10IBIAAAADAA' 通常是base64编码后的信息

下面介绍6种python读取语音文件的方法;

1、librosa

缺点是需要提前知道语音采样率,mono默认是True,双轨录音需注意改为False

import librosa
filepath='./zh.wav'
wav_list,sr=librosa.load(filepath,sr=16000,mono=False)
print (wav_list[:5])
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]

2、soundfile

无需知道采样率,采样率是返回值

import soundfile
wav_list, sr = soundfile.read(filepath,dtype='float32')
print ("sr:"+str(sr))
print (wav_list[:5])
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]

wav_list2, sr = soundfile.read(filepath,dtype='int16')
print ("sr:"+str(sr))
wav_list=wav_list2/2**15
print (wav_list[:5])
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]

#文件回写
soundfile.write('zh1.wav', wav_list, 16000, subtype='PCM_16')

3、wave

该方法能返回最多语音相关信息

import wave
import numpy as np
fp = wave.open(filepath, 'rb')
byte_data = fp.readframes(fp.getnframes())  #无文件头
params = fp.getparams()
nchannels, sampwidth, sr, nframes = params[:4]
print ("音轨数:" +str(nchannels))
print ("位宽:"+str(sampwidth))
print ("采样率:"+str(sr))
print (nframes)
print ("采样点数:"+str(len(byte_data)))
wav_list= np.frombuffer(byte_data, dtype=np.int16).astype(np.float32) / 2**15     #字节流转list
print (byte_data[:5])
print (wav_list[:5])

#音轨:1
#位宽:2
#采样率:16000
#79949
#采样点数:159898
#b'\xfb\xff\xf9\xff\xf9'
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]


with wave.open('zh2.wav', 'wb') as wf:
    wf.setnchannels(1)
    wf.setsampwidth(2)
    wf.setframerate(16000)
    wf.writeframes(byte_file)

4、open

该方法缺点是需要先读取成byte数据然后剔除文件头,再转换成语音list

f=open(filepath,'rb')
print ("文件头内容:"+str(f.read()[:20])) #包含文件头的bytes数据
f = open(filepath, "rb")
data = np.fromfile(f, dtype=np.int16) #包含文件头信息
wav_list=data[22:] #剔除文件头信息
wav_list=wav_list/2**15
print (wav_list[:5])
#文件头内容:b'RIFF\xbep\x02\x00WAVEfmt \x10\x00\x00\x00'
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]

#如若已知文件头信息,可使用以下函数复原
import io
def audiobytes_header(audio_bytes, sample_rate=16000, fileheader=False):
    '''增加文件头方法'''
    if fileheader:
        val = audio_bytes
    else:
        fp = io.BytesIO()
        with wave.open(fp, mode='wb') as waveobj:
            waveobj.setnchannels(1)
            waveobj.setframerate(sample_rate)
            waveobj.setsampwidth(2)
            waveobj.setcomptype('NONE','NONE')
            waveobj.writeframes(audio_bytes)
            val = fp.getvalue()
    return val
    
#base64的编码与解码
import base64
f=open(filepath,'rb')
input_bytes=f.read()
base64_bytes = base64.b64encode(input_bytes)
audio = base64_bytes.decode('utf-8')
    
#input_bytes 包含文件头
#audio utf-8编码的base64加密后的字节流信息
base64_bytes=audio.encode('utf-8') #解码
byte_file = base64.b64decode(base64_bytes) #解密
wav_list=np.frombuffer(byte_file[44:], dtype=np.int16).astype(np.float32) / 2**15  #头44为文件头,需剔除
print (wav_list[:5])

5 、scipy

import scipy.io.wavfile as wavfile
sr, data = wavfile.read(filepath)
wav_list=data/2**15
print ("采样率为:"+str(sr))
print (wav_list[:5])

#采样率为:16000
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]

#文件回写
audio_array = np.array(data, dtype=np.int16)
wavfile.write('output.wav', sample_rate, audio_array)

6、pydub

from pydub import AudioSegment
audio = AudioSegment.from_file(filepath)
sr = audio.frame_rate
data = audio.get_array_of_samples()
wav_list = [i/2**15 for i in list(data)]
print ("采样率:"+str(sr))
print (wav_list[:5])
#采样率为:16000
#[-0.00015259 -0.00021362 -0.00021362 -0.00027466 -0.00015259]

# 创建AudioSegment对象
audio_segment = AudioSegment(
    data=bytes(audio_data), 
    sample_width=sample_width, 
    frame_rate=sample_rate, 
    channels=num_channels
)

# 将音频数据写入文件
audio_segment.export('output.wav', format='wav')