SAF
Loading...
Searching...
No Matches
safmex_faf_IIRFilterbank.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
24
25#include "safmex.h"
26
27/* ===================================================================== */
28/* Config */
29/* ===================================================================== */
30
31#define NUM_INPUT_ARGS_CREATE ( 4 )
32const MEX_DATA_TYPES inputDataTypes_create[NUM_INPUT_ARGS_CREATE] = {
33 SM_INT32,
37};
38#define NUM_INPUT_ARGS_APPLY ( 1 )
39#define NUM_OUTPUT_ARGS_APPLY ( 1 )
40const MEX_DATA_TYPES inputDataTypes_apply[NUM_INPUT_ARGS_APPLY] = {
42};
43const MEX_DATA_TYPES outputDataTypes_apply[NUM_OUTPUT_ARGS_APPLY] = {
45};
46
47
48/* ===================================================================== */
49/* Vars */
50/* ===================================================================== */
51
52/* user arguments */
53int order; /* filter order, 1 or 3 */
54float* fc = NULL; /* filter cutoff frequencies */
55int lSig; /* Number of samples to process at a time */
56float fs; /* sampling rate */
57
58/* internal parameters */
59void* hFaF = NULL; /* faf handle */
60float* data_in = NULL;
61float** data_out = NULL;
62int nCutoffFreqs;
63
64
65/* ===================================================================== */
66/* MEX Wrapper */
67/* ===================================================================== */
68
69void mexFunction
70(
71 int nlhs, /* Number of output argments */
72 mxArray *plhs[], /* Pointers for output arguments */
73 int nrhs, /* Number of input argments */
74 const mxArray *prhs[] /* Pointers for input arguments */
75)
76{
77 /* mex variables */
78 int i, nDims;
79 int *pDims = NULL;
80
81 /* DESTROY */
82 if(nrhs == 0){
83 if(hFaF!=NULL){
84 mexPrintf("Destroying FaF filterbank.\n");
86 free(fc); fc = NULL;
87 free(data_in); data_in = NULL;
88 free(data_out); data_out = NULL;
89 hFaF = NULL;
90 }
91 else
92 mexPrintf("FaF filterbank is already dead!\n");
93 }
94
95 /* CREATE */
96 else if( nrhs==NUM_INPUT_ARGS_CREATE && nlhs==0 ){
97 if(hFaF!=NULL)
98 mexErrMsgIdAndTxt("MyToolbox:inputError","safmex_faf_IIRFilterbank is already initialised! First destroy it if you want to change its configuration.");
99
100 /* Check input argument datatypes are as expected */
101 checkArgDataTypes((mxArray**)prhs, (MEX_DATA_TYPES*)inputDataTypes_create, NUM_INPUT_ARGS_CREATE);
102
103 /* Copy user arguments */
104 order = (int)mxGetScalar(prhs[0]);
105 lSig = (int)mxGetScalar(prhs[2]);
106 fs = (float)mxGetScalar(prhs[3]);
107 MEXdouble2SAFsingle(prhs[1], &fc, &nDims, &pDims);
108
109 /* Extra checks */
110 nCutoffFreqs = pDims[0];
111 if( !((order==1) || (order==3)) )
112 mexErrMsgIdAndTxt("MyToolbox:inputError","'order' must be either 1 or 3.");
113 if( nCutoffFreqs<=1 )
114 mexErrMsgIdAndTxt("MyToolbox:inputError","cut-off frequency vector must be longer than 1 element.");
115
116 /* Create an instance of the hFaF filterbank */
117 faf_IIRFilterbank_create(&hFaF, order, fc, nCutoffFreqs, fs, lSig);
118
119 /* Allocate buffers */
120 data_in = malloc1d(lSig * sizeof(float));
121 data_out = (float**)malloc2d(nCutoffFreqs+1, lSig, sizeof(float));
122
123 /* Mainly just for debugging... */
124 mexPrintf("Creating FaF filterbank:");
125 snprintf(message, MSG_STR_LENGTH, " filter order = %d,", order); mexPrintf(message);
126 snprintf(message, MSG_STR_LENGTH, " signal length = %d,", lSig); mexPrintf(message);
127 mexPrintf(" filter cut-off frequencies = [");
128 for(i=0; i<nCutoffFreqs; i++){
129 snprintf(message, MSG_STR_LENGTH, " %.2f ", fc[i]);
130 mexPrintf(message);
131 }
132 mexPrintf("]\n");
133 }
134
135 /* TRANSFORM */
136 else if(nrhs == 1 && nlhs == 1){
137 if(hFaF==NULL)
138 mexErrMsgIdAndTxt("MyToolbox:inputError","safmex_faf_IIRFilterbank is uninitialised!");
139
140 /* Check input argument datatypes are as expected */
141 checkArgDataTypes((mxArray**)prhs, (MEX_DATA_TYPES*)inputDataTypes_apply, NUM_INPUT_ARGS_APPLY);
142
143 /* Find dimensionality of input */
144 mwSize nDims_mx;
145 const mwSize *pDims_mx;
146 nDims_mx = mxGetNumberOfDimensions(prhs[0]);
147 pDims_mx = mxGetDimensions(prhs[0]);
148
149 /* extra checks */
150 if( pDims_mx[0] != (mwSize)lSig ){
151 snprintf(message, MSG_STR_LENGTH, "Was expecting %d samples.", lSig);
152 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
153 }
154 if( nDims_mx>1 )
155 if(pDims_mx[1] != 1 || nDims_mx>2 )
156 mexErrMsgIdAndTxt("MyToolbox:inputError", "Was expecting just one input channel.");
157
158 /* Apply filterbank */
159 MEXdouble2SAFsingle(prhs[0], &data_in, &nDims, &pDims);
160 faf_IIRFilterbank_apply(hFaF, data_in, data_out, lSig);
161
162 /* output */
163 nDims = 2;
164 pDims = realloc1d(pDims, nDims*sizeof(int));
165 pDims[0] = nCutoffFreqs+1; pDims[1] = lSig;
166 SAFsingle2MEXdouble(FLATTEN2D(data_out), nDims, pDims, &plhs[0]);
167
168 /* Check output argument datatypes are as expected */
169 checkArgDataTypes((mxArray**)plhs, (MEX_DATA_TYPES*)outputDataTypes_apply, NUM_OUTPUT_ARGS_APPLY);
170 }
171
172 /* ERROR */
173 else
174 mexErrMsgIdAndTxt("MyToolbox:inputError","Unrecognised input/output configuration, refer to help instructions.");
175}
void faf_IIRFilterbank_destroy(void **phFaF)
Destroys an instance of the Favrot & Faller filterbank.
void faf_IIRFilterbank_create(void **phFaF, int order, float *fc, int nCutoffFreq, float sampleRate, int maxNumSamples)
Computes a bank of IIR filter coefficients required to divide a signal into frequency bands,...
void faf_IIRFilterbank_apply(void *hFaF, float *inSig, float **outBands, int nSamples)
Applies the Favrot & Faller filterbank.
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 * realloc1d(void *ptr, size_t dim1_data_size)
1-D realloc (same as realloc, but with error checking)
Definition md_malloc.c:79
#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
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
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_REAL_2D
Real 2-D matrix; N x M.
Definition safmex.h:43
@ SM_DOUBLE_REAL_1D
Real 1-D vector; N x 1.
Definition safmex.h:39
void SAFsingle2MEXdouble(float *in, int nDims, int *dims, mxArray **out)
Convert a single precision array used by SAF to mex double-precision array.
Definition safmex.h:309
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