SAF
Loading...
Searching...
No Matches
saf_utility_matrixConv.c
Go to the documentation of this file.
1/*
2 * Copyright 2019 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
27#include "saf_utilities.h"
28#include "saf_externals.h"
29
30/* ========================================================================== */
31/* Matrix Convolver */
32/* ========================================================================== */
33
37typedef struct _safMatConv_data {
38 int hopSize, fftSize, nBins;
39 int length_h, nCHin, nCHout;
40 int numFilterBlocks, numOvrlpAddBlocks;
41 int usePartFLAG;
42 void* hFFT;
43 float* x_pad, *y_pad, *hx_n, *z_n, *ovrlpAddBuffer, *y_n_overlap;
44 float_complex* H_f, *X_n, *HX_n;
45 float_complex** Hpart_f;
46
48
50(
51 void ** const phMC,
52 int hopSize,
53 float* H, /* nCHout x nCHin x length_h */
54 int length_h,
55 int nCHin,
56 int nCHout,
57 int usePartFLAG
58)
59{
60 *phMC = malloc1d(sizeof(safMatConv_data));
61 safMatConv_data *h = (safMatConv_data*)(*phMC);
62 int no, ni, nb;
63 float* h_pad, *h_pad_2hops;
64
65 h->hopSize = hopSize;
66 h->length_h = length_h;
67 h->nCHin = nCHin;
68 h->nCHout = nCHout;
69 h->usePartFLAG = usePartFLAG;
70
71 if(!h->usePartFLAG){
72 /* intialise non-partitioned convolution mode */
73 h->numOvrlpAddBlocks = (int)(ceilf((float)(hopSize+length_h-1)/(float)hopSize)+0.1f);
74 //h->numOvrlpAddBlocks = nextpow2((int)(ceilf((float)(hopSize+length_h-1)/(float)hopSize)+0.1f));
75 h->fftSize = (h->numOvrlpAddBlocks)*hopSize;
76 h->nBins = h->fftSize/2 + 1;
77
78 /* Allocate memory for buffers and perform fft on H */
79 h->ovrlpAddBuffer = calloc1d(nCHout*(h->fftSize), sizeof(float));
80 h->x_pad = calloc1d((h->nCHin)*(h->fftSize), sizeof(float)); // CALLOC
81 h->y_pad = malloc1d((h->nCHout)*(h->fftSize)*sizeof(float));
82 h->hx_n = malloc1d((h->fftSize) * sizeof(float));
83 h->H_f = malloc1d((h->nCHout)*(h->nCHin)*(h->nBins)*sizeof(float_complex));
84 h->X_n = malloc1d((h->nCHout)*(h->nCHin)*(h->nBins)*sizeof(float_complex));
85 h->HX_n = malloc1d((h->nCHout)*(h->nCHin)*(h->nBins)*sizeof(float_complex));
86 h->z_n = malloc1d((h->fftSize) * sizeof(float));
87 saf_rfft_create(&(h->hFFT), h->fftSize);
88 h_pad = calloc1d(h->fftSize, sizeof(float));
89 for(no=0; no<nCHout; no++){
90 for(ni=0; ni<nCHin; ni++){
91 memcpy(h_pad, &(H[no*nCHin*length_h+ni*length_h]), length_h*sizeof(float));
92 saf_rfft_forward(h->hFFT, h_pad, &(h->H_f[no*nCHin*(h->nBins)+ni*(h->nBins)]));
93 }
94 }
95 free(h_pad);
96 }
97 else{
98 /* intialise partitioned convolution mode */
99 h->length_h = length_h;
100 h->fftSize = 2*(h->hopSize);
101 h->nBins = hopSize+1;
102 h->numFilterBlocks = (int)ceilf((float)length_h/(float)hopSize); /* number of partitions */
103 saf_assert(h->numFilterBlocks>=1, "Number of filter blocks/partitions must be at least 1");
104
105 /* Allocate memory for buffers and perform fft on partitioned H */
106 h_pad = calloc1d(h->numFilterBlocks * hopSize, sizeof(float));
107 h_pad_2hops = calloc1d(2 * hopSize, sizeof(float));
108 h->Hpart_f = malloc1d(nCHout*sizeof(float_complex*));
109 h->X_n = calloc1d(h->numFilterBlocks * nCHin * (h->nBins), sizeof(float_complex));
110 h->HX_n = malloc1d(h->numFilterBlocks * nCHin * (h->nBins) * sizeof(float_complex));
111 h->x_pad = calloc1d(2 * hopSize, sizeof(float));
112 h->hx_n = malloc1d(h->numFilterBlocks*nCHin*(h->fftSize)*sizeof(float));
113 h->y_n_overlap = calloc1d(nCHout*hopSize, sizeof(float));
114 h->z_n = malloc1d((h->fftSize) * sizeof(float));
115 saf_rfft_create(&(h->hFFT), h->fftSize);
116 for(no=0; no<nCHout; no++){
117 h->Hpart_f[no] = malloc1d(h->numFilterBlocks*nCHin*(h->nBins)*sizeof(float_complex));
118 for(ni=0; ni<nCHin; ni++){
119 memcpy(h_pad, &H[no*nCHin*length_h+ni*length_h], length_h*sizeof(float)); /* zero pad filter, to be multiple of hopsize */
120 for (nb=0; nb<h->numFilterBlocks; nb++){
121 memcpy(h_pad_2hops, &(h_pad[nb*hopSize]), hopSize*sizeof(float));
122 saf_rfft_forward(h->hFFT, h_pad_2hops, &(h->Hpart_f[no][nb*nCHin*(h->nBins)+ni*(h->nBins)]));
123 }
124 }
125 }
126
127 free(h_pad);
128 free(h_pad_2hops);
129 }
130}
131
133(
134 void ** const phMC
135)
136{
137 safMatConv_data *h = (safMatConv_data*)(*phMC);
138 int no;
139
140 if(h!=NULL){
141 saf_rfft_destroy(&(h->hFFT));
142 free(h->X_n);
143 free(h->x_pad);
144 free(h->z_n);
145 free(h->hx_n);
146 free(h->HX_n);
147 if(!h->usePartFLAG){
148 free(h->ovrlpAddBuffer);
149 free(h->y_pad);
150 free(h->H_f);
151 }
152 else{
153 free(h->y_n_overlap);
154 for(no=0; no<h->nCHout; no++)
155 free(h->Hpart_f[no]);
156 free(h->Hpart_f);
157 }
158 free(h);
159 h = NULL;
160 *phMC = NULL;
161 }
162}
163
165(
166 void * const hMC
167)
168{
169 safMatConv_data *h = (safMatConv_data*)(hMC);
170
171 if(!h->usePartFLAG)
172 memset(h->ovrlpAddBuffer, 0, h->nCHout*(h->fftSize)*sizeof(float));
173 else
174 memset(h->y_n_overlap, 0, h->nCHout*h->hopSize*sizeof(float));
175}
176
178(
179 void * const hMC,
180 float* inputSig,
181 float* outputSig
182)
183{
184 safMatConv_data *h = (safMatConv_data*)(hMC);
185 int ni, no, nb;
186
187 /* apply non-partitioned convolution */
188 if(!h->usePartFLAG){
189 /* zero-pad input signals and perform fft */
190 for(ni=0; ni<h->nCHin; ni++){
191 cblas_scopy(h->hopSize, &inputSig[ni*(h->hopSize)], 1, &(h->x_pad[ni*(h->fftSize)]), 1);
192 saf_rfft_forward(h->hFFT, &(h->x_pad[ni*(h->fftSize)]), &(h->X_n[ni*(h->nBins)]));
193 }
194
195 /* Replicate for all outputs */
196 for(no=1; no<h->nCHout; no++)
197 cblas_ccopy(h->nCHin*(h->nBins), h->X_n, 1, &(h->X_n[no*ni*(h->nBins)]), 1);
198
199 /* Multiply spectra together */
200 utility_cvvmul(h->H_f, h->X_n, (h->nCHout)*(h->nCHin)*h->nBins, h->HX_n);
201
202 /* Loop over outputs */
203 for(no=0; no<h->nCHout; no++){
204 /* ifft and sum */
205 memset(h->z_n, 0, (h->fftSize) * sizeof(float));
206 for(ni=0; ni<h->nCHin; ni++){
207 saf_rfft_backward(h->hFFT, &(h->HX_n[no*(h->nCHin)*(h->nBins)+ni*(h->nBins)]), h->hx_n);
208 cblas_saxpy(h->fftSize, 1.0f, h->hx_n, 1, h->z_n, 1);
209 }
210
211 /* shuffle the over-lap add buffer */
212 memmove(&(h->ovrlpAddBuffer[no*(h->fftSize)]), &(h->ovrlpAddBuffer[no*(h->fftSize)+(h->hopSize)]), (h->numOvrlpAddBlocks-1)*(h->hopSize)*sizeof(float));
213 memset(&(h->ovrlpAddBuffer[no*(h->fftSize)+(h->numOvrlpAddBlocks-1)*(h->hopSize)]), 0, (h->hopSize)*sizeof(float));
214
215 /* sum with overlap-add buffer */
216 cblas_saxpy(h->fftSize, 1.0f, h->z_n, 1, &(h->ovrlpAddBuffer[no*(h->fftSize)]), 1);
217
218 /* truncate buffer and output */
219 cblas_scopy(h->hopSize, &(h->ovrlpAddBuffer[no*(h->fftSize)]), 1, &(outputSig[no*(h->hopSize)]), 1);
220 }
221 }
222 /* apply partitioned convolution */
223 else{
224 /* zero-pad input signals and perform fft. Store in partition slot 1. */
225 memmove(&(h->X_n[1*(h->nCHin)*(h->nBins)]), h->X_n, (h->numFilterBlocks-1)*(h->nCHin)*(h->nBins)*sizeof(float_complex)); /* shuffle */
226 for(ni=0; ni<h->nCHin; ni++){
227 cblas_scopy(h->hopSize, &(inputSig[ni*(h->hopSize)]), 1, h->x_pad, 1);
228 saf_rfft_forward(h->hFFT, h->x_pad, &(h->X_n[0*(h->nCHin)*(h->nBins)+ni*(h->nBins)]));
229 }
230
231 /* apply convolution and inverse fft */
232 for(no=0; no<h->nCHout; no++){
233 utility_cvvmul(h->Hpart_f[no], h->X_n, h->numFilterBlocks * (h->nCHin) * (h->nBins), h->HX_n); /* This is the bulk of the CPU work */
234 for(nb=0; nb<h->numFilterBlocks; nb++)
235 for(ni=0; ni<h->nCHin; ni++)
236 saf_rfft_backward(h->hFFT, &(h->HX_n[nb*(h->nCHin)*(h->nBins)+ni*(h->nBins)]), &(h->hx_n[nb*(h->nCHin)*(h->fftSize)+ni*(h->fftSize)]));
237
238 /* output frame for this channel is the sum over all partitions and input channels */
239 memset(h->z_n, 0, (h->fftSize) * sizeof(float));
240 for(nb=0; nb<h->numFilterBlocks*(h->nCHin); nb++)
241 cblas_saxpy(h->fftSize, 1.0f, &(h->hx_n[nb*(h->fftSize)]), 1, h->z_n, 1);
242
243 /* sum with overlap buffer and copy the result to the output buffer */
244 utility_svvadd(h->z_n, (const float*)&(h->y_n_overlap[no*(h->hopSize)]), h->hopSize, &(outputSig[no*(h->hopSize)]));
245
246 /* for next iteration: */
247 cblas_scopy(h->hopSize, &(h->z_n[h->hopSize]), 1, &(h->y_n_overlap[no*(h->hopSize)]), 1);
248 }
249 }
250}
251
252
253/* ========================================================================== */
254/* Multi-Channel Convolver */
255/* ========================================================================== */
256
260typedef struct _safMulConv_data {
261 int hopSize, fftSize, nBins;
262 int length_h, nCH;
263 int numOvrlpAddBlocks, numFilterBlocks;
264 int usePartFLAG;
265 void* hFFT;
266 float* x_pad, *z_n, *ovrlpAddBuffer, *hx_n, *y_n_overlap;
267 float_complex* X_n, *HX_n, *Z_n, *H_f, *Hpart_f;
268
270
272(
273 void ** const phMC,
274 int hopSize,
275 float* H, /* nCH x length_h */
276 int length_h,
277 int nCH,
278 int usePartFLAG
279)
280{
281 *phMC = malloc1d(sizeof(safMulConv_data));
282 safMulConv_data *h = (safMulConv_data*)(*phMC);
283 int nc, nb;
284 float* h_pad, *h_pad_2hops;
285
286 h->hopSize = hopSize;
287 h->length_h = length_h;
288 h->nCH = nCH;
289 h->usePartFLAG = usePartFLAG;
290
291 if(!h->usePartFLAG){
292 /* intialise non-partitioned convolution mode */
293 h->numOvrlpAddBlocks = (int)(ceilf((float)(hopSize+length_h-1)/(float)hopSize)+0.1f);
294 h->fftSize = (h->numOvrlpAddBlocks*hopSize);
295 h->nBins = h->fftSize/2 + 1;
296
297 /* Allocate memory for buffers and perform fft on partitioned H */
298 h->ovrlpAddBuffer = calloc1d(nCH*h->fftSize, sizeof(float));
299 h_pad = calloc1d(h->fftSize, sizeof(float));
300 h->H_f = malloc1d(nCH*(h->nBins)*sizeof(float_complex));
301 h->X_n = calloc1d(nCH * (h->nBins), sizeof(float_complex));
302 h->Z_n = malloc1d(nCH * (h->nBins) * sizeof(float_complex));
303 h->x_pad = calloc1d(h->fftSize, sizeof(float));
304 h->z_n = malloc1d(nCH*(h->fftSize)*sizeof(float));
305 saf_rfft_create(&(h->hFFT), h->fftSize);
306 for(nc=0; nc<nCH; nc++){
307 memcpy(h_pad, &H[nc*length_h], length_h*sizeof(float)); /* zero pad filter, to be multiple of hopsize */
308 saf_rfft_forward(h->hFFT, h_pad, &(h->H_f[nc*(h->nBins)]));
309 }
310
311 free(h_pad);
312 }
313 else{
314 /* intialise partitioned convolution mode */
315 h->fftSize = 2*(h->hopSize);
316 h->nBins = hopSize+1;
317 h->numFilterBlocks = (int)ceilf((float)length_h/(float)hopSize); /* number of partitions */
318 saf_assert(h->numFilterBlocks>=1, "Number of filter blocks/partitions must be at least 1");
319
320 /* Allocate memory for buffers and perform fft on partitioned H */
321 h_pad = calloc1d(h->numFilterBlocks * hopSize, sizeof(float));
322 h_pad_2hops = calloc1d(2 * hopSize, sizeof(float));
323 h->Hpart_f = malloc1d(h->numFilterBlocks*nCH*(h->nBins)*sizeof(float_complex));
324 h->X_n = calloc1d(h->numFilterBlocks * nCH * (h->nBins), sizeof(float_complex));
325 h->HX_n = calloc1d(h->numFilterBlocks * nCH * (h->nBins), sizeof(float_complex));
326 h->x_pad = calloc1d(2 * hopSize, sizeof(float));
327 h->hx_n = malloc1d(h->numFilterBlocks*nCH*(h->fftSize)*sizeof(float));
328 h->z_n = calloc1d(h->fftSize, sizeof(float));
329 h->y_n_overlap = calloc1d(nCH*hopSize, sizeof(float));
330 saf_rfft_create(&(h->hFFT), h->fftSize);
331 for(nc=0; nc<nCH; nc++){
332 memcpy(h_pad, &H[nc*length_h], length_h*sizeof(float)); /* zero pad filter, to be multiple of hopsize */
333 for (nb=0; nb<h->numFilterBlocks; nb++){
334 memcpy(h_pad_2hops, &(h_pad[nb*hopSize]), hopSize*sizeof(float));
335 saf_rfft_forward(h->hFFT, h_pad_2hops, &(h->Hpart_f[nb*nCH*(h->nBins)+nc*(h->nBins)]));
336 }
337 }
338
339 free(h_pad);
340 free(h_pad_2hops);
341 }
342}
343
345(
346 void ** const phMC
347)
348{
349 safMulConv_data *h = (safMulConv_data*)(*phMC);
350
351 if(h!=NULL){
352 saf_rfft_destroy(&(h->hFFT));
353 free(h->X_n);
354 free(h->x_pad);
355 free(h->z_n);
356 if(!h->usePartFLAG){
357 free(h->Z_n);
358 free(h->H_f);
359 }
360 else{
361 free(h->HX_n);
362 free(h->hx_n);
363 free(h->y_n_overlap);
364 free(h->Hpart_f);
365 }
366 free(h);
367 h = NULL;
368 *phMC = NULL;
369 }
370}
371
373(
374 void * const hMC
375)
376{
377 safMulConv_data *h = (safMulConv_data*)(hMC);
378
379 if(!h->usePartFLAG)
380 memset(h->ovrlpAddBuffer, 0, h->nCH*h->fftSize*sizeof(float));
381 else
382 memset(h->y_n_overlap, 0, h->nCH*h->hopSize*sizeof(float));
383}
384
386(
387 void * const hMC,
388 float* inputSig,
389 float* outputSig
390)
391{
392 safMulConv_data *h = (safMulConv_data*)(hMC);
393 int nc, nb;
394
395 /* apply non-partitioned convolution */
396 if(!h->usePartFLAG){
397 /* zero-pad input signals and perform fft. */
398 for(nc=0; nc<h->nCH; nc++){
399 memcpy(h->x_pad, &(inputSig[nc*(h->hopSize)]), h->hopSize *sizeof(float));
400 saf_rfft_forward(h->hFFT, h->x_pad, &(h->X_n[nc*(h->nBins)]));
401 }
402
403 /* apply convolution and inverse fft */
404 utility_cvvmul(h->H_f, h->X_n, (h->nCH) * (h->nBins), h->Z_n); /* This is the bulk of the CPU work */
405 for(nc=0; nc<h->nCH; nc++){
406 saf_rfft_backward(h->hFFT, &(h->Z_n[nc*(h->nBins)]), &(h->z_n[nc*(h->fftSize)]));
407
408 /* sum with overlap buffer and copy the result to the output buffer */
409 utility_svvcopy(&(h->ovrlpAddBuffer[nc*(h->fftSize)+(h->hopSize)]), (h->numOvrlpAddBlocks-1)*(h->hopSize), &(h->ovrlpAddBuffer[nc*(h->fftSize)]));
410 memset(&(h->ovrlpAddBuffer[nc*(h->fftSize)+(h->numOvrlpAddBlocks-1)*(h->hopSize)]), 0, (h->hopSize)*sizeof(float));
411 cblas_saxpy(h->fftSize, 1.0f, &(h->z_n[nc*(h->fftSize)]), 1, &(h->ovrlpAddBuffer[nc*(h->fftSize)]), 1);
412 utility_svvcopy(&(h->ovrlpAddBuffer[nc*(h->fftSize)]), h->hopSize, &(outputSig[nc*(h->hopSize)]));
413 }
414 }
415 /* apply partitioned convolution */
416 else{
417 /* zero-pad input signals and perform fft. Store in partition slot 1. */
418 memmove(&(h->X_n[1*(h->nCH)*(h->nBins)]), h->X_n, (h->numFilterBlocks-1)*(h->nCH)*(h->nBins)*sizeof(float_complex));
419 for(nc=0; nc<h->nCH; nc++){
420 memcpy(h->x_pad, &(inputSig[nc*(h->hopSize)]), h->hopSize * sizeof(float));
421 saf_rfft_forward(h->hFFT, h->x_pad, &(h->X_n[0*(h->nCH)*(h->nBins)+nc*(h->nBins)]));
422 }
423
424 /* apply convolution and inverse fft */
425 utility_cvvmul(h->Hpart_f, h->X_n, h->numFilterBlocks * (h->nCH) * (h->nBins), h->HX_n); /* This is the bulk of the CPU work */
426 for(nc=0; nc<h->nCH; nc++){
427 for(nb=0; nb<h->numFilterBlocks; nb++)
428 saf_rfft_backward(h->hFFT, &(h->HX_n[nb*(h->nCH)*(h->nBins)+nc*(h->nBins)]), &(h->hx_n[nb*(h->nCH)*(h->fftSize)+nc*(h->fftSize)]));
429
430 /* output frame for this channel is the sum over all partitions */
431 memset(h->z_n, 0, h->fftSize*sizeof(float));
432 for(nb=0; nb<h->numFilterBlocks; nb++)
433 cblas_saxpy(h->fftSize, 1.0f, (const float*)&(h->hx_n[nb*(h->nCH)*(h->fftSize)+nc*(h->fftSize)]), 1, h->z_n, 1);
434
435 /* sum with overlap buffer and copy the result to the output buffer */
436 utility_svvadd(h->z_n, (const float*)&(h->y_n_overlap[nc*(h->hopSize)]), h->hopSize, &(outputSig[nc* (h->hopSize)]));
437
438 /* for next iteration: */
439 memcpy(&(h->y_n_overlap[nc*(h->hopSize)]), &(h->z_n[h->hopSize]), h->hopSize*sizeof(float));
440 }
441 }
442}
443
444/* ========================================================================== */
445/* Time-Varying Convolver */
446/* ========================================================================== */
447
451typedef struct _safTVConv_data {
452 int hopSize, fftSize, nBins;
453 int length_h, nIRs, nCHout;
454 int numFilterBlocks;
455 void* hFFT;
456 float* x_pad, *hx_n,
457 *z_n, *z_n_last, *z_n_last2,
458 *y_n_overlap, *y_n_overlap_last,
459 *out1, *out2,
460 *fadeIn, *fadeOut,
461 *outFadeIn, *outFadeOut;
462 float_complex* X_n, *HX_n;
463 float_complex*** Hpart_f;
464 int posIdx_last, posIdx_last2;
466
468(
469 void ** const phTVC,
470 int hopSize,
471 float** H, /* nIRs x FLAT(nCHout x length_h) */
472 int length_h,
473 int nIRs,
474 int nCHout,
475 int initIdx
476)
477{
478 *phTVC = malloc1d(sizeof(safTVConv_data));
479 safTVConv_data *h = (safTVConv_data*)(*phTVC);
480 int np, no, nb, n;
481 float* h_pad, *h_pad_2hops;
482
483 h->hopSize = hopSize;
484 h->length_h = length_h;
485 h->nIRs = nIRs;
486 h->nCHout = nCHout;
487 if (initIdx < nIRs){
488 h->posIdx_last = initIdx;
489 h->posIdx_last2 = initIdx;
490 } else {
491 h->posIdx_last = 0;
492 h->posIdx_last2 = 0;
493 }
494
495 /* intialise partitioned convolution mode */
496 h->length_h = length_h;
497 h->fftSize = 2*(h->hopSize);
498 h->nBins = hopSize+1;
499 h->numFilterBlocks = (int)ceilf((float)length_h/(float)hopSize); /* number of partitions */
500 saf_assert(h->numFilterBlocks>=1, "Number of filter blocks/partitions must be at least 1");
501
502 /* Allocate memory for buffers and perform fft on partitioned H */
503 h_pad = calloc1d(h->numFilterBlocks * hopSize, sizeof(float));
504 h_pad_2hops = calloc1d(2 * hopSize, sizeof(float));
505 h->Hpart_f = (float_complex***) malloc2d(nIRs, nCHout, sizeof(float_complex*));
506 h->X_n = calloc1d(h->numFilterBlocks * (h->nBins), sizeof(float_complex));
507 h->HX_n = malloc1d(h->numFilterBlocks * (h->nBins) * sizeof(float_complex));
508 h->x_pad = calloc1d(2 * hopSize, sizeof(float));
509 h->hx_n = malloc1d(h->numFilterBlocks*(h->fftSize)*sizeof(float));
510 h->y_n_overlap = calloc1d(nCHout*hopSize, sizeof(float));
511 h->y_n_overlap_last = calloc1d(nCHout*hopSize, sizeof(float));
512 h->z_n = malloc1d((h->fftSize) * sizeof(float));
513 h->z_n_last = malloc1d((h->fftSize) * sizeof(float));
514 h->z_n_last2 = malloc1d((h->fftSize) * sizeof(float));
515 h->out1 = malloc1d(hopSize * sizeof(float));
516 h->out2 = malloc1d(hopSize * sizeof(float));
517 h->fadeIn = malloc1d(hopSize * sizeof(float));
518 h->fadeOut = malloc1d(hopSize * sizeof(float));
519 h->outFadeIn = malloc1d(hopSize * sizeof(float));
520 h->outFadeOut = malloc1d(hopSize * sizeof(float));
521 for(n=0; n<hopSize; n++){
522 h->fadeIn[n] = (float) n / (float) (hopSize-1);
523 h->fadeOut[n] = (float) (hopSize-1-n) / (float) (hopSize-1);
524 }
525 saf_rfft_create(&(h->hFFT), h->fftSize);
526 for(np=0; np<nIRs; np++){
527 for(no=0; no<nCHout; no++){
528 h->Hpart_f[np][no] = malloc1d(h->numFilterBlocks*(h->nBins)*sizeof(float_complex));
529 memcpy(h_pad, &H[np][no*length_h], length_h*sizeof(float)); /* zero pad filter, to be multiple of hopsize */
530 for (nb=0; nb<h->numFilterBlocks; nb++){
531 memcpy(h_pad_2hops, &(h_pad[nb*hopSize]), hopSize*sizeof(float));
532 saf_rfft_forward(h->hFFT, h_pad_2hops, &(h->Hpart_f[np][no][nb*(h->nBins)]));
533 }
534 }
535 }
536
537 free(h_pad);
538 free(h_pad_2hops);
539}
540
542(
543 void ** const phTVC
544)
545{
546 safTVConv_data *h = (safTVConv_data*)(*phTVC);
547 int np, no;
548
549 if(h!=NULL){
550 saf_rfft_destroy(&(h->hFFT));
551 free(h->X_n);
552 free(h->x_pad);
553 free(h->z_n);
554 free(h->z_n_last);
555 free(h->z_n_last2);
556 free(h->hx_n);
557 free(h->HX_n);
558 free(h->y_n_overlap);
559 free(h->y_n_overlap_last);
560 free(h->out1);
561 free(h->out2);
562 free(h->fadeIn);
563 free(h->fadeOut);
564 free(h->outFadeIn);
565 free(h->outFadeOut);
566 for(np=0; np<h->nIRs; np++){
567 for(no=0; no<h->nCHout; no++)
568 free(h->Hpart_f[np][no]);
569 }
570 free(h->Hpart_f);
571 }
572 free(h);
573 h = NULL;
574 *phTVC = NULL;
575}
576
578(
579 void * const hTVC,
580 float* inputSig,
581 float* outputSig,
582 int irIdx
583)
584{
585 safTVConv_data *h = (safTVConv_data*)(hTVC);
586 int no, nb;
587
588 /* zero-pad input signals and perform fft. Store in partition slot 1. */
589 memmove(&(h->X_n[1*(h->nBins)]), h->X_n, (h->numFilterBlocks-1)*(h->nBins)*sizeof(float_complex)); /* shuffle */
590
591 cblas_scopy(h->hopSize, inputSig, 1, h->x_pad, 1);
592 saf_rfft_forward(h->hFFT, h->x_pad, h->X_n);
593
594 /* apply convolution and inverse fft */
595 for(no=0; no<h->nCHout; no++){
596 utility_cvvmul(h->Hpart_f[irIdx][no], h->X_n, h->numFilterBlocks * (h->nBins), h->HX_n); /* This is the bulk of the CPU work */
597 for(nb=0; nb<h->numFilterBlocks; nb++)
598 saf_rfft_backward(h->hFFT, &(h->HX_n[nb*(h->nBins)]), &(h->hx_n[nb*(h->fftSize)]));
599
600 /* output frame for this channel is the sum over all partitions */
601 memset(h->z_n, 0, (h->fftSize) * sizeof(float));
602 for(nb=0; nb<h->numFilterBlocks; nb++)
603 cblas_saxpy(h->fftSize, 1.0f, &(h->hx_n[nb*(h->fftSize)]), 1, h->z_n, 1);
604
605 /* If position changed perform convolution at previous steps too */
606 if(irIdx != h->posIdx_last){
607 utility_cvvmul(h->Hpart_f[h->posIdx_last][no], h->X_n, h->numFilterBlocks * (h->nBins), h->HX_n);
608 for(nb=0; nb<h->numFilterBlocks; nb++)
609 saf_rfft_backward(h->hFFT, &(h->HX_n[nb*(h->nBins)]), &(h->hx_n[nb*(h->fftSize)]));
610
611 /* output frame for this channel is the sum over all partitions */
612 memset(h->z_n_last, 0, (h->fftSize) * sizeof(float));
613 for(nb=0; nb<h->numFilterBlocks; nb++)
614 cblas_saxpy(h->fftSize, 1.0f, &(h->hx_n[nb*(h->fftSize)]), 1, h->z_n_last, 1);
615 }
616 else {
617 utility_svvcopy(h->z_n, h->fftSize, h->z_n_last);
618 }
619 if(h->posIdx_last != h->posIdx_last2){
620 utility_cvvmul(h->Hpart_f[h->posIdx_last2][no], h->X_n, h->numFilterBlocks * (h->nBins), h->HX_n);
621 for(nb=0; nb<h->numFilterBlocks; nb++)
622 saf_rfft_backward(h->hFFT, &(h->HX_n[nb*(h->nBins)]), &(h->hx_n[nb*(h->fftSize)]));
623
624 /* output frame for this channel is the sum over all partitions */
625 memset(h->z_n_last2, 0, (h->fftSize) * sizeof(float));
626 for(nb=0; nb<h->numFilterBlocks; nb++)
627 cblas_saxpy(h->fftSize, 1.0f, &(h->hx_n[nb*(h->fftSize)]), 1, h->z_n_last2, 1);
628 }
629 else {
630 utility_svvcopy(h->z_n_last, h->fftSize, h->z_n_last2);
631 }
632
633 /* sum with overlap buffer */
634 utility_svvadd(h->z_n_last, (const float*)&(h->y_n_overlap[no*(h->hopSize)]), h->hopSize, h->out1);
635 utility_svvadd(h->z_n_last2, (const float*)&(h->y_n_overlap_last[no*(h->hopSize)]), h->hopSize, h->out2);
636 /* multiply by cross-fade ramps */
637 utility_svvmul(h->out1, (const float*)h->fadeIn, h->hopSize, h->outFadeIn);
638 utility_svvmul(h->out2, (const float*)h->fadeOut, h->hopSize, h->outFadeOut);
639 /* cross-fade the filered signals and copy to output buffer */
640 utility_svvadd(h->outFadeIn, (const float*)h->outFadeOut, h->hopSize, &(outputSig[no*(h->hopSize)]));
641
642 /* for next iteration: */
643 cblas_scopy(h->hopSize, &(h->z_n[h->hopSize]), 1, &(h->y_n_overlap[no*(h->hopSize)]), 1);
644 cblas_scopy(h->hopSize, &(h->z_n_last[h->hopSize]), 1, &(h->y_n_overlap_last[no*(h->hopSize)]), 1);
645 }
646
647 h->posIdx_last2 = h->posIdx_last;
648 h->posIdx_last = irIdx;
649}
void saf_multiConv_destroy(void **const phMC)
Destroys an instance of multiConv.
void saf_matrixConv_apply(void *const hMC, float *inputSig, float *outputSig)
Performs the matrix convolution.
#define saf_assert(x, message)
Macro to make an assertion, along with a string explaining its purpose.
void saf_TVConv_apply(void *const hTVC, float *inputSig, float *outputSig, int irIdx)
Performs the matrix convolution.
void utility_cvvmul(const float_complex *a, const float_complex *b, const int len, float_complex *c)
Single-precision, complex, element-wise vector-vector multiplication i.e.
void utility_svvmul(const float *a, const float *b, const int len, float *c)
Single-precision, element-wise vector-vector multiplication i.e.
void saf_multiConv_apply(void *const hMC, float *inputSig, float *outputSig)
Performs the multi-channel convolution.
void saf_multiConv_reset(void *const hMC)
Flushes internal buffers with zeros.
void saf_matrixConv_create(void **const phMC, int hopSize, float *H, int length_h, int nCHin, int nCHout, int usePartFLAG)
Creates an instance of matrixConv.
void saf_TVConv_create(void **const phTVC, int hopSize, float **H, int length_h, int nIRs, int nCHout, int initIdx)
Creates an instance of TVConv.
void utility_svvcopy(const float *a, const int len, float *c)
Single-precision, vector-vector copy, i.e.
void saf_rfft_create(void **const phFFT, int N)
Creates an instance of saf_rfft; real<->half-complex (conjugate-symmetric) FFT.
void saf_multiConv_create(void **const phMC, int hopSize, float *H, int length_h, int nCH, int usePartFLAG)
Creates an instance of multiConv.
void saf_TVConv_destroy(void **const phTVC)
Destroys an instance of matrixConv.
void saf_matrixConv_destroy(void **const phMC)
Destroys an instance of matrixConv.
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_backward(void *const hFFT, float_complex *inputFD, float *outputTD)
Performs the backward-FFT operation; use for complex (conjugate symmetric) to real transformations.
void saf_rfft_destroy(void **const phFFT)
Destroys an instance of saf_rfft.
void utility_svvadd(const float *a, const float *b, const int len, float *c)
Single-precision, vector-vector addition, i.e.
void saf_matrixConv_reset(void *const hMC)
Flushes internal buffers with zeros.
void ** malloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D malloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:89
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 utilities module (SAF_UTILITIES_MODULE)
Data structure for the matrix convolver.
Data structure for the multi-channel convolver.
Data structure for the time-varying convolver.