d3c*_*t0r 11 python audio wav downsampling wave
我必须在不使用任何外部python库的情况下将wav文件从44100Hz下采样到16000Hz,因此最好wave
和/或audioop
.我尝试使用setframerate
函数将wav文件帧速率更改为16000 但这只会减慢整个录制速度.如何将音频文件下采样到16kHz并保持相同的音频长度?
非常感谢你提前
waf*_*cat 18
您可以使用Librosa的load()函数,
import librosa
y, s = librosa.load('test.wav', sr=8000) # Downsample 44.1kHz to 8kHz
Run Code Online (Sandbox Code Playgroud)
安装Librosa的额外工作可能值得您放心。
专家提示:在Anaconda上安装Librosa时,还需要安装ffmpeg,因此
pip install librosa
conda install -c conda-forge ffmpeg
Run Code Online (Sandbox Code Playgroud)
这样可以为您节省NoBackendError()错误。
Jer*_*hoy 14
要对信号进行下采样(也称为抽取)(这意味着降低采样率)或上采样(增加采样率),您需要在数据之间进行插值。
这个想法是您需要以某种方式在您的点之间绘制一条曲线,然后以新的采样率从这条曲线中获取值。这是因为您想知道未采样的某个时间的声波值,因此您必须通过一种或另一种方式来猜测该值。子采样很容易的唯一情况是将采样率除以整数 $k$。在这种情况下,您只需要获取 $k$ 样本桶并仅保留第一个。但这不会回答你的问题。请参见下图,其中您有一条以两种不同比例采样的曲线。
如果您了解原理,您可以手动完成,但我强烈建议您使用库。原因是插入正确的方式并不容易,也不明显。
您可以使用线性插值(用一条线连接点)或二项式插值(用一个多项式连接三个点)或(有时最适合声音)使用傅立叶变换并在频率空间内插值。由于傅立叶变换不是您想手动重写的东西,如果您想要一个好的下采样/上采样,请参阅下图,了解使用与 scipy 不同的算法的上采样的两条曲线。“重采样”函数使用傅立叶变换。
我确实是在加载 44100Hz 波形文件并需要 48000Hz 采样数据的情况下,所以我写了以下几行来加载我的数据:
# 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)
Run Code Online (Sandbox Code Playgroud)
请注意,如果您只进行下采样并且想要比傅立叶更快的东西,您也可以使用抽取方法。
您可以在 中使用重新采样scipy
。这样做有点头疼,因为在本机到bytestring
python 和scipy
. 还有一个令人头疼的问题,因为在Python的wave模块中,无法判断数据是否有符号(仅当它是8位或16位时)。它可能(应该)对两者都有效,但我还没有测试过。
这是一个小程序,可将(无符号)8 位和 16 位单声道从 44.1 转换为 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()
Run Code Online (Sandbox Code Playgroud)
谢谢大家的答案。我已经找到了解决方案,并且效果很好。这是整个功能。
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
Run Code Online (Sandbox Code Playgroud)
小智 6
我尝试使用 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')
Run Code Online (Sandbox Code Playgroud)
上面的代码指出,我以 22050 的帧速率读取的文件更改为速率 16000,并且export
函数使用新的帧速率用此文件覆盖现有文件。它比 librosa 效果更好,但我正在寻找比较两个包之间速度的方法,但由于数据很少,所以还没有弄清楚!!!
参考:https : //github.com/jiaaro/pydub/issues/232
归档时间: |
|
查看次数: |
21383 次 |
最近记录: |