fix the svd_size uninitialized bug
[processor-sdk/audio-preprocessing.git] / file_demo_bios / da830 / components / mss / src / mss.c
1 /**\r
2  *  @file   mss.c\r
3  *  @brief  Contains external API for Multi-Source Selection (MSS) module \r
4  *          instantiation.\r
5  *\r
6  *  (C) Copyright 2011, Texas Instruments, Inc.\r
7  */\r
8 \r
9 #include <xdc/std.h>\r
10 #include <ti/mas/types/types.h>\r
11 #include <ti/mas/fract/fract.h>\r
12 #include <ti/mas/vpe/svd.h>\r
13 \r
14 //#include <ti/mas/aer/mss.h>\r
15 //#include <ti/mas/aer/src/mssloc.h>\r
16 #include "../mss.h"\r
17 #include "mssloc.h"\r
18 \r
19 #define MSS_DEF_SWITCH_WAIT_TIME  250     /* msec */\r
20 #define MSS_DEF_SWITCH_DURATION   500     /* msec */\r
21 #define MSS_DEF_SWITCH_HANGOVER   1000    /* msec */\r
22 #define MSS_DEF_FADE_PHA_INC_8KHZ 268435L  /* Q31 phase increment of crossfade for \r
23                                               switch duration of 1 second at 8kHz:\r
24                                               2^31/8000, where 2^31 corresponds to pi. */\r
25 /* MSS memory buffer descriptors */\r
26 #define MSS_NUM_BUFS 1\r
27 #define MSS_INSTANCE_BUF 0\r
28 ecomemBuffer_t mssBufs[MSS_NUM_BUFS] = {                             \r
29   /* CLASS, LOG2 ALIGNMENT, BUFFER SIZE, VOLATILITY, BASE */\r
30   ecomem_CLASS_EXTERNAL, TYP_STRUCT_LOG2ALIGN, 0, FALSE, NULL\r
31 };\r
32 \r
33 /******************************************************************************\r
34  * FUNCTION PURPOSE: Return buffer sizes for the MSS module\r
35  ******************************************************************************\r
36  * DESCRIPTION: Calculate the worst case buffer sizes for the MSS. Also specify\r
37  *              alignment and volatility requirements.\r
38  *\r
39  *  tint mssGetSizes (\r
40  *    tint              *nbufs,    - address to store number of buffers\r
41  *    const ecomemBuffer_t **bufs, - address to store buffer descriptors\r
42  *    mssSizeConfig_t   *cfg)      - information to be used in calculating the\r
43  *                                   worst case buffer sizes\r
44  *****************************************************************************/\r
45 tint mssGetSizes(tint *nbufs, const ecomemBuffer_t **bufs, mssSizeConfig_t *cfg)\r
46 {\r
47   tint svd_size, mss_size, mss_inst_size, num_src;\r
48 \r
49   /* Get memory requirement of SVD */\r
50   svdGetSizes (&svd_size);\r
51   \r
52   /* Calculate total memory of MSS: instance + all SVDs*/\r
53   svd_size = mss_SIZE_ALIGN(svd_size,TYP_STRUCT_LOG2ALIGN);\r
54   mss_inst_size = sizeof(mssInst_t);\r
55   mss_inst_size = mss_SIZE_ALIGN(mss_inst_size,TYP_STRUCT_LOG2ALIGN);\r
56   num_src =  cfg->max_num_mic_fixed + cfg->max_num_mic_remote\r
57            + cfg->max_num_mic_clean + cfg->max_num_beam;\r
58   mss_size = svd_size*num_src + mss_inst_size;\r
59   mssBufs[MSS_INSTANCE_BUF].size = mss_size;\r
60 \r
61   /* Return number of buffers required by MSS */  \r
62   *nbufs = MSS_NUM_BUFS;\r
63   \r
64   /* Return buffer specifications */\r
65   *bufs = &mssBufs[0];                  \r
66   \r
67   return(mss_NOERR);\r
68   \r
69 } /* mssGetSizes */\r
70 \r
71 /******************************************************************************\r
72  * FUNCTION PURPOSE: Create an instance of the MSS module.\r
73  ******************************************************************************\r
74  * DESCRIPTION: Creates an instance of the MSS and initializes memory buffers.\r
75  *\r
76  *  tint mssNew (\r
77  *    void            **mssInst,  - address of the memory location that will\r
78  *                                  receive a pointer to instance structure\r
79  *    tint            nbufs,      - number of memory buffers\r
80  *    ecomemBuffer_t  *bufs,      - a vector of buffer descriptors\r
81  *    mssNewConfig_t  *cfg)       - a pointer to configuration structure\r
82  *\r
83  *  Return value: \r
84  *          mss_NOERR             - success\r
85  *          mss_ERR_INVALIDPAR    - *mssInst is not NULL or nbufs is not correct \r
86  *          mss_ERR_NOMEMORY      - MSS instance pointer is not NULL, or\r
87  *                                  number of buffers is not correct, or\r
88  *                                  buffer properties are not correct\r
89  *****************************************************************************/\r
90 tint mssNew (void **mssInst, tint nbufs, ecomemBuffer_t *bufs, mssNewConfig_t *cfg)\r
91 {\r
92   mssInst_t       *inst;\r
93   ecomemBuffer_t  *bufp;\r
94   tint svd_size, mss_size, mss_inst_size, num_src;\r
95   int i;\r
96   \r
97   /* Test instance pointer (must be NULL) */\r
98   if ((*mssInst != NULL) || (nbufs != MSS_NUM_BUFS)) {\r
99     return(mss_ERR_INVALIDPAR);\r
100   }\r
101 \r
102   /* Check all dynamic buffers (base address != NULL) */\r
103   for (i=0, bufp=&bufs[0]; i<MSS_NUM_BUFS; i++, bufp++) {\r
104     if ((bufp->size>0) && (bufp->base==NULL)) {\r
105       return(mss_ERR_NOMEMORY);\r
106     }\r
107   }\r
108 \r
109   /* Get the instance buffer descriptor returned by the user */\r
110   bufp = &bufs[MSS_INSTANCE_BUF];\r
111 \r
112   /* Calculate total memory of MSS: instance + all SVDs */\r
113   svdGetSizes (&svd_size);\r
114   svd_size = mss_SIZE_ALIGN(svd_size,TYP_STRUCT_LOG2ALIGN);\r
115   mss_inst_size = sizeof(mssInst_t);\r
116   mss_inst_size = mss_SIZE_ALIGN(mss_inst_size,TYP_STRUCT_LOG2ALIGN);\r
117   num_src =  cfg->sizeCfg.max_num_mic_fixed + cfg->sizeCfg.max_num_mic_remote\r
118            + cfg->sizeCfg.max_num_mic_clean + cfg->sizeCfg.max_num_beam;\r
119   mss_size = svd_size*num_src + mss_inst_size;\r
120   \r
121   /* Check if the provided memory is good: size, alignment, and volatility */\r
122   if ( (bufp->size < mss_size) \r
123       || (!typChkAlign(bufp->base, bufp->log2align)) || bufp->volat) {\r
124     return(mss_ERR_NOMEMORY);\r
125   }\r
126   \r
127   /* Assign instance memory and initialize instance */\r
128   inst = (mssInst_t *)bufp->base;\r
129   inst->max_sampling_rate = cfg->sizeCfg.max_sampling_rate;\r
130   inst->svd = (tword *)bufp->base + mss_inst_size; /* SVD address for 1st src */\r
131   inst->svd_size = svd_size;\r
132   inst->handle = cfg->handle;        /* init handle in instance */\r
133   inst->state = MSS_CLOSED;          /* set MSS state to CLOSED */\r
134 \r
135   /* Return instance address */\r
136   *mssInst = (void *)inst;\r
137 \r
138   return(mss_NOERR);\r
139   \r
140 } /* mssNew() */\r
141 \r
142 /******************************************************************************\r
143  * FUNCTION PURPOSE: Control of MSS\r
144  ******************************************************************************\r
145  * DESCRIPTION: Controls the operation and parameters of the MSS.\r
146  *\r
147  *  tint mssControl (\r
148  *    void  *mssInst,              - a pointer to MSS instance\r
149  *    tint  mssControl *ctl)       - a pointer to the control code structure \r
150  *\r
151  *  Return value: mss_NOERR           - success\r
152  *                mss_ERR_NOTOPENED   - MSS not opened\r
153  *                mss_ERR_INVALIDSRC  - the manually selected source is invalid \r
154  *                mss_ERR_INVALIDPAR  - parameter is invalid \r
155  *****************************************************************************/\r
156 tint mssControl (void *mssInst, mssControl_t *ctl)\r
157 {\r
158   mssInst_t *inst = (mssInst_t *)mssInst;\r
159   tint ret_val;\r
160 \r
161   /* Make sure that MSS is open */\r
162   if (inst->state != MSS_OPEN) {\r
163     return (mss_ERR_NOTOPENED);\r
164   }  \r
165   \r
166   ret_val = mss_NOERR;\r
167 \r
168   /* Change the operation modes bitfield */\r
169   if(mss_chkbit(ctl->valid_bitfield, mss_CTL_MODES)) {\r
170     inst->modes_bf =  (inst->modes_bf & (~ctl->modes.mask))\r
171                     | (ctl->modes.value & ctl->modes.mask);\r
172   } /* mss_CTL_MODES */\r
173   \r
174   /* Manually select source */\r
175   if(mss_chkbit(ctl->valid_bitfield, mss_CTL_SELECT_SRC)) {\r
176     /* Check if selected source is valid:\r
177          - source group must be one of the groups defined in mss.h,      \r
178          - source index must be less than the number of sources in the group. */\r
179     if(   (ctl->source.group > mss_SRC_MAX)\r
180        || (ctl->source.group < mss_SRC_MIC_FIXED) ){\r
181       ret_val = mss_ERR_INVALIDSRC;\r
182     } \r
183     else if (ctl->source.index > inst->num_src_per_group[ctl->source.group]) {\r
184       ret_val = mss_ERR_INVALIDSRC;\r
185     }\r
186     else if (   (ctl->source.group != inst->cur_src.group) \r
187              || (ctl->source.index != inst->cur_src.index) ) {      \r
188       /* Prepare to switch source if selected source is valid. If in the middle of a \r
189          source switch initiated by MSS internally, internal switch will be stopped. */\r
190       inst->switch_src_cnt  = 0;\r
191       inst->crossfade_phase = MSS_FADE_PHA_INIT;\r
192       inst->switch_hang_cnt = inst->params.switch_hangover;\r
193       inst->new_src = ctl->source;\r
194       mss_setbit(inst->state_bf, MSS_STATE_BIT_SWITCH_SRC);\r
195     }\r
196   } /* mss_CTL_SELECT_SRC */\r
197 \r
198   /* Change the threshold of source switch */\r
199   if(mss_chkbit(ctl->valid_bitfield, mss_CTL_SWITCH_THRESH)) {\r
200     /* Convert parameter from msec to # of samples */\r
201     inst->params.switch_threshold = MSS_NUM_SAMP_1MS_8KHZ * inst->sampling_rate\r
202                                     * ctl->switch_thresh;\r
203   }\r
204   \r
205   /* Change the duration of source switch */\r
206   if(mss_chkbit(ctl->valid_bitfield, mss_CTL_SWITCH_DURATION)) {\r
207     /* Convert parameter from msec to # of samples */\r
208     inst->params.switch_duration = MSS_NUM_SAMP_1MS_8KHZ * inst->sampling_rate\r
209                                    * ctl->switch_duration;\r
210     /* Calculate per sample Q31 phase increment for crossfade implementation: \r
211        2^31/duration, where 2^31 corresponds to pi. */                                     \r
212     inst->crossfade_phase_inc = frct_LFRCT_MAX/inst->params.switch_duration;                                     \r
213   } /* mss_CTL_SWITCH_DURATION */\r
214 \r
215   /* Change hangover of source switch */\r
216   if(mss_chkbit(ctl->valid_bitfield, mss_CTL_SWITCH_HNAGOVER)) {\r
217     /* Convert parameter from msec to # of samples */\r
218     inst->params.switch_hangover = MSS_NUM_SAMP_1MS_8KHZ * inst->sampling_rate\r
219                                    * ctl->switch_hangover;\r
220   } /* mss_CTL_SWITCH_HNAGOVER */\r
221   \r
222   return ret_val;\r
223 } /* mssControl */\r
224   \r
225 /******************************************************************************\r
226  * FUNCTION PURPOSE: Open and configure an MSS instance.\r
227  ******************************************************************************\r
228  * DESCRIPTION: This function configures an instance of the MSS.\r
229  *\r
230  *  tint mssOpen (\r
231  *    void        *mssInst,   - a pointer to MSS instance\r
232  *    mssConfig_t *cfg)       - a pointer to MSS configuration structure\r
233  *\r
234  *****************************************************************************/\r
235 tint mssOpen (void *mssInst, mssConfig_t *cfg)\r
236 {\r
237   mssInst_t * inst = (mssInst_t *)mssInst;\r
238   tword * svd_ptr;\r
239   tint num_src, svd_size;\r
240   int i;\r
241   \r
242   /* Return error if state is not CLOSED */  \r
243   if(inst->state != MSS_CLOSED) {\r
244     return(mss_ERR_NOTCLOSED);\r
245   }\r
246   \r
247   /* Return error if no configuration parameters */\r
248   if(cfg == NULL){\r
249     return(mss_ERR_INVALIDPAR);\r
250   }\r
251   \r
252   /* Read configuration */\r
253   num_src = cfg->num_mic_fixed+cfg->num_mic_remote+cfg->num_mic_clean+cfg->num_beam;\r
254   if(num_src <= 0) {\r
255     return(mss_ERR_INVALIDPAR);\r
256   }\r
257   \r
258   inst->sampling_rate  = cfg->sampling_rate;\r
259   inst->num_src_per_group[mss_SRC_MIC_FIXED]  = cfg->num_mic_fixed;\r
260   inst->num_src_per_group[mss_SRC_MIC_REMOTE] = cfg->num_mic_remote;\r
261   inst->num_src_per_group[mss_SRC_MIC_CLEAN]  = cfg->num_mic_clean;\r
262   inst->num_src_per_group[mss_SRC_BEAM]       = cfg->num_beam;\r
263   inst->num_mic_array  = cfg->num_mic_array; /* not considered as source to select */\r
264   \r
265   /* Init SVDs */\r
266   svd_size  = inst->svd_size;\r
267   svd_ptr = (tword *)inst->svd;\r
268   for(i=0; i<num_src; i++) {\r
269     if (!typChkAlign(svd_ptr, TYP_STRUCT_LOG2ALIGN)) {\r
270       return(mss_ERR_NOMEMORY);\r
271     }\r
272     svdInit((void *)svd_ptr, inst->sampling_rate);\r
273     svd_ptr += svd_size;\r
274   }    \r
275   \r
276   /* Set parameters to default */\r
277   inst->params.switch_threshold = MSS_DEF_SWITCH_WAIT_TIME * MSS_NUM_SAMP_1MS_8KHZ\r
278                                  * inst->sampling_rate; /* convert msec to # of samples */\r
279   inst->params.switch_duration = MSS_DEF_SWITCH_DURATION * MSS_NUM_SAMP_1MS_8KHZ\r
280                                  * inst->sampling_rate; /* convert msec to # of samples */\r
281   inst->crossfade_phase_inc    = MSS_DEF_FADE_PHA_INC_8KHZ / inst->sampling_rate;\r
282   inst->params.switch_hangover = MSS_DEF_SWITCH_HANGOVER * MSS_NUM_SAMP_1MS_8KHZ \r
283                                  * inst->sampling_rate; /* convert msec to # of samples */\r
284   inst->modes_bf = mss_CTL_MODES_DEFAULT;\r
285   \r
286   /* Set initially selected source - the first valid source */\r
287   if(cfg->num_mic_fixed > 0) {\r
288     inst->cur_src.group = mss_SRC_MIC_FIXED;\r
289     inst->cur_src.index = 0;\r
290   }\r
291   else if(cfg->num_mic_remote > 0) {\r
292     inst->cur_src.group = mss_SRC_MIC_REMOTE;\r
293     inst->cur_src.index = 0;\r
294   }\r
295   else if(cfg->num_mic_clean > 0) {\r
296     inst->cur_src.group = mss_SRC_MIC_CLEAN;\r
297     inst->cur_src.index = 0;\r
298   }\r
299   else {\r
300     inst->cur_src.group = mss_SRC_BEAM;\r
301     inst->cur_src.index = 0;\r
302   }\r
303   \r
304   /* Initialize instance */ \r
305   inst->frame_size = inst->sampling_rate * MSS_FRAME_SIZE_8KHZ;\r
306   inst->switch_hang_cnt = inst->params.switch_hangover;\r
307   inst->crossfade_cnt  = 0;\r
308   inst->state_bf = 0;\r
309   \r
310   /* Declare the instance OPEN */\r
311   inst->state = MSS_OPEN;   \r
312 \r
313   return(mss_NOERR);\r
314 } /* mssOpen */\r
315 \r
316 /******************************************************************************\r
317  * FUNCTION PURPOSE: Returns debuging information for an MSS instance.\r
318  ******************************************************************************\r
319  * DESCRIPTION: This function returns debuging information.\r
320  *\r
321  *  tint mssDebugStat (\r
322  *    void        *mssInst,   - a pointer to MSS instance\r
323  *    mssDebugStat_t *mssDbg) - a pointer to MSS debug structure\r
324  *\r
325  *****************************************************************************/\r
326 tint mssDebugStat(void *mssInst, mssDebugStat_t *mssDbg)\r
327 {\r
328   tint svd_decision;\r
329   tword *svd_ptr;\r
330   LFract sig_pow;\r
331   Fract spch_db, noise_db;\r
332   UFract svd_thresh;\r
333   mssInst_t *inst = (mssInst_t *)mssInst;\r
334 \r
335   /* Make sure that MSS is open */\r
336   if (inst->state != MSS_OPEN) {\r
337     return (mss_ERR_NOTOPENED);\r
338   }  \r
339   \r
340   mssDbg->cur_src = inst->cur_src;\r
341   mssDbg->new_src = inst->new_src;\r
342   mssDbg->states[0] = (tuint)(inst->crossfade_phase>>16);\r
343   mssDbg->states[1] = (tuint)inst->gain_in;\r
344   mssDbg->states[2] = (tuint)inst->gain_out;\r
345   mssDbg->states[3] = (tuint)inst->switch_src_cnt; \r
346   mssDbg->states[4] = (tuint)inst->state_bf;\r
347 \r
348   /* only debug fixed mics for now */\r
349   if(inst->num_src_per_group[mss_SRC_MIC_FIXED] > 1) {\r
350     svd_ptr = inst->svd;\r
351     svd_decision = svdGetDecision(svd_ptr, &sig_pow);\r
352     mssDbg->states[5] = (tuint)svd_decision;\r
353     \r
354     svdGetLevels (svd_ptr, &spch_db, &noise_db, &svd_thresh);\r
355     mssDbg->states[6] = (tuint)spch_db;\r
356     mssDbg->states[7] = (tuint)noise_db;\r
357   \r
358     svd_ptr += inst->svd_size;\r
359     svd_decision = svdGetDecision(svd_ptr, &sig_pow);\r
360     mssDbg->states[8] = (tuint)svd_decision;\r
361     \r
362     svdGetLevels (svd_ptr, &spch_db, &noise_db, &svd_thresh);\r
363     mssDbg->states[9] = (tuint)spch_db;\r
364     mssDbg->states[10] = (tuint)noise_db;\r
365   }\r
366   \r
367   return(mss_NOERR);\r
368   \r
369 } /* mssDebugStat */\r
370 \r
371 /******************************************************************************\r
372  * FUNCTION PURPOSE: Close an instance of MSS.\r
373  ******************************************************************************\r
374  * DESCRIPTION: This function closes an instance of MSS by simply changing\r
375  *              the state to CLOSED.\r
376  *\r
377  *  tint mssClose (\r
378  *    void *mssInst)    - a pointer to MSS instance\r
379  *\r
380  *****************************************************************************/\r
381 tint mssClose (void *mssInst)\r
382 {\r
383   mssInst_t *inst = (mssInst_t *)mssInst;\r
384 \r
385   if(inst->state != MSS_OPEN) {\r
386     return(mss_ERR_NOTOPENED);\r
387   }\r
388   \r
389   /*Change the MSS state to CLOSED */\r
390   inst->state = MSS_CLOSED;     \r
391   \r
392   return(mss_NOERR);\r
393 } /* mssClose */\r
394 \r
395 /******************************************************************************\r
396  * FUNCTION PURPOSE: Delete an MSS instance.\r
397  ******************************************************************************\r
398  * DESCRIPTION: Deletes an instance of MSS. Clears the instance pointer.\r
399  *              Actual "deallocation" of instance should be done elsewhere\r
400  *              after this function is called. Hence, one has to save the\r
401  *              buffer descriptors to make "deallocation" possible.\r
402  *\r
403  *  tint mssDelete (\r
404  *    void           **mssInst,  - an address of memory location that contains\r
405  *                                 a pointer to instance structure\r
406  *    tint           nbufs,      - number of memory buffers\r
407  *    ecomemBuffer_t *bufs)      - vector of buffer descriptors\r
408  *\r
409  *****************************************************************************/\r
410 tint mssDelete (void **mssInst, tint nbufs, ecomemBuffer_t *bufs)\r
411 {\r
412   mssInst_t *inst = (mssInst_t *)*mssInst;\r
413 \r
414   /* check if instance is already closed */\r
415   if (inst->state != MSS_CLOSED) {      \r
416     return (mss_ERR_NOTCLOSED);\r
417   }\r
418   \r
419   /* check if enough descriptors are provided to store all buffer addresses */\r
420   if (nbufs < MSS_NUM_BUFS) { \r
421     return (mss_ERR_NOMEMORY);\r
422   }\r
423  \r
424   /* return buffer addresses */\r
425   bufs[MSS_INSTANCE_BUF].base      = inst;   /* instance structure */\r
426 \r
427   /* clear the instance pointer */\r
428   *mssInst = NULL;                              \r
429 \r
430   return(mss_NOERR);\r
431 } /* mssDelete */\r
432 \r
433 /******************************************************************************\r
434  * FUNCTION PURPOSE: Validates the input sources to MSS.\r
435  ******************************************************************************\r
436  * DESCRIPTION: This function examines the input sources to MSS to make sure\r
437  *              all sources are valid.\r
438  *\r
439  *****************************************************************************/\r
440 \r
441 tint mss_src_validation(mssInst_t *inst, void *rx_out_sync, void *mic_fix[],\r
442                 void *mic_rem[], void *mic_cln[], void *mic_arr[], void *beam[])\r
443 {                \r
444   int i;\r
445   \r
446   /* Return error if synchronized Rx out doesn't have valid data (NOT USED!!!) */\r
447   /*\r
448    *  if ( rx_out_sync == NULL ) {  \r
449    *    return (mss_ERR_INVALIDSRC); \r
450    *  }\r
451    */\r
452 \r
453   /* Check if all sources have valid data.\r
454      Currently MSS only supports fixed mic, remote mic, and clean mic.\r
455   */\r
456   if(inst->num_src_per_group[mss_SRC_MIC_FIXED] > 0) {\r
457     if(mic_fix == NULL) {\r
458       return (mss_ERR_INVALIDSRC);\r
459     }\r
460     else {\r
461       for (i=0; i<inst->num_src_per_group[mss_SRC_MIC_FIXED]; i++) {\r
462         if(mic_fix[i] == NULL) {\r
463           return (mss_ERR_INVALIDSRC);\r
464         }\r
465       }\r
466     }\r
467   } /* mss_SRC_MIC_FIXED */\r
468   \r
469   if(inst->num_src_per_group[mss_SRC_MIC_REMOTE] > 0) {\r
470     if(mic_rem == NULL) {\r
471       return (mss_ERR_INVALIDSRC);\r
472     }\r
473     else {\r
474       for (i=0; i<inst->num_src_per_group[mss_SRC_MIC_REMOTE]; i++) {\r
475         if(mic_rem[i] == NULL) {\r
476           return (mss_ERR_INVALIDSRC);\r
477         }\r
478       }\r
479     }\r
480   } /* mss_SRC_MIC_REMOTE */\r
481   \r
482   if(inst->num_src_per_group[mss_SRC_MIC_CLEAN] > 0) {\r
483     if(mic_cln == NULL) {\r
484       return (mss_ERR_INVALIDSRC);\r
485     }\r
486     else {\r
487       for (i=0; i<inst->num_src_per_group[mss_SRC_MIC_CLEAN]; i++) {\r
488         if(mic_cln[i] == NULL) {\r
489           return (mss_ERR_INVALIDSRC);\r
490         }\r
491       }\r
492     }\r
493   } /* mss_SRC_MIC_CLEAN */\r
494  \r
495   return (mss_NOERR);  \r
496 } /* mss_src_validation */\r
497 \r
498 /* Nothing past this point */\r