SAF
Loading...
Searching...
No Matches
safmex.h
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#include "mex.h"
25#include "saf.h"
26
28#define MSG_STR_LENGTH ( 2048 )
30/* snprintf(message, MSG_STR_LENGTH, "mem required: %d", numElements); mexPrintf(message); */
31
49
51void checkNumInOutArgs(int nInputs, int nOutputs, int nInputs_expected, int nOutputs_expected)
52{
53 if(nInputs != nInputs_expected){
54 snprintf(message, MSG_STR_LENGTH, "Number of inputs expected: %d", nInputs_expected);
55 mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs", message);
56 }
57 if(nOutputs != nOutputs_expected){
58 snprintf(message, MSG_STR_LENGTH, "Number of outputs expected: %d", nOutputs_expected);
59 mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs", message);
60 }
61}
62
64void checkArgDataTypes(mxArray** hData, MEX_DATA_TYPES* dataTypes, int nArgs)
65{
66 int i,j;
67 mwSize nDims, true_nDims;
68 const mwSize* pDims;
69
70 for(i=0; i<nArgs; i++){
71 /* Find number of dimensions */
72 nDims = mxGetNumberOfDimensions(hData[i]);
73 pDims = mxGetDimensions(hData[i]);
74 true_nDims = 0; /* (note: true_nDims==0 infers argument is a scalar) */
75 for(j=0; j<nDims; j++)
76 true_nDims = pDims[j]!=1 ? true_nDims+1 : true_nDims;
77
78 /* Check data types */
79 switch(dataTypes[i]){
80 case SM_INT32:
81 if (mxIsComplex(hData[i]) || mxGetNumberOfElements(hData[i])!=1){
82 snprintf(message, MSG_STR_LENGTH, "The following input argument must be an integer scalar: %d", i+1);
83 mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notScalar", message);
84 }
85 break;
86 case SM_DOUBLE_REAL:
87 if (!mxIsDouble(hData[i]) || mxIsComplex(hData[i]) || true_nDims!=0){
88 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a real-valued double-precision scalar: %d", i+1);
89 mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notScalar", message);
90 }
91 break;
93 if (!mxIsDouble(hData[i]) || !mxIsComplex(hData[i]) || true_nDims!=0){
94 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a complex-valued double-precision scalar: %d", i+1);
95 mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notScalar", message);
96 }
97 break;
99 if (!mxIsDouble(hData[i]) || mxIsComplex(hData[i]) || true_nDims!=1){
100 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a real-valued double-precision 1-D vector: %d", i+1);
101 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
102 }
103 break;
105 if (!mxIsDouble(hData[i]) || !mxIsComplex(hData[i]) || true_nDims!=1){
106 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a complex-valued double-precision 1-D vector: %d", i+1);
107 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
108 }
109 break;
111 if (!mxIsDouble(hData[i]) || mxIsComplex(hData[i]) || true_nDims==0 || true_nDims>2){
112 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a real-valued double-precision 1-D vector or 2-D matrix: %d", i+1);
113 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
114 }
115 break;
117 if (!mxIsDouble(hData[i]) || !mxIsComplex(hData[i]) || true_nDims==0 || true_nDims>2){
118 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a complex-valued double-precision 1-D vector or 2-D matrix: %d", i+1);
119 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
120 }
121 break;
123 if( !mxIsDouble(hData[i]) || mxIsComplex(hData[i]) || true_nDims!=2) {
124 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a real-valued double-precision 2-D matrix: %d", i+1);
125 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
126 }
127 break;
129 if( !mxIsDouble(hData[i]) || !mxIsComplex(hData[i]) || true_nDims!=2) {
130 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a complex-valued double-precision 2-D matrix: %d", i+1);
131 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
132 }
133 break;
135 if( !mxIsDouble(hData[i]) || mxIsComplex(hData[i]) || nDims!=3) {
136 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a real-valued double-precision 3-D matrix: %d", i+1);
137 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
138 }
139 break;
141 if( !mxIsDouble(hData[i]) || !mxIsComplex(hData[i]) || nDims!=3) {
142 snprintf(message, MSG_STR_LENGTH, "The following input argument must be a complex-valued double-precision 3-D matrix: %d", i+1);
143 mexErrMsgIdAndTxt("MyToolbox:inputError", message);
144 }
145 break;
146 }
147 }
148}
149
151void MEXdouble2SAFsingle(const mxArray* in, float** out, int* nDims, int** pDims)
152{
153 int i, j, numElements;
154 double *inMatrix;
155 mwSize nDims_mx;
156 const mwSize *pDims_mx;
157
158 /* Find dimensionality of input */
159 nDims_mx = mxGetNumberOfDimensions(in);
160 pDims_mx = mxGetDimensions(in);
161
162 /* convert mwSize->int */
163 (*nDims) = (int)nDims_mx;
164 (*pDims) = realloc1d((*pDims), (*nDims)*sizeof(int));
165 for(i=0; i<(*nDims); i++)
166 (*pDims)[i] = (int)pDims_mx[i];
167
168 /* Find number of elements */
169 numElements = 1;
170 for(i=0; i<(*nDims); i++)
171 numElements *= (*pDims)[i];
172
173 /* Convert input mex array to saf array */
174#if MX_HAS_INTERLEAVED_COMPLEX
175 assert(0); /* need to implement switch case for number of dims, and interleave the reading of inMatrix somehow... */
176#endif
177 inMatrix = mxGetData(in);
178 if((*out)==NULL)
179 (*out) = malloc1d(numElements*sizeof(float));
180
181 /* column-major -> row-major */
182 switch(*nDims){
183 case 0: /* scalar */ break;
184 case 1:
185 for(i=0; i<(*pDims)[0]; i++)
186 (*out)[i] = (float)inMatrix[i];
187 break;
188 case 2:
189 for(i=0; i<(*pDims)[0]; i++)
190 for(j=0; j<(*pDims)[1]; j++)
191 (*out)[i*(*pDims)[1]+j] = (float)inMatrix[j*(*pDims)[0]+i];
192 break;
193
194 default: assert(0); break;// incomplete
195 }
196}
197
199void MEXdouble2SAFsingle_complex(const mxArray* in, float_complex** out, int* nDims, int** pDims)
200{
201 int i, j, k, numElements;
202 #if MX_HAS_INTERLEAVED_COMPLEX
203 mxComplexDouble* inMatrix;
204#else
205 double *inMatrix_r;
206 double *inMatrix_i;
207#endif
208 mwSize nDims_mx;
209 const mwSize *pDims_mx;
210
211 /* Find dimensionality of input */
212 nDims_mx = mxGetNumberOfDimensions(in);
213 pDims_mx = mxGetDimensions(in);
214
215 /* convert mwSize->int */
216 (*nDims) = (int)nDims_mx;
217 (*pDims) = malloc1d(*nDims*sizeof(int));
218 for(i=0; i<(*nDims); i++)
219 (*pDims)[i] = (int)pDims_mx[i];
220
221 /* Find number of elements */
222 numElements = 1;
223 for(i=0; i<(*nDims); i++)
224 numElements *= (*pDims)[i];
225
226 /* Convert input mex array to saf array */
227#if MX_HAS_INTERLEAVED_COMPLEX
228 inMatrix = mxGetData(in);
229#else
230 inMatrix_r = mxGetPr(in);
231 inMatrix_i = mxGetPi(in);
232#endif
233 if((*out)==NULL)
234 (*out) = malloc1d(numElements*sizeof(float_complex));
235
236 /* column-major -> row-major */
237 switch(*nDims){
238 case 0: /* scalar */ break;
239 case 1: assert(0); break;
240 case 2:
241#if MX_HAS_INTERLEAVED_COMPLEX
242 assert(0); // incomplete
243#else
244 for(i=0; i<(*pDims)[0]; i++)
245 for(j=0; j<(*pDims)[1]; j++)
246 (*out)[i*(*pDims)[1]+j] = cmplxf((float)inMatrix_r[j*(*pDims)[0]+i], (float)inMatrix_i[j*(*pDims)[0]+i]);
247#endif
248 break;
249 case 3:
250#if MX_HAS_INTERLEAVED_COMPLEX
251 assert(0); // incomplete
252#else
253 for(i=0; i<(*pDims)[0]; i++)
254 for(j=0; j<(*pDims)[1]; j++)
255 for(k=0; k<(*pDims)[2]; k++)
256 (*out)[i*(*pDims)[1]*(*pDims)[2]+j*(*pDims)[2]+k] = cmplxf((float)inMatrix_r[k*(*pDims)[1]*(*pDims)[0]+ j*(*pDims)[0]+i], (float)inMatrix_i[k*(*pDims)[1]*(*pDims)[0]+ j*(*pDims)[0]+i]);
257#endif
258 break;
259 default: assert(0); break;// incomplete
260 }
261}
262
264void MEXdouble2SAFsingle_int(const mxArray* in, int** out, int* nDims, int** pDims)
265{
266 int i, j, numElements;
267 double *inMatrix;
268 mwSize nDims_mx;
269 const mwSize *pDims_mx;
270
271 /* Find dimensionality of input */
272 nDims_mx = mxGetNumberOfDimensions(in);
273 pDims_mx = mxGetDimensions(in);
274
275 /* convert mwSize->int */
276 (*nDims) = (int)nDims_mx;
277 (*pDims) = malloc1d((*nDims)*sizeof(int));
278 for(i=0; i<(*nDims); i++)
279 (*pDims)[i] = (int)pDims_mx[i];
280
281 /* Find number of elements */
282 numElements = 1;
283 for(i=0; i<(*nDims); i++)
284 numElements *= (*pDims)[i];
285
286 /* Convert input mex array to saf array */
287 inMatrix = mxGetData(in);
288 if((*out)==NULL)
289 (*out) = malloc1d(numElements*sizeof(int));
290
291 /* column-major -> row-major */
292 switch(*nDims){
293 case 0: /* scalar */ break;
294 case 1:
295 for(i=0; i<(*pDims)[0]; i++)
296 (*out)[i] = (int)inMatrix[i];
297 break;
298 case 2:
299 for(i=0; i<(*pDims)[0]; i++)
300 for(j=0; j<(*pDims)[1]; j++)
301 (*out)[i*(*pDims)[1]+j] = (int)inMatrix[j*(*pDims)[0]+i];
302 break;
303
304 default: assert(0); break;// incomplete
305 }
306}
307
309void SAFsingle2MEXdouble(float* in, int nDims, int* dims, mxArray** out)
310{
311 int i,j;
312 double* pData;
313 mwSize nDims_mx;
314 mwSize* pDims_mx;
315 nDims_mx = (mwSize)nDims;
316
317 /* Define dimensionality of output and convert to mwSize */
318 pDims_mx = malloc1d(nDims*sizeof(mwSize));
319 for(i=0; i<nDims; i++)
320 pDims_mx[i] = (mwSize)dims[i];
321
322 /* create and copy data to output */
323 *out = mxCreateNumericArray(nDims_mx, pDims_mx, mxDOUBLE_CLASS, mxREAL);
324 pData = mxGetData(*out);
325
326 /* row-major -> column-major */
327 switch(nDims){
328 case 0: /* scalar */ break;
329 case 1: assert(0); break;
330 case 2:
331 for(i=0; i<dims[0]; i++)
332 for(j=0; j<dims[1]; j++)
333 pData[j*dims[0]+i] = (double)in[i*dims[1]+j];
334 break;
335 default: assert(0); break;// incomplete
336 }
337
338 /* clean-up */
339 free(pDims_mx);
340}
341
343void SAFsingle2MEXdouble_complex(float_complex* in, int nDims, int* dims, mxArray** out)
344{
345 int i,j,k;
346#if MX_HAS_INTERLEAVED_COMPLEX
347 mxComplexDouble* pData;
348#else
349 double *pData_r, *pData_i;
350#endif
351 mwSize nDims_mx;
352 mwSize* pDims_mx;
353 nDims_mx = (mwSize)nDims;
354
355 /* Define dimensionality of output and convert to mwSize */
356 pDims_mx = malloc1d(nDims*sizeof(mwSize));
357 for(i=0; i<nDims; i++)
358 pDims_mx[i] = (mwSize)dims[i];
359
360 /* create and copy data to output */
361 *out = mxCreateNumericArray(nDims_mx, pDims_mx, mxDOUBLE_CLASS, mxCOMPLEX);
362#if MX_HAS_INTERLEAVED_COMPLEX
363 pData = mxGetData(*out);
364#else
365 pData_r = mxGetPr(*out);
366 pData_i = mxGetPi(*out);
367#endif
368
369 /* row-major -> column-major */
370 switch(nDims){
371 case 0: /* scalar */ break;
372 case 1: assert(0); break;
373 case 2:
374 for(i=0; i<dims[0]; i++){
375 for(j=0; j<dims[1]; j++){
376#if MX_HAS_INTERLEAVED_COMPLEX
377 pData[j*dims[0]+i].real = (double)crealf(in[i*dims[1]+j]);
378 pData[j*dims[0]+i].imag = (double)cimagf(in[i*dims[1]+j]);
379#else
380 pData_r[j*dims[0]+i] = (double)crealf(in[i*dims[1]+j]);
381 pData_i[j*dims[0]+i] = (double)cimagf(in[i*dims[1]+j]);
382#endif
383 }
384 }
385 break;
386 case 3:
387 for(i=0; i<dims[0]; i++){
388 for(j=0; j<dims[1]; j++){
389 for(k=0; k<dims[2]; k++){
390#if MX_HAS_INTERLEAVED_COMPLEX
391 assert(0);
392 pData[k*dims[1]*dims[0]+j*dims[0]+i].real = (double)crealf(in[i*dims[1]*dims[2]+j*dims[2]+k]);
393 pData[k*dims[1]*dims[0]+j*dims[0]+i].imag = (double)cimagf(in[i*dims[1]*dims[2]+j*dims[2]+k]);
394#else
395 pData_r[k*dims[1]*dims[0]+j*dims[0]+i] = (double)crealf(in[i*dims[1]*dims[2]+j*dims[2]+k]);
396 pData_i[k*dims[1]*dims[0]+j*dims[0]+i] = (double)cimagf(in[i*dims[1]*dims[2]+j*dims[2]+k]);
397#endif
398 }
399 }
400 }
401 break;
402 default: assert(0); break;// incomplete
403 }
404
405 /* clean-up */
406 free(pDims_mx);
407}
408
410void SAFsingle2MEXdouble_int(int* in, int nDims, int* dims, mxArray** out)
411{
412 int i,j;
413 double* pData;
414 mwSize nDims_mx;
415 mwSize* pDims_mx;
416 nDims_mx = (mwSize)nDims;
417
418 /* Define dimensionality of output and convert to mwSize */
419 pDims_mx = malloc1d(nDims*sizeof(mwSize));
420 for(i=0; i<nDims; i++)
421 pDims_mx[i] = (mwSize)dims[i];
422
423 /* create and copy data to output */
424 *out = mxCreateNumericArray(nDims_mx, pDims_mx, mxDOUBLE_CLASS, mxREAL);
425 pData = mxGetData(*out);
426
427 /* row-major -> column-major */
428 switch(nDims){
429 case 0: /* scalar */ break;
430 case 1: assert(0); break;
431 case 2:
432 for(i=0; i<dims[0]; i++)
433 for(j=0; j<dims[1]; j++)
434 pData[j*dims[0]+i] = (double)in[i*dims[1]+j];
435 break;
436 default: assert(0); break;// incomplete
437 }
438
439 /* clean-up */
440 free(pDims_mx);
441}
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
Main include header for the Spatial_Audio_Framework (SAF)
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
void SAFsingle2MEXdouble_int(int *in, int nDims, int *dims, mxArray **out)
Convert a single precision array used by SAF to mex double-precision array (integers)
Definition safmex.h:410
MEX_DATA_TYPES
Supported SAF/MEX data conversions.
Definition safmex.h:33
@ SM_DOUBLE_COMPLEX_2D
Complex 2-D matrix; N x M.
Definition safmex.h:44
@ SM_DOUBLE_COMPLEX
Scalar, complex valued; 1 x 1.
Definition safmex.h:38
@ SM_DOUBLE_COMPLEX_1D
Complex 1-D vector; N x 1.
Definition safmex.h:40
@ SM_DOUBLE_REAL
Scalar, real valued; 1 x 1.
Definition safmex.h:37
@ SM_DOUBLE_REAL_3D
Real 3-D matrix; N x M x K.
Definition safmex.h:45
@ SM_INT32
Integer; 1 x 1.
Definition safmex.h:34
@ SM_DOUBLE_REAL_1D_OR_2D
Real 2-D matrix or 1-D vector; N x M | N x 1.
Definition safmex.h:41
@ SM_DOUBLE_REAL_2D
Real 2-D matrix; N x M.
Definition safmex.h:43
@ SM_DOUBLE_COMPLEX_3D
Complex 3-D matrix; N x M x K.
Definition safmex.h:46
@ SM_DOUBLE_COMPLEX_1D_OR_2D
Complex 2-D matrix or 1-D vector; N x M | N x 1.
Definition safmex.h:42
@ 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 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 checkNumInOutArgs(int nInputs, int nOutputs, int nInputs_expected, int nOutputs_expected)
Helper function to check number of inputs/outputs arguments are as expected.
Definition safmex.h:51
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