SAF
Loading...
Searching...
No Matches
panner.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
44#include "panner_internal.h"
45
47(
48 void ** const phPan
49)
50{
51 panner_data* pData = (panner_data*)malloc1d(sizeof(panner_data));
52 *phPan = (void*)pData;
53 int ch, dummy;
54
55 /* default user parameters */
56 panner_loadSourcePreset(SOURCE_CONFIG_PRESET_DEFAULT, pData->src_dirs_deg, &(pData->new_nSources), &(dummy)); /*check setStateInformation if you change default preset*/
57 pData->nSources = pData->new_nSources;
58 pData->DTT = 0.5f;
59 pData->spread_deg = 0.0f;
60 panner_loadLoudspeakerPreset(LOUDSPEAKER_ARRAY_PRESET_STEREO, pData->loudpkrs_dirs_deg, &(pData->new_nLoudpkrs), &(pData->output_nDims)); /*check setStateInformation if you change default preset*/
61 pData->nLoudpkrs = pData->new_nLoudpkrs;
62 pData->yaw = 0.0f;
63 pData->pitch = 0.0f;
64 pData->roll = 0.0f;
65 pData->bFlipYaw = 0;
66 pData->bFlipPitch = 0;
67 pData->bFlipRoll = 0;
68
69 /* time-frequency transform + buffers */
70 pData->fs = 48000.0f;
71 pData->hSTFT = NULL;
72 pData->inputFrameTD = (float**)malloc2d(MAX_NUM_INPUTS, PANNER_FRAME_SIZE, sizeof(float));
73 pData->outputFrameTD = (float**)malloc2d(MAX_NUM_OUTPUTS, PANNER_FRAME_SIZE, sizeof(float));
74 pData->inputframeTF = (float_complex***)malloc3d(HYBRID_BANDS, MAX_NUM_INPUTS, TIME_SLOTS, sizeof(float_complex));
75 pData->outputframeTF = (float_complex***)malloc3d(HYBRID_BANDS, MAX_NUM_OUTPUTS, TIME_SLOTS, sizeof(float_complex));
76
77 /* flags and gain table */
78 pData->progressBar0_1 = 0.0f;
80 strcpy(pData->progressBarText,"");
83 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
84 pData->recalc_gainsFLAG[ch] = 1;
85 pData->vbap_gtable = NULL;
86 pData->recalc_M_rotFLAG = 1;
87 pData->reInitGainTables = 1;
88}
89
91(
92 void ** const phPan
93)
94{
95 panner_data *pData = (panner_data*)(*phPan);
96
97 if (pData != NULL) {
98 /* not safe to free memory during intialisation/processing loop */
99 while (pData->codecStatus == CODEC_STATUS_INITIALISING ||
101 SAF_SLEEP(10);
102 }
103
104 /* free afSTFT and buffers */
105 if(pData->hSTFT !=NULL)
106 afSTFT_destroy(&(pData->hSTFT));
107 free(pData->inputFrameTD);
108 free(pData->outputFrameTD);
109 free(pData->inputframeTF);
110 free(pData->outputframeTF);
111 free(pData->vbap_gtable);
112 free(pData->progressBarText);
113
114 free(pData);
115 pData = NULL;
116 *phPan = NULL;
117 }
118}
119
121(
122 void * const hPan,
123 int sampleRate
124)
125{
126 panner_data *pData = (panner_data*)(hPan);
127
128 /* define frequency vector */
129 pData->fs = sampleRate;
130 afSTFT_getCentreFreqs(pData->hSTFT, (float)sampleRate, HYBRID_BANDS, pData->freqVector);
131
132 /* calculate pValue per frequency */
133 getPvalues(pData->DTT, pData->freqVector, HYBRID_BANDS, pData->pValue);
134
135 /* reinitialise if needed */
136 pData->recalc_M_rotFLAG = 1;
137}
138
140(
141 void* const hPan
142)
143{
144 panner_data *pData = (panner_data*)(hPan);
145
147 return; /* re-init not required, or already happening */
148 while (pData->procStatus == PROC_STATUS_ONGOING){
149 /* re-init required, but we need to wait for the current processing loop to end */
150 pData->codecStatus = CODEC_STATUS_INITIALISING; /* indicate that we want to init */
151 SAF_SLEEP(10);
152 }
153
154 /* for progress bar */
156 strcpy(pData->progressBarText,"Initialising");
157 pData->progressBar0_1 = 0.0f;
158
159 /* reinit TFT if needed */
160 panner_initTFT(hPan);
161
162 /* reinit gain tables */
163 if(pData->reInitGainTables){
165 pData->reInitGainTables = 0;
166 }
167
168 /* done! */
169 strcpy(pData->progressBarText,"Done!");
170 pData->progressBar0_1 = 1.0f;
172
173}
174
176(
177 void * const hPan,
178 const float *const * inputs,
179 float* const* const outputs,
180 int nInputs,
181 int nOutputs,
182 int nSamples
183)
184{
185 panner_data *pData = (panner_data*)(hPan);
186 int t, ch, ls, i, band, nSources, nLoudspeakers, N_azi, aziIndex, elevIndex, idx3d, idx2D;
187 float aziRes, elevRes, pv_f, gains3D_sum_pvf, gains2D_sum_pvf, Rxyz[3][3], hypotxy;
188 float src_dirs[MAX_NUM_INPUTS][2], pValue[HYBRID_BANDS], gains3D[MAX_NUM_OUTPUTS], gains2D[MAX_NUM_OUTPUTS];
189 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
190 float_complex outputTemp[MAX_NUM_OUTPUTS][TIME_SLOTS];
191
192 /* copy user parameters to local variables */
193 memcpy(src_dirs, pData->src_dirs_deg, MAX_NUM_INPUTS*2*sizeof(float));
194 memcpy(pValue, pData->pValue, HYBRID_BANDS*sizeof(float));
195 nSources = pData->nSources;
196 nLoudspeakers = pData->nLoudpkrs;
197
198 /* apply panner */
199 if ((nSamples == PANNER_FRAME_SIZE) && (pData->vbap_gtable != NULL) && (pData->codecStatus == CODEC_STATUS_INITIALISED) ) {
201
202 /* Load time-domain data */
203 for(i=0; i < SAF_MIN(nSources,nInputs); i++)
204 utility_svvcopy(inputs[i], PANNER_FRAME_SIZE, pData->inputFrameTD[i]);
205 for(; i<MAX_NUM_INPUTS; i++)
206 memset(pData->inputFrameTD[i], 0, PANNER_FRAME_SIZE * sizeof(float));
207
208 /* Apply time-frequency transform (TFT) */
210 memset(FLATTEN3D(pData->outputframeTF), 0, HYBRID_BANDS*MAX_NUM_OUTPUTS*TIME_SLOTS * sizeof(float_complex));
211 memset(outputTemp, 0, MAX_NUM_OUTPUTS*TIME_SLOTS * sizeof(float_complex));
212
213 /* Rotate source directions */
214 if(pData->recalc_M_rotFLAG){
215 yawPitchRoll2Rzyx (pData->yaw, pData->pitch, pData->roll, 0, Rxyz);
216 for(i=0; i<nSources; i++){
217 pData->src_dirs_xyz[i][0] = cosf(DEG2RAD(pData->src_dirs_deg[i][1])) * cosf(DEG2RAD(pData->src_dirs_deg[i][0]));
218 pData->src_dirs_xyz[i][1] = cosf(DEG2RAD(pData->src_dirs_deg[i][1])) * sinf(DEG2RAD(pData->src_dirs_deg[i][0]));
219 pData->src_dirs_xyz[i][2] = sinf(DEG2RAD(pData->src_dirs_deg[i][1]));
220 pData->recalc_gainsFLAG[i] = 1;
221 }
222 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSources, 3, 3, 1.0f,
223 (float*)(pData->src_dirs_xyz), 3,
224 (float*)Rxyz, 3, 0.0f,
225 (float*)(pData->src_dirs_rot_xyz), 3);
226 for(i=0; i<nSources; i++){
227 hypotxy = sqrtf(powf(pData->src_dirs_rot_xyz[i][0], 2.0f) + powf(pData->src_dirs_rot_xyz[i][1], 2.0f));
228 pData->src_dirs_rot_deg[i][0] = RAD2DEG(atan2f(pData->src_dirs_rot_xyz[i][1], pData->src_dirs_rot_xyz[i][0]));
229 pData->src_dirs_rot_deg[i][1] = RAD2DEG(atan2f(pData->src_dirs_rot_xyz[i][2], hypotxy));
230 }
231 pData->recalc_M_rotFLAG = 0;
232 }
233
234 /* Apply VBAP Panning */
235 if(pData->output_nDims == 3){/* 3-D case */
236 aziRes = (float)pData->vbapTableRes[0];
237 elevRes = (float)pData->vbapTableRes[1];
238 N_azi = (int)(360.0f / aziRes + 0.5f) + 1;
239 for (ch = 0; ch < nSources; ch++) {
240 /* recalculate frequency dependent panning gains */
241 if(pData->recalc_gainsFLAG[ch]){
242 //aziIndex = (int)(matlab_fmodf(pData->src_dirs_deg[ch][0] + 180.0f, 360.0f) / aziRes + 0.5f);
243 //elevIndex = (int)((pData->src_dirs_deg[ch][1] + 90.0f) / elevRes + 0.5f);
244 aziIndex = (int)(matlab_fmodf(pData->src_dirs_rot_deg[ch][0] + 180.0f, 360.0f) / aziRes + 0.5f);
245 elevIndex = (int)((pData->src_dirs_rot_deg[ch][1] + 90.0f) / elevRes + 0.5f);
246 idx3d = elevIndex * N_azi + aziIndex;
247 for (ls = 0; ls < nLoudspeakers; ls++)
248 gains3D[ls] = pData->vbap_gtable[idx3d*nLoudspeakers+ls];
249 for (band = 0; band < HYBRID_BANDS; band++){
250 /* apply pValue per frequency */
251 pv_f = pData->pValue[band];
252 if(pv_f != 2.0f){
253 gains3D_sum_pvf = 0.0f;
254 for (ls = 0; ls < nLoudspeakers; ls++)
255 gains3D_sum_pvf += powf(SAF_MAX(gains3D[ls], 0.0f), pv_f);
256 gains3D_sum_pvf = powf(gains3D_sum_pvf, 1.0f/(pv_f+2.23e-9f));
257 for (ls = 0; ls < nLoudspeakers; ls++)
258 pData->G_src[band][ch][ls] = cmplxf(gains3D[ls] / (gains3D_sum_pvf+2.23e-9f), 0.0f);
259 }
260 else
261 for (ls = 0; ls < nLoudspeakers; ls++)
262 pData->G_src[band][ch][ls] = cmplxf(gains3D[ls], 0.0f);
263 }
264 pData->recalc_gainsFLAG[ch] = 0;
265 }
266 }
267 /* apply panning gains */
268 for (band = 0; band < HYBRID_BANDS; band++) {
269 cblas_cgemm(CblasRowMajor, CblasTrans, CblasNoTrans, nLoudspeakers, TIME_SLOTS, nSources, &calpha,
270 pData->G_src[band], MAX_NUM_OUTPUTS,
271 FLATTEN2D(pData->inputframeTF[band]), TIME_SLOTS, &cbeta,
272 outputTemp, TIME_SLOTS);
273 for (i = 0; i < nLoudspeakers; i++)
274 for (t = 0; t < TIME_SLOTS; t++)
275 pData->outputframeTF[band][i][t] = ccaddf(pData->outputframeTF[band][i][t], outputTemp[i][t]);
276 }
277 }
278 else{/* 2-D case */
279 aziRes = (float)pData->vbapTableRes[0];
280 for (ch = 0; ch < nSources; ch++) {
281 /* recalculate frequency dependent panning gains */
282 if(pData->recalc_gainsFLAG[ch]){
283 //idx2D = (int)((matlab_fmodf(pData->src_dirs_deg[ch][0]+180.0f,360.0f)/aziRes)+0.5f);
284 idx2D = (int)((matlab_fmodf(pData->src_dirs_rot_deg[ch][0]+180.0f,360.0f)/aziRes)+0.5f);
285 for (ls = 0; ls < nLoudspeakers; ls++)
286 gains2D[ls] = pData->vbap_gtable[idx2D*nLoudspeakers+ls];
287 for (band = 0; band < HYBRID_BANDS; band++){
288 /* apply pValue per frequency */
289 pv_f = pData->pValue[band];
290 if(pv_f != 2.0f){
291 gains2D_sum_pvf = 0.0f;
292 for (ls = 0; ls < nLoudspeakers; ls++)
293 gains2D_sum_pvf += powf(SAF_MAX(gains2D[ls], 0.0f), pv_f);
294 gains2D_sum_pvf = powf(gains2D_sum_pvf, 1.0f/(pv_f+2.23e-9f));
295 for (ls = 0; ls < nLoudspeakers; ls++)
296 pData->G_src[band][ch][ls] = cmplxf(gains2D[ls] / (gains2D_sum_pvf+2.23e-9f), 0.0f);
297 }
298 else
299 for (ls = 0; ls < nLoudspeakers; ls++)
300 pData->G_src[band][ch][ls] = cmplxf(gains2D[ls], 0.0f);
301 }
302 pData->recalc_gainsFLAG[ch] = 0;
303 }
304
305 /* apply panning gains */
306 for (band = 0; band < HYBRID_BANDS; band++){
307 for (ls = 0; ls < nLoudspeakers; ls++)
308 for (t = 0; t < TIME_SLOTS; t++)
309 pData->outputframeTF[band][ls][t] = ccaddf(pData->outputframeTF[band][ls][t], ccmulf(pData->inputframeTF[band][ch][t], pData->G_src[band][ch][ls]));
310 }
311 }
312 }
313
314 /* scale by sqrt(number of sources) */
315 for (band = 0; band < HYBRID_BANDS; band++)
316 cblas_sscal(/*re+im*/2*nLoudspeakers*TIME_SLOTS, 1.0f/sqrtf((float)nSources), (float*)FLATTEN2D(pData->outputframeTF[band]), 1);
317
318 /* inverse-TFT and copy to output */
320 for (ch = 0; ch < SAF_MIN(nLoudspeakers, nOutputs); ch++)
321 utility_svvcopy(pData->outputFrameTD[ch], PANNER_FRAME_SIZE, outputs[ch]);
322 for (; ch < nOutputs; ch++)
323 memset(outputs[ch], 0, PANNER_FRAME_SIZE*sizeof(float));
324
325 }
326 else
327 for (ch=0; ch < nOutputs; ch++)
328 memset(outputs[ch],0, PANNER_FRAME_SIZE*sizeof(float));
329
330
332}
333
334
335/* Set Functions */
336
337void panner_refreshSettings(void* const hPan)
338{
339 panner_data *pData = (panner_data*)(hPan);
340 int ch;
341 pData->reInitGainTables = 1;
342 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
343 pData->recalc_gainsFLAG[ch] = 1;
345}
346
347void panner_setSourceAzi_deg(void* const hPan, int index, float newAzi_deg)
348{
349 panner_data *pData = (panner_data*)(hPan);
350 if(newAzi_deg>180.0f)
351 newAzi_deg = -360.0f + newAzi_deg;
352 newAzi_deg = SAF_MAX(newAzi_deg, -180.0f);
353 newAzi_deg = SAF_MIN(newAzi_deg, 180.0f);
354 if(pData->src_dirs_deg[index][0] != newAzi_deg){
355 pData->src_dirs_deg[index][0] = newAzi_deg;
356 pData->recalc_gainsFLAG[index] = 1;
357 pData->recalc_M_rotFLAG = 1;
358 }
359}
360
361void panner_setSourceElev_deg(void* const hPan, int index, float newElev_deg)
362{
363 panner_data *pData = (panner_data*)(hPan);
364 newElev_deg = SAF_MAX(newElev_deg, -90.0f);
365 newElev_deg = SAF_MIN(newElev_deg, 90.0f);
366 if(pData->src_dirs_deg[index][1] != newElev_deg){
367 pData->src_dirs_deg[index][1] = newElev_deg;
368 pData->recalc_gainsFLAG[index] = 1;
369 pData->recalc_M_rotFLAG = 1;
370 }
371}
372
373void panner_setNumSources(void* const hPan, int new_nSources)
374{
375 panner_data *pData = (panner_data*)(hPan);
376 int ch;
377 /* determine if TFT must be reinitialised */
378 new_nSources = new_nSources > MAX_NUM_INPUTS ? MAX_NUM_INPUTS : new_nSources;
379 if(pData->nSources != new_nSources){
380 pData->new_nSources = new_nSources;
381 for(ch=pData->nSources; ch<pData->new_nSources; ch++)
382 pData->recalc_gainsFLAG[ch] = 1;
383 pData->recalc_M_rotFLAG = 1;
385 }
386}
387
388void panner_setLoudspeakerAzi_deg(void* const hPan, int index, float newAzi_deg)
389{
390 panner_data *pData = (panner_data*)(hPan);
391 int ch;
392 if(newAzi_deg>180.0f)
393 newAzi_deg = -360.0f + newAzi_deg;
394 newAzi_deg = SAF_MAX(newAzi_deg, -180.0f);
395 newAzi_deg = SAF_MIN(newAzi_deg, 180.0f);
396 if(pData->loudpkrs_dirs_deg[index][0] != newAzi_deg){
397 pData->loudpkrs_dirs_deg[index][0] = newAzi_deg;
398 pData->reInitGainTables=1;
399 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
400 pData->recalc_gainsFLAG[ch] = 1;
401 pData->recalc_M_rotFLAG = 1;
403 }
404}
405
406void panner_setLoudspeakerElev_deg(void* const hPan, int index, float newElev_deg)
407{
408 panner_data *pData = (panner_data*)(hPan);
409 int ch;
410 newElev_deg = SAF_MAX(newElev_deg, -90.0f);
411 newElev_deg = SAF_MIN(newElev_deg, 90.0f);
412 if(pData->loudpkrs_dirs_deg[index][1] != newElev_deg){
413 pData->loudpkrs_dirs_deg[index][1] = newElev_deg;
414 pData->reInitGainTables=1;
415 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
416 pData->recalc_gainsFLAG[ch] = 1;
417 pData->recalc_M_rotFLAG = 1;
419 }
420}
421
422void panner_setNumLoudspeakers(void* const hPan, int new_nLoudspeakers)
423{
424 panner_data *pData = (panner_data*)(hPan);
425 int ch;
426
427 new_nLoudspeakers = new_nLoudspeakers > MAX_NUM_OUTPUTS ? MAX_NUM_OUTPUTS : new_nLoudspeakers;
428 if(pData->new_nLoudpkrs != new_nLoudspeakers){
429 pData->new_nLoudpkrs = new_nLoudspeakers;
430 pData->reInitGainTables=1;
431 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
432 pData->recalc_gainsFLAG[ch] = 1;
433 pData->recalc_M_rotFLAG = 1;
435 }
436}
437
438void panner_setOutputConfigPreset(void* const hPan, int newPresetID)
439{
440 panner_data *pData = (panner_data*)(hPan);
441 int ch, dummy;
442 panner_loadLoudspeakerPreset(newPresetID, pData->loudpkrs_dirs_deg, &(pData->new_nLoudpkrs), &dummy);
443 pData->reInitGainTables=1;
444 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
445 pData->recalc_gainsFLAG[ch] = 1;
446 pData->recalc_M_rotFLAG = 1;
448}
449
450void panner_setInputConfigPreset(void* const hPan, int newPresetID)
451{
452 panner_data *pData = (panner_data*)(hPan);
453 int ch, dummy;
454 panner_loadSourcePreset(newPresetID, pData->src_dirs_deg, &(pData->new_nSources), &dummy);
455 for(ch=0; ch<pData->new_nSources; ch++)
456 pData->recalc_gainsFLAG[ch] = 1;
457 pData->recalc_M_rotFLAG = 1;
459}
460
461void panner_setDTT(void* const hPan, float newValue)
462{
463 panner_data *pData = (panner_data*)(hPan);
464 int ch;
465 if(pData->DTT != newValue){
466 pData->DTT = newValue;
467 getPvalues(pData->DTT, pData->freqVector, HYBRID_BANDS, pData->pValue);
468 for(ch=0; ch<pData->new_nSources; ch++)
469 pData->recalc_gainsFLAG[ch] = 1;
470 pData->recalc_M_rotFLAG = 1;
472 }
473}
474
475void panner_setSpread(void* const hPan, float newValue)
476{
477 panner_data *pData = (panner_data*)(hPan);
478 int ch;
479 if(pData->spread_deg!=newValue){
481 pData->reInitGainTables=1;
482 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
483 pData->recalc_gainsFLAG[ch] = 1;
484 pData->recalc_M_rotFLAG = 1;
486 }
487}
488
489void panner_setYaw(void * const hBin, float newYaw)
490{
491 panner_data *pData = (panner_data*)(hBin);
492 pData->yaw = pData->bFlipYaw == 1 ? -DEG2RAD(newYaw) : DEG2RAD(newYaw);
493 pData->recalc_M_rotFLAG = 1;
494}
495
496void panner_setPitch(void* const hBin, float newPitch)
497{
498 panner_data *pData = (panner_data*)(hBin);
499 pData->pitch = pData->bFlipPitch == 1 ? -DEG2RAD(newPitch) : DEG2RAD(newPitch);
500 pData->recalc_M_rotFLAG = 1;
501}
502
503void panner_setRoll(void* const hBin, float newRoll)
504{
505 panner_data *pData = (panner_data*)(hBin);
506 pData->roll = pData->bFlipRoll == 1 ? -DEG2RAD(newRoll) : DEG2RAD(newRoll);
507 pData->recalc_M_rotFLAG = 1;
508}
509
510void panner_setFlipYaw(void* const hBin, int newState)
511{
512 panner_data *pData = (panner_data*)(hBin);
513 if(newState !=pData->bFlipYaw ){
514 pData->bFlipYaw = newState;
515 panner_setYaw(hBin, -panner_getYaw(hBin));
516 }
517}
518
519void panner_setFlipPitch(void* const hBin, int newState)
520{
521 panner_data *pData = (panner_data*)(hBin);
522 if(newState !=pData->bFlipPitch ){
523 pData->bFlipPitch = newState;
524 panner_setPitch(hBin, -panner_getPitch(hBin));
525 }
526}
527
528void panner_setFlipRoll(void* const hBin, int newState)
529{
530 panner_data *pData = (panner_data*)(hBin);
531 if(newState !=pData->bFlipRoll ){
532 pData->bFlipRoll = newState;
533 panner_setRoll(hBin, -panner_getRoll(hBin));
534 }
535}
536
537
538/* Get Functions */
539
541{
542 return PANNER_FRAME_SIZE;
543}
544
546{
547 panner_data *pData = (panner_data*)(hPan);
548 return pData->codecStatus;
549}
550
551float panner_getProgressBar0_1(void* const hPan)
552{
553 panner_data *pData = (panner_data*)(hPan);
554 return pData->progressBar0_1;
555}
556
557void panner_getProgressBarText(void* const hPan, char* text)
558{
559 panner_data *pData = (panner_data*)(hPan);
560 memcpy(text, pData->progressBarText, PROGRESSBARTEXT_CHAR_LENGTH*sizeof(char));
561}
562
563float panner_getSourceAzi_deg(void* const hPan, int index)
564{
565 panner_data *pData = (panner_data*)(hPan);
566 return pData->src_dirs_deg[index][0];
567}
568
569float panner_getSourceElev_deg(void* const hPan, int index)
570{
571 panner_data *pData = (panner_data*)(hPan);
572 return pData->src_dirs_deg[index][1];
573}
574
575int panner_getNumSources(void* const hPan)
576{
577 panner_data *pData = (panner_data*)(hPan);
578 return pData->new_nSources;
579}
580
582{
583 return MAX_NUM_INPUTS;
584}
585
586float panner_getLoudspeakerAzi_deg(void* const hPan, int index)
587{
588 panner_data *pData = (panner_data*)(hPan);
589 return pData->loudpkrs_dirs_deg[index][0];
590}
591
592float panner_getLoudspeakerElev_deg(void* const hPan, int index)
593{
594 panner_data *pData = (panner_data*)(hPan);
595 return pData->loudpkrs_dirs_deg[index][1];
596}
597
598int panner_getNumLoudspeakers(void* const hPan)
599{
600 panner_data *pData = (panner_data*)(hPan);
601 return pData->new_nLoudpkrs;
602}
603
608
609int panner_getDAWsamplerate(void* const hPan)
610{
611 panner_data *pData = (panner_data*)(hPan);
612 return pData->fs;
613}
614
615float panner_getDTT(void* const hPan)
616{
617 panner_data *pData = (panner_data*)(hPan);
618 return pData->DTT;
619}
620
621float panner_getSpread(void* const hPan)
622{
623 panner_data *pData = (panner_data*)(hPan);
624 return pData->spread_deg;
625}
626
627float panner_getYaw(void* const hBin)
628{
629 panner_data *pData = (panner_data*)(hBin);
630 return pData->bFlipYaw == 1 ? -RAD2DEG(pData->yaw) : RAD2DEG(pData->yaw);
631}
632
633float panner_getPitch(void* const hBin)
634{
635 panner_data *pData = (panner_data*)(hBin);
636 return pData->bFlipPitch == 1 ? -RAD2DEG(pData->pitch) : RAD2DEG(pData->pitch);
637}
638
639float panner_getRoll(void* const hBin)
640{
641 panner_data *pData = (panner_data*)(hBin);
642 return pData->bFlipRoll == 1 ? -RAD2DEG(pData->roll) : RAD2DEG(pData->roll);
643}
644
645int panner_getFlipYaw(void* const hBin)
646{
647 panner_data *pData = (panner_data*)(hBin);
648 return pData->bFlipYaw;
649}
650
651int panner_getFlipPitch(void* const hBin)
652{
653 panner_data *pData = (panner_data*)(hBin);
654 return pData->bFlipPitch;
655}
656
657int panner_getFlipRoll(void* const hBin)
658{
659 panner_data *pData = (panner_data*)(hBin);
660 return pData->bFlipRoll;
661}
662
664{
665 return 12*HOP_SIZE;
666}
#define MAX_NUM_INPUTS
Maximum number of input channels supported.
Definition _common.h:233
#define MAX_NUM_OUTPUTS
Maximum number of output channels supported.
Definition _common.h:236
#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
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_backward_knownDimensions(void *const hSTFT, float_complex ***dataFD, int framesize, int dataFD_nCH, int dataFD_nHops, float **dataTD)
Performs backward afSTFT transform (dataFD dimensions are known)
Definition afSTFTlib.c:391
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
#define TIME_SLOTS
Number of STFT timeslots.
#define HOP_SIZE
STFT hop size.
#define HYBRID_BANDS
Number of frequency bands.
#define SAF_CLAMP(a, min, max)
Ensures value "a" is clamped between the "min" and "max" values.
#define DEG2RAD(x)
Converts degrees to radians.
#define SAF_MAX(a, b)
Returns the maximum of the two values.
float matlab_fmodf(float x, float y)
C fmodf function, except it behaves like 'mod' in Matlab (i.e.
void utility_svvcopy(const float *a, const int len, float *c)
Single-precision, vector-vector copy, i.e.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
void yawPitchRoll2Rzyx(float yaw, float pitch, float roll, int rollPitchYawFLAG, float R[3][3])
Constructs a 3x3 rotation matrix from the Euler angles, using the yaw-pitch-roll (zyx) convention.
#define RAD2DEG(x)
Converts radians to degrees
void getPvalues(float DTT, float *freq, int nFreq, float *pValues)
Calculates the frequency dependent pValues, which can be applied to ENERGY normalised VBAP gains,...
Definition saf_vbap.c:476
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
#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
#define FLATTEN3D(A)
Use this macro when passing a 3-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:72
void panner_setNumSources(void *const hPan, int new_nSources)
Sets the number of inputs/sources to pan.
Definition panner.c:373
void panner_process(void *const hPan, const float *const *inputs, float *const *const outputs, int nInputs, int nOutputs, int nSamples)
Pans the input signals/sources to the loudspeaker channels using VBAP [1], and optional spreading [2]...
Definition panner.c:176
void panner_setFlipPitch(void *const hBin, int newState)
Sets a flag as to whether to "flip" the sign of the current 'pitch' angle (0: do not flip sign,...
Definition panner.c:519
void panner_setLoudspeakerElev_deg(void *const hPan, int index, float newElev_deg)
Sets the elevation of a specific loudspeaker index, in DEGREES.
Definition panner.c:406
void panner_setFlipYaw(void *const hBin, int newState)
Sets a flag as to whether to "flip" the sign of the current 'yaw' angle (0: do not flip sign,...
Definition panner.c:510
float panner_getSourceAzi_deg(void *const hPan, int index)
Returns the input/source azimuth for a given index, in DEGREES.
Definition panner.c:563
float panner_getYaw(void *const hBin)
Returns the 'yaw' rotation angle, in DEGREES.
Definition panner.c:627
int panner_getFlipYaw(void *const hBin)
Returns a flag as to whether to "flip" the sign of the current 'yaw' angle (0: do not flip sign,...
Definition panner.c:645
int panner_getNumLoudspeakers(void *const hPan)
Returns the number of loudspeakers in the current layout.
Definition panner.c:598
float panner_getLoudspeakerAzi_deg(void *const hPan, int index)
Returns the loudspeaker azimuth for a given index, in DEGREES.
Definition panner.c:586
float panner_getProgressBar0_1(void *const hPan)
(Optional) Returns current intialisation/processing progress, between 0..1
Definition panner.c:551
int panner_getDAWsamplerate(void *const hPan)
Returns the DAW/Host sample rate.
Definition panner.c:609
void panner_create(void **const phPan)
Creates an instance of the panner.
Definition panner.c:47
float panner_getDTT(void *const hPan)
Returns the room coefficient value 0..1.
Definition panner.c:615
int panner_getMaxNumSources()
Returns the maximum number of inputs/sources permitted by panner.
Definition panner.c:581
void panner_setSpread(void *const hPan, float newValue)
Sets the degree of spread, in DEGREES.
Definition panner.c:475
void panner_setSourceAzi_deg(void *const hPan, int index, float newAzi_deg)
Sets the azimuth of a specific input/source index, in DEGREES.
Definition panner.c:347
void panner_setLoudspeakerAzi_deg(void *const hPan, int index, float newAzi_deg)
Sets the azimuth of a specific loudspeaker index, in DEGREES.
Definition panner.c:388
void panner_setRoll(void *const hBin, float newRoll)
Sets the 'roll' rotation angle, in DEGREES.
Definition panner.c:503
int panner_getFlipRoll(void *const hBin)
Returns a flag as to whether to "flip" the sign of the current 'roll' angle (0: do not flip sign,...
Definition panner.c:657
void panner_setOutputConfigPreset(void *const hPan, int newPresetID)
Sets a preset for the output configuration (see LOUDSPEAKER_ARRAY_PRESETS enum)
Definition panner.c:438
float panner_getPitch(void *const hBin)
Returns the 'pitch' rotation angle, in DEGREES.
Definition panner.c:633
float panner_getLoudspeakerElev_deg(void *const hPan, int index)
Returns the loudspeaker elevation for a given index, in DEGREES.
Definition panner.c:592
void panner_init(void *const hPan, int sampleRate)
Initialises an instance of panner with default settings.
Definition panner.c:121
int panner_getFrameSize(void)
Returns the processing framesize (i.e., number of samples processed with every _process() call )
Definition panner.c:540
void panner_setDTT(void *const hPan, float newValue)
Sets the room coefficient value 0..1 [1]; 0: normal room, 0.5: dry listening room,...
Definition panner.c:461
void panner_destroy(void **const phPan)
Destroys an instance of the panner.
Definition panner.c:91
int panner_getMaxNumLoudspeakers()
Returns the maximum number of loudspeakers permitted.
Definition panner.c:604
void panner_setYaw(void *const hBin, float newYaw)
Sets the 'yaw' rotation angle, in DEGREES.
Definition panner.c:489
void panner_setPitch(void *const hBin, float newPitch)
Sets the 'pitch' rotation angle, in DEGREES.
Definition panner.c:496
void panner_setInputConfigPreset(void *const hPan, int newPresetID)
Sets a preset for the input configuration (see SOURCE_CONFIG_PRESETS enum)
Definition panner.c:450
float panner_getRoll(void *const hBin)
Returns the 'roll' rotation angle, in DEGREES.
Definition panner.c:639
CODEC_STATUS panner_getCodecStatus(void *const hPan)
Returns current codec status (see CODEC_STATUS enum)
Definition panner.c:545
void panner_getProgressBarText(void *const hPan, char *text)
(Optional) Returns current intialisation/processing progress text
Definition panner.c:557
int panner_getProcessingDelay()
Returns the processing delay in samples (may be used for delay compensation features)
Definition panner.c:663
float panner_getSourceElev_deg(void *const hPan, int index)
Returns the input/source elevation for a given index, in DEGREES.
Definition panner.c:569
void panner_initCodec(void *const hPan)
Intialises the codec variables, based on current global/user parameters.
Definition panner.c:140
void panner_setSourceElev_deg(void *const hPan, int index, float newElev_deg)
Sets the elevation of a specific input/source index, in DEGREES.
Definition panner.c:361
void panner_refreshSettings(void *const hPan)
Sets all intialisation flags to 1; re-initialising all settings/variables as panner is currently conf...
Definition panner.c:337
float panner_getSpread(void *const hPan)
Returns the spread value, in DEGREES.
Definition panner.c:621
int panner_getFlipPitch(void *const hBin)
Returns a flag as to whether to "flip" the sign of the current 'pitch' angle (0: do not flip sign,...
Definition panner.c:651
void panner_setNumLoudspeakers(void *const hPan, int new_nLoudspeakers)
Sets the number of loudspeakers to pan to.
Definition panner.c:422
void panner_setFlipRoll(void *const hBin, int newState)
Sets a flag as to whether to "flip" the sign of the current 'roll' angle (0: do not flip sign,...
Definition panner.c:528
int panner_getNumSources(void *const hPan)
Returns the number of inputs/sources in the current layout.
Definition panner.c:575
#define PANNER_SPREAD_MAX_VALUE
Maximum supported spread angle, degrees.
Definition panner.h:71
#define PANNER_SPREAD_MIN_VALUE
Minimum supported spread angle, degrees.
Definition panner.h:68
void panner_initGainTables(void *const hPan)
Intialises the VBAP gain table used for panning.
void panner_setCodecStatus(void *const hPan, CODEC_STATUS newStatus)
Sets codec status (see CODEC_STATUS enum)
void panner_loadLoudspeakerPreset(LOUDSPEAKER_ARRAY_PRESETS preset, float dirs_deg[MAX_NUM_INPUTS][2], int *newNCH, int *nDims)
Loads source/loudspeaker directions from preset.
void panner_initTFT(void *const hPan)
Initialise the filterbank used by panner.
void panner_loadSourcePreset(SOURCE_CONFIG_PRESETS preset, float dirs_deg[MAX_NUM_INPUTS][2], int *newNCH, int *nDims)
Loads source directions from preset.
A frequency-dependent 3D panner based on the Vector-base Amplitude Panning (VBAP) method [1],...
#define PANNER_FRAME_SIZE
Framesize, in time-domain samples.
Main structure for panner.
float roll
roll (Euler) rotation angle, in degrees
float freqVector[HYBRID_BANDS]
Frequency vector (centre frequencies)
int recalc_gainsFLAG[MAX_NUM_INPUTS]
1: VBAP gains need to be recalculated for this source, 0: do not
float DTT
Room coefficient [3].
float ** inputFrameTD
Input signals, in the time-domain; MAX_NUM_INPUTS x PANNER_FRAME_SIZE.
int vbapTableRes[2]
[0] azimuth, and [1] elevation grid resolution, in degrees
CODEC_STATUS codecStatus
see CODEC_STATUS
int nSources
Current number of inputs/sources.
float_complex *** inputframeTF
Input signals, in the time-frequency domain; HYBRID_BANDS x MAX_NUM_INPUTS x TIME_SLOTS.
float_complex *** outputframeTF
Output signals, in the time-frequency domain; HYBRID_BANDS x MAX_NUM_OUTPUTS x TIME_SLOTS.
int recalc_M_rotFLAG
1: recalculate the rotation matrix, 0: do not
float src_dirs_deg[MAX_NUM_INPUTS][2]
Current source directions.
int output_nDims
Dimensionality of the loudspeaker array, 2: 2-D, 3: 3-D.
int new_nSources
New number of inputs/sources.
int nLoudpkrs
Current number of loudspeakers in the array.
float spread_deg
Source spread/MDAP [2].
float yaw
yaw (Euler) rotation angle, in degrees
float loudpkrs_dirs_deg[MAX_NUM_OUTPUTS][2]
Current loudspeaker directions.
char * progressBarText
Current (re)initialisation step, string.
float src_dirs_xyz[MAX_NUM_INPUTS][3]
Intermediate source directions, as unit-length Cartesian coordinates.
float * vbap_gtable
Current VBAP gains; FLAT: N_hrtf_vbap_gtable x nLoudpkrs.
PROC_STATUS procStatus
see PROC_STATUS
float_complex G_src[HYBRID_BANDS][MAX_NUM_INPUTS][MAX_NUM_OUTPUTS]
Current VBAP gains per source.
float ** outputFrameTD
Output signals, in the time-domain; MAX_NUM_OUTPUTS x PANNER_FRAME_SIZE.
float pitch
pitch (Euler) rotation angle, in degrees
float src_dirs_rot_deg[MAX_NUM_INPUTS][2]
Intermediate rotated source directions, in degrees.
int bFlipRoll
flag to flip the sign of the roll rotation angle
float src_dirs_rot_xyz[MAX_NUM_INPUTS][3]
Intermediate rotated source directions, as unit-length Cartesian coordinates.
int new_nLoudpkrs
New number of loudspeakers in the array.
void * hSTFT
afSTFT handle
float pValue[HYBRID_BANDS]
Used for the frequency-dependent panning normalisation.
int fs
Host sampling rate.
float progressBar0_1
Current (re)initialisation progress, between [0..1].
int reInitGainTables
1: reinitialise the VBAP gain table, 0: do not
int bFlipPitch
flag to flip the sign of the pitch rotation angle
int bFlipYaw
flag to flip the sign of the yaw rotation angle