Binaural vs. Stereo Audio#
Binaural synthesis aims at creating virtual sources anywhere in the 3D space around the listener. In most cases this is done via headphone playback. In contrast, stereo panning creates phantom sources on the line between to loudspeakers. In this assignment, you will generate simple binaural and stereo audio examples and compare them against each other.
Duration: 45-60 Minutes
Requirements: Basic knowledge of HRTFs, coordinate conventions, and digital signal processing.
pip install pyfar>=0.7 sofar nbgrader ipykernel watermark[ ]:
import pyfar as pf
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import Audio, display
import pooch
%matplotlib inline
Before starting the assignment, all necessary files need to be downloaded. This is simply done by executing the cell below.
[ ]:
# adjust this path to your needs. Using `None` will download the file to your
# system cache.
path = None
# Leave this as it is: This is the URL from which the data will be downloaded
# and a hash for checking if the download worked.
url = 'https://github.com/pyfar/files/raw/refs/heads/main/education/VAR_TUB/FABIAN_HRIR_measured_HATO_0.sofa?download='
hash = '83ebbcd9a09d17679b95d201c9775438c0bb1199d565c3fc7a25448a905cdc3c'
file_hrir = pooch.retrieve(
url, hash, fname='FABIAN_HRIR_measured_HATO_0.sofa', path=path)
url = 'https://github.com/pyfar/files/raw/refs/heads/main/education/VAR_TUB/FABIAN_CTF_measured_inverted_smoothed.sofa?download='
hash = '68d79bf54ba8e0d7732bf14c525ac20404e751bba26a3e674036c53b71f70bfb'
file_ctf_inverse = pooch.retrieve(
url, hash, fname='FABIAN_CTF_measured_inverted_smoothed.sofa', path=path)
Load HRTFs and inverted Diffuse Field HRTF#
Load the HRTF set and its source positions contained in file_hrir into pyfar Signal and Coordinates objects, and load the inverse diffuse field HRTF contained in file_ctf_inverse into a pyfar Signal object.
[ ]:
# YOUR CODE HERE
raise NotImplementedError()
Render Auralizations using Binaural Synthesis and Stereo panning#
In Stereo playback, an audio signal \(x(t)\) is panned between the left and the right speaker using the gains \(g_\text{l}\) and \(g_\text{r}\) to produce a phantom source that can be perceived anywhere between the two speakers.
\(l_\text{l}(t) = g_\text{l} \,x(t)\), and
\(l_\text{r}(t) = g_\text{r} \, x(t)\)
with the loudspeaker signals \(l(t)\). The gains must satisfy \(g_\text{l}^2 + g_\text{r}^2 = 1\). Equal gains \(g_\text{l} = g_\text{r}\) evoke a phantom source in the middle of the loudspeakers and \(g_\text{l} = 1\) a phantom source at the position of the left speaker.
In contrast, binaural synthesis convolves the audio signal with HRTFs \(h(\varphi,\vartheta, t)\) and delivers the resulting ear signals \(e(t)\) via headphones
\(e_\text{l,r}(t) = x(t) \ast h_\text{l,r}(\varphi,\vartheta, t) \ast c_\text{l,r}(t)\)
with azimuth \(\varphi\) and elevation \(\vartheta\) and a compensation filter \(c(t)\) that linearizes the transfer function of the headphone to achieve a natural sound color. In this assignment, you will use the inverse diffuse field HRTFs as \(c(t)\), i.e., the HRTF that is first averaged across all source positions and then inverted.
Go ahead and render binaural and stereo signals. You will plot the binaural transfer functions and listen to the resulting auralizations.
[ ]:
# Source position - select one of the following:
# front, back, left, right, up, down
position = 'left'
# flag for applying diffuse field compensation
diffuse_field_compensation = True
# load or generate audio content
# YOUR CODE HERE
raise NotImplementedError()
# set the source positions for binaural rendering and the channel gains for stereo auralization
if position == 'front':
# YOUR CODE HERE
raise NotImplementedError()
elif position == 'back':
# YOUR CODE HERE
raise NotImplementedError()
elif position == 'left':
# YOUR CODE HERE
raise NotImplementedError()
elif position == 'right':
# YOUR CODE HERE
raise NotImplementedError()
elif position == 'up':
# YOUR CODE HERE
raise NotImplementedError()
elif position == 'down':
# YOUR CODE HERE
raise NotImplementedError()
else:
raise ValueError(f'Invalid {position = }')
# render HRTF based auralization
# YOUR CODE HERE
raise NotImplementedError()
# render stereo based auralization
# YOUR CODE HERE
raise NotImplementedError()
# force equal energy in both auralizations as a simple loudness normalization
# YOUR CODE HERE
raise NotImplementedError()
# Normalize the auralizations to the highest occuring amplitude (use the same normalization for both auralizations)
# YOUR CODE HERE
raise NotImplementedError()
# render the audio using the iPython `Audio`` widget
# YOUR CODE HERE
raise NotImplementedError()
# plot the left and right ear HRIR and HRTF
# YOUR CODE HERE
raise NotImplementedError()
License notice#
This notebook is licensed under CC BY 4.0
Watermark#
The following watermark might help others to install specific package versions that might be required to run the notebook. Please give at least the versions of Python, IPython, numpy , and scipy, major third party packagers (e.g., pytorch), and all used pyfar packages.
[ ]:
%load_ext watermark
%watermark -v -m -p numpy,scipy,pyfar,sofar,nbgrader,watermark
Python implementation: CPython
Python version : 3.13.4
IPython version : 9.1.0
numpy : 2.3.0
scipy : 1.15.3
pyfar : 0.7.3
sofar : 1.2.2
nbgrader : 0.9.5
watermark: 2.5.0
Compiler : Clang 14.0.6
OS : Darwin
Release : 24.6.0
Machine : arm64
Processor : arm
CPU cores : 8
Architecture: 64bit