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
43
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;
131 afSTFT_getCentreFreqs(pData->hSTFT, (float)sampleRate, HYBRID_BANDS, pData->freqVector);
132
133 /* calculate pValue per frequency */
134 getPvalues(pData->DTT, pData->freqVector, HYBRID_BANDS, pData->pValue);
135 }
136
137 /* reinitialise if needed */
138 pData->recalc_M_rotFLAG = 1;
139}
140
142(
143 void* const hPan
144)
145{
146 panner_data *pData = (panner_data*)(hPan);
147
149 return; /* re-init not required, or already happening */
150 while (pData->procStatus == PROC_STATUS_ONGOING){
151 /* re-init required, but we need to wait for the current processing loop to end */
152 pData->codecStatus = CODEC_STATUS_INITIALISING; /* indicate that we want to init */
153 SAF_SLEEP(10);
154 }
155
156 /* for progress bar */
158 strcpy(pData->progressBarText,"Initialising");
159 pData->progressBar0_1 = 0.4f;
160
161 /* reinit TFT if needed */
162 panner_initTFT(hPan);
163
164 /* reinit gain tables */
165 if(pData->reInitGainTables){
167 pData->reInitGainTables = 0;
168 }
169
170 /* done! */
171 strcpy(pData->progressBarText,"Done!");
172 pData->progressBar0_1 = 1.0f;
174
175}
176
178(
179 void * const hPan,
180 const float *const * inputs,
181 float* const* const outputs,
182 int nInputs,
183 int nOutputs,
184 int nSamples
185)
186{
187 panner_data *pData = (panner_data*)(hPan);
188 int t, ch, ls, i, band, nSources, nLoudspeakers, N_azi, aziIndex, elevIndex, idx3d, idx2D;
189 float aziRes, elevRes, pv_f, gains3D_sum_pvf, gains2D_sum_pvf, Rxyz[3][3], hypotxy;
190 float src_dirs[MAX_NUM_INPUTS][2], pValue[HYBRID_BANDS], gains3D[MAX_NUM_OUTPUTS], gains2D[MAX_NUM_OUTPUTS];
191 const float_complex calpha = cmplxf(1.0f, 0.0f), cbeta = cmplxf(0.0f, 0.0f);
192 float_complex outputTemp[MAX_NUM_OUTPUTS][TIME_SLOTS];
193
194 /* copy user parameters to local variables */
195 memcpy(src_dirs, pData->src_dirs_deg, MAX_NUM_INPUTS*2*sizeof(float));
196 memcpy(pValue, pData->pValue, HYBRID_BANDS*sizeof(float));
197 nSources = pData->nSources;
198 nLoudspeakers = pData->nLoudpkrs;
199
200 /* apply panner */
201 if ((nSamples == PANNER_FRAME_SIZE) && (pData->codecStatus == CODEC_STATUS_INITIALISED) && (pData->vbap_gtable != NULL) ) {
203
204 /* Load time-domain data */
205 for(i=0; i < SAF_MIN(nSources,nInputs); i++)
206 utility_svvcopy(inputs[i], PANNER_FRAME_SIZE, pData->inputFrameTD[i]);
207 for(; i<MAX_NUM_INPUTS; i++)
208 memset(pData->inputFrameTD[i], 0, PANNER_FRAME_SIZE * sizeof(float));
209
210 /* Apply time-frequency transform (TFT) */
212 memset(FLATTEN3D(pData->outputframeTF), 0, HYBRID_BANDS*MAX_NUM_OUTPUTS*TIME_SLOTS * sizeof(float_complex));
213 memset(outputTemp, 0, MAX_NUM_OUTPUTS*TIME_SLOTS * sizeof(float_complex));
214
215 /* Rotate source directions */
216 if(pData->recalc_M_rotFLAG){
217 yawPitchRoll2Rzyx (pData->yaw, pData->pitch, pData->roll, 0, Rxyz);
218 for(i=0; i<nSources; i++){
219 pData->src_dirs_xyz[i][0] = cosf(DEG2RAD(pData->src_dirs_deg[i][1])) * cosf(DEG2RAD(pData->src_dirs_deg[i][0]));
220 pData->src_dirs_xyz[i][1] = cosf(DEG2RAD(pData->src_dirs_deg[i][1])) * sinf(DEG2RAD(pData->src_dirs_deg[i][0]));
221 pData->src_dirs_xyz[i][2] = sinf(DEG2RAD(pData->src_dirs_deg[i][1]));
222 pData->recalc_gainsFLAG[i] = 1;
223 }
224 cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, nSources, 3, 3, 1.0f,
225 (float*)(pData->src_dirs_xyz), 3,
226 (float*)Rxyz, 3, 0.0f,
227 (float*)(pData->src_dirs_rot_xyz), 3);
228 for(i=0; i<nSources; i++){
229 hypotxy = sqrtf(powf(pData->src_dirs_rot_xyz[i][0], 2.0f) + powf(pData->src_dirs_rot_xyz[i][1], 2.0f));
230 pData->src_dirs_rot_deg[i][0] = RAD2DEG(atan2f(pData->src_dirs_rot_xyz[i][1], pData->src_dirs_rot_xyz[i][0]));
231 pData->src_dirs_rot_deg[i][1] = RAD2DEG(atan2f(pData->src_dirs_rot_xyz[i][2], hypotxy));
232 }
233 pData->recalc_M_rotFLAG = 0;
234 }
235
236 /* Apply VBAP Panning */
237 if(pData->output_nDims == 3){/* 3-D case */
238 aziRes = (float)pData->vbapTableRes[0];
239 elevRes = (float)pData->vbapTableRes[1];
240 N_azi = (int)(360.0f / aziRes + 0.5f) + 1;
241 for (ch = 0; ch < nSources; ch++) {
242 /* recalculate frequency dependent panning gains */
243 if(pData->recalc_gainsFLAG[ch]){
244 //aziIndex = (int)(matlab_fmodf(pData->src_dirs_deg[ch][0] + 180.0f, 360.0f) / aziRes + 0.5f);
245 //elevIndex = (int)((pData->src_dirs_deg[ch][1] + 90.0f) / elevRes + 0.5f);
246 aziIndex = (int)(matlab_fmodf(pData->src_dirs_rot_deg[ch][0] + 180.0f, 360.0f) / aziRes + 0.5f);
247 elevIndex = (int)((pData->src_dirs_rot_deg[ch][1] + 90.0f) / elevRes + 0.5f);
248 idx3d = elevIndex * N_azi + aziIndex;
249 for (ls = 0; ls < nLoudspeakers; ls++)
250 gains3D[ls] = pData->vbap_gtable[idx3d*nLoudspeakers+ls];
251 for (band = 0; band < HYBRID_BANDS; band++){
252 /* apply pValue per frequency */
253 pv_f = pData->pValue[band];
254 if(pv_f != 2.0f){
255 gains3D_sum_pvf = 0.0f;
256 for (ls = 0; ls < nLoudspeakers; ls++)
257 gains3D_sum_pvf += powf(SAF_MAX(gains3D[ls], 0.0f), pv_f);
258 gains3D_sum_pvf = powf(gains3D_sum_pvf, 1.0f/(pv_f+2.23e-9f));
259 for (ls = 0; ls < nLoudspeakers; ls++)
260 pData->G_src[band][ch][ls] = cmplxf(gains3D[ls] / (gains3D_sum_pvf+2.23e-9f), 0.0f);
261 }
262 else
263 for (ls = 0; ls < nLoudspeakers; ls++)
264 pData->G_src[band][ch][ls] = cmplxf(gains3D[ls], 0.0f);
265 }
266 pData->recalc_gainsFLAG[ch] = 0;
267 }
268 }
269 /* apply panning gains */
270 for (band = 0; band < HYBRID_BANDS; band++) {
271 cblas_cgemm(CblasRowMajor, CblasTrans, CblasNoTrans, nLoudspeakers, TIME_SLOTS, nSources, &calpha,
272 pData->G_src[band], MAX_NUM_OUTPUTS,
273 FLATTEN2D(pData->inputframeTF[band]), TIME_SLOTS, &cbeta,
274 outputTemp, TIME_SLOTS);
275 for (i = 0; i < nLoudspeakers; i++)
276 for (t = 0; t < TIME_SLOTS; t++)
277 pData->outputframeTF[band][i][t] = ccaddf(pData->outputframeTF[band][i][t], outputTemp[i][t]);
278 }
279 }
280 else{/* 2-D case */
281 aziRes = (float)pData->vbapTableRes[0];
282 for (ch = 0; ch < nSources; ch++) {
283 /* recalculate frequency dependent panning gains */
284 if(pData->recalc_gainsFLAG[ch]){
285 //idx2D = (int)((matlab_fmodf(pData->src_dirs_deg[ch][0]+180.0f,360.0f)/aziRes)+0.5f);
286 idx2D = (int)((matlab_fmodf(pData->src_dirs_rot_deg[ch][0]+180.0f,360.0f)/aziRes)+0.5f);
287 for (ls = 0; ls < nLoudspeakers; ls++)
288 gains2D[ls] = pData->vbap_gtable[idx2D*nLoudspeakers+ls];
289 for (band = 0; band < HYBRID_BANDS; band++){
290 /* apply pValue per frequency */
291 pv_f = pData->pValue[band];
292 if(pv_f != 2.0f){
293 gains2D_sum_pvf = 0.0f;
294 for (ls = 0; ls < nLoudspeakers; ls++)
295 gains2D_sum_pvf += powf(SAF_MAX(gains2D[ls], 0.0f), pv_f);
296 gains2D_sum_pvf = powf(gains2D_sum_pvf, 1.0f/(pv_f+2.23e-9f));
297 for (ls = 0; ls < nLoudspeakers; ls++)
298 pData->G_src[band][ch][ls] = cmplxf(gains2D[ls] / (gains2D_sum_pvf+2.23e-9f), 0.0f);
299 }
300 else
301 for (ls = 0; ls < nLoudspeakers; ls++)
302 pData->G_src[band][ch][ls] = cmplxf(gains2D[ls], 0.0f);
303 }
304 pData->recalc_gainsFLAG[ch] = 0;
305 }
306
307 /* apply panning gains */
308 for (band = 0; band < HYBRID_BANDS; band++){
309 for (ls = 0; ls < nLoudspeakers; ls++)
310 for (t = 0; t < TIME_SLOTS; t++)
311 pData->outputframeTF[band][ls][t] = ccaddf(pData->outputframeTF[band][ls][t], ccmulf(pData->inputframeTF[band][ch][t], pData->G_src[band][ch][ls]));
312 }
313 }
314 }
315
316 /* scale by sqrt(number of sources) */
317 for (band = 0; band < HYBRID_BANDS; band++)
318 cblas_sscal(/*re+im*/2*nLoudspeakers*TIME_SLOTS, 1.0f/sqrtf((float)nSources), (float*)FLATTEN2D(pData->outputframeTF[band]), 1);
319
320 /* inverse-TFT and copy to output */
322 for (ch = 0; ch < SAF_MIN(nLoudspeakers, nOutputs); ch++)
323 utility_svvcopy(pData->outputFrameTD[ch], PANNER_FRAME_SIZE, outputs[ch]);
324 for (; ch < nOutputs; ch++)
325 memset(outputs[ch], 0, PANNER_FRAME_SIZE*sizeof(float));
326
327 }
328 else
329 for (ch=0; ch < nOutputs; ch++)
330 memset(outputs[ch],0, PANNER_FRAME_SIZE*sizeof(float));
331
332
334}
335
336
337/* Set Functions */
338
339void panner_refreshSettings(void* const hPan)
340{
341 panner_data *pData = (panner_data*)(hPan);
342 int ch;
343 pData->reInitGainTables = 1;
344 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
345 pData->recalc_gainsFLAG[ch] = 1;
347}
348
349void panner_setSourceAzi_deg(void* const hPan, int index, float newAzi_deg)
350{
351 panner_data *pData = (panner_data*)(hPan);
352 if(newAzi_deg>180.0f)
353 newAzi_deg = -360.0f + newAzi_deg;
354 newAzi_deg = SAF_MAX(newAzi_deg, -180.0f);
355 newAzi_deg = SAF_MIN(newAzi_deg, 180.0f);
356 if(pData->src_dirs_deg[index][0] != newAzi_deg){
357 pData->src_dirs_deg[index][0] = newAzi_deg;
358 pData->recalc_gainsFLAG[index] = 1;
359 pData->recalc_M_rotFLAG = 1;
360 }
361}
362
363void panner_setSourceElev_deg(void* const hPan, int index, float newElev_deg)
364{
365 panner_data *pData = (panner_data*)(hPan);
366 newElev_deg = SAF_MAX(newElev_deg, -90.0f);
367 newElev_deg = SAF_MIN(newElev_deg, 90.0f);
368 if(pData->src_dirs_deg[index][1] != newElev_deg){
369 pData->src_dirs_deg[index][1] = newElev_deg;
370 pData->recalc_gainsFLAG[index] = 1;
371 pData->recalc_M_rotFLAG = 1;
372 }
373}
374
375void panner_setNumSources(void* const hPan, int new_nSources)
376{
377 panner_data *pData = (panner_data*)(hPan);
378 int ch;
379 /* determine if TFT must be reinitialised */
380 new_nSources = new_nSources > MAX_NUM_INPUTS ? MAX_NUM_INPUTS : new_nSources;
381 if(pData->nSources != new_nSources){
382 pData->new_nSources = new_nSources;
383 for(ch=pData->nSources; ch<pData->new_nSources; ch++)
384 pData->recalc_gainsFLAG[ch] = 1;
385 pData->recalc_M_rotFLAG = 1;
387 }
388}
389
390void panner_setLoudspeakerAzi_deg(void* const hPan, int index, float newAzi_deg)
391{
392 panner_data *pData = (panner_data*)(hPan);
393 int ch;
394 if(newAzi_deg>180.0f)
395 newAzi_deg = -360.0f + newAzi_deg;
396 newAzi_deg = SAF_MAX(newAzi_deg, -180.0f);
397 newAzi_deg = SAF_MIN(newAzi_deg, 180.0f);
398 if(pData->loudpkrs_dirs_deg[index][0] != newAzi_deg){
399 pData->loudpkrs_dirs_deg[index][0] = newAzi_deg;
400 pData->reInitGainTables=1;
401 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
402 pData->recalc_gainsFLAG[ch] = 1;
403 pData->recalc_M_rotFLAG = 1;
405 }
406}
407
408void panner_setLoudspeakerElev_deg(void* const hPan, int index, float newElev_deg)
409{
410 panner_data *pData = (panner_data*)(hPan);
411 int ch;
412 newElev_deg = SAF_MAX(newElev_deg, -90.0f);
413 newElev_deg = SAF_MIN(newElev_deg, 90.0f);
414 if(pData->loudpkrs_dirs_deg[index][1] != newElev_deg){
415 pData->loudpkrs_dirs_deg[index][1] = newElev_deg;
416 pData->reInitGainTables=1;
417 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
418 pData->recalc_gainsFLAG[ch] = 1;
419 pData->recalc_M_rotFLAG = 1;
421 }
422}
423
424void panner_setNumLoudspeakers(void* const hPan, int new_nLoudspeakers)
425{
426 panner_data *pData = (panner_data*)(hPan);
427 int ch;
428
429 new_nLoudspeakers = new_nLoudspeakers > MAX_NUM_OUTPUTS ? MAX_NUM_OUTPUTS : new_nLoudspeakers;
430 if(pData->new_nLoudpkrs != new_nLoudspeakers){
431 pData->new_nLoudpkrs = new_nLoudspeakers;
432 pData->reInitGainTables=1;
433 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
434 pData->recalc_gainsFLAG[ch] = 1;
435 pData->recalc_M_rotFLAG = 1;
437 }
438}
439
440void panner_setOutputConfigPreset(void* const hPan, int newPresetID)
441{
442 panner_data *pData = (panner_data*)(hPan);
443 int ch, dummy;
444 panner_loadLoudspeakerPreset(newPresetID, pData->loudpkrs_dirs_deg, &(pData->new_nLoudpkrs), &dummy);
445 pData->reInitGainTables=1;
446 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
447 pData->recalc_gainsFLAG[ch] = 1;
448 pData->recalc_M_rotFLAG = 1;
450}
451
452void panner_setInputConfigPreset(void* const hPan, int newPresetID)
453{
454 panner_data *pData = (panner_data*)(hPan);
455 int ch, dummy;
456 panner_loadSourcePreset(newPresetID, pData->src_dirs_deg, &(pData->new_nSources), &dummy);
457 for(ch=0; ch<pData->new_nSources; ch++)
458 pData->recalc_gainsFLAG[ch] = 1;
459 pData->recalc_M_rotFLAG = 1;
461}
462
463void panner_setDTT(void* const hPan, float newValue)
464{
465 panner_data *pData = (panner_data*)(hPan);
466 int ch;
467 if(pData->DTT != newValue){
468 pData->DTT = newValue;
469 getPvalues(pData->DTT, pData->freqVector, HYBRID_BANDS, pData->pValue);
470 for(ch=0; ch<pData->new_nSources; ch++)
471 pData->recalc_gainsFLAG[ch] = 1;
472 pData->recalc_M_rotFLAG = 1;
474 }
475}
476
477void panner_setSpread(void* const hPan, float newValue)
478{
479 panner_data *pData = (panner_data*)(hPan);
480 int ch;
481 if(pData->spread_deg!=newValue){
483 pData->reInitGainTables=1;
484 for(ch=0; ch<MAX_NUM_INPUTS; ch++)
485 pData->recalc_gainsFLAG[ch] = 1;
486 pData->recalc_M_rotFLAG = 1;
488 }
489}
490
491void panner_setYaw(void * const hBin, float newYaw)
492{
493 panner_data *pData = (panner_data*)(hBin);
494 pData->yaw = pData->bFlipYaw == 1 ? -DEG2RAD(newYaw) : DEG2RAD(newYaw);
495 pData->recalc_M_rotFLAG = 1;
496}
497
498void panner_setPitch(void* const hBin, float newPitch)
499{
500 panner_data *pData = (panner_data*)(hBin);
501 pData->pitch = pData->bFlipPitch == 1 ? -DEG2RAD(newPitch) : DEG2RAD(newPitch);
502 pData->recalc_M_rotFLAG = 1;
503}
504
505void panner_setRoll(void* const hBin, float newRoll)
506{
507 panner_data *pData = (panner_data*)(hBin);
508 pData->roll = pData->bFlipRoll == 1 ? -DEG2RAD(newRoll) : DEG2RAD(newRoll);
509 pData->recalc_M_rotFLAG = 1;
510}
511
512void panner_setFlipYaw(void* const hBin, int newState)
513{
514 panner_data *pData = (panner_data*)(hBin);
515 if(newState !=pData->bFlipYaw ){
516 pData->bFlipYaw = newState;
517 panner_setYaw(hBin, -panner_getYaw(hBin));
518 }
519}
520
521void panner_setFlipPitch(void* const hBin, int newState)
522{
523 panner_data *pData = (panner_data*)(hBin);
524 if(newState !=pData->bFlipPitch ){
525 pData->bFlipPitch = newState;
526 panner_setPitch(hBin, -panner_getPitch(hBin));
527 }
528}
529
530void panner_setFlipRoll(void* const hBin, int newState)
531{
532 panner_data *pData = (panner_data*)(hBin);
533 if(newState !=pData->bFlipRoll ){
534 pData->bFlipRoll = newState;
535 panner_setRoll(hBin, -panner_getRoll(hBin));
536 }
537}
538
539
540/* Get Functions */
541
543{
544 return PANNER_FRAME_SIZE;
545}
546
548{
549 panner_data *pData = (panner_data*)(hPan);
550 return pData->codecStatus;
551}
552
553float panner_getProgressBar0_1(void* const hPan)
554{
555 panner_data *pData = (panner_data*)(hPan);
556 return pData->progressBar0_1;
557}
558
559void panner_getProgressBarText(void* const hPan, char* text)
560{
561 panner_data *pData = (panner_data*)(hPan);
562 memcpy(text, pData->progressBarText, PROGRESSBARTEXT_CHAR_LENGTH*sizeof(char));
563}
564
565float panner_getSourceAzi_deg(void* const hPan, int index)
566{
567 panner_data *pData = (panner_data*)(hPan);
568 return pData->src_dirs_deg[index][0];
569}
570
571float panner_getSourceElev_deg(void* const hPan, int index)
572{
573 panner_data *pData = (panner_data*)(hPan);
574 return pData->src_dirs_deg[index][1];
575}
576
577int panner_getNumSources(void* const hPan)
578{
579 panner_data *pData = (panner_data*)(hPan);
580 return pData->new_nSources;
581}
582
584{
585 return MAX_NUM_INPUTS;
586}
587
588float panner_getLoudspeakerAzi_deg(void* const hPan, int index)
589{
590 panner_data *pData = (panner_data*)(hPan);
591 return pData->loudpkrs_dirs_deg[index][0];
592}
593
594float panner_getLoudspeakerElev_deg(void* const hPan, int index)
595{
596 panner_data *pData = (panner_data*)(hPan);
597 return pData->loudpkrs_dirs_deg[index][1];
598}
599
600int panner_getNumLoudspeakers(void* const hPan)
601{
602 panner_data *pData = (panner_data*)(hPan);
603 return pData->new_nLoudpkrs;
604}
605
607{
608 return MAX_NUM_OUTPUTS;
609}
610
611int panner_getDAWsamplerate(void* const hPan)
612{
613 panner_data *pData = (panner_data*)(hPan);
614 return pData->fs;
615}
616
617float panner_getDTT(void* const hPan)
618{
619 panner_data *pData = (panner_data*)(hPan);
620 return pData->DTT;
621}
622
623float panner_getSpread(void* const hPan)
624{
625 panner_data *pData = (panner_data*)(hPan);
626 return pData->spread_deg;
627}
628
629float panner_getYaw(void* const hBin)
630{
631 panner_data *pData = (panner_data*)(hBin);
632 return pData->bFlipYaw == 1 ? -RAD2DEG(pData->yaw) : RAD2DEG(pData->yaw);
633}
634
635float panner_getPitch(void* const hBin)
636{
637 panner_data *pData = (panner_data*)(hBin);
638 return pData->bFlipPitch == 1 ? -RAD2DEG(pData->pitch) : RAD2DEG(pData->pitch);
639}
640
641float panner_getRoll(void* const hBin)
642{
643 panner_data *pData = (panner_data*)(hBin);
644 return pData->bFlipRoll == 1 ? -RAD2DEG(pData->roll) : RAD2DEG(pData->roll);
645}
646
647int panner_getFlipYaw(void* const hBin)
648{
649 panner_data *pData = (panner_data*)(hBin);
650 return pData->bFlipYaw;
651}
652
653int panner_getFlipPitch(void* const hBin)
654{
655 panner_data *pData = (panner_data*)(hBin);
656 return pData->bFlipPitch;
657}
658
659int panner_getFlipRoll(void* const hBin)
660{
661 panner_data *pData = (panner_data*)(hBin);
662 return pData->bFlipRoll;
663}
664
666{
667 return 12*HOP_SIZE;
668}
#define MAX_NUM_INPUTS
Maximum number of input channels supported.
Definition _common.h:237
#define MAX_NUM_OUTPUTS
Maximum number of output channels supported.
Definition _common.h:240
#define PROGRESSBARTEXT_CHAR_LENGTH
Length of progress bar string.
Definition _common.h:231
@ PROC_STATUS_ONGOING
Codec is processing input audio, and should not be reinitialised at this time.
Definition _common.h:224
@ PROC_STATUS_NOT_ONGOING
Codec is not processing input audio, and may be reinitialised if needed.
Definition _common.h:226
CODEC_STATUS
Current status of the codec.
Definition _common.h:205
@ CODEC_STATUS_NOT_INITIALISED
Codec has not yet been initialised, or the codec configuration has changed.
Definition _common.h:208
@ CODEC_STATUS_INITIALISED
Codec is initialised and ready to process input audio.
Definition _common.h:206
@ CODEC_STATUS_INITIALISING
Codec is currently being initialised, input audio should not be processed.
Definition _common.h:211
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:375
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:178
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:521
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:408
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:512
float panner_getSourceAzi_deg(void *const hPan, int index)
Returns the input/source azimuth for a given index, in DEGREES.
Definition panner.c:565
int panner_getMaxNumSources(void)
Returns the maximum number of inputs/sources permitted by panner.
Definition panner.c:583
float panner_getYaw(void *const hBin)
Returns the 'yaw' rotation angle, in DEGREES.
Definition panner.c:629
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:647
int panner_getNumLoudspeakers(void *const hPan)
Returns the number of loudspeakers in the current layout.
Definition panner.c:600
float panner_getLoudspeakerAzi_deg(void *const hPan, int index)
Returns the loudspeaker azimuth for a given index, in DEGREES.
Definition panner.c:588
float panner_getProgressBar0_1(void *const hPan)
(Optional) Returns current intialisation/processing progress, between 0..1
Definition panner.c:553
int panner_getDAWsamplerate(void *const hPan)
Returns the DAW/Host sample rate.
Definition panner.c:611
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:617
void panner_setSpread(void *const hPan, float newValue)
Sets the degree of spread, in DEGREES.
Definition panner.c:477
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:349
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:390
void panner_setRoll(void *const hBin, float newRoll)
Sets the 'roll' rotation angle, in DEGREES.
Definition panner.c:505
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:659
void panner_setOutputConfigPreset(void *const hPan, int newPresetID)
Sets a preset for the output configuration (see LOUDSPEAKER_ARRAY_PRESETS enum)
Definition panner.c:440
float panner_getPitch(void *const hBin)
Returns the 'pitch' rotation angle, in DEGREES.
Definition panner.c:635
float panner_getLoudspeakerElev_deg(void *const hPan, int index)
Returns the loudspeaker elevation for a given index, in DEGREES.
Definition panner.c:594
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:542
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:463
void panner_destroy(void **const phPan)
Destroys an instance of the panner.
Definition panner.c:91
void panner_setYaw(void *const hBin, float newYaw)
Sets the 'yaw' rotation angle, in DEGREES.
Definition panner.c:491
void panner_setPitch(void *const hBin, float newPitch)
Sets the 'pitch' rotation angle, in DEGREES.
Definition panner.c:498
void panner_setInputConfigPreset(void *const hPan, int newPresetID)
Sets a preset for the input configuration (see SOURCE_CONFIG_PRESETS enum)
Definition panner.c:452
float panner_getRoll(void *const hBin)
Returns the 'roll' rotation angle, in DEGREES.
Definition panner.c:641
CODEC_STATUS panner_getCodecStatus(void *const hPan)
Returns current codec status (see CODEC_STATUS enum)
Definition panner.c:547
int panner_getProcessingDelay(void)
Returns the processing delay in samples (may be used for delay compensation features)
Definition panner.c:665
void panner_getProgressBarText(void *const hPan, char *text)
(Optional) Returns current intialisation/processing progress text
Definition panner.c:559
int panner_getMaxNumLoudspeakers(void)
Returns the maximum number of loudspeakers permitted.
Definition panner.c:606
float panner_getSourceElev_deg(void *const hPan, int index)
Returns the input/source elevation for a given index, in DEGREES.
Definition panner.c:571
void panner_initCodec(void *const hPan)
Intialises the codec variables, based on current global/user parameters.
Definition panner.c:142
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:363
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:339
float panner_getSpread(void *const hPan)
Returns the spread value, in DEGREES.
Definition panner.c:623
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:653
void panner_setNumLoudspeakers(void *const hPan, int new_nLoudspeakers)
Sets the number of loudspeakers to pan to.
Definition panner.c:424
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:530
int panner_getNumSources(void *const hPan)
Returns the number of inputs/sources in the current layout.
Definition panner.c:577
#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_initTFT(void *const hPan)
Initialise the filterbank used by panner.
void panner_loadSourcePreset(SOURCE_CONFIG_PRESETS preset, _Atomic_FLOAT32 dirs_deg[MAX_NUM_INPUTS][2], _Atomic_INT32 *newNCH, int *nDims)
Loads source directions from preset.
void panner_loadLoudspeakerPreset(LOUDSPEAKER_ARRAY_PRESETS preset, _Atomic_FLOAT32 dirs_deg[MAX_NUM_INPUTS][2], _Atomic_INT32 *newNCH, int *nDims)
Loads source/loudspeaker 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.
_Atomic_FLOAT32 src_dirs_deg[MAX_NUM_INPUTS][2]
Current source directions.
_Atomic_CODEC_STATUS codecStatus
see CODEC_STATUS
_Atomic_FLOAT32 DTT
Room coefficient [3].
_Atomic_PROC_STATUS procStatus
see PROC_STATUS
float freqVector[HYBRID_BANDS]
Frequency vector (centre frequencies)
_Atomic_INT32 recalc_gainsFLAG[MAX_NUM_INPUTS]
1: VBAP gains need to be recalculated for this source, 0: do not
_Atomic_INT32 recalc_M_rotFLAG
1: recalculate the rotation matrix, 0: do not
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
float_complex *** inputframeTF
Input signals, in the time-frequency domain; HYBRID_BANDS x MAX_NUM_INPUTS x TIME_SLOTS.
_Atomic_FLOAT32 loudpkrs_dirs_deg[MAX_NUM_OUTPUTS][2]
Current loudspeaker directions.
_Atomic_FLOAT32 roll
roll (Euler) rotation angle, in degrees
_Atomic_INT32 bFlipYaw
flag to flip the sign of the yaw rotation angle
float_complex *** outputframeTF
Output signals, in the time-frequency domain; HYBRID_BANDS x MAX_NUM_OUTPUTS x TIME_SLOTS.
int output_nDims
Dimensionality of the loudspeaker array, 2: 2-D, 3: 3-D.
_Atomic_INT32 nSources
Current number of inputs/sources.
_Atomic_FLOAT32 spread_deg
Source spread/MDAP [2].
_Atomic_FLOAT32 pitch
pitch (Euler) rotation angle, in degrees
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.
_Atomic_INT32 new_nSources
New number of inputs/sources.
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 src_dirs_rot_deg[MAX_NUM_INPUTS][2]
Intermediate rotated source directions, in degrees.
_Atomic_FLOAT32 yaw
yaw (Euler) rotation angle, in degrees
float src_dirs_rot_xyz[MAX_NUM_INPUTS][3]
Intermediate rotated source directions, as unit-length Cartesian coordinates.
void * hSTFT
afSTFT handle
float pValue[HYBRID_BANDS]
Used for the frequency-dependent panning normalisation.
int fs
Host sampling rate.
_Atomic_INT32 nLoudpkrs
Current number of loudspeakers in the array.
_Atomic_INT32 new_nLoudpkrs
New number of loudspeakers in the array.
_Atomic_FLOAT32 progressBar0_1
Current (re)initialisation progress, between [0..1].
_Atomic_INT32 bFlipRoll
flag to flip the sign of the roll rotation angle
_Atomic_INT32 bFlipPitch
flag to flip the sign of the pitch rotation angle
_Atomic_INT32 reInitGainTables
1: reinitialise the VBAP gain table, 0: do not