使用python过滤wav文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24920346/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 05:28:59  来源:igfitidea点击:

Filtering a wav file using python

pythonaudiofilteringwav

提问by Philip R.

So i recently successfully built a system which will record, plot, and playback an audio wav file entirely with python. Now, I'm trying to put some filtering and audio mixing in between the when i record and when i start plotting and outputting the file to the speakers. However, i have no idea where to start. Right now I'm to read in a the intial wav file, apply a low pass filter, and then re-pack the newly filtered data into a new wav file. Here is the code i used to plot the initial data once i recorded it.

所以我最近成功构建了一个系统,可以完全使用 python 记录、绘制和播放音频 wav 文件。现在,我试图在我录制和开始绘制文件并将文件输出到扬声器之间进行一些过滤和音频混合。但是,我不知道从哪里开始。现在我要读入初始 wav 文件,应用低通滤波器,然后将新过滤的数据重新打包到一个新的 wav 文件中。这是我记录后用于绘制初始数据的代码。

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

plt.figure(1)
plt.title('Signal Wave...')
plt.plot(signal)

And here is some code i used to generate a test audio file of a single tone:

这是我用来生成单音测试音频文件的一些代码:

import numpy as np
import wave
import struct

freq = 440.0
data_size = 40000
fname = "High_A.wav"
frate = 11025.0  
amp = 64000.0    

sine_list_x = []
for x in range(data_size):
    sine_list_x.append(np.sin(2*np.pi*freq*(x/frate)))

wav_file = wave.open(fname, "w")

nchannels = 1
sampwidth = 2
framerate = int(frate)
nframes = data_size
comptype = "NONE"
compname = "not compressed"

wav_file.setparams((nchannels, sampwidth, framerate, nframes,
comptype, compname))

for s in sine_list_x:
    wav_file.writeframes(struct.pack('h', int(s*amp/2)))

wav_file.close()

I'm not really sure how to apply said audio filter and repack it, though. Any help and/or advice you could offer would be greatly appreciated.

不过,我不确定如何应用所述音频过滤器并重新打包。您可以提供的任何帮助和/或建议将不胜感激。

回答by piercus

First step : What kind of audio filter do you need ?

第一步:您需要什么样的音频过滤器?

Choose the filtered band

选择过滤带

For the following steps, i assume you need a Low-pass Filter.

对于以下步骤,我假设您需要一个Low-pass Filter

Choose your cutoff frequency

选择您的截止频率

The Cutoff frequencyis the frequency where your signal will be attenuated by -3dB.

截止频率是你的信号将通过-3dB衰减频率。

Your example signal is 440Hz, so let's choose a Cutoff frequencyof 400Hz. Then your 440Hz-signal is attenuated (more than -3dB), by the Low-pass 400Hz filter.

你的榜样信号的440Hz,让我们选择一个截止频率400Hz的。然后您的 440Hz 信号被低通 400Hz 滤波器衰减(超过 -3dB)。

Choose your filter type

选择您的过滤器类型

According to this other stackoverflow answer

根据this other stackoverflow answer

Filter design is beyond the scope of Stack Overflow - that's a DSP problem, not a programming problem. Filter design is covered by any DSP textbook - go to your library. I like Proakis and Manolakis' Digital Signal Processing. (Ifeachor and Jervis' Digital Signal Processing isn't bad either.)

滤波器设计超出了堆栈溢出的范围——这是一个 DSP 问题,而不是一个编程问题。任何 DSP 教科书都涵盖了滤波器设计 - 请访问您的图书馆。我喜欢 Proakis 和 Manolakis 的数字信号处理。(Ifeachor 和 Jervis 的数字信号处理也不错。)

To go inside a simple example, I suggest to use a moving averagefilter (for a simple low-pass filter).

为了进入一个简单的例子,我建议使用移动平均滤波器(对于简单的低通滤波器)。

See Moving average

移动平均线

Mathematically, a moving average is a type of convolution and so it can be viewed as an example of a low-pass filter used in signal processing

在数学上,移动平均是一种卷积,因此它可以被视为信号处理中使用的低通滤波器的一个例子

This Moving average Low-pass Filter is a basic filter, and it is quite easy to use and to understand.

