使用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
Filtering a wav file using python
提问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
选择过滤带
- Low-pass Filter: remove highest frequency from your audio signal
- High-pass Filter: remove lowest frequencies from your audio signal
- Band-pass Filter: remove both highest and lowest frequencies from your audio signal
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
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()