HRTFs: Reading and Inspecting#
Head-related transfer functions (HRTFs) are fundamental to 3D audio. In this notebook, you will learn how to read and visualize HRTFs, and how to estimate (broadband) interaural time and level differences from HRTFs.
Duration: 45-60 Minutes
Requirements: Basic knowledge of spatial hearing, HRTFs, coordinate conventions, and SOFA files
pip install pyfar>=0.7 pooch nbgrader ipykernel watermark[ ]:
import pyfar as pf
import sofar as sf
import numpy as np
import matplotlib.pyplot as plt
import pooch
import os
%matplotlib inline
Reading HRTFs#
HRTFs are stored in so called sofa-files. SOFA is a standardized file format for storing spatially distributed acoustic data, e.g., HRTFs. SOFA files contain the acoustic data along with meta data. In this case the most important meta data are the source positions at which the HRTFs are available.
If you want to know more about the SOFA file standard, we recommend the sofar documentation
Start by downloading the file FABIAN_HRIR_measured_HATO_0.sofa by executing the cell below.
[ ]:
# adjust this path to your needs. Using `None` will download the file to your
# system cash.
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 = pooch.retrieve(
url, hash, fname='FABIAN_HRIR_measured_HATO_0.sofa', path=path)
Now load the file. Your goal is to get the HRIRs as a pyfar Signal and the source positions at which the HRIRs were measured as a pyfar Coordinates object.
[ ]:
# %% read HRTFs from SOFA file ------------------------------------------------
# YOUR CODE HERE
raise NotImplementedError()
Source Positions#
A plethora of HRTF datasets are freely available online and they were all measured for different sampling grids, i.e., different source positions. A good first step is to get an idea of the sampling grid to know how many HRTFs were measured and how they are distributed in space.
[ ]:
# %% print the number of source positions and plot their spatial position -----
# YOUR CODE HERE
raise NotImplementedError()
Visualization and feature estimation for a single HRIR#
Whenever you are dealing with third party data or measuring your own data, it is a good idea to get familiar with it, e.g., by visualization.
Find and plot HRIRS and HRTF for a single source position and check your result for plausibilty: Does your plot look as expected? Typical source positions for this inspection could be sources to the front/back, left/right, and above/below the subject. What angles describe these source positions, and how do you get the corresponding HRIRs from the Signal and Coordinates objects?
Once you finished the plot, estimate the broadband interaural time and level difference (ITD and ILD) for the source positions and display it as part of the plot.
ITD estimation: There are multiple ways to estimate the broadband ITD (see [2]). A simple yet perceptually meaning full approach is to low-pass the HRIR at 3 kHz and then find the first sample in the HRIR that is less then 20 or 10 dB below the absolute maximum of the HRIR (per channel). To estimate the ITD with subsample precision, it can be resamples to a higher sampling rate before.
ILD estimation: A simple way to estimate the broadband ILD is to compute the energy of the left and right ear HRIR and compute their ratio in decibel.
[ ]:
# %% plot HRTF for single source position -------------------------------------
# use the pyfar default plot style
pf.plot.use()
# define the desired source position
# YOUR CODE HERE
raise NotImplementedError()
# find the closest source position in data
# YOUR CODE HERE
raise NotImplementedError()
# estimate ITD ----------------------------------------------------------------
# YOUR CODE HERE
raise NotImplementedError()
# estimate ILD ------------------------------------------------------------
# YOUR CODE HERE
raise NotImplementedError()
# plot --------------------------------------------------------------------
# YOUR CODE HERE
raise NotImplementedError()
Note that the onsets were computed on the lowpassed HRIRs. Hence they appear earlier than one might expect in the plot above.
Plot multiple HRIRs#
Plot all HRIRs and HRTFs in the horizontal and median plane. You can do this by color coding the amplitude of the HRIRs and HRTFs using pyfars 2D plots.
How are the horizontal and median plane defined?
What is the easiest way to find the corresponding source positions?
What do you see in the plots?
[ ]:
# %% plot horizontal and median plane -----------------------------------------
for plane in ['Horizontal', 'Median']:
if plane == 'Horizontal':
# find and sort source positions and HRTFs in the horizontal plane
# YOUR CODE HERE
raise NotImplementedError()
else:
# find and sort source positions and HRTFs in the median plane
# YOUR CODE HERE
raise NotImplementedError()
# plot the selected HRTFs in the time and frequency domain
# YOUR CODE HERE
raise NotImplementedError()
Optional: Feature estimation in auditory resolution#
You estimated the broadband interaural time and level differences (ITD and ILD) above. Sometimes a frequency-dependent analysis of these (or other) features is of interest. Estimate and visualize the frequency-dependent ILD for a single HRTF with auditory resolution using pyfar’s Gammatone filter bank.
You can also estimate the frequency dependent ITD if you want. In this case it would be more common to estimate the ITD by computing the cross-correlation between left and right ear signals and then find the time shift that yields the maximum cross-correlation. This can be done with pyfar.dsp.correlate introduced in pyfar 0.8.0.
Depending on how important it is to model actual hearing, additional pre-processing such as half-wave rectification and square root compression is applied as well to model the behavior of the middle and inner ear with more detail.
[ ]:
# %% compute and plot frequency-dependent ILD ---------------------------------
# select an HRIR
# YOUR CODE HERE
raise NotImplementedError()
# filter in auditory bands (zero pad HRIRs to increase FFT resolution)
# YOUR CODE HERE
raise NotImplementedError()
# compute ILD in auditory bands
# YOUR CODE HERE
raise NotImplementedError()
# Visualize
# 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