我需要将一个wav文件从44100Hz降采样到16000Hz,不使用任何外部的Python库,最好只用wave
和/或audioop
。我尝试使用setframerate
函数将wav文件的帧率更改为16000,但那只会减慢整个录音的速度。我该如何仅将音频文件降采样到16kHz并保持相同的音频长度?
我需要将一个wav文件从44100Hz降采样到16000Hz,不使用任何外部的Python库,最好只用wave
和/或audioop
。我尝试使用setframerate
函数将wav文件的帧率更改为16000,但那只会减慢整个录音的速度。我该如何仅将音频文件降采样到16kHz并保持相同的音频长度?
import librosa
y, s = librosa.load('test.wav', sr=8000) # Downsample 44.1kHz to 8kHz
安装Librosa所需的额外努力可能会换来内心的宁静。
专业提示:在Anaconda上安装Librosa时,您还需要安装ffmpeg。
pip install librosa
conda install -c conda-forge ffmpeg
这将帮助您避免出现NoBackendError()错误。
librosa.output.write_wav(filename, y, sr)
就行了。 - hyit # Imports
from scipy.io import wavfile
import scipy.signal as sps
# Your new sampling rate
new_rate = 48000
# Read file
sampling_rate, data = wavfile.read(path)
# Resample data
number_of_samples = round(len(data) * float(new_rate) / sampling_rate)
data = sps.resample(data, number_of_samples)
请注意,如果您只进行下采样并希望比傅里叶变换更快的方法,则可以使用decimate方法。
scipy.signal.resample_poly
在时间域中使用多项式。 resample
在频域中操作,您可以显式地控制傅里叶变换所使用的window
。对于resample_poly
,您可以使用padtype
和cval
控制填充。我认为只有在重新采样时看到伪影时,您才需要根据自己的需求调整参数。这肯定取决于您正在处理的信号类型。 - Jeremy Cochoy非常感谢大家的回答。我已经找到了解决方案,而且它运行得非常好。以下是整个函数。
def downsampleWav(src, dst, inrate=44100, outrate=16000, inchannels=2, outchannels=1):
if not os.path.exists(src):
print 'Source not found!'
return False
if not os.path.exists(os.path.dirname(dst)):
os.makedirs(os.path.dirname(dst))
try:
s_read = wave.open(src, 'r')
s_write = wave.open(dst, 'w')
except:
print 'Failed to open files!'
return False
n_frames = s_read.getnframes()
data = s_read.readframes(n_frames)
try:
converted = audioop.ratecv(data, 2, inchannels, inrate, outrate, None)
if outchannels == 1:
converted = audioop.tomono(converted[0], 2, 1, 0)
except:
print 'Failed to downsample wav'
return False
try:
s_write.setparams((outchannels, 2, outrate, 0, 'NONE', 'Uncompressed'))
s_write.writeframes(converted)
except:
print 'Failed to write wav'
return False
try:
s_read.close()
s_write.close()
except:
print 'Failed to close wav files'
return False
return True
我尝试使用Librosa,但是即使给出了以下行:y, s = librosa.load('test.wav', sr=16000)
和librosa.output.write_wav(filename, y, sr)
,声音文件也不能以给定的采样率(16000,从44kHz下采样)保存。
但是pydub
可以正常工作。这是由jiaaro提供的一个很棒的库,我使用了以下命令:
from pydub import AudioSegment as am
sound = am.from_file(filepath, format='wav', frame_rate=22050)
sound = sound.set_frame_rate(16000)
sound.export(filepath, format='wav')
export
函数用新的帧率覆盖现有文件。它比librosa表现更好,但我正在寻找比较两个软件包速度的方法,但由于数据很少,我还没有想出来!参考:https://github.com/jiaaro/pydub/issues/232
sound.set_frame_rate(16000)
而不是分配sound = sound.set_frame_rate(16000)
,它将无法工作,因为set_frame_rate(..)
会产生一个新的对象。 - Nikolasscipy
中的重采样功能。不过,这需要进行一些类型转换,将Python本地的bytestring
转换为scipy
所需的数组,这可能会有些棘手。还有一个问题是,在Python的wave模块中,无法确定数据是否带符号(只能确定是否为8或16位)。虽然它应该适用于两种情况,但我没有测试过。
这是一个小程序,将44.1kHz的无符号8位和16位单声道音频转换成16位。如果您有立体声或使用其他格式,调整代码应该不难。在程序开头编辑输入/输出名称即可。我从未试图使用命令行参数。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# downsample.py
#
# Copyright 2015 John Coppens <john@jcoppens.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
inwave = "sine_44k.wav"
outwave = "sine_16k.wav"
import wave
import numpy as np
import scipy.signal as sps
class DownSample():
def __init__(self):
self.in_rate = 44100.0
self.out_rate = 16000.0
def open_file(self, fname):
try:
self.in_wav = wave.open(fname)
except:
print("Cannot open wav file (%s)" % fname)
return False
if self.in_wav.getframerate() != self.in_rate:
print("Frame rate is not %d (it's %d)" % \
(self.in_rate, self.in_wav.getframerate()))
return False
self.in_nframes = self.in_wav.getnframes()
print("Frames: %d" % self.in_wav.getnframes())
if self.in_wav.getsampwidth() == 1:
self.nptype = np.uint8
elif self.in_wav.getsampwidth() == 2:
self.nptype = np.uint16
return True
def resample(self, fname):
self.out_wav = wave.open(fname, "w")
self.out_wav.setframerate(self.out_rate)
self.out_wav.setnchannels(self.in_wav.getnchannels())
self.out_wav.setsampwidth (self.in_wav.getsampwidth())
self.out_wav.setnframes(1)
print("Nr output channels: %d" % self.out_wav.getnchannels())
audio = self.in_wav.readframes(self.in_nframes)
nroutsamples = round(len(audio) * self.out_rate/self.in_rate)
print("Nr output samples: %d" % nroutsamples)
audio_out = sps.resample(np.fromstring(audio, self.nptype), nroutsamples)
audio_out = audio_out.astype(self.nptype)
self.out_wav.writeframes(audio_out.copy(order='C'))
self.out_wav.close()
def main():
ds = DownSample()
if not ds.open_file(inwave): return 1
ds.resample(outwave)
return 0
if __name__ == '__main__':
main()
fromstring
变成了frombuffer
(第72行),但这不是唯一的问题。 - undefined您可以在 Windows、macOS 或 Linux 上使用 ffmpeg
工具来完成此操作。从官方链接(https://ffmpeg.org/download.html)下载 ffmpeg
。我下载了 gyan.dev
版本。对于 Windows,按照以下步骤进行:
ffmpeg
C
驱动器bin
文件夹,其中包含ffmpeg.exe
C:\ffmpeg\bin
env
打开环境变量高级
选项卡下,单击环境变量
按钮用户变量
下选择Path
并单击编辑
新建
按钮,并在字段中粘贴
已复制的路径确定
CMD
并键入ffmpeg -version
以确认是否已正确将路径添加到环境变量中。如果是,则会显示有关ffmpeg
的信息,否则会出现错误。现在,我们已经准备好重新采样音频了。现在在您的python
文件中添加以下代码。
import os
source_file = "path/to/input/file/with/extension" # "source_file.wav"
output_file = "path/to/output/file/with/extension" # "compressed_output_file.wav"
output_str = f"ffmpeg -i {source_file} -ac 1 -ar 16000 {output_file}"
os.system(output_str)
print(output_str)
wav
和mp3
文件的上采样和下采样。-sample_fmts
明确要求,ffmpeg
将输出16位音频样本。我无法理解ffmpeg
的这种设计选择... - Itamar Katz!pip install tensorflow-io==0.25.0 # что сломалось с ==0.26.0
import tensorflow_io as tfio
import tensorflow as tf
import numpy as np
srcFilePath = '/content/data/dataset_phoneme_in/she/pronunciation_en_she.mp3'
dstFilePath = '/content/temp/1.wav'
#wavFensor=getAudioTensorFromFilePath(src)
rateOut=16000
audioIOTensor = tfio.audio.AudioIOTensor(srcFilePath) #читает разный формат работает на версии !pip install tensorflow-io==0.25.0
print(audioIOTensor.shape)
chanalsIn=(int)(audioIOTensor.shape[1])
rateIn=(int)(audioIOTensor.rate)
print(audioIOTensor.shape[1])
audioTensor = audioIOTensor[0:] #get audio block получить звуковый блок
if (chanalsIn>1): #sterio to mono
audioTensor=audioTensor.numpy()
audioTensor=np.average(audioTensor,axis=1)
audio_slice=tf.convert_to_tensor(audioTensor)
print(audioTensor.shape)
#change rate
audioTensor=tfio.audio.resample(audioTensor, rateIn,rateOut)
print(audioTensor.shape)
# remove last dimension
#audioTensor = tf.squeeze(audioTensor, axis=[1])
# convert to wav and save
#wav = tf.cast(audioTensor, tf.float32) / 32768.0
print(audioTensor.shape)
audioTensor=tf.expand_dims(audioTensor, axis=1) # add axis for tf.audio.encode_wav
print(audioTensor.shape)
outWavAudio=tf.audio.encode_wav(audio=audioTensor,sample_rate=rateOut)
tf.io.write_file(dst,outWavAudio)
首先,您需要导入'librosa'库 使用'librosa.load'重新采样音频文件 librosa.load(path,sr) 最初的sr(采样率)= 22050。如果您想保留原始采样率,请使sr=None。否则,音频将被重新采样为所提供的采样率