SAF
Loading...
Searching...
No Matches
saf_hrir.c
Go to the documentation of this file.
1/*
2 * Copyright 2016-2018 Leo McCormack
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
32#include "saf_hrir.h"
34#include "saf_externals.h"
35
36/* ========================================================================== */
37/* Main Functions */
38/* ========================================================================== */
39
41(
42 float* hrirs /* N_dirs x NUM_EARS x hrir_len */,
43 int N_dirs,
44 int hrir_len,
45 int fs,
46 float* itds_s
47)
48{
49 int i, n, j, k, maxIdx, xcorr_len;
50 float maxVal, itd_bounds, fc, Q, K, KK, D, wn, Wz1[2], Wz2[2], b[3], a[3];
51 float* xcorr_LR, *ir_L, *ir_R, *hrir_lpf;
52
53 /* calculate LPF coefficients, 2nd order IIR design equations from DAFX (2nd ed) p50 */
54 fc = 750.0f;
55 Q = 0.7071f;
56 K = tanf(SAF_PI * fc/(float)fs);
57 KK = K * K;
58 D = KK * Q + K + Q;
59 b[0] = (KK * Q) / D; b[1] = (2.0f * KK * Q) / D; b[2] = (KK * Q) / D;
60 a[0] = 1.0f; a[1] = (2.0f * Q * (KK - 1.0f)) / D; a[2] = (KK * Q - K + Q) / D;
61
62 /* determine the ITD via the cross-correlation between the LPF'd left and right HRIR signals */
63 xcorr_len = 2*(hrir_len)-1;
64 itd_bounds = sqrtf(2.0f)/2e3f;
65 xcorr_LR = (float*)malloc1d(xcorr_len*sizeof(float));
66 ir_L = (float*)malloc1d(hrir_len*sizeof(float));
67 ir_R = (float*)malloc1d(hrir_len*sizeof(float));
68 hrir_lpf = (float*)malloc1d(hrir_len*2*sizeof(float));
69 for(i=0; i<N_dirs; i++){
70 /* apply lpf */
71 memset(Wz1, 0, 2*sizeof(float));
72 memset(Wz2, 0, 2*sizeof(float));
73 for (n=0; n<hrir_len; n++){
74 for(j=0; j<NUM_EARS; j++){
75 /* biquad difference equation (Direct form 2) */
76 wn = hrirs[i*NUM_EARS*hrir_len + j*hrir_len + n] - a[1] * Wz1[j] - a[2] * Wz2[j];
77 hrir_lpf[n*2+j] = b[0] * wn + b[1]*Wz1[j] + b[2]*Wz2[j];
78
79 /* shuffle delays */
80 Wz2[j] = Wz1[j];
81 Wz1[j] = wn;
82 }
83 }
84
85 /* xcorr between L and R */
86 for(k=0; k<hrir_len; k++){
87 ir_L[k] = hrir_lpf[k*2+0];
88 ir_R[k] = hrir_lpf[k*2+1];
89 }
90 cxcorr(ir_L, ir_R, xcorr_LR, hrir_len, hrir_len);
91 maxIdx = 0;
92 maxVal = 0.0f;
93 for(j=0; j<xcorr_len; j++){
94 if(xcorr_LR[j] > maxVal){
95 maxIdx = j;
96 maxVal = xcorr_LR[j];
97 }
98 }
99 itds_s[i] = ((float)hrir_len-(float)maxIdx-1.0f)/(float)fs;
100 itds_s[i] = itds_s[i] > itd_bounds ? itd_bounds : itds_s[i];
101 itds_s[i] = itds_s[i] < -itd_bounds ? -itd_bounds : itds_s[i];
102 }
103
104 free(xcorr_LR);
105 free(ir_L);
106 free(ir_R);
107 free(hrir_lpf);
108}
109
111(
112 float* hrirs, /* N_dirs x NUM_EARS x hrir_len */
113 int N_dirs,
114 int hrir_len,
115 int hopsize,
116 int LDmode,
117 int hybridmode,
118 float_complex* hrtf_fb /* nBands x NUM_EARS x N_dirs */
119)
120{
121 /* convert the HRIRs to filterbank coefficients */
122 afSTFT_FIRtoFilterbankCoeffs(hrirs, N_dirs, NUM_EARS, hrir_len, hopsize, LDmode, hybridmode, hrtf_fb);
123}
124
126(
127 float* hrirs, /* N_dirs x NUM_EARS x hrir_len */
128 int N_dirs,
129 int hrir_len,
130 int hopsize,
131 int hybridmode,
132 float_complex* hrtf_fb /* nBands x NUM_EARS x N_dirs */
133)
134{
135 /* convert the HRIRs to filterbank coefficients */
136 qmf_FIRtoFilterbankCoeffs(hrirs, N_dirs, NUM_EARS, hrir_len, hopsize, hybridmode, hrtf_fb);
137}
138
140(
141 float* hrirs, /* N_dirs x NUM_EARS x hrir_len */
142 int N_dirs,
143 int hrir_len,
144 int fftSize,
145 float_complex* hrtfs /* (fftSize/2+1) x NUM_EARS x N_dirs */
146)
147{
148 int i, j, k, nBins;
149 void* hSafFFT;
150 float* hrir_pad;
151 float_complex* hrtf;
152
153 //TODO: if fftSize is shorter than hrir_len, maybe truncate based on the median peak?
154 /* Perform FFT */
155 nBins = fftSize/2 + 1;
156 saf_rfft_create(&hSafFFT, fftSize);
157 hrir_pad = calloc1d(fftSize, sizeof(float));
158 hrtf = malloc1d(nBins*sizeof(float_complex));
159 for(i=0; i<N_dirs; i++){
160 for(j=0; j<NUM_EARS; j++){
161 memcpy(hrir_pad, &hrirs[i*NUM_EARS*hrir_len+j*hrir_len], SAF_MIN(fftSize, hrir_len)*sizeof(float));
162 saf_rfft_forward(hSafFFT, hrir_pad, hrtf);
163 for(k=0; k<nBins; k++)
164 hrtfs[k*NUM_EARS*N_dirs + j*N_dirs + i] = hrtf[k];
165 }
166 }
167
168 saf_rfft_destroy(&hSafFFT);
169 free(hrir_pad);
170 free(hrtf);
171}
172
174(
175 int N_dirs,
176 float* itds_s,
177 float* centreFreq,
178 int N_bands,
179 float* weights,
180 int applyEQ,
181 int applyPhase,
182 float_complex* hrtfs /* N_bands x #NUM_EARS x N_dirs */
183)
184{
185 /* Anything to do at all? */
186 if(applyEQ + applyPhase)
187 {
188 int i, j, nd, band;
189 float* ipd, *hrtf_diff, *_weights;
190
191 /* diffuse-field equalise */
192 if(applyEQ){
193 hrtf_diff = calloc1d(N_bands*NUM_EARS, sizeof(float));
194 if(weights == NULL){
195 _weights = malloc1d(N_dirs*sizeof(float));
196 for(int idx=0; idx < N_dirs; idx++)
197 _weights[idx] = 4.f*SAF_PI / (float)N_dirs;
198 }
199 else
200 _weights = weights;
201 for(band=0; band<N_bands; band++)
202 for(i=0; i<NUM_EARS; i++)
203 for(j=0; j<N_dirs; j++)
204 hrtf_diff[band*NUM_EARS + i] += _weights[j]/(4.f*SAF_PI) * powf(cabsf(hrtfs[band*NUM_EARS*N_dirs + i*N_dirs + j]), 2.0f);
205 for(band=0; band<N_bands; band++)
206 for(i=0; i<NUM_EARS; i++)
207 hrtf_diff[band*NUM_EARS + i] = sqrtf(SAF_MAX(hrtf_diff[band*NUM_EARS + i], 0.00001f));
208 for(band=0; band<N_bands; band++)
209 for(i=0; i<NUM_EARS; i++)
210 for(nd=0; nd<N_dirs; nd++)
211 hrtfs[band*NUM_EARS*N_dirs + i*N_dirs + nd] = ccdivf(hrtfs[band*NUM_EARS*N_dirs + i*N_dirs + nd], cmplxf(hrtf_diff[band*NUM_EARS + i] + 2.23e-8f, 0.0f));
212 free(hrtf_diff);
213 if(weights==NULL)
214 free(_weights);
215 }
216
217 /* Create complex HRTFs by introducing the interaural phase differences
218 * (IPDs) to the HRTF magnitude responses */
219 if(applyPhase){
220 /* convert ITDs to phase differences -pi..pi */
221 ipd = malloc1d(N_bands*N_dirs*sizeof(float));
222 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, N_bands, N_dirs, 1, 1.0,
223 centreFreq, 1,
224 itds_s, 1, 0.0,
225 ipd, N_dirs);
226 for(i=0; i<N_bands; i++)
227 for(j=0; j<N_dirs; j++)
228 ipd[i*N_dirs+j] = (matlab_fmodf(2.0f*SAF_PI*ipd[i*N_dirs+j] + SAF_PI, 2.0f*SAF_PI) - SAF_PI)/2.0f; /* /2 here, not later */
229
230 for(band=0; band<N_bands; band++){
231 for(nd=0; nd<N_dirs; nd++){
232 hrtfs[band*NUM_EARS*N_dirs + 0*N_dirs + nd] = crmulf( cexpf(cmplxf(0.0f, ipd[band*N_dirs + nd])), cabsf(hrtfs[band*NUM_EARS*N_dirs + 0*N_dirs + nd]) );
233 hrtfs[band*NUM_EARS*N_dirs + 1*N_dirs + nd] = crmulf( cexpf(cmplxf(0.0f,-ipd[band*N_dirs + nd])), cabsf(hrtfs[band*NUM_EARS*N_dirs + 1*N_dirs + nd]) );
234 }
235 }
236 free(ipd);
237 }
238 }
239}
240
242(
243 float_complex* hrtfs, /* N_bands x 2 x N_hrtf_dirs */
244 float* itds,
245 float* freqVector,
246 float* interp_table,
247 int N_hrtf_dirs,
248 int N_bands,
249 int N_interp_dirs,
250 float_complex* hrtfs_interp /* pre-alloc, N_bands x 2 x N_interp_dirs */
251)
252{
253 int i, band;
254 float* itd_interp, *mags_interp, *ipd_interp;
255 float** mags;
256 float_complex* interp_table_cmplx;
257 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
258
259 if(itds==NULL || freqVector==NULL){
260 /* prep */
261 interp_table_cmplx = calloc1d(N_interp_dirs*N_hrtf_dirs, sizeof(float_complex));
262 cblas_scopy(N_interp_dirs*N_hrtf_dirs, interp_table, 1, (float*)interp_table_cmplx, 2);
263
264 /* interpolate HRTF spectra */
265 for(band=0; band<N_bands; band++){
266 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasTrans, NUM_EARS, N_interp_dirs, N_hrtf_dirs, &calpha,
267 &hrtfs[band*NUM_EARS*N_hrtf_dirs], N_hrtf_dirs,
268 interp_table_cmplx, N_hrtf_dirs, &cbeta,
269 &hrtfs_interp[band*NUM_EARS*N_interp_dirs], N_interp_dirs);
270 }
271
272 /* clean-up */
273 free(interp_table_cmplx);
274 }
275 else{
276 /* prep */
277 mags = (float**)malloc1d(N_bands*sizeof(float*));
278 itd_interp = malloc1d(N_interp_dirs*sizeof(float));
279 mags_interp = malloc1d(N_interp_dirs*NUM_EARS*sizeof(float));
280 ipd_interp = malloc1d(N_interp_dirs*sizeof(float));
281
282 /* calculate HRTF magnitudes */
283 for(band=0; band<N_bands; band++){
284 mags[band] = malloc1d(NUM_EARS * N_hrtf_dirs*sizeof(float));
285 for(i=0; i< NUM_EARS * N_hrtf_dirs ; i++)
286 mags[band][i] = cabsf(hrtfs[band*NUM_EARS * N_hrtf_dirs + i]);
287 }
288
289 /* interpolate ITDs */
290 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, N_interp_dirs, 1, N_hrtf_dirs, 1.0f,
291 interp_table, N_hrtf_dirs,
292 itds, 1, 0.0f,
293 itd_interp, 1);
294 for(band=0; band<N_bands; band++){
295 /* interpolate HRTF magnitudes */
296 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, N_interp_dirs, NUM_EARS, N_hrtf_dirs, 1.0f,
297 interp_table, N_hrtf_dirs,
298 mags[band], N_hrtf_dirs, 0.0f,
299 mags_interp, NUM_EARS);
300
301 /* convert ITDs to phase differences -pi..pi */
302 for(i=0; i<N_interp_dirs; i++)
303 ipd_interp[i] = (matlab_fmodf(2.0f*SAF_PI*freqVector[band]*itd_interp[i] + SAF_PI, 2.0f*SAF_PI) - SAF_PI)/2.0f; /* /2 here, not later */
304
305 /* reintroduce the interaural phase differences (IPD) */
306 for(i=0; i<N_interp_dirs; i++){
307 hrtfs_interp[band*NUM_EARS*N_interp_dirs + 0* N_interp_dirs +i] = ccmulf( cmplxf(mags_interp[i*NUM_EARS+0],0.0f), cexpf(cmplxf(0.0f, ipd_interp[i])) );
308 hrtfs_interp[band*NUM_EARS*N_interp_dirs + 1* N_interp_dirs +i] = ccmulf( cmplxf(mags_interp[i*NUM_EARS+1],0.0f), cexpf(cmplxf(0.0f,-ipd_interp[i])) );
309 }
310 }
311
312 /* clean-up */
313 free(itd_interp);
314 for(band=0; band<N_bands; band++)
315 free(mags[band]);
316 free(mags);
317 free(mags_interp);
318 free(ipd_interp);
319 }
320}
321
323(
324 float_complex* hrtfs, /* N_bands x 2 x N_hrtf_dirs */
325 float* itds,
326 float* freqVector,
327 int N_hrtf_dirs,
328 int N_bands,
329 float* HRTFcoh
330)
331{
332 int i, j;
333 float* ipd;
334 float_complex *hrtf_ipd_lr;
335
336 /* convert ITDs to phase differences -pi..pi */
337 ipd = malloc1d(N_bands*N_hrtf_dirs*sizeof(float));
338 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasTrans, N_bands, N_hrtf_dirs, 1, 1.0,
339 freqVector, 1,
340 itds, 1, 0.0,
341 ipd, N_hrtf_dirs);
342 for(i=0; i<N_bands; i++)
343 for(j=0; j<N_hrtf_dirs; j++)
344 ipd[i*N_hrtf_dirs+j] = (matlab_fmodf(2.0f*SAF_PI*ipd[i*N_hrtf_dirs+j] + SAF_PI, 2.0f*SAF_PI) - SAF_PI);
345
346 /* compute complex coherence */
347 hrtf_ipd_lr = calloc1d(N_bands, sizeof(float_complex));
348 for(i=0; i<N_bands; i++){
349 for(j=0; j<N_hrtf_dirs; j++)
350 hrtf_ipd_lr[i] = ccaddf(hrtf_ipd_lr[i], crmulf(cexpf(crmulf(cmplxf(0.0f, 1.0f), ipd[i*N_hrtf_dirs+j])),
351 cabsf(hrtfs[i*NUM_EARS*N_hrtf_dirs + 0*N_hrtf_dirs + j])*
352 cabsf(hrtfs[i*NUM_EARS*N_hrtf_dirs + 1*N_hrtf_dirs + j])));
353 hrtf_ipd_lr[i] = ccdivf(hrtf_ipd_lr[i], cmplxf((float)N_hrtf_dirs, 0.0f));
354 }
355
356 /* due to almost axisymmetry of ITD, the coherence is almost real */
357 for(i=0; i<N_bands; i++)
358 HRTFcoh[i] = crealf(hrtf_ipd_lr[i]) < 0.0f ? 0.0f : crealf(hrtf_ipd_lr[i]);
359 HRTFcoh[0] = 1.0f; /* force 1 at DC */
360
361 free(ipd);
362 free(hrtf_ipd_lr);
363}
364
366(
367 float* hrirs_in,
368 int hrirs_N_dirs,
369 int hrirs_in_len,
370 int hrirs_in_fs,
371 int hrirs_out_fs,
372 int padToNextPow2,
373 float** hrirs_out,
374 int* hrirs_out_len
375)
376{
377 int ch, hrirs_out_ld;
378 float resample_factor;
379#if defined(SAF_USE_INTEL_IPP) && 0 /* works fine on macOS, but not on MSVC. Not tried Linux. Use SPEEX for now... */
380 Ipp64f pTime;
381 const int history = 128;
382 float *inBuffer, *outBuffer;
383 int filterLength, pSize, numFilters, outL;
384 IppStatus error;
385#else
386 unsigned int in_length, out_length;
387 int ERROR_VAL, out_latency, nsample_proc;
388 float *zeros;
389 SpeexResamplerState *pRS;
390#endif
391
392 /* New HRIR length */
393 resample_factor = (float)hrirs_out_fs / (float)hrirs_in_fs;
394 (*hrirs_out_len) = (int)ceilf((float)hrirs_in_len * resample_factor);
395 hrirs_out_ld = padToNextPow2 ? (int)pow(2.0, ceil(log((double)(*hrirs_out_len))/log(2.0))) : (*hrirs_out_len);
396
397#if defined(SAF_USE_INTEL_IPP) && 0 /* works fine on macOS, but not on MSVC. Not tried Linux. Use SPEEX for now... */
398 /* Initialise IPP resampler */
399 error = ippsResamplePolyphaseFixedGetSize_32f(hrirs_in_fs, hrirs_out_fs, 2*(history-1), &pSize, &filterLength, &numFilters, ippAlgHintFast);
400 saf_assert(!error, "IPP error");
401 IppsResamplingPolyphaseFixed_32f* spec;
402 spec = (IppsResamplingPolyphaseFixed_32f*)ippsMalloc_8u(pSize);
403 error = ippsResamplePolyphaseFixedInit_32f(hrirs_in_fs, hrirs_out_fs, 2*(history-1), 0.98f, 12.0f, spec, ippAlgHintFast);
404 saf_assert(!error, "IPP error");
405 inBuffer = ippsMalloc_32f(hrirs_in_len + history * 2 + 2);
406 outBuffer = ippsMalloc_32f(hrirs_out_ld + 2);
407 ippsZero_32f(inBuffer, hrirs_in_len + history * 2 + 2);
408
409 /* Apply IPP resampler */
410 (*hrirs_out) = calloc1d(hrirs_N_dirs*NUM_EARS*(hrirs_out_ld), sizeof(float));
411 for(ch=0; ch<hrirs_N_dirs*NUM_EARS; ch++){
412 pTime = history;
413 outL = 0;
414
415 /* Apply resampling */
416 ippsCopy_32f(hrirs_in + ch * hrirs_in_len, inBuffer + history, hrirs_in_len);
417 saf_assert(!ippsResamplePolyphaseFixed_32f(inBuffer, hrirs_in_len, outBuffer, 1.0f, &pTime, &outL, spec), "IPP error");
418 saf_assert(hrirs_out_ld==outL, "Not all samples were processed!");
419 ippsCopy_32f(outBuffer, (*hrirs_out) + ch * (hrirs_out_ld), hrirs_out_ld);
420 }
421
422 (*hrirs_out_len) = hrirs_out_ld;
423
424 /* Clean-up */
425 ippsFree(spec);
426 ippsFree(inBuffer);
427 ippsFree(outBuffer);
428
429#else
430 /* Initialise SPEEX resampler */
431 pRS = speex__resampler_init(1 /*one channel at a time*/, hrirs_in_fs, hrirs_out_fs, SPEEX_RESAMPLER_QUALITY_MAX, &ERROR_VAL);
432 out_latency = speex__resampler_get_output_latency(pRS);
433 zeros = calloc1d(out_latency, sizeof(float));
434
435 /* Apply SPEEX resampler */
436 (*hrirs_out) = calloc1d(hrirs_N_dirs*NUM_EARS*(hrirs_out_ld), sizeof(float));
437 for(ch=0; ch<hrirs_N_dirs*NUM_EARS; ch++){
438 speex__resampler_reset_mem(pRS);
439 speex__resampler_skip_zeros(pRS);
440 nsample_proc = 0;
441
442 /* Pass the FIR through the resampler */
443 in_length = hrirs_in_len;
444 out_length = hrirs_out_ld;
445 ERROR_VAL = speex__resampler_process_float((pRS), 0, hrirs_in + ch * hrirs_in_len, &in_length,
446 (*hrirs_out) + ch * (hrirs_out_ld), &out_length);
447 nsample_proc += out_length; /* Current number of output samples processed */
448
449 /* Pass through zeros to get the tail of the filter too */
450 while(nsample_proc<(hrirs_out_ld)){
451 in_length = out_latency;
452 out_length = (hrirs_out_ld)-nsample_proc;
453 ERROR_VAL = speex__resampler_process_float((pRS), 0, zeros, &in_length,
454 (*hrirs_out) + ch * (hrirs_out_ld) + nsample_proc, &out_length);
455 nsample_proc += out_length;
456 }
457 saf_assert(nsample_proc==(hrirs_out_ld), "Not all samples were processed!");
458 }
459
460 (*hrirs_out_len) = hrirs_out_ld;
461
462 /* Clean-up */
463 speex__resampler_destroy(pRS);
464 free(zeros);
465#endif
466}
void afSTFT_FIRtoFilterbankCoeffs(float *hIR, int N_dirs, int nCH, int ir_len, int hopSize, int LDmode, int hybridmode, float_complex *hFB)
Converts FIR filters into Filterbank Coefficients by passing them through the afSTFT filterbank.
Definition afSTFTlib.c:593
void HRIRs2HRTFs(float *hrirs, int N_dirs, int hrir_len, int fftSize, float_complex *hrtfs)
Converts HRIRs to HRTFs for a given FFT size.
Definition saf_hrir.c:140
void diffuseFieldEqualiseHRTFs(int N_dirs, float *itds_s, float *centreFreq, int N_bands, float *weights, int applyEQ, int applyPhase, float_complex *hrtfs)
Applies pre-processing to a set of HRTFs, which can either be diffuse-field EQ of an (optionally weig...
Definition saf_hrir.c:174
void resampleHRIRs(float *hrirs_in, int hrirs_N_dirs, int hrirs_in_len, int hrirs_in_fs, int hrirs_out_fs, int padToNextPow2, float **hrirs_out, int *hrirs_out_len)
Resamples a set of HRIRs from its original samplerate to a new samplerate.
Definition saf_hrir.c:366
void interpHRTFs(float_complex *hrtfs, float *itds, float *freqVector, float *interp_table, int N_hrtf_dirs, int N_bands, int N_interp_dirs, float_complex *hrtfs_interp)
Interpolates a set of HRTFs based on a specified interpolation table.
Definition saf_hrir.c:242
void binauralDiffuseCoherence(float_complex *hrtfs, float *itds, float *freqVector, int N_hrtf_dirs, int N_bands, float *HRTFcoh)
Computes the binaural diffuse coherence per frequency for a given HRTF set, as described in [1].
Definition saf_hrir.c:323
void HRIRs2HRTFs_qmf(float *hrirs, int N_dirs, int hrir_len, int hopsize, int hybridmode, float_complex *hrtf_fb)
Passes zero padded HRIRs through the qmf filterbank.
Definition saf_hrir.c:126
void estimateITDs(float *hrirs, int N_dirs, int hrir_len, int fs, float *itds_s)
Estimates the interaural time-differences (ITDs) for each HRIR based on the cross-correlation between...
Definition saf_hrir.c:41
void HRIRs2HRTFs_afSTFT(float *hrirs, int N_dirs, int hrir_len, int hopsize, int LDmode, int hybridmode, float_complex *hrtf_fb)
Passes zero padded HRIRs through the afSTFT filterbank.
Definition saf_hrir.c:111
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
#define SAF_PI
pi constant (single precision)
void qmf_FIRtoFilterbankCoeffs(float *hIR, int N_dirs, int nCH, int ir_len, int hopSize, int hybridmode, float_complex *hFB)
Converts FIR filters into Filterbank Coefficients by passing them through the QMF filterbank.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
#define NUM_EARS
2 (true for most humans)
float matlab_fmodf(float x, float y)
C fmodf function, except it behaves like 'mod' in Matlab (i.e.
void cxcorr(float *a, float *b, float *x_ab, size_t la, size_t lb)
Calculates the cross correlation between two vectors.
void saf_rfft_create(void **const phFFT, int N)
Creates an instance of saf_rfft; real<->half-complex (conjugate-symmetric) FFT.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
void saf_rfft_forward(void *const hFFT, float *inputTD, float_complex *outputFD)
Performs the forward-FFT operation; use for real to complex (conjugate symmetric) transformations.
void saf_rfft_destroy(void **const phFFT)
Destroys an instance of saf_rfft.
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void * calloc1d(size_t dim1, size_t data_size)
1-D calloc (same as calloc, but with error checking)
Definition md_malloc.c:69
Include header for SAF externals.
Main header for the HRIR/HRTF processing module (SAF_HRIR_MODULE)
Main header for the utilities module (SAF_UTILITIES_MODULE)