使用python过滤WAV文件 [英] Filtering a wav file using python
问题描述
因此,我最近成功构建了一个系统,该系统将完全使用python记录,绘制和播放音频wav文件.现在,我尝试在录制和开始绘制文件并将其输出到扬声器之间进行一些过滤和音频混合.但是,我不知道从哪里开始.现在,我要读取一个初始wav文件,应用一个低通滤波器,然后将新过滤的数据重新打包到一个新的wav文件中.这是我记录初始数据后用来绘制初始数据的代码.
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.
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.
推荐答案
第一步:您需要哪种音频滤波器?
选择已过滤的频段
- 低通滤波器:从音频信号中去除最高频率 >
- 高通滤波器:从音频信号中去除最低频率 >
- 带通滤波器:从音频信号中去除最高和最低频率
- 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
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.
截止频率是您的信号将被衰减-3dB的频率.
The Cutoff frequency is the frequency where your signal will be attenuated by -3dB.
您的示例信号为440Hz,所以我们选择 400Hz的截止频率 .然后,低通400Hz滤波器会衰减440Hz信号(超过-3dB).
Your example signal is 440Hz, so let's choose a Cutoff frequency of 400Hz. Then your 440Hz-signal is attenuated (more than -3dB), by the Low-pass 400Hz filter.
滤波器设计超出了堆栈溢出的范围-这是DSP 问题,而不是编程问题.过滤器的设计涵盖了 DSP教科书-转到您的资料库.我喜欢Proakis和Manolakis' 数字信号处理. (Ifeachor和Jervis的数字信号 处理也不错.)
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.)
举个简单的例子,我建议使用移动平均值过滤器(用于简单的低通滤波器).
To go inside a simple example, I suggest to use a moving average filter (for a simple low-pass filter).
请参见移动平均值
从数学上讲,移动平均是卷积的一种,因此可以看作信号处理中使用的低通滤波器的一个例子
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 relationship between moving average window length and Cutoff frequency needs little bit mathematics and is explained here
代码将是
import math
sampleRate = 11025.0
cutOffFrequency = 400.0
freqRatio = cutOffFrequency / sampleRate
N = int(math.sqrt(0.196201 + freqRatio**2) / freqRatio)
因此,在此示例中,窗口长度将为 12
So, in the example, the window length will be 12
来自 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)
使用lfilter
或者,按照 dpwilson 的建议,我们也可以使用lfilter
Using lfilter
Alternatively, as suggested by dpwilson, we can also use lfilter
win = numpy.ones(N)
win *= 1.0/N
filtered = scipy.signal.lfilter(win, [1], signal).astype(channels.dtype)
第三步:让我们放在一起
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()
这篇关于使用python过滤WAV文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!