This Jupyter notebook is part of a collection of notebooks in the bachelors module Signals and Systems, Comunications Engineering, Universität Rostock. Please direct questions and suggestions to Sascha.Spors@uni-rostock.de.
The propagation of sound in rooms is modeled by the linear wave equation, a second-order linear partial differential equation with constant coefficients. Consequently, the propagation path from a source (e.g. loudspeaker) at one position to a receiver (e.g. microphone) at another position can be interpreted as a linear time-invariant (LTI) system. This system is characterized for instance by the impulse response between these two positions. This fact can be used for the synthesis of virtual acoustic environments. If a source signal (e.g. speech, instrument) without any room effect is convolved with the impulse response of a room (e.g. concert hall), the impression is created that the source plays in the room. This is also known as convolution reverb.
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import soundfile as sf
import scipy.signal as sig
x, fs = sf.read('../data/speech.wav')
The input signal $x[k]$ is plotted. For ease of illustration, the sample index $k$ is interpreted as time $t = k T$ with the sampling interaval $T$.
plt.figure(figsize=(8,4))
t = np.arange(len(x)) / fs
plt.plot(t, x)
plt.xlabel(r'$t$ in s')
plt.ylabel(r'$x[k]$')
plt.axis([0, t[-1], -1, 1]);
The impulse response $h[k]$ of the room is loaded into the vector h
h, fsh = sf.read('../data/room_impulse_response.wav')
The room impulse response is plotted for illustration
plt.figure(figsize=(8,4))
t = 1/fs*np.arange(len(h))
plt.plot(t, h)
plt.xlabel(r'$t$ in s')
plt.ylabel(r'$h[k]$');
The source signal $x[k]$ is convolved with the room impulse response $h[k]$ in order to compute the output signal $y[k] = x[k] * h[k]$. The computation may take a while due to the involved numerical complexity.
y = np.convolve(h, x)
The output signal $y[k]$ is plotted for illustration. The effect of the room on the source signal is clearly visible.
plt.figure(figsize=(8,4))
t = 1/fs*np.arange(len(y))
plt.plot(t, y)
plt.xlabel(r'$t$ in s')
plt.ylabel(r'$y[k]$');
The input signal $x[k]$ and the output signal $y[k]$ are normalized and written to files for the purpose of auralization.
sf.write('dry_source.wav', x, fs)
y = max(x) * y / np.max(np.abs(y))
sf.write('wet_source.wav', y, fs)
Listen to the 'dry' source signal without room effect (input) and the 'wet' signal including the room effect (output) using the embedded controls below.
Dry source signal without room dry_source.wav
Resulting signal including room wet_source.wav
Copyright
This notebook is provided as Open Educational Resource. Feel free to use the notebook for your own purposes. The text is licensed under Creative Commons Attribution 4.0, the code of the IPython examples under the MIT license. Please attribute the work as follows: Sascha Spors, Continuous- and Discrete-Time Signals and Systems - Theory and Computational Examples.