SAF
Loading...
Searching...
No Matches
safmex_latticeDecorrelator.c
Go to the documentation of this file.
1/*
2 * Copyright 2020 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
25#include "safmex.h"
26
27/* ===================================================================== */
28/* Config */
29/* ===================================================================== */
30
31#define NUM_INPUT_ARGS_CREATE ( 8 )
32const MEX_DATA_TYPES inputDataTypes_create[NUM_INPUT_ARGS_CREATE] = {
34 SM_INT32,
41};
42#define NUM_INPUT_ARGS_APPLY ( 1 )
43#define NUM_OUTPUT_ARGS_APPLY ( 1 )
44const MEX_DATA_TYPES inputDataTypes_apply[NUM_INPUT_ARGS_APPLY] = {
46};
47const MEX_DATA_TYPES outputDataTypes_apply[NUM_OUTPUT_ARGS_APPLY] = {
49};
50
51
52/* ===================================================================== */
53/* Vars */
54/* ===================================================================== */
55
56/* user arguments */
57float fs;
58int hopsize;
59int nCH; /* Number of channels */
60int* orders = NULL; /* Lattice all-pass filter orders (2,3,4,6,8,10,12,14,
61 15,16 18, or 20) per band grouping; nCutoffs x 1 */
62float* freqCutoffs = NULL; /* Frequency cut-offs defining the band groupings;
63 nCutoffs x 1 */
64int maxDelay; /* Maximum delay */
65float* freqVector = NULL; /* Frequency vector; nBands x 1 */
66int nTimeSlots; /* Number of TF frames to process at a time */
67
68/* internal parameters */
69void* hDecor = NULL; /* decor handle */
70int nBands;
71int nCutoffs;
72float_complex*** dataFD_in = NULL;
73float_complex*** dataFD_out = NULL;
74
75const int nSupportedOrders = 12;
76const int supportedOrders[12] = {2,3,4,6,8,10,12,14,15,16,18,20};
77
78
79/* ===================================================================== */
80/* MEX Wrapper */
81/* ===================================================================== */
82
83void mexFunction
84(
85 int nlhs, /* Number of output argments */
86 mxArray *plhs[], /* Pointers for output arguments */
87 int nrhs, /* Number of input argments */
88 const mxArray *prhs[] /* Pointers for input arguments */
89)
90{
91 /* mex variables */
92 int i,j,nDims;
93 int *pDims = NULL;
94
95 /* DESTROY */
96 if(nrhs == 0){
97 if(hDecor!=NULL){
98 mexPrintf("Destroying latticeDecorrelator.\n");
100 free(orders); orders = NULL;
101 free(freqCutoffs); freqCutoffs = NULL;
102 free(freqVector); freqVector = NULL;
103 free(dataFD_in); dataFD_in = NULL;
104 free(dataFD_out); dataFD_out = NULL;
105 hDecor = NULL;
106 }
107 else
108 mexPrintf("latticeDecorrelator is already dead!\n");
109 }
110
111 /* CREATE */
112 else if(nrhs==NUM_INPUT_ARGS_CREATE){
113 if(hDecor!=NULL)
114 mexErrMsgIdAndTxt("MyToolbox:inputError","safmex_latticeDecorrelator is already initialised! First destroy it if you want to change its configuration.");
115
116 /* Check input argument datatypes are as expected */
117 checkArgDataTypes((mxArray**)prhs, (MEX_DATA_TYPES*)inputDataTypes_create, NUM_INPUT_ARGS_CREATE);
118
119 /* Copy user arguments */
120 fs = (float)mxGetScalar(prhs[0]);
121 hopsize = (int)mxGetScalar(prhs[1]);
122 nCH = (int)mxGetScalar(prhs[2]);
123 MEXdouble2SAFsingle_int(prhs[3], &orders, &nDims, &pDims);
124
125 nCutoffs = pDims[0];
126 if( nCutoffs<=1 )
127 mexErrMsgIdAndTxt("MyToolbox:inputError","freqCutoffs vector must be longer than 1 element.");
128 for(i=0; i<nCutoffs; i++){
129 int supportedOrder = 0;
130 for(j=0; j<nSupportedOrders; j++)
131 if(orders[i] == supportedOrders[j])
132 supportedOrder = 1;
133
134 if(!supportedOrder)
135 mexErrMsgIdAndTxt("MyToolbox:inputError","Supported 'orders' are: 2,3,4,6,8,10,12,14,15,16,18,20.");
136 }
137
138 MEXdouble2SAFsingle(prhs[4], &freqCutoffs, &nDims, &pDims);
139 if(pDims[0] != nCutoffs )
140 mexErrMsgIdAndTxt("MyToolbox:inputError","freqCutoffs vector must be the same length as orders vector.");
141
142 maxDelay = (int)mxGetScalar(prhs[5]);
143
144 MEXdouble2SAFsingle(prhs[6], &freqVector, &nDims, &pDims);
145 nBands = pDims[0];
146 nTimeSlots = (int)mxGetScalar(prhs[7]);
147
148 /* Create an instance of latticeDecorrelator */
149 latticeDecorrelator_create(&hDecor, fs, hopsize, freqVector, nBands, nCH, orders, freqCutoffs, nCutoffs, maxDelay, 0, 0.75f);
150
151 /* Allocate buffers */
152 dataFD_in = (float_complex***)malloc3d(nBands, nCH, nTimeSlots, sizeof(float_complex));
153 dataFD_out = (float_complex***)malloc3d(nBands, nCH, nTimeSlots, sizeof(float_complex));
154
155 /* Mainly just for debugging... */
156 mexPrintf("Creating latticeDecorrelator:");
157 snprintf(message, MSG_STR_LENGTH, " %d channels,", nCH); mexPrintf(message);
158 mexPrintf(" filter orders = [");
159 for(i=0; i<nCutoffs; i++){
160 snprintf(message, MSG_STR_LENGTH, " %d ", orders[i]);
161 mexPrintf(message);
162 }
163 mexPrintf("], ");
164 mexPrintf(" cut-offs = [");
165 for(i=0; i<nCutoffs; i++){
166 snprintf(message, MSG_STR_LENGTH, " %.2f ", freqCutoffs[i]);
167 mexPrintf(message);
168 }
169 mexPrintf("], ");
170 snprintf(message, MSG_STR_LENGTH, " %d nBands,", nBands); mexPrintf(message);
171 snprintf(message, MSG_STR_LENGTH, " %d timeslots\n", nTimeSlots); mexPrintf(message);
172 }
173
174 /* APPLY */
175 else if(nrhs == 1 && nlhs == 1){
176 if(hDecor==NULL)
177 mexErrMsgIdAndTxt("MyToolbox:inputError","safmex_latticeDecorrelator is uninitialised!");
178
179 /* Find dimensionality of input */
180 mwSize nDims_mx;
181 const mwSize *pDims_mx;
182 nDims_mx = mxGetNumberOfDimensions(prhs[0]);
183 pDims_mx = mxGetDimensions(prhs[0]);
184
185 /* Check input argument datatypes are as expected */
186 checkArgDataTypes((mxArray**)prhs, (MEX_DATA_TYPES*)inputDataTypes_apply, NUM_INPUT_ARGS_APPLY);
187
188 /* extra checks */
189 if( !(pDims_mx[0] == (mwSize)nBands) ){
190 snprintf(message, MSG_STR_LENGTH, "Was expecting %d bands.", nBands);
191 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
192 }
193 if( !(pDims_mx[1] == (mwSize)nCH) ){
194 snprintf(message, MSG_STR_LENGTH, "Was expecting %d channels.", nCH);
195 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
196 }
197 if( !(pDims_mx[2] == (mwSize)nTimeSlots) ){
198 snprintf(message, MSG_STR_LENGTH, "Was expecting %d down-sampled time indices.", nTimeSlots);
199 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
200 }
201
202 /* Apply decorrelator */
203 MEXdouble2SAFsingle_complex(prhs[0], &FLATTEN3D(dataFD_in), &nDims, &pDims);
204 latticeDecorrelator_apply(hDecor, dataFD_in, nTimeSlots, dataFD_out);
205
206 /* output */
207 nDims = 3;
208 pDims = realloc1d(pDims, nDims*sizeof(int));
209 pDims[0] = nBands; pDims[1] = nCH; pDims[2] = nTimeSlots;
210 SAFsingle2MEXdouble_complex(FLATTEN3D(dataFD_out), nDims, pDims, &plhs[0]);
211
212 /* Check output argument datatypes are as expected */
213 checkArgDataTypes((mxArray**)plhs, (MEX_DATA_TYPES*)outputDataTypes_apply, NUM_OUTPUT_ARGS_APPLY);
214 }
215
216 /* ERROR */
217 else
218 mexErrMsgIdAndTxt("MyToolbox:inputError","Unrecognised input/output configuration, refer to help instructions.");
219}
void latticeDecorrelator_apply(void *hDecor, float_complex ***inFrame, int nTimeSlots, float_complex ***decorFrame)
Applies the lattice all-pass-filter-based multi-channel signal decorrelator.
void latticeDecorrelator_create(void **phDecor, float fs, int hopsize, float *freqVector, int nBands, int nCH, int *orders, float *freqCutoffs, int nCutoffs, int maxDelay, int lookupOffset, float enComp_coeff)
Creates an instance of the lattice all-pass-filter-based multi-channel signal decorrelator.
void latticeDecorrelator_destroy(void **phDecor)
Destroys an instance of the lattice all-pass-filter-based multi-channel signal decorrelator.
void * realloc1d(void *ptr, size_t dim1_data_size)
1-D realloc (same as realloc, but with error checking)
Definition md_malloc.c:79
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 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
Main include header for safmex.
void MEXdouble2SAFsingle(const mxArray *in, float **out, int *nDims, int **pDims)
Convert a mex double-precision array into single precision array for SAF.
Definition safmex.h:151
#define MSG_STR_LENGTH
Warning/error message character length.
Definition safmex.h:28
char message[MSG_STR_LENGTH]
Current warning/error message.
Definition safmex.h:29
void MEXdouble2SAFsingle_int(const mxArray *in, int **out, int *nDims, int **pDims)
Convert a mex double-precision array into single precision array for SAF (integers)
Definition safmex.h:264
MEX_DATA_TYPES
Supported SAF/MEX data conversions.
Definition safmex.h:33
@ SM_DOUBLE_REAL
Scalar, real valued; 1 x 1.
Definition safmex.h:37
@ SM_INT32
Integer; 1 x 1.
Definition safmex.h:34
@ SM_DOUBLE_COMPLEX_3D
Complex 3-D matrix; N x M x K.
Definition safmex.h:46
@ SM_DOUBLE_REAL_1D
Real 1-D vector; N x 1.
Definition safmex.h:39
void MEXdouble2SAFsingle_complex(const mxArray *in, float_complex **out, int *nDims, int **pDims)
Convert a mex double-precision array into single precision array for SAF (complex-valued)
Definition safmex.h:199
void SAFsingle2MEXdouble_complex(float_complex *in, int nDims, int *dims, mxArray **out)
Convert a single precision array used by SAF to mex double-precision array (complex valued)
Definition safmex.h:343
void checkArgDataTypes(mxArray **hData, MEX_DATA_TYPES *dataTypes, int nArgs)
Helper function to check the format of the input/output arguments are as expected.
Definition safmex.h:64