使用 scipy 和 python 中的 librosa 读取 wav 文件
Reading a wav file with scipy and librosa in python
我正在尝试使用 scipy 文件夹在 Python 中加载 .wav
文件。我最后的 objective 是创建该音频文件的频谱图。读取文件的代码可以总结如下:
import scipy.io.wavfile as wav
(sig, rate) = wav.read(_wav_file_)
对于某些 .wav
文件,我收到以下错误:
WavFileWarning: Chunk (non-data) not understood, skipping it.
WavFileWarning) ** ValueError: Incomplete wav chunk.
因此,我决定使用 librosa 来读取文件:
import librosa
(sig, rate) = librosa.load(_wav_file_, sr=None)
这在所有情况下都能正常工作,但是,我注意到频谱图的颜色有所不同。然而,虽然它是完全相同的图形,但颜色却以某种方式颠倒了。更具体地说,我注意到当保留相同的函数来计算规格并仅更改我阅读 .wav
的方式时,存在这种差异。知道什么可以产生那种东西吗?两种方法读取 .wav
文件的方式之间是否存在默认差异?
编辑:
(rate1, sig1) = wav.read(spec_file) # rate1 = 16000
sig, rate = librosa.load(spec_file) # rate 22050
sig = np.array(α*sig, dtype = "int16")
几乎有效的方法是将 sig 的结果乘以常数 α
alpha,它是来自 scipy wavread 的信号的最大值与来自 librosa 的信号之间的比例。尽管信号速率不同。
这听起来像是一个量化问题。如果 wave 文件中的样本存储为 float
并且 librosa 只是直接转换为 int
,并且小于 1 的值将被截断为 0。这很可能是为什么 sig
是全零数组。 float
必须缩放以将其映射到 int
的范围内。例如,
>>> a = sp.randn(10)
>>> a
array([-0.04250369, 0.244113 , 0.64479281, -0.3665814 , -0.2836227 ,
-0.27808428, -0.07668698, -1.3104602 , 0.95253315, -0.56778205])
在不缩放的情况下将 a 转换为类型 int
>>> a.astype(int)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
将 a 转换为 int
,缩放为 16 位整数
>>> b = (a* 32767).astype(int)
>>> b
array([ -1392, 7998, 21127, -12011, -9293, -9111, -2512, -42939,
31211, -18604])
将缩放后的 int
转换回 float
>>> c = b/32767.0
>>> c
array([-0.04248177, 0.24408704, 0.64476455, -0.36655782, -0.28360851,
-0.27805414, -0.0766625 , -1.31043428, 0.9525132 , -0.56776635])
c
和 b
由于量化为 int
.
仅等于小数点后 3 或 4 位
如果 librosa 返回 float
,您可以按 2**15
缩放它并将其转换为 int
以获得与 scipy wave reader回来了。由于 librosa 返回的是 float
,因此这些值可能会位于比 [-32768, +32767]
中的 16 位整数小得多的范围内,例如 [-1, +1]
。所以你需要缩放一个以获得匹配的范围。例如,
sig, rate = librosa.load(spec_file, mono=True)
sig = sig × 32767
如果您自己不想进行量化,那么您可以使用 pylab
和 pylab.specgram
函数来为您完成。您可以查看函数内部并查看它如何使用 vmin
和 vmax
.
你的post(至少对我而言)并不能完全清楚你想要实现的目标(因为既没有样本输入文件也没有你事先提供的任何脚本) .但是无论如何,为了检查波形文件的频谱图是否根据从任何读取函数返回的信号数据是 float32
或 int
的情况而存在显着差异,我测试了以下 3 个函数。
Python 脚本:
_wav_file_ = "africa-toto.wav"
def spectogram_librosa(_wav_file_):
import librosa
import pylab
import numpy as np
(sig, rate) = librosa.load(_wav_file_, sr=None, mono=True, dtype=np.float32)
pylab.specgram(sig, Fs=rate)
pylab.savefig('spectrogram3.png')
def graph_spectrogram_wave(wav_file):
import wave
import pylab
def get_wav_info(wav_file):
wav = wave.open(wav_file, 'r')
frames = wav.readframes(-1)
sound_info = pylab.fromstring(frames, 'int16')
frame_rate = wav.getframerate()
wav.close()
return sound_info, frame_rate
sound_info, frame_rate = get_wav_info(wav_file)
pylab.figure(num=3, figsize=(10, 6))
pylab.title('spectrogram pylab with wav_file')
pylab.specgram(sound_info, Fs=frame_rate)
pylab.savefig('spectrogram2.png')
def graph_wavfileread(_wav_file_):
import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
import numpy as np
sample_rate, samples = wavfile.read(_wav_file_)
frequencies, times, spectrogram = signal.spectrogram(samples,sample_rate,nfft=1024)
plt.pcolormesh(times, frequencies, 10*np.log10(spectrogram))
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.savefig("spectogram1.png")
spectogram_librosa(_wav_file_)
#graph_wavfileread(_wav_file_)
#graph_spectrogram_wave(_wav_file_)
- 产生了以下 3 个输出:
除了大小和强度上的细微差别外,无论是读取方法、库还是数据类型,这看起来都非常相似,这让我有点疑问,出于什么目的需要输出相同 'exactly'以及它们应该有多精确。
补充一下,Librosa 有一个实用程序可以将整数数组转换为浮点数。
float_audio = librosa.util.buf_to_float(sig)
我在制作 Pydub 音频片段的频谱图时使用它取得了巨大的成功。请记住,它的参数之一是每个样本的字节数。它默认为 2。您可以在 documentation here. Here is the source code:
中阅读更多信息
def buf_to_float(x, n_bytes=2, dtype=np.float32):
"""Convert an integer buffer to floating point values.
This is primarily useful when loading integer-valued wav data
into numpy arrays.
See Also
--------
buf_to_float
Parameters
----------
x : np.ndarray [dtype=int]
The integer-valued data buffer
n_bytes : int [1, 2, 4]
The number of bytes per sample in `x`
dtype : numeric type
The target output type (default: 32-bit float)
Returns
-------
x_float : np.ndarray [dtype=float]
The input data buffer cast to floating point
"""
# Invert the scale of the data
scale = 1./float(1 << ((8 * n_bytes) - 1))
# Construct the format string
fmt = '<i{:d}'.format(n_bytes)
# Rescale and format the data buffer
return scale * np.frombuffer(x, fmt).astype(dtype)
我正在尝试使用 scipy 文件夹在 Python 中加载 .wav
文件。我最后的 objective 是创建该音频文件的频谱图。读取文件的代码可以总结如下:
import scipy.io.wavfile as wav
(sig, rate) = wav.read(_wav_file_)
对于某些 .wav
文件,我收到以下错误:
WavFileWarning: Chunk (non-data) not understood, skipping it. WavFileWarning) ** ValueError: Incomplete wav chunk.
因此,我决定使用 librosa 来读取文件:
import librosa
(sig, rate) = librosa.load(_wav_file_, sr=None)
这在所有情况下都能正常工作,但是,我注意到频谱图的颜色有所不同。然而,虽然它是完全相同的图形,但颜色却以某种方式颠倒了。更具体地说,我注意到当保留相同的函数来计算规格并仅更改我阅读 .wav
的方式时,存在这种差异。知道什么可以产生那种东西吗?两种方法读取 .wav
文件的方式之间是否存在默认差异?
编辑:
(rate1, sig1) = wav.read(spec_file) # rate1 = 16000
sig, rate = librosa.load(spec_file) # rate 22050
sig = np.array(α*sig, dtype = "int16")
几乎有效的方法是将 sig 的结果乘以常数 α
alpha,它是来自 scipy wavread 的信号的最大值与来自 librosa 的信号之间的比例。尽管信号速率不同。
这听起来像是一个量化问题。如果 wave 文件中的样本存储为 float
并且 librosa 只是直接转换为 int
,并且小于 1 的值将被截断为 0。这很可能是为什么 sig
是全零数组。 float
必须缩放以将其映射到 int
的范围内。例如,
>>> a = sp.randn(10)
>>> a
array([-0.04250369, 0.244113 , 0.64479281, -0.3665814 , -0.2836227 ,
-0.27808428, -0.07668698, -1.3104602 , 0.95253315, -0.56778205])
在不缩放的情况下将 a 转换为类型 int
>>> a.astype(int)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
将 a 转换为 int
,缩放为 16 位整数
>>> b = (a* 32767).astype(int)
>>> b
array([ -1392, 7998, 21127, -12011, -9293, -9111, -2512, -42939,
31211, -18604])
将缩放后的 int
转换回 float
>>> c = b/32767.0
>>> c
array([-0.04248177, 0.24408704, 0.64476455, -0.36655782, -0.28360851,
-0.27805414, -0.0766625 , -1.31043428, 0.9525132 , -0.56776635])
c
和 b
由于量化为 int
.
如果 librosa 返回 float
,您可以按 2**15
缩放它并将其转换为 int
以获得与 scipy wave reader回来了。由于 librosa 返回的是 float
,因此这些值可能会位于比 [-32768, +32767]
中的 16 位整数小得多的范围内,例如 [-1, +1]
。所以你需要缩放一个以获得匹配的范围。例如,
sig, rate = librosa.load(spec_file, mono=True)
sig = sig × 32767
如果您自己不想进行量化,那么您可以使用
pylab
和pylab.specgram
函数来为您完成。您可以查看函数内部并查看它如何使用vmin
和vmax
.你的post(至少对我而言)并不能完全清楚你想要实现的目标(因为既没有样本输入文件也没有你事先提供的任何脚本) .但是无论如何,为了检查波形文件的频谱图是否根据从任何读取函数返回的信号数据是
float32
或int
的情况而存在显着差异,我测试了以下 3 个函数。
Python 脚本:
_wav_file_ = "africa-toto.wav"
def spectogram_librosa(_wav_file_):
import librosa
import pylab
import numpy as np
(sig, rate) = librosa.load(_wav_file_, sr=None, mono=True, dtype=np.float32)
pylab.specgram(sig, Fs=rate)
pylab.savefig('spectrogram3.png')
def graph_spectrogram_wave(wav_file):
import wave
import pylab
def get_wav_info(wav_file):
wav = wave.open(wav_file, 'r')
frames = wav.readframes(-1)
sound_info = pylab.fromstring(frames, 'int16')
frame_rate = wav.getframerate()
wav.close()
return sound_info, frame_rate
sound_info, frame_rate = get_wav_info(wav_file)
pylab.figure(num=3, figsize=(10, 6))
pylab.title('spectrogram pylab with wav_file')
pylab.specgram(sound_info, Fs=frame_rate)
pylab.savefig('spectrogram2.png')
def graph_wavfileread(_wav_file_):
import matplotlib.pyplot as plt
from scipy import signal
from scipy.io import wavfile
import numpy as np
sample_rate, samples = wavfile.read(_wav_file_)
frequencies, times, spectrogram = signal.spectrogram(samples,sample_rate,nfft=1024)
plt.pcolormesh(times, frequencies, 10*np.log10(spectrogram))
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.savefig("spectogram1.png")
spectogram_librosa(_wav_file_)
#graph_wavfileread(_wav_file_)
#graph_spectrogram_wave(_wav_file_)
- 产生了以下 3 个输出:
除了大小和强度上的细微差别外,无论是读取方法、库还是数据类型,这看起来都非常相似,这让我有点疑问,出于什么目的需要输出相同 'exactly'以及它们应该有多精确。
补充一下,Librosa 有一个实用程序可以将整数数组转换为浮点数。
float_audio = librosa.util.buf_to_float(sig)
我在制作 Pydub 音频片段的频谱图时使用它取得了巨大的成功。请记住,它的参数之一是每个样本的字节数。它默认为 2。您可以在 documentation here. Here is the source code:
中阅读更多信息def buf_to_float(x, n_bytes=2, dtype=np.float32):
"""Convert an integer buffer to floating point values.
This is primarily useful when loading integer-valued wav data
into numpy arrays.
See Also
--------
buf_to_float
Parameters
----------
x : np.ndarray [dtype=int]
The integer-valued data buffer
n_bytes : int [1, 2, 4]
The number of bytes per sample in `x`
dtype : numeric type
The target output type (default: 32-bit float)
Returns
-------
x_float : np.ndarray [dtype=float]
The input data buffer cast to floating point
"""
# Invert the scale of the data
scale = 1./float(1 << ((8 * n_bytes) - 1))
# Construct the format string
fmt = '<i{:d}'.format(n_bytes)
# Rescale and format the data buffer
return scale * np.frombuffer(x, fmt).astype(dtype)