SAF
Loading...
Searching...
No Matches
sldoa_internal.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
49void sldoa_setCodecStatus(void* const hSld, CODEC_STATUS newStatus)
50{
51 sldoa_data *pData = (sldoa_data*)(hSld);
52 if(newStatus==CODEC_STATUS_NOT_INITIALISED){
53 /* Pause until current initialisation is complete */
55 SAF_SLEEP(10);
56 }
57 pData->codecStatus = newStatus;
58}
59
60void sldoa_initAna(void* const hSld)
61{
62 sldoa_data *pData = (sldoa_data*)(hSld);
63 int i, n, j, k, order, nSectors, nSH, grid_N_vbap_gtable, grid_nGroups, maxOrder;
64 float* sec_dirs_deg, *grid_vbap_gtable, *w_SG, *pinv_Y, *grid_vbap_gtable_T;
65 float** secPatterns;//[4][NUM_GRID_DIRS];
66
67 secPatterns = (float**)calloc2d(4, pData->nGrid, sizeof(float));
68
69 maxOrder = pData->new_masterOrder;
70
71 grid_vbap_gtable_T = malloc1d(ORDER2NUMSECTORS(maxOrder) * pData->nGrid * sizeof(float));
72
73 for(i=0, order=2; order<=maxOrder; i++,order++){
74 nSectors = SAF_MIN(ORDER2NUMSECTORS(order), MAX_NUM_SECTORS/*max available in sphcovering below*/);
75 nSH = (order+1)*(order+1);
76
77 /* define sector directions */
78 sec_dirs_deg = malloc1d(nSectors*2*sizeof(float));
79 memcpy(sec_dirs_deg, __HANDLES_SphCovering_dirs_deg[nSectors-1], nSectors*2*sizeof(float));
80
81 /* generate VBAP gain table */
82 generateVBAPgainTable3D_srcs(FLATTEN2D(pData->grid_dirs_deg), pData->nGrid, sec_dirs_deg, nSectors, 0, 0, 0.0f,
83 &(grid_vbap_gtable), &(grid_N_vbap_gtable), &(grid_nGroups));
84
85 /* convert to amplitude preserving gains */
86 VBAPgainTable2InterpTable(grid_vbap_gtable, pData->nGrid, nSectors);
87
88 /* transpose */
89 for(n=0; n<nSectors; n++)
90 for(j=0; j<pData->nGrid; j++)
91 grid_vbap_gtable_T[n*pData->nGrid+j] = grid_vbap_gtable[j*nSectors+n];
92
93 /* generate sector coefficients */
94 if(pData->secCoeffs[i]!=NULL)
95 free(pData->secCoeffs[i]);
96 pData->secCoeffs[i] = malloc1d(4 * (nSH*nSectors) * sizeof(float_complex));
97 w_SG = malloc1d(4 * (nSH) * sizeof(float));
98 pinv_Y = malloc1d(pData->nGrid*nSH*sizeof(float));
99 for(n=0; n<nSectors; n++){
100 utility_svvmul(&(grid_vbap_gtable_T[n*pData->nGrid]), pData->grid_Y[0], pData->nGrid, secPatterns[0]);
101 for(j=0; j<3; j++)
102 utility_svvmul(&(grid_vbap_gtable_T[n*pData->nGrid]), pData->grid_Y_dipoles_norm[j], pData->nGrid, secPatterns[j+1]);
103 utility_spinv(NULL, FLATTEN2D(pData->grid_Y), nSH, pData->nGrid, pinv_Y);
104 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 4, nSH, pData->nGrid, 1.0f,
105 &(secPatterns[0][0]), pData->nGrid,
106 pinv_Y, nSH, 0.0f,
107 w_SG, nSH);
108
109 /* stack the sector coefficients */
110 for(j=0; j<4; j++)
111 for(k=0; k<nSH; k++)
112 pData->secCoeffs[i][j*(nSectors*nSH)+n*nSH+k] = cmplxf(w_SG[j*nSH+k], 0.0f);
113 }
114 free(w_SG);
115 free(pinv_Y);
116 free(grid_vbap_gtable);
117 free(sec_dirs_deg);
118 }
119
120 free(grid_vbap_gtable_T);
121
122 pData->masterOrder = maxOrder;
123
124 free(secPatterns);
125}
126
128(
129 void* const hSld
130)
131{
132 sldoa_data *pData = (sldoa_data*)(hSld);
133 int nSH, new_nSH;
134
135 nSH = (pData->masterOrder+1)*(pData->masterOrder+1);
136 new_nSH = (pData->new_masterOrder+1)*(pData->new_masterOrder+1);
137 if(pData->hSTFT==NULL)
138 afSTFT_create(&(pData->hSTFT), new_nSH, 0, HOP_SIZE, 0, 1, AFSTFT_BANDS_CH_TIME);
139 else if(nSH!=new_nSH){
140 afSTFT_channelChange(pData->hSTFT, new_nSH, 0);
142 }
143}
144
146(
147 float_complex** SHframeTF,
148 int anaOrder,
149 float_complex* secCoeffs,
150 float doa[MAX_NUM_SECTORS][TIME_SLOTS][2],
151 float energy[MAX_NUM_SECTORS][TIME_SLOTS]
152)
153{
154 int n, ch, i, j, nSectors, analysisOrder, nSH;
155 float_complex secSig[4][TIME_SLOTS];
156 float_complex* sec_c;
157 float secEnergy[TIME_SLOTS], secIntensity[3][TIME_SLOTS], secAzi[TIME_SLOTS], secElev[TIME_SLOTS];
158 const float_complex calpha = cmplxf(1.0f, 0.0f); const float_complex cbeta = cmplxf(0.0f, 0.0f);
159
160 /* prep */
161 memset(doa,0,MAX_NUM_SECTORS*TIME_SLOTS*2*sizeof(float));
162 memset(energy,0,MAX_NUM_SECTORS*TIME_SLOTS*sizeof(float));
163 analysisOrder = SAF_MAX(SAF_MIN(MAX_SH_ORDER, anaOrder),1);
164 nSectors = SAF_MIN(ORDER2NUMSECTORS(analysisOrder), MAX_NUM_SECTORS);
165 nSH = (analysisOrder+1)*(analysisOrder+1);
166 sec_c = malloc1d(4*nSH*sizeof(float_complex));
167
168 /* calculate energy and DoA for each sector */
169 for( n=0; n<nSectors; n++){
170 if(anaOrder==1 || secCoeffs == NULL) /* standard first order active-intensity based DoA estimation */
171 for (i=0; i<4; i++)
172 memcpy(secSig[i], SHframeTF[i], TIME_SLOTS * sizeof(float_complex));
173 else{ /* spatially localised active-intensity based DoA estimation */
174 for (i=0; i<4; i++)
175 for (j=0; j<nSH; j++)
176 sec_c[i*nSH+j] = secCoeffs[i*(nSectors*nSH)+n*nSH+j];
177 cblas_cgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 4, TIME_SLOTS, nSH, &calpha,
178 sec_c, nSH,
179 FLATTEN2D(SHframeTF), TIME_SLOTS, &cbeta,
180 secSig, TIME_SLOTS);
181 }
182
183 /* convert N3D to SN3D */
184 for (ch = 1; ch<4; ch++)
185 for(i = 0; i<TIME_SLOTS; i++)
186 secSig[ch][i] = crmulf(secSig[ch][i], 1.0f/sqrtf(3.0f));
187
188 /* calculate sector energy and intensity vector */
189 memset(secEnergy, 0, TIME_SLOTS*sizeof(float));
190 for (i=0; i<4; i++)
191 for (j=0; j<TIME_SLOTS; j++)
192 secEnergy[j] += 0.5f*powf(cabsf(secSig[i][j]), 2.0f);
193 for (i=0; i<3; i++)
194 for (j=0; j<TIME_SLOTS; j++)
195 secIntensity[i][j] = crealf(ccmulf(conjf(secSig[0][j]), secSig[1+i][j]));
196
197 /* extract DoA */
198 for (j=0; j<TIME_SLOTS; j++){
199 secAzi[j] = atan2f( secIntensity[0][j], secIntensity[2][j] );
200 secElev[j] = atan2f( secIntensity[1][j], sqrtf( powf(secIntensity[2][j], 2.0f) + powf(secIntensity[0][j], 2.0f)) );
201 }
202
203 /* store energy and DoA estimate */
204 for (j=0; j<TIME_SLOTS; j++){
205 doa[n][j][0] = secAzi[j];
206 doa[n][j][1] = secElev[j];
207 energy[n][j] = secEnergy[j]*1e6f;
208 }
209 }
210
211 free(sec_c);
212}
213
#define MAX_SH_ORDER
Maximum supported Ambisonic order.
Definition _common.h:52
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_INITIALISING
Codec is currently being initialised, input audio should not be processed.
Definition _common.h:207
void afSTFT_clearBuffers(void *const hSTFT)
Flushes time-domain buffers with zeros.
Definition afSTFTlib.c:519
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_channelChange(void *const hSTFT, int new_nCHin, int new_nCHout)
Re-allocates memory to support a change in the number of input/output channels.
Definition afSTFTlib.c:477
@ 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.
const float * __HANDLES_SphCovering_dirs_deg[64]
Sphere covering handles ( between 4..64 points only)
void utility_svvmul(const float *a, const float *b, const int len, float *c)
Single-precision, element-wise vector-vector multiplication i.e.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
void utility_spinv(void *const hWork, const float *inM, const int dim1, const int dim2, float *outM)
General matrix pseudo-inverse (the svd way): single precision, i.e.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
void generateVBAPgainTable3D_srcs(float *src_dirs_deg, int S, float *ls_dirs_deg, int L, int omitLargeTriangles, int enableDummies, float spread, float **gtable, int *N_gtable, int *nTriangles)
Generates a 3-D VBAP [1] gain table based on specified source and loudspeaker directions,...
Definition saf_vbap.c:53
void VBAPgainTable2InterpTable(float *vbap_gtable, int nTable, int nDirs)
Renormalises a VBAP gain table (in-place) so it may be utilised for interpolation of data (for exampl...
Definition saf_vbap.c:370
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
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
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 ORDER2NUMSECTORS(L)
Macro to convert SH order to number of sectors.
Main struct for sldoa.
int new_masterOrder
New master/maximum analysis order (current value will be replaced by this after next re-init)
void * hSTFT
afSTFT handle
float_complex * secCoeffs[MAX_SH_ORDER-1]
Sector beamforming weights/coefficients.
CODEC_STATUS codecStatus
see CODEC_STATUS
float ** grid_Y_dipoles_norm
SH basis.
float ** grid_dirs_deg
Grid directions, in degrees.
float ** grid_Y
SH basis.
int masterOrder
Current master/maximum analysis order.
int nGrid
Number of grid directions.