外部のPythonライブラリを使用せずに、44100Hzから16000Hzにwavファイルをダウンサンプリングする必要があるため、wave
やaudioop
を使用することをお勧めします。 wavファイルはsetframerate
関数を使用して16000にフレームレートしますが、それだけで録音全体が遅くなります。オーディオファイルを16kHzにダウンサンプリングし、オーディオの長さを同じに保つにはどうすればよいですか?
Librosaのload()関数を使用できます。
import librosa
y, s = librosa.load('test.wav', sr=8000) # Downsample 44.1kHz to 8kHz
Librosaをインストールするための余分な労力は、おそらく安心する価値があります。
Pro-tip:LibrosaをAnacondaにインストールするときは、 install ffmpeg も必要なので、
pip install librosa
conda install -c conda-forge ffmpeg
これにより、NoBackendError()エラーが保存されます。
ご回答ありがとうございます。私はすでに解決策を見つけました、そしてそれはとてもうまくいきます。これが全体の関数です。
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
scipy
でresampleを使用できます。 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 <[email protected]>
#
# 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()
信号をダウンサンプリング(または decimate )するには(サンプリングレートを下げることを意味します)、またはアップサンプリング(サンプリングレートを上げる)するには、データ間を補間する必要があります。
アイデアは、どういうわけか、ポイント間でカーブをdrawし、新しいサンプリングレートでこのカーブから値を取得する必要があるということです。これは、サンプリングされなかったある時点での音波の値を知りたいためです。そのため、何らかの方法でこの値を推測する必要があります。サブサンプリングが簡単になる唯一のケースは、サンプリングレートを整数$ k $で除算する場合です。この場合、$ k $サンプルのバケットを取得し、最初のサンプルのみを保持する必要があります。しかし、これはあなたの質問に答えません。 2つの異なるスケールでカーブをサンプリングした下の図を参照してください。
原理を理解していれば手動で行うこともできますが、ライブラリを使用することを強くお勧めします。その理由は、補間正しい方法は簡単ではないか、明白ではないためです。
線形補間(ラインでポイントを接続)または二項補間(多項式で3ポイントを接続)を使用したり、(場合によっては音に最適な)フーリエ変換を使用して周波数の空間で補間したりできます。フーリエ変換は手動で書き直す必要がないため、適切なサブサンプリング/サブサンプリングが必要な場合は、scipyとは異なるアルゴリズムを使用した2つのアップサンプリングの曲線について、次の図を参照してください。 「リサンプリング」機能はフーリエ変換を使用します。
確かに、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)
ダウンサンプリングのみを実行していて、フーリエよりも高速なものが必要な場合は、メソッド decimate を使用することもできます。
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')
上記のコードは、22050のframe_rateで読み取るファイルが16000のレートに変更され、export
関数がこのファイルで既存のファイルを新しいframe_rateで上書きすることを示しています。 librosaよりもうまく機能しますが、2つのパッケージの速度を比較する方法を探していますが、データが非常に少ないため、まだ分かりません。