SAF
Loading...
Searching...
No Matches
saf_reverb_internal.c
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
29#include "saf_reverb.h"
30#include "saf_reverb_internal.h"
31
32/* ========================================================================== */
33/* IMS Shoebox Room Simulator */
34/* ========================================================================== */
35
37(
38 void** phEcho,
39 int include_rt_vars
40)
41{
42 *phEcho = malloc1d(sizeof(echogram_data));
43 echogram_data *ec = (echogram_data*)(*phEcho);
44 int i;
45
46 saf_assert(include_rt_vars==0 || include_rt_vars==1, "include_rt_vars is a bool");
47
48 /* Echogram data */
49 ec->numImageSources = 0;
50 ec->nChannels = 0;
51 ec->value = NULL;
52 ec->time = NULL;
53 ec->order = NULL;
54 ec->coords = NULL;
55 ec->sortedIdx = NULL;
56
57 /* Optional helper variables */
58 ec->include_rt_vars = include_rt_vars;
59 ec->tmp1 = NULL;
60 ec->tmp2 = NULL;
61 ec->rIdx = NULL;
62 for(i=0; i<IMS_LAGRANGE_ORDER; i++)
63 ec->rIdx_frac[i] = NULL;
64 ec->h_frac = NULL;
65 ec->cb_vals = NULL;
66 ec->contrib = NULL;
67 ec->ones_dummy = NULL;
68}
69
71(
72 void* hEcho,
73 int numImageSources,
74 int nChannels
75)
76{
77 echogram_data *ec = (echogram_data*)(hEcho);
78 int i;
79
80 if(ec->nChannels != nChannels || ec->numImageSources != numImageSources){
81 /* Resize echogram data */
82 ec->nChannels = nChannels;
83 ec->numImageSources = numImageSources;
84 ec->value = (float**)realloc2d((void**)ec->value, nChannels, numImageSources, sizeof(float));
85 ec->time = realloc1d(ec->time, numImageSources*sizeof(float));
86 ec->order = (int**)realloc2d((void**)ec->order, numImageSources, 3, sizeof(int));
87 ec->coords = realloc1d(ec->coords, numImageSources * sizeof(ims_pos_xyz));
88 ec->sortedIdx = realloc1d(ec->sortedIdx, numImageSources*sizeof(int));
89
90 /* Resize the optional helper variables (used for run-time speed-ups) */
91 if(ec->include_rt_vars){
92 ec->tmp1 = realloc1d(ec->tmp1, numImageSources*sizeof(float));
93 ec->tmp2 = realloc1d(ec->tmp2, numImageSources*sizeof(float));
94 ec->rIdx = realloc1d(ec->rIdx, numImageSources*sizeof(int));
95 for(i=0; i<IMS_LAGRANGE_ORDER; i++)
96 ec->rIdx_frac[i] = realloc1d(ec->rIdx_frac[i], numImageSources*sizeof(int));
97 ec->h_frac = (float**)realloc2d((void**)ec->h_frac, IMS_LAGRANGE_ORDER+1, numImageSources, sizeof(float));
98 ec->cb_vals = (float**)realloc2d((void**)ec->cb_vals, nChannels, numImageSources, sizeof(float));
99 ec->contrib = (float**)realloc2d((void**)ec->contrib, nChannels, numImageSources, sizeof(float));
100 ec->ones_dummy = realloc1d(ec->ones_dummy, numImageSources*sizeof(float));
101 for(i=0; i<numImageSources; i++)
102 ec->ones_dummy[i] = 1.0f;
103 }
104 }
105}
106
108(
109 void* hEchoX,
110 void* hEchoY
111)
112{
113 echogram_data *ecX = (echogram_data*)(hEchoX);
114 echogram_data *ecY = (echogram_data*)(hEchoY);
115 int nChannels, numImageSources;
116
117 saf_assert(hEchoX!=NULL && hEchoY!=NULL, "Echograms must be allocated first");
118 if(hEchoX==hEchoY)
119 return; /* no copying required... */
120
121 if(ecX->nChannels==0 || ecX->numImageSources==0)
122 return;
123
124 /* Resize container 'Y' to be the same as container 'X' (if needed) */
125 nChannels = ecX->nChannels;
126 numImageSources = ecX->numImageSources;
127 if(ecY->nChannels != nChannels || ecY->numImageSources != numImageSources)
128 ims_shoebox_echogramResize(hEchoY, numImageSources, nChannels);
129
130 /* Copy echogram data from X to Y */
131 cblas_scopy(nChannels*numImageSources, FLATTEN2D(ecX->value), 1, FLATTEN2D(ecY->value), 1);
132 cblas_scopy(numImageSources, ecX->time, 1, ecY->time, 1);
133 memcpy(FLATTEN2D(ecY->order), FLATTEN2D(ecX->order), numImageSources*3*sizeof(int));
134 memcpy(ecY->coords, ecX->coords, numImageSources*sizeof(ims_pos_xyz));
135 memcpy(ecY->sortedIdx, ecX->sortedIdx, numImageSources*sizeof(int));
136}
137
139(
140 void** phEcho
141)
142{
143 echogram_data *ec = (echogram_data*)(*phEcho);
144 int i;
145
146 if(ec!=NULL){
147 /* Free echogram data */
148 free(ec->value);
149 free(ec->time);
150 free(ec->order);
151 free(ec->coords);
152 free(ec->sortedIdx);
153
154 /* Free the optional helper variables */
155 if(ec->include_rt_vars){
156 free(ec->tmp1);
157 free(ec->tmp2);
158 free(ec->rIdx);
159 for(i=0; i<IMS_LAGRANGE_ORDER; i++)
160 free(ec->rIdx_frac[i]);
161 free(ec->h_frac);
162 free(ec->cb_vals);
163 free(ec->contrib);
164 free(ec->ones_dummy);
165 }
166
167 free(ec);
168 ec=NULL;
169 *phEcho = NULL;
170 }
171}
172
174(
175 void** phWork,
176 int nBands
177)
178{
180 *phWork = malloc1d(sizeof(ims_core_workspace));
181 ims_core_workspace *wrk = (ims_core_workspace*)(*phWork);
182 int i, band;
183
184 /* locals */
185 wrk->d_max = -1.0f;
186 wrk->N_max = -1;
187 wrk->lengthVec = 0;
188 wrk->numImageSources = 0;
189 memset(wrk->room, 0, 3*sizeof(int));
190 for(i=0; i<3; i++){
191 wrk->src.v[i] = -1;
192 wrk->rec.v[i] = -1;
193 }
194 wrk->nBands = nBands;
195
196 /* Internals */
197 wrk->validIDs = NULL;
198 wrk->II = wrk->JJ = wrk->KK = NULL;
199 wrk->iII = wrk->iJJ = wrk->iKK = NULL;
200 wrk->s_x = wrk->s_y = wrk->s_z = wrk->s_d = NULL;
201 wrk->s_t = wrk->s_att = NULL;
202 wrk->s_ord = NULL;
203
204 /* Echogram containers */
205 wrk->refreshEchogramFLAG = 1;
208 wrk->hEchogram_abs = malloc1d(nBands*sizeof(voidPtr));
209 wrk->hPrevEchogram_abs = malloc1d(nBands*sizeof(voidPtr));
210 for(band=0; band<nBands; band++){
213 }
214
215 /* Room impulse responses */
216 wrk->refreshRIRFLAG = 1;
217 wrk->rir_len_samples = 0;
218 wrk->rir_len_seconds = 0.0f;
219 wrk->rir_bands = (float***)malloc1d(nBands*sizeof(float**));
220 for(band=0; band < nBands; band++)
221 wrk->rir_bands[band] = NULL;
222}
223
225(
226 void** phWork
227)
228{
229 ims_core_workspace *wrk = (ims_core_workspace*)(*phWork);
230 int band;
231
232 if(wrk!=NULL){
233 /* free internals */
234 free(wrk->validIDs);
235 free(wrk->II);
236 free(wrk->JJ);
237 free(wrk->KK);
238 free(wrk->iII);
239 free(wrk->iJJ);
240 free(wrk->iKK);
241 free(wrk->s_x);
242 free(wrk->s_y);
243 free(wrk->s_z);
244 free(wrk->s_d);
245 free(wrk->s_t);
246 free(wrk->s_att);
247 free(wrk->s_ord);
248
249 /* Destroy echogram containers */
252 for(band=0; band< wrk->nBands; band++){
255 }
256 free(wrk->hEchogram_abs);
257 free(wrk->hPrevEchogram_abs);
258
259 /* free rirs */
260 for(band=0; band < wrk->nBands; band++)
261 free(wrk->rir_bands[band]);
262
263 free(wrk);
264 wrk=NULL;
265 *phWork = NULL;
266 }
267}
268
270(
271 void* hWork,
272 float room[3],
273 ims_pos_xyz src,
274 ims_pos_xyz rec,
275 float maxTime_s,
276 float c_ms
277)
278{
279 ims_core_workspace *wrk = (ims_core_workspace*)(hWork);
280 echogram_data *echogram = (echogram_data*)(wrk->hEchogram);
281 ims_pos_xyz src_orig, rec_orig;
282 int imsrc, vIdx;
283 int ii, jj, kk;
284 float d_max;
285
286 d_max = maxTime_s*c_ms;
287
288 /* move origin to the centre of the room */
289 src_orig.x = src.x - room[0]/2.0f;
290 src_orig.y = room[1]/2.0f - src.y;
291 src_orig.z = src.z - room[2]/2.0f;
292 rec_orig.x = rec.x - room[0]/2.0f;
293 rec_orig.y = room[1]/2.0f - rec.y;
294 rec_orig.z = rec.z - room[2]/2.0f;
295
296 /* Update indices only if the maximum permitted delay or room dimensions have changed */
297 if( (wrk->d_max != d_max) ||
298 (wrk->room[0] != room[0]) || (wrk->room[1] != room[1]) || (wrk->room[2] != room[2]) )
299 {
300 wrk->Nx = (int)(d_max/room[0] + 1.0f); /* ceil */
301 wrk->Ny = (int)(d_max/room[1] + 1.0f); /* ceil */
302 wrk->Nz = (int)(d_max/room[2] + 1.0f); /* ceil */
303 wrk->lengthVec = (2*(wrk->Nx)+1) * (2*(wrk->Ny)+1) * (2*(wrk->Nz)+1);
304
305 /* i,j,k indices for calculation in x,y,z respectively */
306 wrk->II = realloc1d(wrk->II, wrk->lengthVec*sizeof(float));
307 wrk->JJ = realloc1d(wrk->JJ, wrk->lengthVec*sizeof(float));
308 wrk->KK = realloc1d(wrk->KK, wrk->lengthVec*sizeof(float));
309 ii = -(wrk->Nx); jj = -(wrk->Ny); kk = -(wrk->Nz);
310 for(imsrc = 0; imsrc<wrk->lengthVec; imsrc++){
311 wrk->II[imsrc] = (float)ii;
312 wrk->JJ[imsrc] = (float)jj;
313 wrk->KK[imsrc] = (float)kk;
314 ii++;
315 if(ii>wrk->Nx){
316 ii = -(wrk->Nx);
317 jj++;
318 }
319 if(jj>wrk->Ny){
320 jj = -(wrk->Ny);
321 kk++;
322 }
323 if(kk>wrk->Nz){
324 kk = -(wrk->Nz);
325 }
326 }
327
328 /* Re-allocate memory */
329 wrk->validIDs = realloc1d(wrk->validIDs, wrk->lengthVec*sizeof(int));
330 wrk->s_x = realloc1d(wrk->s_x, wrk->lengthVec*sizeof(float));
331 wrk->s_y = realloc1d(wrk->s_y, wrk->lengthVec*sizeof(float));
332 wrk->s_z = realloc1d(wrk->s_z, wrk->lengthVec*sizeof(float));
333 wrk->s_d = realloc1d(wrk->s_d, wrk->lengthVec*sizeof(float));
334 wrk->s_t = realloc1d(wrk->s_t, wrk->lengthVec*sizeof(float));
335 wrk->s_att = realloc1d(wrk->s_att, wrk->lengthVec*sizeof(float));
336 }
337
338 /* Update echogram only if the source/receiver positions or room dimensions have changed */
339 if( (wrk->d_max != d_max) ||
340 (wrk->rec.x != rec_orig.x) || (wrk->rec.y != rec_orig.y) || (wrk->rec.z != rec_orig.z) ||
341 (wrk->src.x != src_orig.x) || (wrk->src.y != src_orig.y) || (wrk->src.z != src_orig.z) ||
342 (wrk->room[0] != room[0]) || (wrk->room[1] != room[1]) || (wrk->room[2] != room[2]))
343 {
344 wrk->d_max = d_max;
345 wrk->room[0] = room[0];
346 wrk->room[1] = room[1];
347 wrk->room[2] = room[2];
348 memcpy(&(wrk->rec), &rec_orig, sizeof(ims_pos_xyz));
349 memcpy(&(wrk->src), &src_orig, sizeof(ims_pos_xyz));
350
351 /* image source coordinates with respect to receiver, and distance */
352 for(imsrc = 0; imsrc<wrk->lengthVec; imsrc++){
353 wrk->s_x[imsrc] = wrk->II[imsrc]*room[0] + powf(-1.0f, wrk->II[imsrc])*src_orig.x - rec_orig.x;
354 wrk->s_y[imsrc] = wrk->JJ[imsrc]*room[1] + powf(-1.0f, wrk->JJ[imsrc])*src_orig.y - rec_orig.y;
355 wrk->s_z[imsrc] = wrk->KK[imsrc]*room[2] + powf(-1.0f, wrk->KK[imsrc])*src_orig.z - rec_orig.z;
356 wrk->s_d[imsrc] = sqrtf(powf(wrk->s_x[imsrc], 2.0f) + powf(wrk->s_y[imsrc], 2.0f) + powf(wrk->s_z[imsrc], 2.0f));
357 }
358
359 /* Determine the indices where the distance is below the specified maximum */
360 for(imsrc = 0, wrk->numImageSources = 0; imsrc<wrk->lengthVec; imsrc++){
361 if(wrk->s_d[imsrc]<d_max){
362 wrk->validIDs[imsrc] = 1;
363 wrk->numImageSources++; /* (within maximum distance) */
364 }
365 else
366 wrk->validIDs[imsrc] = 0;
367 }
368
369 /* Resize echogram container (only done if needed) */
370 ims_shoebox_echogramResize(wrk->hEchogram, wrk->numImageSources, 1/*omni-pressure*/);
371
372 /* Copy data into echogram struct */
373 for(imsrc = 0, vIdx = 0; imsrc<wrk->lengthVec; imsrc++){
374 if(wrk->validIDs[imsrc]){
375 echogram->time[vIdx] = wrk->s_d[imsrc]/c_ms;
376
377 /* reflection propagation attenuation - if distance is <1m set
378 * attenuation to 1 to avoid amplification */
379 echogram->value[0][vIdx] = wrk->s_d[imsrc]<=1 ? 1.0f : 1.0f / wrk->s_d[imsrc];
380
381 /* Order */
382 echogram->order[vIdx][0] = (int)(wrk->II[imsrc] + (wrk->II[imsrc]>0 ? 0.1f : -0.1f)); /* round */
383 echogram->order[vIdx][1] = (int)(wrk->JJ[imsrc] + (wrk->JJ[imsrc]>0 ? 0.1f : -0.1f));
384 echogram->order[vIdx][2] = (int)(wrk->KK[imsrc] + (wrk->KK[imsrc]>0 ? 0.1f : -0.1f));
385
386 /* Coordinates */
387 echogram->coords[vIdx].x = wrk->s_x[imsrc];
388 echogram->coords[vIdx].y = wrk->s_y[imsrc];
389 echogram->coords[vIdx].z = wrk->s_z[imsrc];
390 vIdx++;
391 }
392 }
393
394 /* Find indices to sort reflections according to propagation time (accending order) */
395 sortf(echogram->time, NULL, echogram->sortedIdx, echogram->numImageSources, 0);
396 }
397}
398
400(
401 void* hWork,
402 float room[3],
403 ims_pos_xyz src,
404 ims_pos_xyz rec,
405 int maxN,
406 float c_ms
407)
408{
409 ims_core_workspace *wrk = (ims_core_workspace*)(hWork);
410 echogram_data *echogram = (echogram_data*)(wrk->hEchogram);
411 ims_pos_xyz src_orig, rec_orig;
412 int imsrc;
413 int ii, jj, kk;
414
415 /* move origin to the centre of the room */
416 src_orig.x = src.x - room[0]/2.0f;
417 src_orig.y = room[1]/2.0f - src.y;
418 src_orig.z = src.z - room[2]/2.0f;
419 rec_orig.x = rec.x - room[0]/2.0f;
420 rec_orig.y = room[1]/2.0f - rec.y;
421 rec_orig.z = rec.z - room[2]/2.0f;
422
423 /* Update indices only if the maximum reflection order has changed */
424 if( (wrk->N_max != maxN) )
425 {
426 wrk->lengthVec = (2*(maxN)+1) * (2*(maxN)+1) * (2*(maxN)+1);
427
428 /* i,j,k indices for calculation in x,y,z respectively */
429 wrk->iII = realloc1d(wrk->iII, wrk->lengthVec*sizeof(int));
430 wrk->iJJ = realloc1d(wrk->iJJ, wrk->lengthVec*sizeof(int));
431 wrk->iKK = realloc1d(wrk->iKK, wrk->lengthVec*sizeof(int));
432 wrk->s_ord = realloc1d(wrk->s_ord, wrk->lengthVec*sizeof(int));
433 ii = -maxN; jj = -maxN; kk = -maxN;
434 for(imsrc = 0; imsrc<wrk->lengthVec; imsrc++){
435 wrk->iII[imsrc] = ii;
436 wrk->iJJ[imsrc] = jj;
437 wrk->iKK[imsrc] = kk;
438 wrk->s_ord[imsrc] = abs(wrk->iII[imsrc]) + abs(wrk->iJJ[imsrc]) + abs(wrk->iKK[imsrc]);
439 ii++;
440 if(ii>maxN){
441 ii = -(maxN);
442 jj++;
443 }
444 if(jj>maxN){
445 jj = -(maxN);
446 kk++;
447 }
448 if(kk>maxN){
449 kk = -(maxN);
450 }
451 }
452
453 /* Cull the indices where the order is below the specified maximum */
454 wrk->II = realloc1d(wrk->II, wrk->lengthVec*sizeof(float));
455 wrk->JJ = realloc1d(wrk->JJ, wrk->lengthVec*sizeof(float));
456 wrk->KK = realloc1d(wrk->KK, wrk->lengthVec*sizeof(float));
457 for(imsrc = 0, wrk->numImageSources = 0; imsrc<wrk->lengthVec; imsrc++){
458 if(wrk->s_ord[imsrc]<=maxN){
459 wrk->II[wrk->numImageSources] = (float)wrk->iII[imsrc];
460 wrk->JJ[wrk->numImageSources] = (float)wrk->iJJ[imsrc];
461 wrk->KK[wrk->numImageSources] = (float)wrk->iKK[imsrc];
462 wrk->numImageSources++; /* (within maximum order) */
463 }
464 }
465
466 /* Re-allocate memory */
467 wrk->s_x = realloc1d(wrk->s_x, wrk->numImageSources*sizeof(float));
468 wrk->s_y = realloc1d(wrk->s_y, wrk->numImageSources*sizeof(float));
469 wrk->s_z = realloc1d(wrk->s_z, wrk->numImageSources*sizeof(float));
470 wrk->s_d = realloc1d(wrk->s_d, wrk->numImageSources*sizeof(float));
471 wrk->s_t = realloc1d(wrk->s_t, wrk->numImageSources*sizeof(float));
472 wrk->s_att = realloc1d(wrk->s_att, wrk->numImageSources*sizeof(float));
473 }
474
475 /* Update echogram only if the maximum reflection order, source/receiver positions or room dimensions have changed */
476 if( (wrk->N_max != maxN) ||
477 (wrk->rec.x != rec_orig.x) || (wrk->rec.y != rec_orig.y) || (wrk->rec.z != rec_orig.z) ||
478 (wrk->src.x != src_orig.x) || (wrk->src.y != src_orig.y) || (wrk->src.z != src_orig.z) ||
479 (wrk->room[0] != room[0]) || (wrk->room[1] != room[1]) || (wrk->room[2] != room[2]))
480 {
481 wrk->N_max = maxN;
482 wrk->room[0] = room[0];
483 wrk->room[1] = room[1];
484 wrk->room[2] = room[2];
485 memcpy(&(wrk->rec), &rec_orig, sizeof(ims_pos_xyz));
486 memcpy(&(wrk->src), &src_orig, sizeof(ims_pos_xyz));
487
488 /* image source coordinates with respect to receiver, and distance */
489 for(imsrc = 0; imsrc<wrk->numImageSources; imsrc++){
490 wrk->s_x[imsrc] = wrk->II[imsrc]*room[0] + powf(-1.0f, wrk->II[imsrc])*src_orig.x - rec_orig.x;
491 wrk->s_y[imsrc] = wrk->JJ[imsrc]*room[1] + powf(-1.0f, wrk->JJ[imsrc])*src_orig.y - rec_orig.y;
492 wrk->s_z[imsrc] = wrk->KK[imsrc]*room[2] + powf(-1.0f, wrk->KK[imsrc])*src_orig.z - rec_orig.z;
493 wrk->s_d[imsrc] = sqrtf(powf(wrk->s_x[imsrc], 2.0f) + powf(wrk->s_y[imsrc], 2.0f) + powf(wrk->s_z[imsrc], 2.0f));
494 }
495
496 /* Resize echogram container (only done if needed) */
497 ims_shoebox_echogramResize(wrk->hEchogram, wrk->numImageSources, 1/*omni-pressure*/);
498
499 /* Copy data into echogram struct */
500 for(imsrc = 0; imsrc<wrk->numImageSources; imsrc++){
501 echogram->time[imsrc] = wrk->s_d[imsrc]/c_ms;
502
503 /* reflection propagation attenuation - if distance is <1m set
504 * attenuation to 1 to avoid amplification */
505 echogram->value[0][imsrc] = wrk->s_d[imsrc]<=1 ? 1.0f : 1.0f / wrk->s_d[imsrc];
506
507 /* Order */
508 echogram->order[imsrc][0] = (int)(wrk->II[imsrc] + (wrk->II[imsrc]>0 ? 0.1f : -0.1f)); /* round */
509 echogram->order[imsrc][1] = (int)(wrk->JJ[imsrc] + (wrk->JJ[imsrc]>0 ? 0.1f : -0.1f));
510 echogram->order[imsrc][2] = (int)(wrk->KK[imsrc] + (wrk->KK[imsrc]>0 ? 0.1f : -0.1f));
511
512 /* Coordinates */
513 echogram->coords[imsrc].x = wrk->s_x[imsrc];
514 echogram->coords[imsrc].y = wrk->s_y[imsrc];
515 echogram->coords[imsrc].z = wrk->s_z[imsrc];
516 }
517
518 /* Find indices to sort reflections according to propagation time (accending order) */
519 sortf(echogram->time, NULL, echogram->sortedIdx, echogram->numImageSources, 0);
520 }
521}
522
524(
525 void* hWork,
526 int sh_order
527)
528{
529 ims_core_workspace *wrk = (ims_core_workspace*)(hWork);
530 echogram_data *echogram = (echogram_data*)(wrk->hEchogram);
531 echogram_data *echogram_rec = (echogram_data*)(wrk->hEchogram_rec);
532 int i, j, nSH;
533 float aziElev_rad[2];
534 float* sh_gains;
535
536 nSH = ORDER2NSH(sh_order);
537
538 /* Resize container (only done if needed) */
540
541 /* Copy 'time', 'coord', 'order', except in ascending order w.r.t propagation time */
542 for(i=0; i<echogram_rec->numImageSources; i++){
543 echogram_rec->time[i] = echogram->time[echogram->sortedIdx[i]];
544 echogram_rec->order[i][0] = echogram->order[echogram->sortedIdx[i]][0];
545 echogram_rec->order[i][1] = echogram->order[echogram->sortedIdx[i]][1];
546 echogram_rec->order[i][2] = echogram->order[echogram->sortedIdx[i]][2];
547 echogram_rec->coords[i].v[0] = echogram->coords[echogram->sortedIdx[i]].v[0];
548 echogram_rec->coords[i].v[1] = echogram->coords[echogram->sortedIdx[i]].v[1];
549 echogram_rec->coords[i].v[2] = echogram->coords[echogram->sortedIdx[i]].v[2];
550
551 echogram_rec->sortedIdx[i] = i; /* Should already sorted in ims_shoebox_coreInit() */
552 }
553
554 /* Copy 'value' (the core omni-pressure), except also in ascending order w.r.t propagation time */
555 if(sh_order==0){
556 for(i=0; i<echogram_rec->numImageSources; i++)
557 echogram_rec->value[0][i] = echogram->value[0][echogram->sortedIdx[i]];
558 }
559 /* Impose spherical harmonic directivities onto 'value', and store in ascending order w.r.t propagation time */
560 else{
561 sh_gains = malloc1d(nSH*sizeof(float));
562 for(i=0; i<echogram_rec->numImageSources; i++){
563 /* Cartesian coordinates to spherical coordinates */
564 unitCart2sph(echogram_rec->coords[i].v, 1, 0, (float*)aziElev_rad);
565 aziElev_rad[1] = SAF_PI/2.0f-aziElev_rad[1]; /* AziElev to AziInclination conversion */
566
567 /* Apply spherical harmonic weights */
568 getSHreal_recur(sh_order, (float*)aziElev_rad, 1, sh_gains);
569 for(j=0; j<nSH; j++)
570 echogram_rec->value[j][i] = sh_gains[j] * (echogram->value[0][echogram->sortedIdx[i]]);
571 }
572 free(sh_gains);
573 }
574}
575
577(
578 void* hWork,
579 float** abs_wall
580)
581{
582 ims_core_workspace *wrk = (ims_core_workspace*)(hWork);
583 echogram_data *echogram_abs;
584 int i,band,ch;
585 float r_x[2], r_y[2], r_z[2];
586 float abs_x, abs_y, abs_z, s_abs_tot;
587
588 for(band=0; band < wrk->nBands; band++){
589 echogram_abs = (echogram_data*)wrk->hEchogram_abs[band];
590
591 /* Copy "receiver" echogram data into "absorption" echogram container */
593
594 /* Then apply the wall absorption onto it, for this band... */
595
596 /* Reflection coefficients given the absorption coefficients for x, y, z
597 * walls per frequency */
598 r_x[0] = sqrtf(1.0f - abs_wall[band][0]);
599 r_x[1] = sqrtf(1.0f - abs_wall[band][1]);
600 r_y[0] = sqrtf(1.0f - abs_wall[band][2]);
601 r_y[1] = sqrtf(1.0f - abs_wall[band][3]);
602 r_z[0] = sqrtf(1.0f - abs_wall[band][4]);
603 r_z[1] = sqrtf(1.0f - abs_wall[band][5]);
604
605 /* find total absorption coefficients by calculating the number of hits on
606 * every surface, based on the order per dimension */
607 for(i=0; i<echogram_abs->numImageSources; i++){
608 /* Surfaces intersecting the x-axis */
609 if((echogram_abs->order[i][0]%2)==0) /* ISEVEN */
610 abs_x = powf(r_x[0], (float)abs(echogram_abs->order[i][0])/2.0f) * powf(r_x[1], (float)abs(echogram_abs->order[i][0])/2.0f);
611 else if (echogram_abs->order[i][0]>0) /* ISODD AND POSITIVE */
612 abs_x = powf(r_x[0], ceilf((float)echogram_abs->order[i][0]/2.0f)) * powf(r_x[1], floorf((float)echogram_abs->order[i][0]/2.0f));
613 else /* ISODD AND NEGATIVE */
614 abs_x = powf(r_x[0], floorf((float)abs(echogram_abs->order[i][0])/2.0f)) * powf(r_x[1], ceilf((float)abs(echogram_abs->order[i][0])/2.0f));
615
616 /* Surfaces intersecting the y-axis */
617 if((echogram_abs->order[i][1]%2)==0) /* ISEVEN */
618 abs_y = powf(r_y[0], (float)abs(echogram_abs->order[i][1])/2.0f) * powf(r_y[1], (float)abs(echogram_abs->order[i][1])/2.0f);
619 else if (echogram_abs->order[i][1]>0) /* ISODD AND POSITIVE */
620 abs_y = powf(r_y[0], ceilf((float)echogram_abs->order[i][1]/2.0f)) * powf(r_y[1], floorf((float)echogram_abs->order[i][1]/2.0f));
621 else /* ISODD AND NEGATIVE */
622 abs_y = powf(r_y[0], floorf((float)abs(echogram_abs->order[i][1])/2.0f)) * powf(r_y[1], ceilf((float)abs(echogram_abs->order[i][1])/2.0f));
623
624 /* Surfaces intersecting the y-axis */
625 if((echogram_abs->order[i][2]%2)==0) /* ISEVEN */
626 abs_z = powf(r_z[0], (float)abs(echogram_abs->order[i][2])/2.0f) * powf(r_z[1], (float)abs(echogram_abs->order[i][2])/2.0f);
627 else if (echogram_abs->order[i][2]>0) /* ISODD AND POSITIVE */
628 abs_z = powf(r_z[0], ceilf((float)echogram_abs->order[i][2]/2.0f)) * powf(r_z[1], floorf((float)echogram_abs->order[i][2]/2.0f));
629 else /* ISODD AND NEGATIVE */
630 abs_z = powf(r_z[0], floorf((float)abs(echogram_abs->order[i][2])/2.0f)) * powf(r_z[1], ceilf((float)abs(echogram_abs->order[i][2])/2.0f));
631
632 /* Apply total absorption */
633 s_abs_tot = abs_x * abs_y * abs_z;
634 for(ch=0; ch<echogram_abs->nChannels; ch++)
635 echogram_abs->value[ch][i] *= s_abs_tot;
636 }
637 }
638}
639
641(
642 void* hWork,
643 int fractionalDelayFLAG,
644 float fs,
645 float** H_filt,
646 ims_rir* rir
647)
648{
649 ims_core_workspace *wrk = (ims_core_workspace*)(hWork);
650 echogram_data *echogram_abs;
651 float* temp;
652 int i, j, refl_idx, band, rir_len_samples;
653 float endtime, rir_len_seconds;
654
655 /* Render RIR for each octave band */
656 for(band=0; band<wrk->nBands; band++){
657 echogram_abs = (echogram_data*)wrk->hEchogram_abs[band];
658
659 /* Determine length of rir */
660 endtime = echogram_abs->time[echogram_abs->numImageSources-1];
661 rir_len_samples = (int)(endtime * fs + 1.0f) + 1; /* ceil + 1 */
662 rir_len_seconds = (float)rir_len_samples/fs;
663
664 /* Render rir */
665 if(fractionalDelayFLAG){
666 // TODO: implement
667 saf_print_error("Not implemented yet!");
668 }
669 else{
670 /* Resize RIR vector */
671 wrk->rir_bands[band] = (float**)realloc2d((void**)wrk->rir_bands[band], echogram_abs->nChannels, rir_len_samples, sizeof(float));
672 wrk->rir_len_samples = rir_len_samples;
673 wrk->rir_len_seconds = rir_len_seconds;
674 memset(FLATTEN2D(wrk->rir_bands[band]), 0, (echogram_abs->nChannels)*rir_len_samples*sizeof(float)); /* flush */
675
676 /* Accumulate 'values' for each image source */
677 for(i=0; i<echogram_abs->numImageSources; i++){
678 refl_idx = (int)(echogram_abs->time[i]*fs+0.5f); /* round */
679 for(j=0; j<echogram_abs->nChannels; j++)
680 wrk->rir_bands[band][j][refl_idx] += echogram_abs->value[j][i];
681 }
682 }
683 }
684
685 temp = malloc1d((wrk->rir_len_samples+IMS_FIR_FILTERBANK_ORDER)*sizeof(float));
686
687 /* Resize rir->data if needed, then flush with 0s */
688 echogram_abs = (echogram_data*)wrk->hEchogram_abs[0];
689 if( (echogram_abs->nChannels!=rir->nChannels) || (wrk->rir_len_samples !=rir->length) ){
690 rir->data = realloc1d(rir->data, echogram_abs->nChannels * (wrk->rir_len_samples) * sizeof(float));
691 rir->length = wrk->rir_len_samples;
692 rir->nChannels = echogram_abs->nChannels;
693 }
694 memset(rir->data, 0, echogram_abs->nChannels * (wrk->rir_len_samples) * sizeof(float));
695
696 /* Apply filterbank to rir_bands and sum them up */
697 for(band=0; band<wrk->nBands; band++){
698 echogram_abs = (echogram_data*)wrk->hEchogram_abs[band];
699
700 /* Apply the LPF (lowest band), HPF (highest band), and BPF (all other bands) */
701 for(j=0; j<echogram_abs->nChannels; j++)
702 fftconv(wrk->rir_bands[band][j], H_filt[band], wrk->rir_len_samples, IMS_FIR_FILTERBANK_ORDER+1, 1, temp);
703
704 /* Sum */
705 for(i=0; i<echogram_abs->nChannels; i++)
706 cblas_saxpy(wrk->rir_len_samples, 1.0f, wrk->rir_bands[band][i], 1, &(rir->data[i*(wrk->rir_len_samples)]), 1);
707 }
708
709 free(temp);
710}
#define ORDER2NSH(order)
Converts spherical harmonic order to number of spherical harmonic components i.e: (order+1)^2.
Definition saf_sh.h:51
void getSHreal_recur(int N, float *dirs_rad, int nDirs, float *Y)
Computes real-valued spherical harmonics [1] for each given direction on the unit sphere.
Definition saf_sh.c:254
#define saf_print_error(message)
Macro to print a error message along with the filename and line number.
#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 sortf(float *in_vec, float *out_vec, int *new_idices, int len, int descendFLAG)
Sort a vector of floating-point values into ascending/decending order (optionally returning the new i...
void fftconv(float *x, float *h, int x_len, int h_len, int nCH, float *y)
FFT-based convolution of signal 'x' with filter 'h'.
void unitCart2sph(float *dirs_xyz, int nDirs, int anglesInDegreesFLAG, float *dirs)
Converts Cartesian coordinates of unit length to spherical coordinates.
void ** realloc2d(void **ptr, size_t dim1, size_t dim2, size_t data_size)
2-D realloc which does NOT retain previous data order
Definition md_malloc.c:115
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void * realloc1d(void *ptr, size_t dim1_data_size)
1-D realloc (same as realloc, but with error checking)
Definition md_malloc.c:79
#define FLATTEN2D(A)
Use this macro when passing a 2-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:65
Main header for the reverb processing module (SAF_REVERB_MODULE)
void ims_shoebox_coreWorkspaceCreate(void **phWork, int nBands)
Creates an instance of the core workspace.
void ims_shoebox_coreInitT(void *hWork, float room[3], ims_pos_xyz src, ims_pos_xyz rec, float maxTime_s, float c_ms)
Calculates an echogram of a rectangular space using the image source method, for a specific source/re...
void ims_shoebox_coreWorkspaceDestroy(void **phWork)
Destroys an instance of the core workspace.
void ims_shoebox_coreRecModuleSH(void *hWork, int sh_order)
Imposes spherical harmonic directivies onto the echogram computed with ims_shoebox_coreInit() for a s...
void ims_shoebox_echogramResize(void *hEcho, int numImageSources, int nChannels)
Resizes an echogram container.
void ims_shoebox_coreAbsorptionModule(void *hWork, float **abs_wall)
Applies boundary absoption per frequency band, onto the echogram computed with ims_shoebox_coreRecMod...
void ims_shoebox_renderRIR(void *hWork, int fractionalDelayFLAG, float fs, float **H_filt, ims_rir *rir)
Renders a room impulse response for a specific source/reciever combination.
void ims_shoebox_echogramCreate(void **phEcho, int include_rt_vars)
Creates an instance of an echogram container.
void ims_shoebox_echogramCopy(void *hEchoX, void *hEchoY)
Copies echogram data from container 'X' into container 'Y' (also resizing 'Y' as needed)
void ims_shoebox_coreInitN(void *hWork, float room[3], ims_pos_xyz src, ims_pos_xyz rec, int maxN, float c_ms)
Calculates an echogram of a rectangular space using the image source method, for a specific source/re...
void ims_shoebox_echogramDestroy(void **phEcho)
Destroys an instance of an echogram container.
Internal header for the reverb processing module (SAF_REVERB_MODULE)
#define IMS_LAGRANGE_ORDER
Order of lagrange interpolation filters.
void * voidPtr
Void pointer (just to improve code readability when working with arrays of handles)
#define IMS_FIR_FILTERBANK_ORDER
FIR filter order (must be even)
Echogram structure.
float ** value
Echogram magnitudes per image source and channel; nChannels x numImageSources.
float ** contrib
Total contribution (i.e.
int numImageSources
Number of image sources in current echogram.
int ** order
Reflection order for each image and dimension; numImageSources x 3.
int * rIdx_frac[IMS_LAGRANGE_ORDER]
Current circular buffer read indices for fractional buffers; IMS_LAGRANGE_ORDER x numImageSources.
int * rIdx
Current circular buffer read indices; numImageSources x 1.
ims_pos_xyz * coords
Reflection coordinates (Cartesian); numImageSources x 3.
int nChannels
Number of channels.
float ** h_frac
Current fractional delay coeffs; (IMS_LAGRANGE_ORDER+1) x numImageSources x.
float ** cb_vals
Current circular buffer values (per channel & image source); nChannels x numImageSources.
int include_rt_vars
0: the below vars are disabled, 1: enabled
float * time
Propagation time (in seconds) for each image source; numImageSources x 1.
int * sortedIdx
Indices that sort the echogram based on propagation time in ascending order; numImageSources x 1.
float * tmp1
1st temporary vector; numImageSources x 1
float * ones_dummy
Just a vector of ones, for the cblas_sdot sum hack, and fmodf; numImageSources x 1.
float * tmp2
2nd temporary vector; numImageSources x 1
Helper structure, comprising variables used when computing echograms and rendering RIRs.
float room[3]
Room dimensions, in meters.
void * hEchogram_rec
Echogram with the receiver directivities applied (multi-channel)
voidPtr * hPrevEchogram_abs
Previous echograms (hEchogram_abs), one per band, which can be used for cross- fading.
ims_pos_xyz rec
Receiver position.
voidPtr * hEchogram_abs
Echograms with the receiver directivities and also wall absorption applied (multi- channel); one echo...
int refreshEchogramFLAG
1: Refresh needed, 0: refresh not needed
void * hEchogram
Pressure echogram (single-channel)
int N_max
Maximum reflection order.
ims_pos_xyz src
Source position.
int nBands
Number of bands.
float d_max
Maximum distance, in meters.
Union struct for Cartesian coordinates (access as .x,.y,.z, or .v[3])
float y
y Cartesian coordinate, in metres
float z
z Cartesian coordinate, in metres
float v[3]
x,y,z Cartesian coordinates, in metres
float x
x Cartesian coordinate, in metres
Output format of the rendered room impulse responses (RIR)
Definition saf_reverb.h:58