Binaural HRIR Spatial Map
Head-Related Impulse Response (HRIR) lookup table for real-time binaural audio rendering.
Grid Specification
| Parameter | Value |
|---|---|
| Azimuth | 0°–355° (Δ5.0°, 72 points) |
| Distance | 0.10m–2.00m (26 points) |
| Elevation | 0.0° (fixed) |
| Total points | 1,872 |
| IR length | 512 samples (10.7 ms) |
| Sample rate | 48000 Hz |
| Dtype | float32 |
Distance Grid (near-field dense)
0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.22, 0.25, 0.28, 0.30, 0.33, 0.36, 0.40, 0.45, 0.50, 0.60, 0.75, 1.00, 1.25, 1.50, 2.00
- 10–20 cm: 1 cm step (11 points) — near-field, high HRTF variation
- 20–40 cm: 2–3 cm step (7 points)
- 40 cm–1 m: 5–15 cm step (4 points)
- 1–2 m: 25–50 cm step (4 points)
HRTF Model
Rigid sphere model with:
- Spherical wave expansion (near-field)
- Ear canal resonance (angle/distance dependent)
- Pinna diffraction
- Interaural Time Difference (ITD)
- Torso reflection
- Air absorption
Usage
import numpy as np
data = np.load("hrir_spatial_map.npz")
azimuths = data["azimuths"] # (72,) float32 — [0, 5, 10, ..., 355]
distances = data["distances"] # (26,) float32 — [0.10, 0.11, ..., 2.00]
hrir_L = data["hrir_L"] # (72, 26, 512) float32
hrir_R = data["hrir_R"] # (72, 26, 512) float32
# Look up HRIR for azimuth=270° (right), distance=0.10m
az_idx = int(270 / 5) # = 54
dist_idx = 0 # = 0.10m
ir_L = hrir_L[az_idx, dist_idx] # (512,) float32
ir_R = hrir_R[az_idx, dist_idx] # (512,) float32
# Binaural rendering via direct convolution
out_L = np.convolve(mono_audio, ir_L, mode="full")[:len(mono_audio)]
out_R = np.convolve(mono_audio, ir_R, mode="full")[:len(mono_audio)]
stereo = np.stack([out_L, out_R], axis=-1)
Interpolation for arbitrary positions
def interpolate_hrir(hrir_L, hrir_R, azimuths, distances, az_deg, dist_m):
az_step = azimuths[1] - azimuths[0]
az_idx_f = (az_deg % 360) / az_step
az_i0 = int(az_idx_f) % len(azimuths)
az_i1 = (az_i0 + 1) % len(azimuths)
az_alpha = az_idx_f - int(az_idx_f)
dist_m = np.clip(dist_m, distances[0], distances[-1])
d_idx = np.searchsorted(distances, dist_m, side="right") - 1
d_idx = np.clip(d_idx, 0, len(distances) - 2)
d_alpha = (dist_m - distances[d_idx]) / (distances[d_idx + 1] - distances[d_idx])
L00 = hrir_L[az_i0, d_idx]
L01 = hrir_L[az_i0, d_idx + 1]
L10 = hrir_L[az_i1, d_idx]
L11 = hrir_L[az_i1, d_idx + 1]
L = (1 - az_alpha) * ((1 - d_alpha) * L00 + d_alpha * L01) \
+ az_alpha * ((1 - d_alpha) * L10 + d_alpha * L11)
R00 = hrir_R[az_i0, d_idx]
R01 = hrir_R[az_i0, d_idx + 1]
R10 = hrir_R[az_i1, d_idx]
R11 = hrir_R[az_i1, d_idx + 1]
R = (1 - az_alpha) * ((1 - d_alpha) * R00 + d_alpha * R01) \
+ az_alpha * ((1 - d_alpha) * R10 + d_alpha * R11)
return L.astype(np.float32), R.astype(np.float32)
License
MIT
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support