31#define NUM_INPUT_ARGS_CREATE ( 7 )
32const MEX_DATA_TYPES inputDataTypes_create[NUM_INPUT_ARGS_CREATE] = {
41#define NUM_INPUT_ARGS_FWD ( 1 )
42#define NUM_OUTPUT_ARGS_FWD ( 1 )
43#define NUM_INPUT_ARGS_BKWD ( 1 )
44#define NUM_OUTPUT_ARGS_BKWD ( 1 )
75float* freqVector = NULL;
79float** dataTD_in = NULL;
80float** dataTD_out = NULL;
81float_complex*** dataFD_in = NULL;
82float_complex*** dataFD_out = NULL;
104 mexPrintf(
"Destroying QMF filterbank.\n");
106 free(freqVector); freqVector = NULL;
107 free(dataTD_in); dataTD_in = NULL;
108 free(dataFD_in); dataFD_in = NULL;
109 free(dataTD_out); dataTD_out = NULL;
110 free(dataFD_out); dataFD_out = NULL;
114 mexPrintf(
"QMF filterbank is already dead!\n");
118 else if(nrhs==NUM_INPUT_ARGS_CREATE && (nlhs==0 || nlhs==1 || nlhs==2)){
120 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"safmex_qmf is already initialised! First destroy it if you want to change its configuration.");
126 nCHin = (int)mxGetScalar(prhs[0]);
127 nCHout = (int)mxGetScalar(prhs[1]);
128 hopsize = (int)mxGetScalar(prhs[2]);
129 blocksize = (int)mxGetScalar(prhs[3]);
130 hybridmode = (int)mxGetScalar(prhs[4]);
131 formatFlag = (int)mxGetScalar(prhs[5]);
132 fs = (float)mxGetScalar(prhs[6]);
137 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"the value of the fifth argument should be 0 or 1");
141 if( !(hybridmode==0 || hybridmode==1) )
142 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"'hybridmode' should be 0 (disabled) or 1 (enabled)");
143 if( !(formatFlag==0 || formatFlag==1) )
144 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"'formatFlag' should be 0 (bands x channels x time) or 1 (time x channels x bands)");
145 if( !(hopsize==4 || hopsize==8 || hopsize==16 || hopsize==32 || hopsize==64 || hopsize==128) )
146 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"the 'hopsize' should be 4, 8, 16, 32, 64, or 128");
147 if( blocksize % hopsize != 0)
148 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"'blocksize' must be a multiple of 'hopsize'");
151 timeSlots = blocksize/hopsize;
152 qmf_create(&hQMF, nCHin, nCHout, hopsize, hybridmode, format);
155 freqVector =
malloc1d(nBands*
sizeof(
float));
159 dataTD_in = (
float**)
malloc2d(nCHin, blocksize,
sizeof(
float));
160 dataTD_out = (
float**)
malloc2d(nCHout, blocksize,
sizeof(
float));
163 dataFD_in = (float_complex***)
malloc3d(nBands, nCHin, timeSlots,
sizeof(float_complex));
164 dataFD_out = (float_complex***)
malloc3d(nBands, nCHout, timeSlots,
sizeof(float_complex));
167 dataFD_in = (float_complex***)
malloc3d(timeSlots, nCHin, nBands,
sizeof(float_complex));
168 dataFD_out = (float_complex***)
malloc3d(timeSlots, nCHout, nBands,
sizeof(float_complex));
181 plhs[1] = mxCreateDoubleScalar(procDelay);
185 mexPrintf(
"Creating QMF filterbank:");
191 mexPrintf(
" hybrid mode enabled,");
193 mexPrintf(
" hybrid mode disabled,");
195 mexPrintf(
" format: time x channels x bands.\n");
197 mexPrintf(
" format: bands x channels x time.\n");
201 else if(nrhs == 1 && nlhs == 1){
203 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"safmex_qmf is uninitialised!");
207 const mwSize *pDims_mx;
208 nDims_mx = mxGetNumberOfDimensions(prhs[0]);
209 pDims_mx = mxGetDimensions(prhs[0]);
212 if(!mxIsComplex(prhs[0])){
217 if( !(pDims_mx[0] == (mwSize)nCHin) ){
219 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
221 if( !(pDims_mx[1] == (mwSize)blocksize) ){
223 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
232 pDims =
realloc1d(pDims, nDims*
sizeof(
int));
234 case 0: pDims[0] = nBands; pDims[1] = nCHin; pDims[2] = timeSlots;
break;
235 case 1: pDims[0] = timeSlots; pDims[1] = nCHin; pDims[2] = nBands;
break;
244 else if(mxIsComplex(prhs[0])){
249 if( !(pDims_mx[0] == (mwSize)nBands) && formatFlag==0 ){
251 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
253 if( !(pDims_mx[0] == (mwSize)timeSlots) && formatFlag==1 ){
255 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
257 if( !(pDims_mx[1] == (mwSize)nCHout) ){
259 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
261 if( !(pDims_mx[2] == (mwSize)timeSlots) && formatFlag==0 ){
263 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
265 if( !(pDims_mx[2] == (mwSize)nBands) && formatFlag==1 ){
267 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
message);
276 pDims =
realloc1d(pDims, nDims*
sizeof(
int));
278 pDims[1] = blocksize;
285 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"Unrecognised input/output configuration, refer to help instructions.");
290 mexErrMsgIdAndTxt(
"MyToolbox:inputError",
"Unrecognised input/output configuration, refer to help instructions.");
void qmf_getCentreFreqs(void *const hQMF, float fs, int nBands, float *centreFreq)
Computes the QMF/hybrid-QMF centre frequencies.
QMF_FDDATA_FORMAT
Options for how the frequency domain data is permuted when using qmf.
int qmf_getProcDelay(void *const hQMF)
Returns the processing delay in samples.
void qmf_synthesis(void *const hQMF, float_complex ***dataFD, int framesize, float **dataTD)
Performs QMF synthesis of the input frequency-domain signals.
void qmf_analysis(void *const hQMF, float **dataTD, int framesize, float_complex ***dataFD)
Performs QMF analysis of the input time-domain signals.
void qmf_destroy(void **const phQMF)
Destroys an instance of the qmf filterbank.
int qmf_getNBands(void *const hQMF)
Returns the number of frequency bands.
void qmf_create(void **const phQMF, int nCHin, int nCHout, int hopsize, int hybridmode, QMF_FDDATA_FORMAT format)
Creates an instance of the qmf filterbank.
@ QMF_BANDS_CH_TIME
nBands x nChannels x nTimeHops
@ QMF_TIME_CH_BANDS
nTimeHops x nChannels x nBands
void ** malloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D malloc (contiguously allocated, so use free() as usual to deallocate)
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
void * realloc1d(void *ptr, size_t dim1_data_size)
1-D realloc (same as realloc, but with error checking)
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)
#define FLATTEN2D(A)
Use this macro when passing a 2-D dynamic multi-dimensional array to memset, memcpy or any other func...
#define FLATTEN3D(A)
Use this macro when passing a 3-D dynamic multi-dimensional array to memset, memcpy or any other func...
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.
#define MSG_STR_LENGTH
Warning/error message character length.
char message[MSG_STR_LENGTH]
Current warning/error message.
MEX_DATA_TYPES
Supported SAF/MEX data conversions.
@ SM_DOUBLE_REAL
Scalar, real valued; 1 x 1.
@ SM_INT32
Integer; 1 x 1.
@ SM_DOUBLE_REAL_1D_OR_2D
Real 2-D matrix or 1-D vector; N x M | N x 1.
@ SM_DOUBLE_COMPLEX_3D
Complex 3-D matrix; N x M x K.
void SAFsingle2MEXdouble(float *in, int nDims, int *dims, mxArray **out)
Convert a single precision array used by SAF to mex double-precision array.
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)
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)
void checkArgDataTypes(mxArray **hData, MEX_DATA_TYPES *dataTypes, int nArgs)
Helper function to check the format of the input/output arguments are as expected.