【问题标题】:How to plot a wav file如何绘制一个wav文件
【发布时间】:2013-09-08 14:59:01
【问题描述】:

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

【问题讨论】:

  • print a 输出什么?
  • 这是单通道还是多通道 wavfile?
  • 打印一个,只显示一个带有音频文件原始数据的元组。它是一个单声道 wavfile。

标签: python audio matplotlib


【解决方案1】:

这是绘制波形文件的波形和频谱的代码

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()

【讨论】:

    【解决方案2】:

    我想出了一个更灵活、更高效的解决方案:

    • 下采样用于实现每秒两个样本。这是通过计算每个窗口的绝对值的平均值来实现的。结果看起来像来自 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()
    

    【讨论】:

    • 我在 np.pad 上收到错误消息,说“ValueError:无法将浮点 NaN 转换为整数”,知道如何修复它吗?
    【解决方案3】:

    您可以调用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 函数创建一个与音频文件大小呈线性间隔的时间向量,最后您可以再次使用情节,如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 轴:

    【讨论】:

    • 那是完美的人,但如果我想查看 x 轴上的时间(以秒为单位)怎么办?我怎样才能做到这一点??
    • Ederwander,由于某种原因,我不知道当我绘制文件时它只是向后显示数据!enter image description here:我复制了你写的相同内容!有什么建议吗?
    • 没有意义,如果你真的认为数据是倒置的,使用numpy的任何函数来转置你的向量....
    • 出于好奇,我将结果与python和Audacity中的绘图进行了比较,您可以看到相同的波形here
    • 如何将输出保存为 JPG 或 PNG 而不是在屏幕上显示?
    【解决方案4】:

    我想我可以把它放在评论中,但是基于@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)
    

    【讨论】:

      【解决方案5】:

      这是处理单声道/立体声和 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()
      

      【讨论】:

        【解决方案6】:

        只是一个观察(我无法添加评论)。

        您将收到以下消息:

        DeprecationWarning:不推荐使用数字样式的类型代码,并将 导致以后出错。

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

          • 工作,虽然很慢。使用 oneliner channels = [signal[channel::num_channels] for channel in range(num_channels)] 快​​速疯狂。
          【解决方案8】:

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

          【讨论】:

          • 关于如何编辑它以处理 24 位深度 wav 文件的任何建议?
          猜你喜欢
          • 2012-05-26
          • 1970-01-01
          • 1970-01-01
          • 2013-08-11
          • 1970-01-01
          • 2021-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多