SAF
Loading...
Searching...
No Matches
sldoa.c
Go to the documentation of this file.
1/*
2 * Copyright 2017-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
46#include "sldoa.h"
47#include "sldoa_internal.h"
48
50(
51 void ** const phSld
52)
53{
54 sldoa_data* pData = (sldoa_data*)malloc1d(sizeof(sldoa_data));
55 *phSld = (void*)pData;
56 int i, band;
57
58 /* Default user parameters */
59 pData->new_masterOrder = pData->masterOrder = 1;
60 for(band=0; band<HYBRID_BANDS; band++){
61 pData->analysisOrderPerBand[band] = pData->masterOrder;
63 }
64 pData->minFreq = 500.0f;
65 pData->maxFreq = 5e3f;
66 pData->avg_ms = 500.0f;
67 pData->chOrdering = CH_ACN;
68 pData->norm = NORM_SN3D;
69
70 /* TFT */
72 pData->SHframeTD = (float**)malloc2d(MAX_NUM_SH_SIGNALS, SLDOA_FRAME_SIZE, sizeof(float));
73 pData->SHframeTF = (float_complex***)malloc3d(HYBRID_BANDS, MAX_NUM_SH_SIGNALS, TIME_SLOTS, sizeof(float_complex));
74
75 /* internal */
76 pData->progressBar0_1 = 0.0f;
78 strcpy(pData->progressBarText,"");
81 for(i=0; i<MAX_SH_ORDER-1; i++)
82 pData->secCoeffs[i] = NULL;
83
84 /* Grid/basis stuff */
86 pData->grid_Y = (float**)calloc2d(ORDER2NSH(MAX_SH_ORDER), pData->nGrid, sizeof(float));
88 pData->grid_Y_dipoles_norm = (float**)calloc2d(3, pData->nGrid, sizeof(float));
89 for(i=0; i<3; i++)
90 cblas_scopy(pData->nGrid, pData->grid_Y[i+1], 1, pData->grid_Y_dipoles_norm[i], 1);
91 cblas_sscal(3*pData->nGrid, 1.0f/sqrtf(3.0f), FLATTEN2D(pData->grid_Y_dipoles_norm), 1);
92 pData->grid_dirs_deg = (float**)calloc2d(pData->nGrid, 2, sizeof(float));
93 cblas_scopy(pData->nGrid*2, (float*)__Tdesign_degree_70_dirs_deg, 1, FLATTEN2D(pData->grid_dirs_deg), 1);
94
95 /* display */
96 for(i=0; i<NUM_DISP_SLOTS; i++){
97 pData->azi_deg[i] = malloc1d(HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
98 pData->elev_deg[i] = malloc1d(HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
99 pData->colourScale[i] = malloc1d(HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
100 pData->alphaScale[i] = malloc1d(HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
101 }
102
103 /* set FIFO buffer */
104 pData->fs = 48000.0f;
105 pData->FIFO_idx = 0;
106 pData->inFIFO = (float**)calloc2d(MAX_NUM_SH_SIGNALS, SLDOA_FRAME_SIZE, sizeof(float));
107}
108
110(
111 void ** const phSld
112)
113{
114 sldoa_data *pData = (sldoa_data*)(*phSld);
115 int i;
116
117 if (pData != NULL) {
118 /* not safe to free memory during intialisation/processing loop */
119 while (pData->codecStatus == CODEC_STATUS_INITIALISING ||
121 SAF_SLEEP(10);
122 }
123
124 /* free afSTFT and buffers */
125 afSTFT_destroy(&(pData->hSTFT));
126 free(pData->SHframeTD);
127 free(pData->SHframeTF);
128
129 for(i=0; i<NUM_DISP_SLOTS; i++){
130 free(pData->azi_deg[i]);
131 free(pData->elev_deg[i]);
132 free(pData->colourScale[i]);
133 free(pData->alphaScale[i]);
134 }
135 free(pData->progressBarText);
136
137 /* Grid/basis stuff */
138 free(pData->grid_Y);
139 free(pData->grid_Y_dipoles_norm);
140 free(pData->grid_dirs_deg);
141
142 free(pData->inFIFO);
143
144 free(pData);
145 pData = NULL;
146 *phSld = NULL;
147 }
148}
149
151(
152 void * const hSld,
153 float sampleRate
154)
155{
156 sldoa_data *pData = (sldoa_data*)(hSld);
157 int i;
158
159 pData->fs = sampleRate;
160
161 /* specify frequency vector and determine the number of bands */
162 afSTFT_getCentreFreqs(pData->hSTFT, sampleRate, HYBRID_BANDS, pData->freqVector);
163
164 /* intialise display parameters */
165 pData->current_disp_idx = 0;
166 memset(pData->doa_rad, 0, HYBRID_BANDS*MAX_NUM_SECTORS*2* sizeof(float));
167 memset(pData->energy, 0, HYBRID_BANDS*MAX_NUM_SECTORS* sizeof(float));
168 for(i=0; i<NUM_DISP_SLOTS; i++){
169 memset(pData->azi_deg[i], 0, HYBRID_BANDS*MAX_NUM_SECTORS* sizeof(float));
170 memset(pData->elev_deg[i], 0, HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
171 memset(pData->colourScale[i], 0, HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
172 memset(pData->alphaScale[i], 0, HYBRID_BANDS*MAX_NUM_SECTORS * sizeof(float));
173 }
174}
175
177(
178 void* const hSld
179)
180{
181 sldoa_data *pData = (sldoa_data*)(hSld);
182
184 return; /* re-init not required, or already happening */
185 while (pData->procStatus == PROC_STATUS_ONGOING){
186 /* re-init required, but we need to wait for the current processing loop to end */
187 pData->codecStatus = CODEC_STATUS_INITIALISING; /* indicate that we want to init */
188 SAF_SLEEP(10);
189 }
190
191 /* for progress bar */
193 strcpy(pData->progressBarText,"Initialising");
194 pData->progressBar0_1 = 0.0f;
195
196 sldoa_initTFT(hSld);
197 sldoa_initAna(hSld);
198
199 /* done! */
200 strcpy(pData->progressBarText,"Done!");
201 pData->progressBar0_1 = 1.0f;
203}
204
206(
207 void * const hSld,
208 const float *const * inputs,
209 int nInputs,
210 int nSamples,
211 int isPlaying
212)
213{
214 sldoa_data *pData = (sldoa_data*)(hSld);
215 int s, i, j, t, ch, band, nSectors, min_band, numAnalysisBands, current_disp_idx;
216 float avgCoeff, max_en[HYBRID_BANDS], min_en[HYBRID_BANDS];
217 float new_doa[MAX_NUM_SECTORS][TIME_SLOTS][2], new_doa_xyz[3], doa_xyz[3], avg_xyz[3];
218 float new_energy[MAX_NUM_SECTORS][TIME_SLOTS];
219
220 /* local parameters */
221 int nSH, masterOrder;
222 int analysisOrderPerBand[HYBRID_BANDS];
223 int nSectorsPerBand[HYBRID_BANDS];
224 float minFreq, maxFreq, avg_ms;
225 CH_ORDER chOrdering;
226 NORM_TYPES norm;
227 memcpy(analysisOrderPerBand, pData->analysisOrderPerBand, HYBRID_BANDS*sizeof(int));
228 memcpy(nSectorsPerBand, pData->nSectorsPerBand, HYBRID_BANDS*sizeof(int));
229 minFreq = pData->minFreq;
230 maxFreq = pData->maxFreq;
231 avg_ms = pData->avg_ms;
232 chOrdering = pData->chOrdering;
233 norm = pData->norm;
234 masterOrder = pData->masterOrder;
235 nSH = ORDER2NSH(masterOrder);
236
237 /* Loop over all samples */
238 for(s=0; s<nSamples; s++){
239 /* Load input signals into inFIFO buffer */
240 for(ch=0; ch<SAF_MIN(nInputs,nSH); ch++)
241 pData->inFIFO[ch][pData->FIFO_idx] = inputs[ch][s];
242 for(; ch<nSH; ch++) /* Zero any channels that were not given */
243 pData->inFIFO[ch][pData->FIFO_idx] = 0.0f;
244
245 /* Increment buffer index */
246 pData->FIFO_idx++;
247
248 /* Process frame if inFIFO is full and codec is ready for it */
249 if (pData->FIFO_idx >= SLDOA_FRAME_SIZE && (pData->codecStatus == CODEC_STATUS_INITIALISED) && isPlaying) {
250 pData->FIFO_idx = 0;
252 current_disp_idx = pData->current_disp_idx;
253
254 /* Load time-domain data */
255 for(ch=0; ch<nSH; ch++)
256 memcpy(pData->SHframeTD[ch],pData->inFIFO[ch], SLDOA_FRAME_SIZE*sizeof(float));
257
258 /* account for input channel order */
259 switch(chOrdering){
260 case CH_ACN: /* already ACN */ break; /* Otherwise, convert to ACN... */
262 }
263
264 /* account for input normalisation scheme */
265 switch(norm){
266 case NORM_N3D: /* already in N3D, do nothing */ break; /* Otherwise, convert to N3D... */
269 }
270
271 /* apply the time-frequency transform */
273
274 /* apply sector-based, frequency-dependent DOA analysis */
275 numAnalysisBands = 0;
276 min_band = 0;
277 for(band=1/* ignore DC */; band<HYBRID_BANDS; band++){
278 if(pData->freqVector[band] <= minFreq)
279 min_band = band;
280 if(pData->freqVector[band] >= minFreq && pData->freqVector[band]<=maxFreq){
281 nSectors = nSectorsPerBand[band];
282 avgCoeff = avg_ms < 10.0f ? 1.0f : 1.0f / ((avg_ms/1e3f) / (1.0f/(float)HOP_SIZE) + 2.23e-9f);
283 avgCoeff = SAF_MAX(SAF_MIN(avgCoeff, 0.99999f), 0.0f); /* ensures stability */
284 sldoa_estimateDoA(pData->SHframeTF[band],
285 analysisOrderPerBand[band],
286 pData->secCoeffs[analysisOrderPerBand[band]-2], /* -2, as first order is skipped */
287 new_doa,
288 new_energy);
289
290 /* average the raw data over time */
291 for(i=0; i<nSectors; i++){
292 for( t = 0; t<TIME_SLOTS; t++){
293 /* avg doa estimate */
294 unitSph2cart((float*)new_doa[i][t], 1, 0, (float*)new_doa_xyz);
295 unitSph2cart((float*)pData->doa_rad[band][i], 1, 0, (float*)doa_xyz);
296 for(j=0; j<3; j++)
297 avg_xyz[j] = new_doa_xyz[j]*avgCoeff + doa_xyz[j] * (1.0f-avgCoeff);
298 unitCart2sph((float*)avg_xyz, 1, 0, (float*)pData->doa_rad[band][i]);
299
300 /* avg energy */
301 pData->energy[band][i] = new_energy[i][t]*avgCoeff + pData->energy[band][i] * (1.0f-avgCoeff);
302 }
303 }
304 numAnalysisBands++;
305 }
306 }
307
308 /* determine the minimum and maximum sector energies per frequency (to scale them 0..1) */
309 for(band=1/* ignore DC */; band<HYBRID_BANDS; band++){
310 if(pData->freqVector[band] >= minFreq && pData->freqVector[band]<=maxFreq){
311 nSectors = nSectorsPerBand[band];
312 max_en[band] = 2.3e-13f; min_en[band] = 2.3e13f; /* starting values */
313 for(i=0; i<nSectors; i++){
314 max_en[band] = pData->energy[band][i] > max_en[band] ? pData->energy[band][i] : max_en[band];
315 min_en[band] = pData->energy[band][i] < min_en[band] ? pData->energy[band][i] : min_en[band];
316 }
317 }
318 }
319
320 /* prep data for plotting */
321 for(band=1/* ignore DC */; band<HYBRID_BANDS; band++){
322 if(pData->freqVector[band] >= minFreq && pData->freqVector[band]<=maxFreq){
323 nSectors = nSectorsPerBand[band];
324 /* store averaged values */
325 for(i=0; i<nSectors; i++){
326 pData->azi_deg [current_disp_idx][band*MAX_NUM_SECTORS + i] = pData->doa_rad[band][i][0]*180.0f/SAF_PI;
327 pData->elev_deg[current_disp_idx][band*MAX_NUM_SECTORS + i] = pData->doa_rad[band][i][1]*180.0f/SAF_PI;
328
329 /* colour should indicate the different frequencies */
330 pData->colourScale[current_disp_idx][band*MAX_NUM_SECTORS + i] = (float)(band-min_band)/(float)(numAnalysisBands+1);
331
332 /* transparancy should indicate the energy of the sector for each DoA estimate, for each frequency */
333 if( analysisOrderPerBand[band]==1 )
334 pData->alphaScale[current_disp_idx][band*MAX_NUM_SECTORS + i] = 1.0f;
335 else
336 pData->alphaScale[current_disp_idx][band*MAX_NUM_SECTORS + i] = SAF_MIN(SAF_MAX((pData->energy[band][i]-min_en[band])/(max_en[band]-min_en[band]+2.3e-10f), 0.05f),1.0f);
337 }
338 }
339 else{
340 memset(&(pData->azi_deg [current_disp_idx][band*MAX_NUM_SECTORS]), 0, MAX_NUM_SECTORS*sizeof(float));
341 memset(&(pData->elev_deg [current_disp_idx][band*MAX_NUM_SECTORS]), 0, MAX_NUM_SECTORS*sizeof(float));
342 memset(&(pData->colourScale [current_disp_idx][band*MAX_NUM_SECTORS]), 0, MAX_NUM_SECTORS*sizeof(float));
343 memset(&(pData->alphaScale [current_disp_idx][band*MAX_NUM_SECTORS]), 0, MAX_NUM_SECTORS*sizeof(float));
344 }
345 }
346 }
347 else if(pData->FIFO_idx >= SLDOA_FRAME_SIZE){
348 /* reset FIFO_idx if codec was not ready */
349 pData->FIFO_idx = 0;
350 }
351 }
352
354}
355
356/* SETS */
357
358void sldoa_setMasterOrder(void* const hSld, int newValue)
359{
360 sldoa_data *pData = (sldoa_data*)(hSld);
361 if(pData->new_masterOrder != newValue){
362 pData->new_masterOrder = newValue;
364 }
365 /* FUMA only supports 1st order */
366 if(pData->new_masterOrder!=SH_ORDER_FIRST && pData->chOrdering == CH_FUMA)
367 pData->chOrdering = CH_ACN;
368 if(pData->new_masterOrder!=SH_ORDER_FIRST && pData->norm == NORM_FUMA)
369 pData->norm = NORM_SN3D;
370}
371
376
377void sldoa_setMaxFreq(void* const hSld, float newFreq)
378{
379 sldoa_data *pData = (sldoa_data*)(hSld);
380 newFreq = SAF_MAX(SAF_MIN(newFreq, pData->fs/2.0f),0.0f);
381 if(newFreq < pData->minFreq )
382 pData->minFreq = newFreq;
383 pData->maxFreq = newFreq;
384}
385
386void sldoa_setMinFreq(void* const hSld, float newFreq)
387{
388 sldoa_data *pData = (sldoa_data*)(hSld);
389 newFreq = SAF_MAX(SAF_MIN(newFreq, pData->fs/2.0f),0.0f);
390 if(newFreq > pData->maxFreq )
391 pData->maxFreq = newFreq;
392 pData->minFreq = newFreq;
393}
394
395void sldoa_setAvg(void* const hSld, float newAvg)
396{
397 sldoa_data *pData = (sldoa_data*)(hSld);
398 pData->avg_ms = newAvg;
399}
400
401void sldoa_setSourcePreset(void* const hSld, int newPresetID)
402{
403 sldoa_data *pData = (sldoa_data*)(hSld);
404 int band, rangeIdx, curOrder, reverse;
405
406 rangeIdx = 0;
407 curOrder = 1;
408 reverse = 0;
409 switch(newPresetID){
410 case MIC_PRESET_IDEAL:
411 for(band=0; band<HYBRID_BANDS; band++)
412 pData->analysisOrderPerBand[band] = pData->new_masterOrder;
413 break;
414
415 case MIC_PRESET_ZYLIA:
416 for(band=0; band<HYBRID_BANDS; band++){
417 if(rangeIdx<2*(__Zylia_maxOrder-1)){
418 if(pData->freqVector[band]>__Zylia_freqRange[rangeIdx]){
419 if(!reverse)
420 curOrder++;
421 else
422 curOrder--;
423 reverse = (curOrder == __Zylia_maxOrder) || (reverse) ? 1 : 0;
424 rangeIdx++;
425 }
426 }
427 pData->analysisOrderPerBand[band] = SAF_MIN(pData->new_masterOrder,curOrder);
428 }
430 break;
431
432 case MIC_PRESET_EIGENMIKE32:
433 for(band=0; band<HYBRID_BANDS; band++){
434 if(rangeIdx<2*(__Eigenmike32_maxOrder-1)){
435 if(pData->freqVector[band]>__Eigenmike32_freqRange[rangeIdx]){
436 if(!reverse)
437 curOrder++;
438 else
439 curOrder--;
440 reverse = (curOrder == __Eigenmike32_maxOrder) || (reverse) ? 1 : 0;
441 rangeIdx++;
442 }
443 }
444 pData->analysisOrderPerBand[band] = SAF_MIN(pData->new_masterOrder,curOrder);
445 }
447 break;
448
449 case MIC_PRESET_DTU_MIC:
450 for(band=0; band<HYBRID_BANDS; band++){
451 if(rangeIdx<2*(__DTU_mic_maxOrder-1)){
452 if(pData->freqVector[band]>__DTU_mic_freqRange[rangeIdx]){
453 if(!reverse)
454 curOrder++;
455 else
456 curOrder--;
457 reverse = (curOrder == __DTU_mic_maxOrder) || (reverse) ? 1 : 0;
458 rangeIdx++;
459 }
460 }
461 pData->analysisOrderPerBand[band] = SAF_MIN(pData->new_masterOrder,curOrder);
462 }
464 break;
465 }
466 for(band=0; band<HYBRID_BANDS; band++)
468}
469
470void sldoa_setAnaOrder(void * const hSld, int newValue, int bandIdx)
471{
472 sldoa_data *pData = (sldoa_data*)(hSld);
473 pData->analysisOrderPerBand[bandIdx] = SAF_MIN(SAF_MAX(newValue,1), pData->new_masterOrder);
475}
476
477void sldoa_setAnaOrderAllBands(void * const hSld, int newValue)
478{
479 sldoa_data *pData = (sldoa_data*)(hSld);
480 int band;
481
482 for(band=0; band<HYBRID_BANDS; band++){
483 pData->analysisOrderPerBand[band] = SAF_MIN(SAF_MAX(newValue,1), pData->new_masterOrder);
485 }
486}
487
488void sldoa_setChOrder(void* const hSld, int newOrder)
489{
490 sldoa_data *pData = (sldoa_data*)(hSld);
491 if((CH_ORDER)newOrder != CH_FUMA || pData->new_masterOrder==SH_ORDER_FIRST)/* FUMA only supports 1st order */
492 pData->chOrdering = (CH_ORDER)newOrder;
493}
494
495void sldoa_setNormType(void* const hSld, int newType)
496{
497 sldoa_data *pData = (sldoa_data*)(hSld);
498 if((NORM_TYPES)newType != NORM_FUMA || pData->new_masterOrder==SH_ORDER_FIRST)/* FUMA only supports 1st order */
499 pData->norm = (NORM_TYPES)newType;
500}
501
502
503/* GETS */
504
506{
507 return SLDOA_FRAME_SIZE;
508}
509
511{
512 sldoa_data *pData = (sldoa_data*)(hSld);
513 return pData->codecStatus;
514}
515
516float sldoa_getProgressBar0_1(void* const hSld)
517{
518 sldoa_data *pData = (sldoa_data*)(hSld);
519 return pData->progressBar0_1;
520}
521
522void sldoa_getProgressBarText(void* const hSld, char* text)
523{
524 sldoa_data *pData = (sldoa_data*)(hSld);
525 memcpy(text, pData->progressBarText, PROGRESSBARTEXT_CHAR_LENGTH*sizeof(char));
526}
527
528int sldoa_getMasterOrder(void* const hSld)
529{
530 sldoa_data *pData = (sldoa_data*)(hSld);
531 return pData->new_masterOrder;
532}
533
534int sldoa_getSamplingRate(void* const hSld)
535{
536 sldoa_data *pData = (sldoa_data*)(hSld);
537 return (int)(pData->fs+0.5f);
538}
539
540float sldoa_getMaxFreq(void* const hSld)
541{
542 sldoa_data *pData = (sldoa_data*)(hSld);
543 return pData->maxFreq;
544}
545
546float sldoa_getMinFreq(void* const hSld)
547{
548 sldoa_data *pData = (sldoa_data*)(hSld);
549 return pData->minFreq;
550}
551
552float sldoa_getAvg(void* const hSld)
553{
554 sldoa_data *pData = (sldoa_data*)(hSld);
555 return pData->avg_ms;
556}
557
558/* Not very elegent, but does the job */
560(
561 void * const hSld,
562 float** azi_deg,
563 float** elev_deg,
564 float** colourScale,
565 float** alphaScale,
566 int** pNsectorsPerBand,
567 int* maxNumSectors,
568 int* startBand,
569 int* endBand
570)
571{
572 sldoa_data *pData = (sldoa_data*)(hSld);
573 int i;
574
575 (*azi_deg) = pData->azi_deg[pData->current_disp_idx];
576 (*elev_deg) = pData->elev_deg[pData->current_disp_idx];
577 (*colourScale) = pData->colourScale[pData->current_disp_idx];
578 (*alphaScale) = pData->alphaScale[pData->current_disp_idx];
579 (*pNsectorsPerBand) = pData->nSectorsPerBand;
580 (*maxNumSectors) = MAX_NUM_SECTORS;
581 (*startBand) =1;
582 (*endBand) =1;
583 for(i=1/*ignore DC*/; i<HYBRID_BANDS; i++){
584 if(pData->freqVector[i]<pData->minFreq)
585 (*startBand) = i+1;
586 if(pData->freqVector[i]<pData->maxFreq)
587 (*endBand) = i;
588 }
589 /* read the next buffer for the next call */
590 pData->current_disp_idx++;
591 if(pData->current_disp_idx >= NUM_DISP_SLOTS)
592 pData->current_disp_idx = 0;
593}
594
595int sldoa_getAnaOrder(void * const hSld, int bandIdx)
596{
597 sldoa_data *pData = (sldoa_data*)(hSld);
598 return pData->analysisOrderPerBand[bandIdx];
599}
600
601int sldoa_getAnaOrderAllBands(void * const hSld)
602{
603 sldoa_data *pData = (sldoa_data*)(hSld);
604 return pData->analysisOrderPerBand[0];
605}
606
608(
609 void* const hSld,
610 float** pX_vector,
611 int** pY_values,
612 int* pNpoints
613)
614{
615 sldoa_data *pData = (sldoa_data*)(hSld);
616 (*pX_vector) = &(pData->freqVector[0]);
617 (*pY_values) = &(pData->analysisOrderPerBand[0]);
618 (*pNpoints) = HYBRID_BANDS;
619}
620
622{
623 return HYBRID_BANDS;
624}
625
626int sldoa_getNSHrequired(void* const hSld)
627{
628 sldoa_data *pData = (sldoa_data*)(hSld);
629 return (pData->new_masterOrder+1)*(pData->new_masterOrder+1);
630}
631
632int sldoa_getChOrder(void* const hSld)
633{
634 sldoa_data *pData = (sldoa_data*)(hSld);
635 return (int)pData->chOrdering;
636}
637
638int sldoa_getNormType(void* const hSld)
639{
640 sldoa_data *pData = (sldoa_data*)(hSld);
641 return (int)pData->norm;
642}
643
645{
646 return SLDOA_FRAME_SIZE + 12*HOP_SIZE;
647}
#define MAX_SH_ORDER
Maximum supported Ambisonic order.
Definition _common.h:52
#define PROGRESSBARTEXT_CHAR_LENGTH
Length of progress bar string.
Definition _common.h:227
@ PROC_STATUS_ONGOING
Codec is processing input audio, and should not be reinitialised at this time.
Definition _common.h:220
@ PROC_STATUS_NOT_ONGOING
Codec is not processing input audio, and may be reinitialised if needed.
Definition _common.h:222
NORM_TYPES
Available Ambisonic normalisation conventions.
Definition _common.h:74
@ NORM_SN3D
Schmidt semi-normalisation (SN3D)
Definition _common.h:76
@ NORM_FUMA
(Legacy) Furse-Malham scaling
Definition _common.h:77
@ NORM_N3D
orthonormalised (N3D)
Definition _common.h:75
CH_ORDER
Available Ambisonic channel ordering conventions.
Definition _common.h:59
@ CH_ACN
Ambisonic Channel Numbering (ACN)
Definition _common.h:60
@ CH_FUMA
(Legacy) Furse-Malham/B-format (WXYZ)
Definition _common.h:61
#define MAX_NUM_SH_SIGNALS
Maximum number of spherical harmonic components/signals supported.
Definition _common.h:239
@ SH_ORDER_FIRST
First-order (4 channels)
Definition _common.h:39
CODEC_STATUS
Current status of the codec.
Definition _common.h:201
@ CODEC_STATUS_NOT_INITIALISED
Codec has not yet been initialised, or the codec configuration has changed.
Definition _common.h:204
@ CODEC_STATUS_INITIALISED
Codec is initialised and ready to process input audio.
Definition _common.h:202
@ CODEC_STATUS_INITIALISING
Codec is currently being initialised, input audio should not be processed.
Definition _common.h:207
void afSTFT_create(void **const phSTFT, int nCHin, int nCHout, int hopsize, int lowDelayMode, int hybridmode, AFSTFT_FDDATA_FORMAT format)
Creates an instance of afSTFT.
Definition afSTFTlib.c:143
void afSTFT_forward_knownDimensions(void *const hSTFT, float **dataTD, int framesize, int dataFD_nCH, int dataFD_nHops, float_complex ***dataFD)
Performs forward afSTFT transform (dataFD dimensions are known)
Definition afSTFTlib.c:268
void afSTFT_getCentreFreqs(void *const hSTFT, float fs, int nBands, float *freqVector)
Returns current frequency vector.
Definition afSTFTlib.c:546
void afSTFT_destroy(void **const phSTFT)
Destroys an instance of afSTFT.
Definition afSTFTlib.c:199
@ AFSTFT_BANDS_CH_TIME
nBands x nChannels x nTimeHops
Definition afSTFTlib.h:80
#define TIME_SLOTS
Number of STFT timeslots.
#define HOP_SIZE
STFT hop size.
#define HYBRID_BANDS
Number of frequency bands.
#define NUM_DISP_SLOTS
Number of display slots.
void convertHOAChannelConvention(float *insig, int order, int signalLength, HOA_CH_ORDER inConvention, HOA_CH_ORDER outConvention)
Converts an Ambisonic signal from one channel ordering convention to another.
Definition saf_hoa.c:41
void getRSH(int N, float *dirs_deg, int nDirs, float *Y)
Computes real-valued spherical harmonics [1] for each given direction on the unit sphere.
Definition saf_hoa.c:119
void convertHOANormConvention(float *insig, int order, int signalLength, HOA_NORM inConvention, HOA_NORM outConvention)
Converts an Ambisonic signal from one normalisation convention to another.
Definition saf_hoa.c:73
@ HOA_CH_ORDER_FUMA
Furse-Malham (FuMa) convention, often used by older recordings.
Definition saf_hoa.h:187
@ HOA_CH_ORDER_ACN
Ambisonic Channel numbering (ACN) convention, which is employed by all spherical harmonic related fun...
Definition saf_hoa.h:184
@ HOA_NORM_FUMA
Furse-Malham (FuMa) convention.
Definition saf_hoa.h:208
@ HOA_NORM_SN3D
Schmidt semi-normalisation (SN3D) convention, as used by the AmbiX standard.
Definition saf_hoa.h:206
@ HOA_NORM_N3D
Orthonormalised (N3D) convention, which is the default convention used by SAF.
Definition saf_hoa.h:204
#define ORDER2NSH(order)
Converts spherical harmonic order to number of spherical harmonic components i.e: (order+1)^2.
Definition saf_sh.h:51
#define SAF_PI
pi constant (single precision)
#define SAF_MAX(a, b)
Returns the maximum of the two values.
const float __Tdesign_degree_70_dirs_deg[2520][2]
Directions [azimuth, Elevation] in degrees, for minimum Tdesign degree: 70.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
const float __Eigenmike32_freqRange[6]
Sensor array frequency ranges for each SH order, for the Eigenmike32 (should only be used as a rough ...
void unitSph2cart(float *dirs, int nDirs, int anglesInDegreesFLAG, float *dirs_xyz)
Converts spherical coordinates to Cartesian coordinates of unit length.
void unitCart2sph(float *dirs_xyz, int nDirs, int anglesInDegreesFLAG, float *dirs)
Converts Cartesian coordinates of unit length to spherical coordinates.
const int __Eigenmike32_maxOrder
Max spherical harmonic order for the Eigenmike32.
const float __Zylia_freqRange[4]
Sensor array frequency ranges for each SH order, for the Zylia array (should only be used as a rough ...
const int __DTU_mic_maxOrder
Max spherical harmonic order for the custom 52-sensor array built at the Technical University of Denm...
const float __DTU_mic_freqRange[10]
Sensor array frequency ranges for each SH order, for the DTU mic (should only be used as a rough esti...
const int __Tdesign_degree_70_nPoints
Number of directions in a minimum Tdesign of degree: 70.
const int __Zylia_maxOrder
Max spherical harmonic order for the Zylia mic.
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 *** malloc3d(size_t dim1, size_t dim2, size_t dim3, size_t data_size)
3-D malloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:151
void ** calloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:102
#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
int sldoa_getNumberOfBands(void)
Returns the number frequency bands employed by sldoa.
Definition sldoa.c:621
void sldoa_destroy(void **const phSld)
Destroys an instance of the sldoa.
Definition sldoa.c:110
int sldoa_getMasterOrder(void *const hSld)
Returns the current maximum analysis/input order (see SH_ORDERS enum)
Definition sldoa.c:528
int sldoa_getAnaOrder(void *const hSld, int bandIdx)
Returns the input/analysis order for one specific frequency band.
Definition sldoa.c:595
int sldoa_getChOrder(void *const hSld)
Returns the Ambisonic channel ordering convention currently being used to decode with,...
Definition sldoa.c:632
void sldoa_refreshSettings(void *const hSld)
Sets all intialisation flags to 1; re-initialising all settings/variables as sldoa is currently confi...
Definition sldoa.c:372
void sldoa_initCodec(void *const hSld)
Intialises the codec variables, based on current global/user parameters.
Definition sldoa.c:177
int sldoa_getAnaOrderAllBands(void *const hSld)
Returns the input/analysis order for the first frequency band.
Definition sldoa.c:601
void sldoa_setChOrder(void *const hSld, int newOrder)
Sets the Ambisonic channel ordering convention to decode with, in order to match the convention emplo...
Definition sldoa.c:488
void sldoa_setSourcePreset(void *const hSld, int newPresetID)
Sets an input preset, the microphone/hyrophone array used to capture the input signals (see MIC_PRESE...
Definition sldoa.c:401
void sldoa_setMaxFreq(void *const hSld, float newFreq)
Sets the maximum analysis frequency, in Hz.
Definition sldoa.c:377
int sldoa_getFrameSize(void)
Returns the processing framesize (i.e., number of samples processed with every _process() call )
Definition sldoa.c:505
void sldoa_setAnaOrder(void *const hSld, int newValue, int bandIdx)
Sets the input/analysis order for one specific frequency band.
Definition sldoa.c:470
void sldoa_getDisplayData(void *const hSld, float **azi_deg, float **elev_deg, float **colourScale, float **alphaScale, int **pNsectorsPerBand, int *maxNumSectors, int *startBand, int *endBand)
Returns the analysis output data.
Definition sldoa.c:560
float sldoa_getMaxFreq(void *const hSld)
Returns the maximum analysis frequency, in Hz.
Definition sldoa.c:540
void sldoa_setNormType(void *const hSld, int newType)
Sets the Ambisonic normalisation convention to decode with, in order to match with the convention emp...
Definition sldoa.c:495
void sldoa_setAnaOrderAllBands(void *const hSld, int newValue)
Sets the input/analysis order for all frequency bands.
Definition sldoa.c:477
int sldoa_getNormType(void *const hSld)
Returns the Ambisonic normalisation convention currently being usedto decode with,...
Definition sldoa.c:638
void sldoa_getAnaOrderHandle(void *const hSld, float **pX_vector, int **pY_values, int *pNpoints)
Returns the input/analysis order for all frequency bands.
Definition sldoa.c:608
void sldoa_init(void *const hSld, float sampleRate)
Initialises an instance of sldoa with default settings.
Definition sldoa.c:151
void sldoa_analysis(void *const hSld, const float *const *inputs, int nInputs, int nSamples, int isPlaying)
Applies the spatially-localised active-intensity based direction-of-arrival estimator (SLDoA) onto th...
Definition sldoa.c:206
float sldoa_getProgressBar0_1(void *const hSld)
(Optional) Returns current intialisation/processing progress, between 0..1
Definition sldoa.c:516
float sldoa_getAvg(void *const hSld)
Returns the current DoA averaging coefficient value, 0..1.
Definition sldoa.c:552
float sldoa_getMinFreq(void *const hSld)
Returns the minimum analysis frequency, in Hz.
Definition sldoa.c:546
int sldoa_getProcessingDelay()
Returns the processing delay in samples (may be used for delay compensation features)
Definition sldoa.c:644
CODEC_STATUS sldoa_getCodecStatus(void *const hSld)
Returns current codec status (see CODEC_STATUS enum)
Definition sldoa.c:510
void sldoa_setAvg(void *const hSld, float newAvg)
Sets the DoA averaging coefficient, 0..1.
Definition sldoa.c:395
int sldoa_getNSHrequired(void *const hSld)
Returns the number of spherical harmonic signals required by the current analysis order: (current_ord...
Definition sldoa.c:626
void sldoa_setMasterOrder(void *const hSld, int newValue)
Sets the maximum input/analysis order (see SH_ORDERS enum)
Definition sldoa.c:358
void sldoa_getProgressBarText(void *const hSld, char *text)
(Optional) Returns current intialisation/processing progress text
Definition sldoa.c:522
void sldoa_create(void **const phSld)
Creates an instance of the sldoa.
Definition sldoa.c:50
int sldoa_getSamplingRate(void *const hSld)
Returns the current sampling rate, in Hz.
Definition sldoa.c:534
void sldoa_setMinFreq(void *const hSld, float newFreq)
Sets the minimum analysis frequency, in Hz.
Definition sldoa.c:386
A spatially-localised active-intensity (SLAI) based direction-of- arrival estimator (SLDoA)
void sldoa_setCodecStatus(void *const hSld, CODEC_STATUS newStatus)
Sets codec status (see CODEC_STATUS enum)
void sldoa_initAna(void *const hSld)
Intialises the codec variables, based on current global/user parameters.
void sldoa_initTFT(void *const hSld)
Initialise the filterbank used by sldoa.
void sldoa_estimateDoA(float_complex **SHframeTF, int anaOrder, float_complex *secCoeffs, float doa[MAX_NUM_SECTORS][TIME_SLOTS][2], float energy[MAX_NUM_SECTORS][TIME_SLOTS])
Estimates the DoA using the active intensity vectors derived from spatially localised sectors,...
A spatially-localised active-intensity (SLAI) based direction-of- arrival estimator (SLDoA)
#define MAX_NUM_SECTORS
maximum number of sectors, TODO: expand beyond 64 (which is the max possible in the spherecovering gr...
#define SLDOA_FRAME_SIZE
Framesize, in time-domain samples.
#define ORDER2NUMSECTORS(L)
Macro to convert SH order to number of sectors.
Main struct for sldoa.
int FIFO_idx
FIFO buffer index.
float maxFreq
Maximum display frequency, in Hz.
float energy[HYBRID_BANDS][MAX_NUM_SECTORS]
Current Sector energies.
int new_masterOrder
New master/maximum analysis order (current value will be replaced by this after next re-init)
float fs
Host sampling rate, in Hz.
float progressBar0_1
Current (re)initialisation progress, between [0..1].
PROC_STATUS procStatus
see PROC_STATUS
float ** inFIFO
FIFO buffer.
void * hSTFT
afSTFT handle
float * colourScale[NUM_DISP_SLOTS]
Values dictating each DoA marker colour.
float * alphaScale[NUM_DISP_SLOTS]
Values dictating each DoA marker transparency.
int analysisOrderPerBand[HYBRID_BANDS]
Analysis order MIN(anaPerBand, masterOrder) for each frequency band.
float * elev_deg[NUM_DISP_SLOTS]
DoA elevations, in degrees.
float_complex * secCoeffs[MAX_SH_ORDER-1]
Sector beamforming weights/coefficients.
CODEC_STATUS codecStatus
see CODEC_STATUS
float minFreq
Minimum display frequency, in Hz.
float doa_rad[HYBRID_BANDS][MAX_NUM_SECTORS][2]
Current DoA estimates per band and sector, in radians.
float ** grid_Y_dipoles_norm
SH basis.
char * progressBarText
Current (re)initialisation step, string.
NORM_TYPES norm
Ambisonic normalisation convention (see NORM_TYPES)
float_complex *** SHframeTF
time-frequency domain SH input frame; HYBRID_BANDS x MAX_NUM_SH_SIGNALS x TIME_SLOTS
float ** grid_dirs_deg
Grid directions, in degrees.
float ** SHframeTD
time-domain SH input frame; MAX_NUM_SH_SIGNALS x SLDOA_FRAME_SIZE
float avg_ms
Temporal averaging, in ms.
CH_ORDER chOrdering
Ambisonic channel order convention (see CH_ORDER)
float ** grid_Y
SH basis.
int masterOrder
Current master/maximum analysis order.
int nSectorsPerBand[HYBRID_BANDS]
Number of sectors per band.
int nGrid
Number of grid directions.
int current_disp_idx
Current display slot.
float freqVector[HYBRID_BANDS]
Frequency vector (filterbank centre frequencies)
float * azi_deg[NUM_DISP_SLOTS]
DoA azimuths, in degrees.