annotate libaf/af_hrtf.c @ 14091:08ad36d32696

synced to 1.17
author gabrov
date Fri, 03 Dec 2004 00:41:35 +0000
parents be8f4abbe960
children 3c56b18bbb0c
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) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
111 af_msg(AF_MSG_ERROR,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
112 "[hrtf] ERROR: Sampling rate is not 48000 Hz (%d)!\n",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
113 af->data->rate);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
114 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
115 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
116 af->data->nch = ((af_data_t*)arg)->nch;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
117 if(af->data->nch < 5) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
118 af_msg(AF_MSG_ERROR,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
119 "[hrtf] ERROR: Insufficient channels (%d < 5).\n",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
120 af->data->nch);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
121 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
122 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
123 af->data->format = AF_FORMAT_SI | AF_FORMAT_NE;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
124 af->data->bps = 2;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
125 return AF_OK;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
126 case AF_CONTROL_COMMAND_LINE:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
127 sscanf((char*)arg, "%c", &mode);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
128 switch(mode) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
129 case 'm':
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
130 s->matrix_mode = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
131 break;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
132 case '0':
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
133 s->matrix_mode = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
134 break;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
135 default:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
136 af_msg(AF_MSG_ERROR,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
137 "[hrtf] Mode is neither 'm', nor '0' (%c).\n",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
138 mode);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
139 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
140 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
141 return AF_OK;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
142 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
143
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
144 af_msg(AF_MSG_INFO,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
145 "[hrtf] Using HRTF to mix %s discrete surround into "
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
146 "L, R channels\n", s->matrix_mode ? "5" : "5+1");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
147 if(s->matrix_mode)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
148 af_msg(AF_MSG_INFO,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
149 "[hrtf] Using active matrix to decode rear center "
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
150 "channel\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
151
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
152 return AF_UNKNOWN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
153 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
154
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
155 /* Deallocate memory */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
156 static void uninit(struct af_instance_s *af)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
157 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
158 if(af->setup) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
159 af_hrtf_t *s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
160
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
161 if(s->lf)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
162 free(s->lf);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
163 if(s->rf)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
164 free(s->rf);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
165 if(s->lr)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
166 free(s->lr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
167 if(s->rr)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
168 free(s->rr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
169 if(s->cf)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
170 free(s->cf);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
171 if(s->cr)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
172 free(s->cr);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
173 if(s->ba_l)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
174 free(s->ba_l);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
175 if(s->ba_r)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
176 free(s->ba_r);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
177 if(s->ba_ir)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
178 free(s->ba_ir);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
179 free(af->setup);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
180 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
181 if(af->data)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
182 free(af->data);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
183 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
184
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
185 /* Filter data through filter
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
186
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
187 Two "tricks" are used to compensate the "color" of the KEMAR data:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
188
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
189 1. The KEMAR data is refiltered to ensure that the front L, R channels
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
190 on the same side of the ear are equalized (especially in the high
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
191 frequencies).
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
192
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
193 2. A bass compensation is introduced to ensure that 0-200 Hz are not
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
194 damped (without any real 3D acoustical image, however).
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
195 */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
196 static af_data_t* play(struct af_instance_s *af, af_data_t *data)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
197 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
198 af_hrtf_t *s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
199 short *in = data->audio; // Input audio data
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
200 short *out = NULL; // Output audio data
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
201 short *end = in + data->len / sizeof(short); // Loop end
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
202 float common, left, right, diff, left_b, right_b;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
203 const int dblen = s->dlbuflen, hlen = s->hrflen, blen = s->basslen;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
204
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
205 if(AF_OK != RESIZE_LOCAL_BUFFER(af, data))
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
206 return NULL;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
207
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
208 out = af->data->audio;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
209
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
210 /* MPlayer's 5 channel layout (notation for the variable):
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
211 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
212 * 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
213 * encoded: Cs (CR)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
214 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
215 * or: L = left, C = center, R = right, F = front, R = rear
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
216 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
217 * Filter notation:
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
218 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
219 * CF
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
220 * OF AF
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
221 * Ear->
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
222 * OR AR
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
223 * CR
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
224 *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
225 * or: C = center, A = same side, O = opposite, F = front, R = rear
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
226 */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
227
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
228 while(in < end) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
229 const int k = s->cyc_pos;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
230
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
231 update_ch(s, in, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
232
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
233 /* Simulate a 7.5 ms -20 dB echo of the center channel in the
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
234 front channels (like reflection from a room wall) - a kind of
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
235 psycho-acoustically "cheating" to focus the center front
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
236 channel, which is normally hard to be perceived as front */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
237 s->lf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
238 s->rf[k] += CFECHOAMPL * s->cf[(k + CFECHODELAY) % s->dlbuflen];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
239
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
240 /* Mixer filter matrix */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
241 common = conv(dblen, hlen, s->cf, s->cf_ir, k + s->cf_o);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
242 if(s->matrix_mode) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
243 /* In matrix decoding mode, the rear channel gain must be
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
244 renormalized, as there is an additional channel. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
245 matrix_decode_cr(s, in, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
246 common +=
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
247 conv(dblen, hlen, s->cr, s->cr_ir, k + s->cr_o) *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
248 M1_76DB;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
249 left =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
250 ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
251 conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
252 (conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
253 conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o)) *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
254 M1_76DB + common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
255 right =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
256 ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
257 conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
258 (conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
259 conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o)) *
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
260 M1_76DB + common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
261 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
262 else {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
263 left =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
264 ( conv(dblen, hlen, s->lf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
265 conv(dblen, hlen, s->rf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
266 conv(dblen, hlen, s->lr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
267 conv(dblen, hlen, s->rr, s->or_ir, k + s->or_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
268 common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
269 right =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
270 ( conv(dblen, hlen, s->rf, s->af_ir, k + s->af_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
271 conv(dblen, hlen, s->lf, s->of_ir, k + s->of_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
272 conv(dblen, hlen, s->rr, s->ar_ir, k + s->ar_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
273 conv(dblen, hlen, s->lr, s->or_ir, k + s->or_o) +
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
274 common);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
275 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
276
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
277 /* Bass compensation for the lower frequency cut of the HRTF. A
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
278 cross talk of the left and right channel is introduced to
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
279 match the directional characteristics of higher frequencies.
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
280 The bass will not have any real 3D perception, but that is
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
281 OK. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
282 left_b = conv(dblen, blen, s->ba_l, s->ba_ir, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
283 right_b = conv(dblen, blen, s->ba_r, s->ba_ir, k);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
284 left += (1 - BASSCROSS) * left_b + BASSCROSS * right_b;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
285 right += (1 - BASSCROSS) * right_b + BASSCROSS * left_b;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
286 /* Also mix the LFE channel (if available) */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
287 if(af->data->nch >= 6) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
288 left += out[5] * M3_01DB;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
289 right += out[5] * M3_01DB;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
290 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
291
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
292 /* Amplitude renormalization. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
293 left *= AMPLNORM;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
294 right *= AMPLNORM;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
295
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
296 /* "Cheating": linear stereo expansion to amplify the 3D
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
297 perception. Note: Too much will destroy the acoustic space
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
298 and may even result in headaches. */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
299 diff = STEXPAND2 * (left - right);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
300 out[0] = (int16_t)(left + diff);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
301 out[1] = (int16_t)(right - diff);
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
302
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
303 /* The remaining channels are not needed any more */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
304 out[2] = out[3] = out[4] = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
305 if(af->data->nch >= 6)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
306 out[5] = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
307
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
308 /* Next sample... */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
309 in = &in[data->nch];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
310 out = &out[af->data->nch];
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
311 (s->cyc_pos)--;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
312 if(s->cyc_pos < 0)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
313 s->cyc_pos += dblen;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
314 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
315
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
316 /* Set output data */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
317 data->audio = af->data->audio;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
318 data->len = (data->len * af->mul.n) / af->mul.d;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
319 data->nch = af->data->nch;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
320
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
321 return data;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
322 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
323
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
324 static int allocate(af_hrtf_t *s)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
325 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
326 if ((s->lf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
327 if ((s->rf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
328 if ((s->lr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
329 if ((s->rr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
330 if ((s->cf = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
331 if ((s->cr = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
332 if ((s->ba_l = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
333 if ((s->ba_r = malloc(s->dlbuflen * sizeof(float))) == NULL) return -1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
334 return 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
335 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
336
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
337 /* Allocate memory and set function pointers */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
338 static int open(af_instance_t* af)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
339 {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
340 int i;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
341 af_hrtf_t *s;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
342 float fc;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
343
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
344 af_msg(AF_MSG_INFO,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
345 "[hrtf] Head related impulse response (HRIR) derived from KEMAR measurement\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
346 "[hrtf] data by Bill Gardner <billg@media.mit.edu>\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
347 "[hrtf] and Keith Martin <kdm@media.mit.edu>.\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
348 "[hrtf] This data is Copyright 1994 by the MIT Media Laboratory. It is\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
349 "[hrtf] provided free with no restrictions on use, provided the authors are\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
350 "[hrtf] cited when the data is used in any research or commercial application.\n"
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
351 "[hrtf] URL: http://sound.media.mit.edu/KEMAR.html\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
352
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
353 af->control = control;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
354 af->uninit = uninit;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
355 af->play = play;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
356 af->mul.n = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
357 af->mul.d = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
358 af->data = calloc(1, sizeof(af_data_t));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
359 af->setup = calloc(1, sizeof(af_hrtf_t));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
360 if((af->data == NULL) || (af->setup == NULL))
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
361 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
362
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
363 s = af->setup;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
364
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
365 s->dlbuflen = DELAYBUFLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
366 s->hrflen = HRTFFILTLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
367 s->basslen = BASSFILTLEN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
368
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
369 s->cyc_pos = s->dlbuflen - 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
370 s->matrix_mode = 1;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
371
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
372 if (allocate(s) != 0) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
373 af_msg(AF_MSG_ERROR, "[hrtf] Memory allocation error.\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
374 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
375 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
376
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
377 for(i = 0; i < s->dlbuflen; i++)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
378 s->lf[i] = s->rf[i] = s->lr[i] = s->rr[i] = s->cf[i] =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
379 s->cr[i] = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
380
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
381 s->lr_fwr =
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
382 s->rr_fwr = 0;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
383
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
384 s->cf_ir = cf_filt + (s->cf_o = pulse_detect(cf_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
385 s->af_ir = af_filt + (s->af_o = pulse_detect(af_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
386 s->of_ir = of_filt + (s->of_o = pulse_detect(of_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
387 s->ar_ir = ar_filt + (s->ar_o = pulse_detect(ar_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
388 s->or_ir = or_filt + (s->or_o = pulse_detect(or_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
389 s->cr_ir = cr_filt + (s->cr_o = pulse_detect(cr_filt));
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
390
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
391 if((s->ba_ir = malloc(s->basslen * sizeof(float))) == NULL) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
392 af_msg(AF_MSG_ERROR, "[hrtf] Memory allocation error.\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
393 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
394 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
395 fc = 2.0 * BASSFILTFREQ / (float)af->data->rate;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
396 if(design_fir(s->basslen, s->ba_ir, &fc, LP | KAISER, 4 * M_PI) ==
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
397 -1) {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
398 af_msg(AF_MSG_ERROR, "[hrtf] Unable to design low-pass "
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
399 "filter.\n");
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
400 return AF_ERROR;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
401 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
402 for(i = 0; i < s->basslen; i++)
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
403 s->ba_ir[i] *= BASSGAIN;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
404
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
405 return AF_OK;
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
406 }
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
407
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
408 /* Description of this filter */
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
409 af_info_t af_info_hrtf = {
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
410 "HRTF Headphone",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
411 "hrtf",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
412 "ylai",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
413 "",
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
414 AF_FLAGS_REENTRANT,
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
415 open
be8f4abbe960 head related transfer function
henry
parents:
diff changeset
416 };