繁体   English   中英

使用python过滤wav文件

[英]Filtering a wav file using python

所以我最近成功构建了一个系统,可以完全使用 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)

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

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

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

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

选择过滤带

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

选择您的截止频率

截止频率是您的信号衰减 -3dB 的频率。

您的示例信号是 440Hz,所以让我们选择400Hz截止频率 然后您的 440Hz 信号被低通 400Hz 滤波器衰减(超过 -3dB)。

选择您的过滤器类型

根据this other stackoverflow answer

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

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

移动平均线

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

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

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

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

代码将是

import math

sampleRate = 11025.0 
cutOffFrequency = 400.0
freqRatio = cutOffFrequency / sampleRate

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

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

第二步:编码过滤器

手工制作的移动平均线

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM