带有 Wav 文件的卷积室脉冲响应 (python)

信息处理 卷积 冲动反应 声学
2022-02-11 14:11:58

我编写了以下代码,应该将 echo 放在可用的声音文件上。不幸的是,输出是一个非常嘈杂的结果,我并不完全理解。有人可以帮我解决这个问题吗?有没有跳过的步骤?

#convolving a room impulse response function with a sound sample both of stereo type
from scipy.io import wavfile
inp = wavfile.read(sound_path + sound_file_name)
IR = wavfile.read(IR_path + IR_file_name)
if inp[0] != IR[0]:
    print "Size mismatch"
    sys.exit(-1)
else:
    rate = inp[0]
print sound_file_name
out_0 = fftconvolve(inp[1][:, 1], IR[1][:, 1])
out_1 = fftconvolve(inp[1][:, 1], IR[1][:, 1])
in_counter += 1
out = np.vstack((out_0, out_1)).T
wavfile.write(sound_path + sound_file_name + '_echoed.wav', rate, out)
3个回答
  1. 您阅读文件的方式有点奇怪。此处使用的方法在采样率和信号方面更加清晰。
  2. 你会注意到上面的例子在阅读后调用了 pcm2float。这可能是您的问题的原因。波形阅读器返回一个整数数组。处理那些(相当大的)值很可能会导致问题。在进行卷积之前尝试将您的波形数据转换为浮点数。

有点晚了,但我现在也在研究卷积混响。如果仍然感兴趣,您可以使用我的代码。只需调用函数 convolution_reverb 并将路径传递给两个音频文件(音频和脉冲响应,都需要是 .wav 文件),以及要创建的结果文件的名称。

import numpy as np
from wave import open
import soundfile


class Wave:
    def __init__(self, data, frame_rate):
        self.data = normalize(data)
        self.frame_rate = frame_rate

    def make_spectrum(self):
        amplitudes = np.fft.rfft(self.data)
        frequencies = np.fft.rfftfreq(len(self.data), 1 / self.frame_rate)

        return Spectrum(amplitudes, frequencies, self.frame_rate)

    def zero_padding(self, n):
        zeros = np.zeros(n)
        zeros[:len(self.data)] = self.data

        self.data = zeros

    def write(self, file):
        reader = open(file, 'w')

        reader.setnchannels(1)
        reader.setsampwidth(2)
        reader.setframerate(self.frame_rate)

        frames = self.quantize().tostring()
        reader.writeframes(frames)

        reader.close()

    def quantize(self):
        if max(self.data) > 1 or min(self.data) < -1:
            self.data = normalize(self.data)

        return (self.data * 32767).astype(np.int16)


class Spectrum:
    def __init__(self, amplitudes, frequencies, frame_rate):
        self.amplitudes = np.asanyarray(amplitudes)
        self.frequencies = np.asanyarray(frequencies)
        self.frame_rate = frame_rate

    def __mul__(self, other):
        return Spectrum(self.amplitudes * other.amplitudes, self.frequencies, self.frame_rate)

    def make_wave(self):
        return Wave(np.fft.irfft(self.amplitudes), self.frame_rate)


def convert_wav(file):
    data, samprate = soundfile.read(file)
    soundfile.write(file, data, samprate, subtype='PCM_16')


def read_wave(file):
    reader = open(file)

    _, sampwidth, framerate, nframes, _, _ = reader.getparams()
    frames = reader.readframes(nframes)

    reader.close()

    dtypes = {1: np.int8, 2: np.int16, 4: np.int32}

    if sampwidth not in dtypes:
        raise ValueError('unsupported sample width')

    data = np.frombuffer(frames, dtype=dtypes[sampwidth])

    num_channels = reader.getnchannels()
    if num_channels == 2:
        data = data[::2]

    return Wave(data, framerate)


def normalize(data):
    high, low = abs(max(data)), abs(min(data))
    return data / max(high, low)


def convolution_reverb(audio_file, ir_file, output_file):
    convert_wav(audio_file)
    convert_wav(ir_file)

    audio = read_wave(audio_file)
    ir = read_wave(ir_file)

    if len(audio.data) > len(ir.data):
        ir.zero_padding(len(audio.data))

    else:
        audio.zero_padding(len(ir.data))

    ir_spectrum = ir.make_spectrum()
    audio_spectrum = audio.make_spectrum()

    convolution = audio_spectrum * ir_spectrum
    wave = convolution.make_wave()
    wave.write(output_file)


convolution_reverb('audio.wav', 'ir.wav', 'result.wav')

我终于做了一些操作,主要基于@JRE 的建议,我也独立发现了。我之前已经在SO上发布了这个答案。将波形文件转换为浮点类型并最终重新转换为原始的 16 位 Wav 后,需要对信号进行操作(如卷积)。还需要一个额外的步骤,将原始信号与我添加到以下代码中的卷积信号相加。

from utility import pcm2float,float2pcm
input_rate,input_sig=wavfile.read(sound_path+sound_file_name)
input_sig=pcm2float(input_sig,'float32')
IR_rate,IR_sig=wavfile.read(IR_path+IR_file_name)
IR_sig=pcm2float(IR_sig,'float32')

if input_rate!=IR_rate:
    print "Size mismatch"
    sys.exit(-1)
else:
    rate=input_rate
print sound_file_name
    out_0=fftconvolve(input_sig[:,0],IR_sig[:,0])
out_0=out_0/np.max(np.abs(out_0))
out_1=fftconvolve(input_sig[:,1],IR_sig[:,1])
out_1=out_1/np.max(np.abs(out_1))
out=np.vstack((out_0,out_1)).T
out=float2pcm(out,'int16')
out[:input_sig[:,0].shape[0]]=out[:input_sig[:,0].shape[0]]+input_sig
wavfile.write(sound_path+'echoed outputs/'+sound_file_name+'_'+IR_file_name+'_echoed.wav',rate,out)

我仍然对结果并不完全满意。使用 openair 网站的结果比我的要好得多,我仍然不知道原因: http ://www.openairlib.net/auralizationdb/content/elveden-hall-suffolk-england