这个移动平均低通滤波器是一个基本的滤波器,它很容易使用和理解。

The parameter of the moving average is the window length.

移动平均线的参数是窗口长度

The relationship between moving averagewindow length and Cutoff frequencyneeds little bit mathematics and is explained here

移动平均窗口长度和截止频率之间的关系需要一点点数学,在这里解释

The code will be

代码将是

import math

sampleRate = 11025.0 
cutOffFrequency = 400.0
freqRatio = (cutOffFrequency/sampleRate)

N = int(math.sqrt(0.196196 + freqRatio**2)/freqRatio)

So, in the example, the window length will be 11

因此,在示例中,窗口长度将为11

Second step : coding the filter

第二步:编码过滤器

Hand-made moving average

手工制作的移动平均线

see specific discussion on how to create a moving average in python

请参阅有关如何在 python 中创建移动平均线的具体讨论

Solution from Alleois

Alleo 的解决方案是

def running_mean(x, windowSize):
   cumsum = numpy.cumsum(numpy.insert(x, 0, 0)) 
   return (cumsum[windowSize:] - cumsum[:-windowSize]) / windowSize 

filtered = running_mean(signal, N)

Using lfilter

使用 lfilter

Alternatively, as suggested by dpwilson, we can also use lfilter

或者,根据dpwilson 的建议,我们也可以使用 lfilter

win = numpy.ones(N)
win *= 1.0/N
filtered = scipy.signal.lfilter(win, [1], signal).astype(channels.dtype)

Third step : Let's Put It All Together

第三步:让我们把它们放在一起

import matplotlib.pyplot as plt
import numpy as np
import wave
import sys
import math
import contextlib

fname = 'test.wav'
outname = 'filtered.wav'

cutOffFrequency = 400.0

# from http://stackoverflow.com/questions/13728392/moving-average-or-running-mean
def running_mean(x, windowSize):
  cumsum = np.cumsum(np.insert(x, 0, 0)) 
  return (cumsum[windowSize:] - cumsum[:-windowSize]) / windowSize

# from http://stackoverflow.com/questions/2226853/interpreting-wav-data/2227174#2227174
def interpret_wav(raw_bytes, n_frames, n_channels, sample_width, interleaved = True):

    if sample_width == 1:
        dtype = np.uint8 # unsigned char
    elif sample_width == 2:
        dtype = np.int16 # signed 2-byte short
    else:
        raise ValueError("Only supports 8 and 16 bit audio formats.")

    channels = np.fromstring(raw_bytes, dtype=dtype)

    if interleaved:
        # channels are interleaved, i.e. sample N of channel M follows sample N of channel M-1 in raw data
        channels.shape = (n_frames, n_channels)
        channels = channels.T
    else:
        # channels are not interleaved. All samples from channel M occur before all samples from channel M-1
        channels.shape = (n_channels, n_frames)

    return channels

with contextlib.closing(wave.open(fname,'rb')) as spf:
    sampleRate = spf.getframerate()
    ampWidth = spf.getsampwidth()
    nChannels = spf.getnchannels()
    nFrames = spf.getnframes()

    # Extract Raw Audio from multi-channel Wav File
    signal = spf.readframes(nFrames*nChannels)
    spf.close()
    channels = interpret_wav(signal, nFrames, nChannels, ampWidth, True)

    # get window size
    # from http://dsp.stackexchange.com/questions/9966/what-is-the-cut-off-frequency-of-a-moving-average-filter
    freqRatio = (cutOffFrequency/sampleRate)
    N = int(math.sqrt(0.196196 + freqRatio**2)/freqRatio)

    # Use moviung average (only on first channel)
    filtered = running_mean(channels[0], N).astype(channels.dtype)

    wav_file = wave.open(outname, "w")
    wav_file.setparams((1, ampWidth, sampleRate, nFrames, spf.getcomptype(), spf.getcompname()))
    wav_file.writeframes(filtered.tobytes('C'))
    wav_file.close()

回答by penduDev

sox librarycan be used for static noise removal.

sox library可用于去除静态噪声。

I found this gistwhich has some useful commands as examples

我发现这个要点有一些有用的命令作为例子