annotate libaf/af_hrtf.c @ 14213:3c56b18bbb0c

Make filters request a supported input format instead of failing.
author reimar
date Wed, 22 Dec 2004 00:12:00 +0000
parents be8f4abbe960
children 815f03b7cee5
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
13996
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
1 /* Experimental audio filter that mixes 5.1 and 5.1 with matrix
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
2 encoded rear channels into headphone signal using FIR filtering
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
3 with HRTF.
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
4 */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
5 //#include <stdio.h>
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
6 #include <stdlib.h>
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
7 #include <string.h>
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
8 #include <unistd.h>
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
9 #include <inttypes.h>
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
10
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
11 #include <math.h>
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
12
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
13 #include "af.h"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
14 #include "dsp.h"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
15
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
16 /* HRTF filter coefficients and adjustable parameters */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
17 #include "af_hrtf.h"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
18
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
19 typedef struct af_hrtf_s {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
20 /* Lengths */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
21 int dlbuflen, hrflen, basslen;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
22 /* L, C, R, Ls, Rs channels */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
23 float *lf, *rf, *lr, *rr, *cf, *cr;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
24 float *cf_ir, *af_ir, *of_ir, *ar_ir, *or_ir, *cr_ir;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
25 int cf_o, af_o, of_o, ar_o, or_o, cr_o;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
26 /* Bass */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
27 float *ba_l, *ba_r;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
28 float *ba_ir;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
29 /* Whether to matrix decode the rear center channel */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
30 int matrix_mode;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
31 /* Full wave rectified amplitude used to steer the active matrix
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
32 decoding of center rear channel */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
33 float lr_fwr, rr_fwr;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
34 /* Cyclic position on the ring buffer */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
35 int cyc_pos;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
36 } af_hrtf_t;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
37
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
38 /* Convolution on a ring buffer
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
39 * nx: length of the ring buffer
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
40 * nk: length of the convolution kernel
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
41 * sx: ring buffer
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
42 * sk: convolution kernel
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
43 * offset: offset on the ring buffer, can be
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
44 */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
45 static float conv(const int nx, const int nk, float *sx, float *sk,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
46 const int offset)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
47 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
48 /* k = reminder of offset / nx */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
49 int k = offset >= 0 ? offset % nx : nx + (offset % nx);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
50
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
51 if(nk + k <= nx)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
52 return fir(nk, sx + k, sk);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
53 else
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
54 return fir(nk + k - nx, sx, sk + nx - k) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
55 fir(nx - k, sx + k, sk);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
56 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
57
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
58 /* Detect when the impulse response starts (significantly) */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
59 int pulse_detect(float *sx)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
60 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
61 /* nmax must be the reference impulse response length (128) minus
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
62 s->hrflen */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
63 const int nmax = 128 - HRTFFILTLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
64 const float thresh = IRTHRESH;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
65 int i;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
66
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
67 for(i = 0; i < nmax; i++)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
68 if(fabs(sx[i]) > thresh)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
69 return i;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
70 return 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
71 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
72
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
73 inline void update_ch(af_hrtf_t *s, short *in, const int k)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
74 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
75 /* Update the full wave rectified total amplutude */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
76 s->lr_fwr += abs(in[2]) - fabs(s->lr[k]);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
77 s->rr_fwr += abs(in[3]) - fabs(s->rr[k]);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
78
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
79 s->lf[k] = in[0];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
80 s->cf[k] = in[4];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
81 s->rf[k] = in[1];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
82 s->lr[k] = in[2];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
83 s->rr[k] = in[3];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
84
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
85 s->ba_l[k] = in[0] + in[4] + in[2];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
86 s->ba_r[k] = in[4] + in[1] + in[3];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
87 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
88
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
89 inline void matrix_decode_cr(af_hrtf_t *s, short *in, const int k)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
90 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
91 /* Active matrix decoding of the center rear channel, 1 in the
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
92 denominator is to prevent singularity */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
93 float lr_agc = in[2] * (s->lr_fwr + s->rr_fwr) /
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
94 (1 + s->lr_fwr + s->lr_fwr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
95 float rr_agc = in[3] * (s->lr_fwr + s->rr_fwr) /
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
96 (1 + s->rr_fwr + s->rr_fwr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
97
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
98 s->cr[k] = (lr_agc + rr_agc) * M_SQRT1_2;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
99 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
100
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
101 /* Initialization and runtime control */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
102 static int control(struct af_instance_s *af, int cmd, void* arg)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
103 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
104 af_hrtf_t *s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
105 char mode;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
106
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
107 switch(cmd) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
108 case AF_CONTROL_REINIT:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
109 af->data->rate = ((af_data_t*)arg)->rate;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
110 if(af->data->rate != 48000) {
14213
3c56b18bbb0c Make filters request a supported input format instead of failing.
reimar
parents: 13996
diff changeset
111 // automatic samplerate adjustment in the filter chain
3c56b18bbb0c Make filters request a supported input format instead of failing.
reimar
parents: 13996
diff changeset
112 // is not yet supported.
13996
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
113 af_msg(AF_MSG_ERROR,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
114 "[hrtf] ERROR: Sampling rate is not 48000 Hz (%d)!\n",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
115 af->data->rate);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
116 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
117 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
118 af->data->nch = ((af_data_t*)arg)->nch;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
119 if(af->data->nch < 5) {
14213
3c56b18bbb0c Make filters request a supported input format instead of failing.
reimar
parents: 13996
diff changeset
120 af->data->nch = 5;
13996
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
121 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
122 af->data->format = AF_FORMAT_SI | AF_FORMAT_NE;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
123 af->data->bps = 2;
14213
3c56b18bbb0c Make filters request a supported input format instead of failing.
reimar
parents: 13996
diff changeset
124 return af_test_output(af, (af_data_t*)arg);
13996
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
125 case AF_CONTROL_COMMAND_LINE:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
126 sscanf((char*)arg, "%c", &mode);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
127 switch(mode) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
128 case 'm':
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
129 s->matrix_mode = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
130 break;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
131 case '0':
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
132 s->matrix_mode = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
133 break;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
134 default:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
135 af_msg(AF_MSG_ERROR,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
136 "[hrtf] Mode is neither 'm', nor '0' (%c).\n",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
137 mode);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
138 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
139 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
140 return AF_OK;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
141 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
142
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
143 af_msg(AF_MSG_INFO,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
144 "[hrtf] Using HRTF to mix %s discrete surround into "
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
145 "L, R channels\n", s->matrix_mode ? "5" : "5+1");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
146 if(s->matrix_mode)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
147 af_msg(AF_MSG_INFO,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
148 "[hrtf] Using active matrix to decode rear center "
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
149 "channel\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
150
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
151 return AF_UNKNOWN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
152 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
153
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
154 /* Deallocate memory */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
155 static void uninit(struct af_instance_s *af)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
156 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
157 if(af->setup) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
158 af_hrtf_t *s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
159
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
160 if(s->lf)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
161 free(s->lf);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
162 if(s->rf)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
163 free(s->rf);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
164 if(s->lr)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
165 free(s->lr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
166 if(s->rr)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
167 free(s->rr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
168 if(s->cf)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
169 free(s->cf);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
170 if(s->cr)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
171 free(s->cr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
172 if(s->ba_l)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
173 free(s->ba_l);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
174 if(s->ba_r)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
175 free(s->ba_r);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
176 if(s->ba_ir)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
177 free(s->ba_ir);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
178 free(af->setup);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
179 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
180 if(af->data)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
181 free(af->data);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
182 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
183
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
184 /* Filter data through filter
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
185
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
186 Two "tricks" are used to compensate the "color" of the KEMAR data:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
187
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
188 1. The KEMAR data is refiltered to ensure that the front L, R channels
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
189 on the same side of the ear are equalized (especially in the high
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
190 frequencies).
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
191
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
192 2. A bass compensation is introduced to ensure that 0-200 Hz are not
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
193 damped (without any real 3D acoustical image, however).
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
194 */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
195 static af_data_t* play(struct af_instance_s *af, af_data_t *data)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
196 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
197 af_hrtf_t *s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
198 short *in = data->audio; // Input audio data
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
199 short *out = NULL; // Output audio data
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
200 short *end = in + data->len / sizeof(short); // Loop end
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
201 float common, left, right, diff, left_b, right_b;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
202 const int dblen = s->dlbuflen, hlen = s->hrflen, blen = s->basslen;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
203
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
204 if(AF_OK != RESIZE_LOCAL_BUFFER(af, data))
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
205 return NULL;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
206
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
207 out = af->data->audio;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
208
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
209 /* MPlayer's 5 channel layout (notation for the variable):
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
210 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
211 * 0: L (LF), 1: R (RF), 2: Ls (LR), 3: Rs (RR), 4: C (CF), matrix
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
212 * encoded: Cs (CR)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
213 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
214 * or: L = left, C = center, R = right, F = front, R = rear
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
215 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
216 * Filter notation:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
217 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
218 * CF
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
219 * OF AF
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
220 * Ear->
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
221 * OR AR
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
222 * CR
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
223 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
224 * or: C = center, A = same side, O = opposite, F = front, R = rear
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
225 */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
226
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
227 while(in < end) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
228 const int k = s->cyc_pos;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
229
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
230 update_ch(s, in, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
231
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
232 /* Simulate a 7.5 ms -20 dB echo of the center channel in the
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
233 front channels (like reflection from a room wall) - a kind of
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
234 psycho-acoustically "cheating" to focus the center front
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
235 channel, which is normally hard to be perceived as front */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
236 s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
237 s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
238
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
239 /* Mixer filter matrix */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
240 common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
241 if(s->matrix_mode) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
242 /* In matrix decoding mode, the rear channel gain must be
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
243 renormalized, as there is an additional channel. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
244 matrix_decode_cr(s, in, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
245 common +=
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
246 conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
247 M1_76DB;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
248 left =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
249 ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
250 conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
251 (conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
252 conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
253 M1_76DB + common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
254 right =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
255 ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
256 conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
257 (conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
258 conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
259 M1_76DB + common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
260 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
261 else {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
262 left =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
263 ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
264 conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
265 conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
266 conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
267 common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
268 right =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
269 ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
270 conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
271 conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
272 conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
273 common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
274 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
275
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
276 /* Bass compensation for the lower frequency cut of the HRTF. A
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
277 cross talk of the left and right channel is introduced to
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
278 match the directional characteristics of higher frequencies.
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
279 The bass will not have any real 3D perception, but that is
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
280 OK. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
281 left_b = conv(dblen, blen, s->ba_l, s->ba_ir, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
282 right_b = conv(dblen, blen, s->ba_r, s->ba_ir, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
283 left += (1 - BASSCROSS) * left_b + BASSCROSS * right_b;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
284 right += (1 - BASSCROSS) * right_b + BASSCROSS * left_b;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
285 /* Also mix the LFE channel (if available) */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
286 if(af->data->nch >= 6) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
287 left += out[5] * M3_01DB;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
288 right += out[5] * M3_01DB;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
289 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
290
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
291 /* Amplitude renormalization. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
292 left *= AMPLNORM;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
293 right *= AMPLNORM;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
294
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
295 /* "Cheating": linear stereo expansion to amplify the 3D
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
296 perception. Note: Too much will destroy the acoustic space
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
297 and may even result in headaches. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
298 diff = STEXPAND2 * (left - right);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
299 out[0] = (int16_t)(left + diff);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
300 out[1] = (int16_t)(right - diff);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
301
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
302 /* The remaining channels are not needed any more */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
303 out[2] = out[3] = out[4] = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
304 if(af->data->nch >= 6)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
305 out[5] = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
306
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
307 /* Next sample... */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
308 in = &in[data->nch];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
309 out = &out[af->data->nch];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
310 (s->cyc_pos)--;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
311 if(s->cyc_pos < 0)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
312 s->cyc_pos += dblen;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
313 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
314
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
315 /* Set output data */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
316 data->audio = af->data->audio;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
317 data->len = (data->len * af->mul.n) / af->mul.d;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
318 data->nch = af->data->nch;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
319
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
320 return data;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
321 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
322
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
323 static int allocate(af_hrtf_t *s)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
324 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
325 if ((s->lf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
326 if ((s->rf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
327 if ((s->lr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
328 if ((s->rr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
329 if ((s->cf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
330 if ((s->cr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
331 if ((s->ba_l = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
332 if ((s->ba_r = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
333 return 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
334 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
335
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
336 /* Allocate memory and set function pointers */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
337 static int open(af_instance_t* af)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
338 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
339 int i;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
340 af_hrtf_t *s;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
341 float fc;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
342
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
343 af_msg(AF_MSG_INFO,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
344 "[hrtf] Head related impulse response (HRIR) derived from KEMAR measurement\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
345 "[hrtf] data by Bill Gardner <billg@media.mit.edu>\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
346 "[hrtf] and Keith Martin <kdm@media.mit.edu>.\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
347 "[hrtf] This data is Copyright 1994 by the MIT Media Laboratory. It is\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
348 "[hrtf] provided free with no restrictions on use, provided the authors are\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
349 "[hrtf] cited when the data is used in any research or commercial application.\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
350 "[hrtf] URL: http://sound.media.mit.edu/KEMAR.html\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
351
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
352 af->control = control;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
353 af->uninit = uninit;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
354 af->play = play;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
355 af->mul.n = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
356 af->mul.d = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
357 af->data = calloc(1, sizeof(af_data_t));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
358 af->setup = calloc(1, sizeof(af_hrtf_t));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
359 if((af->data == NULL) || (af->setup == NULL))
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
360 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
361
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
362 s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
363
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
364 s->dlbuflen = DELAYBUFLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
365 s->hrflen = HRTFFILTLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
366 s->basslen = BASSFILTLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
367
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
368 s->cyc_pos = s->dlbuflen - 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
369 s->matrix_mode = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
370
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
371 if (allocate(s) != 0) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
372 af_msg(AF_MSG_ERROR, "[hrtf] Memory allocation error.\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
373 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
374 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
375
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
376 for(i = 0; i < s->dlbuflen; i++)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
377 s->lf[i] = s->rf[i] = s->lr[i] = s->rr[i] = s->cf[i] =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
378 s->cr[i] = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
379
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
380 s->lr_fwr =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
381 s->rr_fwr = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
382
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
383 s->cf_ir = cf_filt + (s->cf_o = pulse_detect(cf_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
384 s->af_ir = af_filt + (s->af_o = pulse_detect(af_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
385 s->of_ir = of_filt + (s->of_o = pulse_detect(of_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
386 s->ar_ir = ar_filt + (s->ar_o = pulse_detect(ar_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
387 s->or_ir = or_filt + (s->or_o = pulse_detect(or_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
388 s->cr_ir = cr_filt + (s->cr_o = pulse_detect(cr_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
389
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
390 if((s->ba_ir = malloc(s->basslen * sizeof(float))) == NULL) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
391 af_msg(AF_MSG_ERROR, "[hrtf] Memory allocation error.\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
392 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
393 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
394 fc = 2.0 * BASSFILTFREQ / (float)af->data->rate;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
395 if(design_fir(s->basslen, s->ba_ir, &fc, LP | KAISER, 4 * M_PI) ==
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
396 -1) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
397 af_msg(AF_MSG_ERROR, "[hrtf] Unable to design low-pass "
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
398 "filter.\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
399 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
400 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
401 for(i = 0; i < s->basslen; i++)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
402 s->ba_ir[i] *= BASSGAIN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
403
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
404 return AF_OK;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
405 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
406
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
407 /* Description of this filter */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
408 af_info_t af_info_hrtf = {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
409 "HRTF Headphone",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
410 "hrtf",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
411 "ylai",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
412 "",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
413 AF_FLAGS_REENTRANT,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
414 open
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
415 };