How to plot a wav file

前端 未结 8 1036
时光取名叫无心
时光取名叫无心 2020-12-12 10:51

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

相关标签:
8条回答
  • 2020-12-12 11:05

    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').

    0 讨论(0)
  • 2020-12-12 11:09

    Alternatively, if you want to use SciPy, you may also do the following:

    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()
    
    0 讨论(0)
  • 2020-12-12 11:10

    Here is a version that handles mono/stereo and 8-bit/16-bit 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()
    
    0 讨论(0)
  • 2020-12-12 11:13

    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.
    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()
    
    0 讨论(0)
  • 2020-12-12 11:22

    Here's a version that will also handle stereo inputs, based on the answer by @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()
    

    0 讨论(0)
  • 2020-12-12 11:23

    You can call wave lib to read an audio file.

    To plot the waveform, use the "plot" function from matplotlib

    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:enter image description here

    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)

    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:

    enter image description here

    0 讨论(0)
提交回复
热议问题