File size: 3,105 Bytes
a9be140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
---
license: mit
tags:
  - audio
  - binaural
  - hrtf
  - hrir
  - spatial-audio
  - asmr
language:
  - en
  - ja
---

# 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

```python
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

```python
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