Python 如何绘制 wav 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18625085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to plot a wav file
提问by Diego Martínez Giardini
I have just read a wav file with scipy and now I want to make the plot of the file using matplotlib, on the "y scale" I want to see the aplitude and over the "x scale" I want to see the numbers of frames! Any help how can I do this?? Thank you!
我刚刚用 scipy 读取了一个 wav 文件,现在我想使用 matplotlib 绘制文件图,在“y 比例”上我想查看振幅,在“x 比例”上我想查看帧数!任何帮助我该怎么做?谢谢!
from scipy.io.wavfile import read
import numpy as np
from numpy import*
import matplotlib.pyplot as plt
a=read("C:/Users/Martinez/Desktop/impulso.wav")
print a
采纳答案by ederwander
You can call wave lib to read an audio file.
您可以调用 wave lib 来读取音频文件。
To plot the waveform, use the "plot" function from matplotlib
要绘制波形,请使用 matplotlib 中的“plot”函数
import matplotlib.pyplot as plt
import numpy as np
import wave
import sys
spf = wave.open("wavfile.wav", "r")
# Extract Raw Audio from Wav File
signal = spf.readframes(-1)
signal = np.fromstring(signal, "Int16")
# If Stereo
if spf.getnchannels() == 2:
print("Just mono files")
sys.exit(0)
plt.figure(1)
plt.title("Signal Wave...")
plt.plot(signal)
plt.show()
you will have something like:
你会有类似的东西:
To Plot the x-axis in seconds you need get the frame rate and divide by size of your signal, you can use linspace function from numpy to create a Time Vector spaced linearly with the size of the audio file and finally you can use plot again like plt.plot(Time,signal)
要以秒为单位绘制 x 轴,您需要获得帧速率并除以信号大小,您可以使用 numpy 中的 linspace 函数创建一个与音频文件大小线性间隔的时间向量,最后您可以再次使用 plot喜欢 plt.plot(Time,signal)
import matplotlib.pyplot as plt
import numpy as np
import wave
import sys
spf = wave.open("Animal_cut.wav", "r")
# Extract Raw Audio from Wav File
signal = spf.readframes(-1)
signal = np.fromstring(signal, "Int16")
fs = spf.getframerate()
# If Stereo
if spf.getnchannels() == 2:
print("Just mono files")
sys.exit(0)
Time = np.linspace(0, len(signal) / fs, num=len(signal))
plt.figure(1)
plt.title("Signal Wave...")
plt.plot(Time, signal)
plt.show()
New plot x-axis in seconds:
以秒为单位的新图 x 轴:
回答by CuriousCoder
Alternatively, if you want to use SciPy, you may also do the following:
或者,如果您想使用 SciPy,您还可以执行以下操作:
from scipy.io.wavfile import read
import matplotlib.pyplot as plt
# read audio samples
input_data = read("Sample.wav")
audio = input_data[1]
# plot the first 1024 samples
plt.plot(audio[0:1024])
# label the axes
plt.ylabel("Amplitude")
plt.xlabel("Time")
# set the title
plt.title("Sample Wav")
# display the plot
plt.show()
回答by Alter
Here's a version that will also handle stereo inputs, based on the answer by @ederwander
根据@ederwander 的回答,这是一个也可以处理立体声输入的版本
import matplotlib.pyplot as plt
import numpy as np
import wave
file = 'test.wav'
with wave.open(file,'r') as wav_file:
#Extract Raw Audio from Wav File
signal = wav_file.readframes(-1)
signal = np.fromstring(signal, 'Int16')
#Split the data into channels
channels = [[] for channel in range(wav_file.getnchannels())]
for index, datum in enumerate(signal):
channels[index%len(channels)].append(datum)
#Get time from indices
fs = wav_file.getframerate()
Time=np.linspace(0, len(signal)/len(channels)/fs, num=len(signal)/len(channels))
#Plot
plt.figure(1)
plt.title('Signal Wave...')
for channel in channels:
plt.plot(Time,channel)
plt.show()
回答by Eduardo Freitas
Just an observation (I cannot add comment).
只是一个观察(我不能添加评论)。
You will receive the following mesage:
您将收到以下消息:
DeprecationWarning: Numeric-style type codes are deprecated and will resultin an error in the future.
弃用警告:不推荐使用数字样式的类型代码,将来会导致错误。
Do not use np.fromstring with binaries. Instead of signal = np.fromstring(signal, 'Int16')
, it's preferred to use signal = np.frombuffer(signal, dtype='int16')
.
不要将 np.fromstring 与二进制文件一起使用。而不是 signal = np.fromstring(signal, 'Int16')
,最好使用 signal = np.frombuffer(signal, dtype='int16')
。
回答by TimSC
Here is a version that handles mono/stereo and 8-bit/16-bit PCM.
这是一个处理单声道/立体声和 8 位/16 位 PCM 的版本。
import matplotlib.pyplot as plt
import numpy as np
import wave
file = 'test.wav'
wav_file = wave.open(file,'r')
#Extract Raw Audio from Wav File
signal = wav_file.readframes(-1)
if wav_file.getsampwidth() == 1:
signal = np.array(np.frombuffer(signal, dtype='UInt8')-128, dtype='Int8')
elif wav_file.getsampwidth() == 2:
signal = np.frombuffer(signal, dtype='Int16')
else:
raise RuntimeError("Unsupported sample width")
# http://schlameel.com/2017/06/09/interleaving-and-de-interleaving-data-with-python/
deinterleaved = [signal[idx::wav_file.getnchannels()] for idx in range(wav_file.getnchannels())]
#Get time from indices
fs = wav_file.getframerate()
Time=np.linspace(0, len(signal)/wav_file.getnchannels()/fs, num=len(signal)/wav_file.getnchannels())
#Plot
plt.figure(1)
plt.title('Signal Wave...')
for channel in deinterleaved:
plt.plot(Time,channel)
plt.show()
回答by Nikhil Parashar
Here is the code to draw a waveform and a frequency spectrum of a wavefile
这是绘制波形文件的波形和频谱的代码
import wave
import numpy as np
import matplotlib.pyplot as plt
signal_wave = wave.open('voice.wav', 'r')
sample_rate = 16000
sig = np.frombuffer(signal_wave.readframes(sample_rate), dtype=np.int16)
For the whole segment of the wave file
对于整个波形文件段
sig = sig[:]
For partial segment of the wave file
对于波形文件的部分片段
sig = sig[25000:32000]
Separating stereo channels
分离立体声通道
left, right = data[0::2], data[1::2]
Plot the waveform (plot_a) and the frequency spectrum (plot_b)
绘制波形 (plot_a) 和频谱 (plot_b)
plt.figure(1)
plot_a = plt.subplot(211)
plot_a.plot(sig)
plot_a.set_xlabel('sample rate * time')
plot_a.set_ylabel('energy')
plot_b = plt.subplot(212)
plot_b.specgram(sig, NFFT=1024, Fs=sample_rate, noverlap=900)
plot_b.set_xlabel('Time')
plot_b.set_ylabel('Frequency')
plt.show()
回答by CRGreen
I suppose I could've put this in a comment, but building slightly on the answers from both @ederwander and @TimSC, I wanted to make something more fine (as in detailed) and aesthetically pleasing. The code below creates what I think is a very nice waveform of a stereo or mono wave file (I didn't need a title so I just commented that out, nor did I need the show method - just needed to save the image file).
我想我可以把它放在评论中,但稍微建立在@ederwander 和 @TimSC 的答案的基础上,我想做一些更精细(如详细)和美观的东西。下面的代码创建了我认为非常好的立体声或单声道波形文件的波形(我不需要标题,所以我只是将其注释掉,也不需要 show 方法 - 只需要保存图像文件) .
Here's an example of a stereo wav rendered:
And the code, with the differences I mentioned:
和代码,与我提到的差异:
import matplotlib.pyplot as plt
import numpy as np
import wave
file = '/Path/to/my/audio/file/DeadMenTellNoTales.wav'
wav_file = wave.open(file,'r')
#Extract Raw Audio from Wav File
signal = wav_file.readframes(-1)
if wav_file.getsampwidth() == 1:
signal = np.array(np.frombuffer(signal, dtype='UInt8')-128, dtype='Int8')
elif wav_file.getsampwidth() == 2:
signal = np.frombuffer(signal, dtype='Int16')
else:
raise RuntimeError("Unsupported sample width")
# http://schlameel.com/2017/06/09/interleaving-and-de-interleaving-data-with-python/
deinterleaved = [signal[idx::wav_file.getnchannels()] for idx in range(wav_file.getnchannels())]
#Get time from indices
fs = wav_file.getframerate()
Time=np.linspace(0, len(signal)/wav_file.getnchannels()/fs, num=len(signal)/wav_file.getnchannels())
plt.figure(figsize=(50,3))
#Plot
plt.figure(1)
#don't care for title
#plt.title('Signal Wave...')
for channel in deinterleaved:
plt.plot(Time,channel, linewidth=.125)
#don't need to show, just save
#plt.show()
plt.savefig('/testing_folder/deadmentellnotales2d.png', dpi=72)
回答by Arthur C
I came up with a solution that's more flexible and more performant:
我想出了一个更灵活、更高效的解决方案:
- Downsampling is used to achieve two samples per second. This is achieved by calculating the average of absolute values for each window. The result looks like the waveforms from streaming sites like SoundCloud.
- Multi-channel is supported (thanks @Alter)
- Numpy is used for each operation, which is much more performant than looping through the array.
- The file is processed in batches to support very large files.
- 下采样用于实现每秒两个样本。这是通过计算每个窗口的绝对值的平均值来实现的。结果看起来像来自 SoundCloud 等流媒体网站的波形。
- 支持多通道(感谢@Alter)
- Numpy 用于每个操作,这比循环遍历数组的性能要高得多。
- 文件被批量处理以支持非常大的文件。
import matplotlib.pyplot as plt
import numpy as np
import wave
import math
file = 'audiofile.wav'
with wave.open(file,'r') as wav_file:
num_channels = wav_file.getnchannels()
frame_rate = wav_file.getframerate()
downsample = math.ceil(frame_rate * num_channels / 2) # Get two samples per second!
process_chunk_size = 600000 - (600000 % frame_rate)
signal = None
waveform = np.array([])
while signal is None or signal.size > 0:
signal = np.frombuffer(wav_file.readframes(process_chunk_size), dtype='int16')
# Take mean of absolute values per 0.5 seconds
sub_waveform = np.nanmean(
np.pad(np.absolute(signal), (0, ((downsample - (signal.size % downsample)) % downsample)), mode='constant', constant_values=np.NaN).reshape(-1, downsample),
axis=1
)
waveform = np.concatenate((waveform, sub_waveform))
#Plot
plt.figure(1)
plt.title('Waveform')
plt.plot(waveform)
plt.show()