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

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support