簡體   English   中英

如何繪制 wav 文件

[英]How to plot a wav file

我剛剛用 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

您可以調用 wave lib 來讀取音頻文件。

要繪制波形,請使用 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()

你會有類似的東西:在此處輸入圖片說明

要以秒為單位繪制 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()

以秒為單位的新圖 x 軸:

在此處輸入圖片說明

或者,如果您想使用 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()

根據@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()

在此處輸入圖片說明

只是一個觀察(我不能添加評論)。

您將收到以下消息:

棄用警告:不推薦使用數字樣式的類型代碼,將來會導致錯誤。

不要將 np.fromstring 與二進制文件一起使用。 而不是signal = np.fromstring(signal, 'Int16') ,最好使用signal = np.frombuffer(signal, dtype='int16')

這是繪制波形文件的波形和頻譜的代碼

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)

對於整個波形文件段

sig = sig[:]

對於波形文件的部分片段

sig = sig[25000:32000]

分離立體聲通道

left, right = data[0::2], data[1::2]

繪制波形 (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()

波信號和信號的頻譜圖

這是一個處理單聲道/立體聲和 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()

我想我可以把它放在評論中,但稍微建立在@ederwander 和 @TimSC 的答案的基礎上,我想做一些更精細(如詳細)和美觀的東西。 下面的代碼創建了我認為非常好的立體聲或單聲道波形文件的波形(我不需要標題,所以我只是將其注釋掉,也不需要 show 方法 - 只需要保存圖像文件) .

下面是一個立體聲 wav 渲染的例子: 在此處輸入圖片說明

和代碼,與我提到的差異:

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)

我想出了一個更靈活、更高效的解決方案:

  • 下采樣用於實現每秒兩個樣本。 這是通過計算每個窗口的絕對值的平均值來實現的。 結果看起來像來自 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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM