void mtxmul_eye_tests(float32_t eps) { float32_t errf; ambix_matrix_t *left, *result, *eye; STARTTEST(""); eye=ambix_matrix_init(4, 4, NULL); fail_if((eye!=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY)), __LINE__, "filling unity matrix %p did not return original matrix %p", eye); left=ambix_matrix_init(4, 2, NULL); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(left, resultdata_4_2), __LINE__, "filling left data failed"); result=ambix_matrix_init(4, 2, NULL); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(result, resultdata_4_2), __LINE__, "filling result data failed"); fail_if((result!=ambix_matrix_multiply(eye, left, result)), __LINE__, "multiplication into matrix did not return original matrix"); #if 0 matrix_print(eye); matrix_print(result); matrix_print(left); #endif errf=matrix_diff(__LINE__, left, result, eps); fail_if((errf>eps), __LINE__, "diffing matrix M with E*M returned %f (>%f)", errf, eps); ambix_matrix_destroy(left); ambix_matrix_destroy(result); ambix_matrix_destroy(eye); }
void create_tests(float32_t eps) { int rows=4; int cols=3; int cols2=2; ambix_matrix_t matrix, *left, *right; STARTTEST(""); memset(&matrix, 0, sizeof(matrix)); left=ambix_matrix_create(); fail_if((left==NULL), __LINE__, "failed to create left matrix"); fail_if((left->rows || left->cols), __LINE__, "created empty matrix has non-zero size"); fail_if((left!=ambix_matrix_init(rows, cols, left)), __LINE__, "initializing existing matrix* returned new matrix"); fail_if((left->rows!=rows || left->cols!=cols), __LINE__, "created matrix [%dx%d] does not match [%dx%d]", left->rows, left->cols, cols, cols2); right=ambix_matrix_init(cols, cols2, NULL); fail_if((right==NULL), __LINE__, "failed to create right matrix"); fail_if((right->rows!=cols || right->cols!=cols2), __LINE__, "created matrix [%dx%d] does not match [%dx%d]", right->rows, right->cols, cols, cols2); fail_if((&matrix!=ambix_matrix_init(rows, cols2, &matrix)), __LINE__, "initializing existing matrix returned new matrix"); fail_if((matrix.rows!=rows || matrix.cols!=cols2), __LINE__, "initialized matrix [%dx%d] does not match [%dx%d]", matrix.rows, matrix.cols, rows, cols2); ambix_matrix_deinit(&matrix); fail_if((matrix.rows || matrix.cols), __LINE__, "deinitialized matrix is non-zero"); ambix_matrix_deinit(left); fail_if((left->rows || left->cols), __LINE__, "deinitialized matrix is non-zero"); ambix_matrix_destroy(left); ambix_matrix_destroy(right); }
void check_matrix(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) { ambix_matrix_t*mtx=NULL; ambix_matrix_t*result=NULL; ambix_matrix_t*zeros=NULL; float32_t errf=0.f; float32_t eps=1e-20; STARTTEST(name); mtx=ambix_matrix_init(rows, cols, mtx); result=ambix_matrix_fill(mtx, typ); fail_if((result==NULL), __LINE__, "matrix_fill returned NULL"); fail_if((result!=mtx ), __LINE__, "matrix_fill did not return matrix %p (got %p)", mtx, result); zeros=ambix_matrix_init(result->rows, result->cols, zeros); zeros=ambix_matrix_fill(zeros, AMBIX_MATRIX_ZERO); errf=matrix_check_diff(name, result, zeros); if(AMBIX_MATRIX_ZERO==typ) { fail_if(!(errf<eps), __LINE__, "zero matrix non-zero (%f>%f)", errf, eps); } else { fail_if((errf<eps), __LINE__, "non-zero matrix zero (%f<%f)", errf, eps); } ambix_matrix_destroy(mtx); ambix_matrix_destroy(zeros); }
void mtx_copy(float32_t eps) { float32_t errf; ambix_matrix_t *left=NULL, *right=NULL; unsigned int i; float32_t maxeps=eps; STARTTEST("\n"); right=ambix_matrix_copy(left, NULL); fail_if((NULL!=right), __LINE__, "copying from NULL matrix erroneously succeeded"); left=ambix_matrix_create(); fail_if((left !=ambix_matrix_init(4, 3, left )), __LINE__, "initializing left matrix failed"); ambix_matrix_fill_data(left, leftdata_4_3); right=ambix_matrix_copy(left, NULL); fail_if((NULL==right), __LINE__, "copying to NULL matrix failed"); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf>0.f, __LINE__, "diffing mtx with copy0 returned %g (>%g)", errf, 0.f); right=ambix_matrix_copy(left, right); fail_if((NULL==right), __LINE__, "copying to right matrix failed"); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf>0.f, __LINE__, "diffing mtx with copy returned %g (>%g)", errf, 0.f); ambix_matrix_destroy(left); ambix_matrix_destroy(right); STOPTEST("\n"); }
void datamul_eye_tests(float32_t eps) { float32_t errf; uint64_t frames=4096; uint32_t channels=16; float32_t*inputdata; float32_t*outputdata; float32_t freq=500; ambix_matrix_t eye = {0, 0, NULL}; STARTTEST(""); inputdata =data_sine(frames, channels, freq); outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*channels); fail_if((NULL==outputdata), __LINE__, "couldn't mallocate outputdata"); ambix_matrix_init(channels, channels, &eye); ambix_matrix_fill(&eye, AMBIX_MATRIX_IDENTITY); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames), __LINE__, "data multilplication failed"); errf=data_diff(__LINE__, inputdata, outputdata, frames*channels, eps); fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps); #if 0 printf("matrix:\n"); matrix_print(&eye); printf("input :\n"); data_print(inputdata, frames*channels); printf("output:\n"); data_print(outputdata,frames*channels); #endif free(inputdata); free(outputdata); ambix_matrix_deinit(&eye); }
ambix_matrix_t*_matrix_diag(ambix_matrix_t*orgmatrix, const float32_t*diag, uint32_t count) { uint32_t i; ambix_matrix_t*matrix=ambix_matrix_init(count, count, orgmatrix); for(i=0; i<count; i++) matrix->data[i][i]=diag[i]; return matrix; }
static ambix_matrix_t*matrix_read(const char*path, ambix_matrix_t*matrix) { SF_INFO info; uint32_t rows, cols; float*data=NULL; ambix_matrix_t*mtx=NULL, *result=NULL; uint32_t frames; memset(&info, 0, sizeof(info)); SNDFILE*file=sf_open(path, SFM_READ, &info); if(!file) { fprintf(stderr, "ambix_interleave: matrix open failed '%s'\n", path); return NULL; } rows=info.channels; cols=info.frames; data=(float*)malloc(rows*cols*sizeof(float)); frames=sf_readf_float(file, data, cols); if(cols!=frames) { fprintf(stderr, "ambix_interleave: matrix reading %d frames returned %d\n", frames, cols); goto cleanup; } mtx=ambix_matrix_init(cols, rows, NULL); if(mtx && (AMBIX_ERR_SUCCESS==ambix_matrix_fill_data(mtx, data))) { uint32_t r, c; matrix=ambix_matrix_init(rows, cols, matrix); for(r=0; r<rows; r++) for(c=0; c<cols; c++) matrix->data[r][c]=mtx->data[c][r]; } result=matrix; // fprintf(stderr, "ambix_interleave: matrices not yet supported\n"); cleanup: if(mtx) ambix_matrix_destroy(mtx); sf_close(file); free(data); return result; }
void mtxmul_tests(float32_t eps) { float32_t errf; ambix_matrix_t *left=NULL, *right=NULL, *result, *testresult; STARTTEST("\n"); /* fill in some test data */ left=ambix_matrix_init(4, 3, NULL); ambix_matrix_fill_data(left, leftdata_4_3); right=ambix_matrix_init(3, 2, NULL); ambix_matrix_fill_data(right, rightdata_3_2); testresult=ambix_matrix_init(4, 2, NULL); ambix_matrix_fill_data(testresult, resultdata_4_2); errf=matrix_diff(__LINE__, left, left, eps); fail_if(!(errf<eps), __LINE__, "diffing matrix with itself returned %f (>%f)", errf, eps); /* NULL multiplications */ result=ambix_matrix_multiply(NULL, NULL, NULL); fail_if(NULL!=result, __LINE__, "multiplying NULL*NULL returned success"); result=ambix_matrix_multiply(left, NULL, result); fail_if(NULL!=result, __LINE__, "multiplying left*NULL returned success"); result=ambix_matrix_multiply(NULL, left, result); fail_if(NULL!=result, __LINE__, "multiplying NULL*left returned success"); /* do some matrix multiplication */ result=ambix_matrix_multiply(left, right, NULL); fail_if((NULL==result), __LINE__, "multiply into NULL did not create matrix"); fail_if((result!=ambix_matrix_multiply(left, right, result)), __LINE__, "multiply into existing matrix returned new matrix"); #if 0 matrix_print(left); matrix_print(right); matrix_print(result); printf("------------\n"); #endif errf=matrix_diff(__LINE__, testresult, result, eps); fail_if((errf>eps), __LINE__, "diffing two results of same multiplication returned %f (>%f)", errf, eps); ambix_matrix_destroy(left); ambix_matrix_destroy(right); ambix_matrix_destroy(result); ambix_matrix_destroy(testresult); STOPTEST("\n"); }
ambix_matrix_t*inverse_matrices(ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) { ambix_matrixtype_t pyt = (ambix_matrixtype_t)(AMBIX_MATRIX_TO_AMBIX | typ); ambix_matrix_t*mtx=ambix_matrix_init(rows, cols, NULL); ambix_matrix_t*xtm=ambix_matrix_init(cols, rows, NULL); ambix_matrix_t*a2f=ambix_matrix_fill(mtx, typ); ambix_matrix_t*f2a=ambix_matrix_fill(xtm, pyt); // ambix_matrix_t*result=ambix_matrix_multiply(a2f, f2a, NULL); ambix_matrix_t*result=ambix_matrix_multiply(f2a, a2f, NULL); if(a2f!=mtx) ambix_matrix_destroy(a2f); ambix_matrix_destroy(mtx); if(f2a!=xtm) ambix_matrix_destroy(f2a); ambix_matrix_destroy(xtm); return result; }
void datamul_tests(float32_t eps) { float32_t errf; float32_t*resultdata = (float32_t*)calloc(2*4, sizeof(float32_t)); float32_t*resultdataT = (float32_t*)calloc(4*2, sizeof(float32_t)); float32_t*inputdata = (float32_t*)calloc(2*3, sizeof(float32_t)); fail_if((NULL==resultdata), __LINE__, "couldn't callocate resultdata"); fail_if((NULL==resultdataT), __LINE__, "couldn't callocate resultdataT"); fail_if((NULL==inputdata), __LINE__, "couldn't callocate inputdata"); ambix_matrix_t*mtx=NULL; STARTTEST("\n"); mtx=ambix_matrix_init(4, 3, NULL); ambix_matrix_fill_data(mtx, leftdata_4_3); data_transpose(inputdata, rightdata_3_2, 3, 2); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(resultdata, mtx, inputdata, 2), __LINE__, "data multiplication failed"); data_transpose(resultdataT, resultdata, 2, 4); errf=data_diff(__LINE__, FLOAT32, resultdataT, resultdata_4_2, 4*2, eps); if(errf>eps) { printf("matrix:\n"); matrix_print(mtx); printf("input:\n"); data_print(FLOAT32, inputdata, 3*2); printf("expected:\n"); data_print(FLOAT32, resultdata_4_2, 4*2); printf("calculated:\n"); data_print(FLOAT32, resultdataT , 4*2); } fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps); #if 0 printf("matrix:\n");matrix_print(mtx); printf("input :\n"); data_print(FLOAT32, rightdata_3_2, 3*2); printf("output:\n"); data_print(FLOAT32, resultdata, 4*2); printf("target:\n"); data_print(FLOAT32, resultdata_4_2, 4*2); #endif if(mtx)ambix_matrix_destroy(mtx); free(resultdata); free(resultdataT); free(inputdata); STOPTEST("\n"); }
int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp, uint32_t xtrachannels, uint32_t chunksize, float32_t eps) { int result=0; ambix_matrix_t*mtx=0; STARTTEST("%s\n", name); mtx=ambix_matrix_init(rows,cols,mtx); if(!mtx)return 1; ambix_matrix_fill(mtx, mtyp); result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16, mtx,xtrachannels, chunksize, FLOAT32, eps); ambix_matrix_destroy(mtx); return result; }
ambix_matrix_t*_matrix_router(ambix_matrix_t*orgmatrix, const float32_t*route, uint32_t count, int swap) { uint32_t i; ambix_matrix_t*matrix=NULL; for(i=0; i<count; i++) { uint32_t o=(uint32_t)route[i]; if(route[i]<0. || o>count) return NULL; } matrix=ambix_matrix_init(count, count, orgmatrix); for(i=0; i<count; i++) { uint32_t o=(uint32_t)route[i]; if(swap) matrix->data[o][i]=1.; else matrix->data[i][o]=1.; } return matrix; }
static void mtxinverse_test(const ambix_matrix_t *mtx, const ambix_matrix_t *result, float32_t eps) { ambix_matrix_t *pinv = 0; ambix_matrix_t *mul=0; ambix_matrix_t *eye=0; float32_t errf; int min_rowcol=(mtx->cols<mtx->rows)?mtx->cols:mtx->rows; fail_if((NULL==mtx), __LINE__, "cannot invert NULL-matrix"); eye=ambix_matrix_init(min_rowcol, min_rowcol, eye); eye=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY); fail_if((NULL==eye), __LINE__, "cannot create eye-matrix for pinv-verification"); pinv=ambix_matrix_pinv(mtx, pinv); if(NULL==pinv)matrix_print(mtx); fail_if((NULL==pinv), __LINE__, "could not invert matrix"); if(mtx->cols < mtx->rows) mul=ambix_matrix_multiply(pinv, mtx, 0); else mul=ambix_matrix_multiply(mtx, pinv, 0); #if 0 matrix_print(mtx); matrix_print(pinv); matrix_print(mul); if(result)matrix_print(result); printf("------------\n"); #endif if(result) { errf=matrix_diff(__LINE__, pinv, result, eps); fail_if((errf>eps), __LINE__, "diffing (pseudo)inverse returned %g (>%g)", errf, eps); errf=matrix_diff(__LINE__, mul, eye, eps); fail_if((errf>eps), __LINE__, "diffing mtx*pinv(mtx) returned %g (>%g)", errf, eps); } else { errf=matrix_diff(__LINE__, mul, eye, eps); fail_if((!(isnan(errf) || isinf(errf) || (errf>eps))), __LINE__, "diffing invalid mtx*pinv(mtx) returned %g (!>%g)", errf, eps); } ambix_matrix_destroy(pinv); ambix_matrix_destroy(mul); ambix_matrix_destroy(eye); }
ambix_matrix_t* ambix_matrix_transpose(const ambix_matrix_t*matrix, ambix_matrix_t*xirtam) { uint32_t rows, cols, r, c; float32_t**mtx, **xtm; if(!xirtam) xirtam=ambix_matrix_init(matrix->cols, matrix->rows, NULL); rows=matrix->rows; cols=matrix->cols; mtx=matrix->data; xtm=xirtam->data; for(r=0; r<rows; r++) for(c=0; c<cols; c++) xtm[c][r]=mtx[r][c]; return xirtam; }
ambix_matrix_t* ambix_matrix_multiply(const ambix_matrix_t*left, const ambix_matrix_t*right, ambix_matrix_t*dest) { uint32_t r, c, rows, cols, common; float32_t**ldat,**rdat,**ddat; float32_t lv, rv; if(!left || !right) return NULL; if(left->cols != right->rows) return NULL; if(!dest) dest=(ambix_matrix_t*)calloc(1, sizeof(ambix_matrix_t)); if((dest->rows != left->rows) || (dest->cols != right->cols)) ambix_matrix_init(left->rows, right->cols, dest); rows=dest->rows; cols=dest->cols; common=left->cols; ldat=left->data; rdat=right->data; ddat=dest->data; for(r=0; r<rows; r++) for(c=0; c<cols; c++) { double sum=0.; uint32_t i; for(i=0; i<common; i++) { lv=ldat[r][i]; rv=rdat[i][c]; sum+=lv*rv; } ddat[r][c]=(float32_t)sum; } return dest; }
ambix_err_t ambix_matrix_fill_data_transposed(ambix_matrix_t*mtx, const float32_t*data, int byteswap) { ambix_err_t err=AMBIX_ERR_SUCCESS; ambix_matrix_t*xtm=ambix_matrix_init(mtx->cols, mtx->rows, NULL); if(!xtm) return AMBIX_ERR_UNKNOWN; if(byteswap) err=_ambix_matrix_fill_data_byteswapped(xtm, (const number32_t*)data); else err=ambix_matrix_fill_data(xtm, data); if(AMBIX_ERR_SUCCESS==err) { ambix_matrix_t*resu=ambix_matrix_transpose(mtx, xtm); if(!resu) err=AMBIX_ERR_UNKNOWN; } ambix_matrix_destroy(xtm); return err; }
ambix_matrix_t* ambix_matrix_copy(const ambix_matrix_t*src, ambix_matrix_t*dest) { if(!src) return NULL; if(!dest) dest=(ambix_matrix_t*)calloc(1, sizeof(ambix_matrix_t)); if((dest->rows != src->rows) || (dest->cols != src->cols)) ambix_matrix_init(src->rows, src->cols, dest); do { uint32_t r, c; float32_t**s=src->data; float32_t**d=dest->data; for(r=0; r<src->rows; r++) { for(c=0; c<src->cols; c++) { d[r][c]=s[r][c]; } } } while(0); return dest; }
void check_inversion(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) { ambix_matrix_t*eye=NULL; ambix_matrix_t*result=NULL; float32_t errf; float32_t eps=1e-6; STARTTEST(name); result=inverse_matrices(typ, rows, cols); eye=ambix_matrix_init(result->rows, result->cols, eye); eye=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY); errf=matrix_check_diff(name, result, eye); if(!(errf<eps)){ matrix_print(result); } fail_if(!(errf<eps), __LINE__, "diffing matrices (%s) returned %g-%g=%g", name, errf, eps, errf-eps); ambix_matrix_destroy(result); ambix_matrix_destroy(eye); }
static void ambix_write_matrix(t_ambix_write *x, t_symbol*s, int argc, t_atom*argv) { int rows, cols; float32_t*data=NULL; int count; if(x->x_matrix) ambix_matrix_destroy(x->x_matrix); x->x_matrix=NULL; if(argc>=2) { rows=atom_getint(argv+0); cols=atom_getint(argv+1); argc-=2; argv+=2; } else { pd_error(x, "invalid matrix message"); return; } if(argc!=rows*cols) { pd_error(x, "invalid matrix"); return; } data=(float32_t*)malloc(rows*cols*sizeof(float32_t)); for(count=0; count<argc; count++) { data[count]=atom_getfloat(argv+count); } x->x_matrix=ambix_matrix_init(rows, cols, x->x_matrix); if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(x->x_matrix, data)) { pd_error(x, "invalid matrix data [%dx%d]=%p", rows, cols, data); if(x->x_matrix) ambix_matrix_destroy(x->x_matrix); x->x_matrix=NULL; } free(data); if(x->x_matrix) printmatrix(x->x_matrix); }
/* this modifies the input matrix! */ ambix_matrix_t* _ambix_matrix_invert_gaussjordan(ambix_matrix_t*input, ambix_matrix_t*inverse, float32_t eps) { ambix_matrix_t*inverse_org = inverse; int i, k; float32_t *a1, *b1, *a2, *b2; int errors=0; /* error counter */ if(input==0) { // no input matrix return NULL; } if (input->cols != input->rows) {// matrix is not squared return NULL; } int col=input->cols, row=input->rows; /* 1a reserve space for the inverted matrix */ if(!inverse) { inverse=ambix_matrix_init(row, col, NULL); } float32_t **original=input->data; float32_t **inverted=inverse->data; /* 1b make an eye-shaped float-buf for B */ ambix_matrix_fill(inverse, AMBIX_MATRIX_IDENTITY); /* 2. do the Gauss-Jordan */ //printf("GaussJordan\n"); for (k=0; k<row; k++) { /* adjust current row */ float32_t diagel = original[k][k]; float32_t i_diagel = 0; if(diagel>-eps && diagel<eps) errors++; else i_diagel = 1./diagel; /* normalize current row (set the diagonal-element to 1 */ for (i=0; i < row; i++) { original[k][i] *= i_diagel; inverted[k][i] *= i_diagel; } /* eliminate the k-th element in each row by adding the weighted normalized row */ for (i=0; i < row; i++) { if (i-k) { float32_t f =-original[i][k]; int j; for (j=row-1; j >= 0; j--) { original[i][j] += f * original[k][j]; inverted[i][j] += f * inverted[k][j]; } } } } if (errors > 0) { if(inverse != inverse_org) /* if the 'inverse' was locally allocated, free it */ ambix_matrix_destroy(inverse); inverse=NULL; } return inverse; }
void mtx_diff(float32_t eps) { float32_t errf; ambix_matrix_t *left=NULL, *right=NULL; unsigned int i; const unsigned int rows=4; const unsigned int cols=3; float32_t*leftdata=leftdata_4_3; float32_t*rightdata=malloc(sizeof(leftdata_4_3)); float32_t maxeps=eps; STARTTEST("\n"); left=ambix_matrix_create(); right=ambix_matrix_create(); /* comparisons: - failing tests: - different dimensions - left/right matrix is NULL - non-failing tests: - all values diff==0 - all values diff<eps - few values diff<eps - many values diff<eps */ fail_if((left !=ambix_matrix_init(3, 4, left )), __LINE__, "initializing left matrix failed"); fail_if((right!=ambix_matrix_init(3, 4, right)), __LINE__, "initializing right matrix failed"); /* compare equal matrices */ STARTTEST("ident\n"); ambix_matrix_fill_data(left, leftdata); errf=matrix_diff(__LINE__, left, left, eps); fail_if(errf>0.f, __LINE__, "diffing mtx with itself returned %g (>%g)", errf, 0.f); /* compare equal matrices */ STARTTEST("equal\n"); for(i=0; i<rows*cols; i++) { rightdata[i]=leftdata[i]; } ambix_matrix_fill_data(left , leftdata); ambix_matrix_fill_data(right, rightdata); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf>0.f, __LINE__, "diffing mtx with copy returned %g (>%g)", errf, 0.f); /* compare matrices where all values differ, but <eps */ STARTTEST("all<eps\n"); for(i=0; i<rows*cols; i++) { rightdata[i]=leftdata[i]+eps*0.5; } ambix_matrix_fill_data(left , leftdata); ambix_matrix_fill_data(right, rightdata); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf>eps, __LINE__, "diffing mtx with mtx+eps/2 returned %g (>%g)", errf, eps); for(i=0; i<rows*cols; i++) { rightdata[i]=leftdata[i]-eps*0.5; } ambix_matrix_fill_data(left , leftdata); ambix_matrix_fill_data(right, rightdata); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf>eps, __LINE__, "diffing mtx with mtx-eps/2 returned %g (>%g)", errf, eps); /* compare matrices where many values differ with <eps; but one with >eps */ STARTTEST("most<eps;one>eps\n"); for(i=0; i<rows*cols; i++) { rightdata[i]=leftdata[i]; } for(i=0; i<rows; i++) { rightdata[i]=leftdata[i]+eps*0.5; } rightdata[0]=leftdata[0]+eps*1.5; ambix_matrix_fill_data(left , leftdata); ambix_matrix_fill_data(right, rightdata); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf>(eps*2.0), __LINE__, "diffing mtx with one value>eps returned %g (>%g)", errf, eps); fail_if(errf<(eps*1.0), __LINE__, "diffing mtx with one value>eps returned %g (>%g)", errf, eps); /* compare matrices where most values differ with >eps */ STARTTEST("most>eps\n"); for(i=0; i<rows*cols; i++) { rightdata[i]=leftdata[i]; } maxeps=eps*1.5; for(i=0; i<(rows*cols)-1; i++) { rightdata[i]=leftdata[i]-maxeps; } ambix_matrix_fill_data(left , leftdata); ambix_matrix_fill_data(right, rightdata); errf=matrix_diff(__LINE__, left, right, eps); fail_if(errf<eps*1.0, __LINE__, "diffing mtx with one value>eps returned %g (<%g)", errf, eps*1.0); fail_if(errf>eps*2.0, __LINE__, "diffing mtx with one value>eps returned %g (<%g)", errf, eps*2.0); ambix_matrix_destroy(left); ambix_matrix_destroy(right); free(rightdata); STOPTEST("\n"); }
ambix_matrix_t* ambix_matrix_create(void) { return ambix_matrix_init(0, 0, NULL); }
ambix_matrix_t* _ambix_uuid1_to_matrix(const void*vdata, uint64_t datasize, ambix_matrix_t*orgmtx, int swap) { const char*cdata=(const char*)vdata; ambix_matrix_t*mtx=orgmtx; uint32_t rows; uint32_t cols; uint64_t size; uint32_t index; if(datasize<(sizeof(rows)+sizeof(cols))) return NULL; index = 0; memcpy(&rows, cdata+index, sizeof(uint32_t)); index += sizeof(uint32_t); memcpy(&cols, cdata+index, sizeof(uint32_t)); index += sizeof(uint32_t); if(swap) { rows=swap4(rows); cols=swap4(cols); } size=rows*cols; if(rows<1 || cols<1 || size < 1) goto cleanup; if(size*sizeof(float32_t) > datasize) { goto cleanup; } if(!mtx) { mtx=(ambix_matrix_t*)calloc(1, sizeof(ambix_matrix_t)); if(!mtx) goto cleanup; } if(!ambix_matrix_init(rows, cols, mtx)) goto cleanup; if(swap) { if(_ambix_matrix_fill_data_byteswapped(mtx, (number32_t*)(cdata+index)) != AMBIX_ERR_SUCCESS) goto cleanup; } else { if(ambix_matrix_fill_data(mtx, (float32_t*)(cdata+index)) != AMBIX_ERR_SUCCESS) goto cleanup; } return mtx; cleanup: if(mtx && mtx!=orgmtx) { ambix_matrix_deinit(mtx); free(mtx); mtx=NULL; } return NULL; }
ambix_t* ambix_open (const char *path, const ambix_filemode_t mode, ambix_info_t*ambixinfo) { ambix_t*ambix=NULL; ambix_err_t err = AMBIX_ERR_UNKNOWN; int32_t ambichannels=0, otherchannels=0; if((AMBIX_WRITE & mode) && (AMBIX_READ & mode)) { /* RDRW not yet implemented */ return NULL; } if(AMBIX_WRITE & mode) { err=_check_write_ambixinfo(ambixinfo); if(err!=AMBIX_ERR_SUCCESS) return NULL; ambichannels=ambixinfo->ambichannels; otherchannels=ambixinfo->extrachannels; } ambix=(ambix_t*)calloc(1, sizeof(ambix_t)); if(AMBIX_ERR_SUCCESS == _ambix_open(ambix, path, mode, ambixinfo)) { const ambix_fileformat_t wantformat=ambixinfo->fileformat; ambix_fileformat_t haveformat; uint32_t channels = ambix->channels; /* successfully opened, initialize common stuff... */ if(ambix->is_AMBIX) { if(AMBIX_WRITE & mode) { switch(wantformat) { case(AMBIX_NONE): _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); break; case(AMBIX_BASIC): _ambix_info_set(ambix, AMBIX_BASIC, 0, channels, channels); break; case(AMBIX_EXTENDED): /* the number of full channels is not clear yet! * the user has to call setAdaptorMatrix() first */ _ambix_info_set(ambix, AMBIX_EXTENDED, otherchannels, ambichannels, 0); break; } } else { if(ambix->format>AMBIX_BASIC) { /* check whether channels are (N+1)^2 * if so, we have a simple-ambix file, else it is just an ordinary caf */ if(ambix->matrix.cols <= channels && /* reduced set must be fully present */ ambix_is_fullset(ambix->matrix.rows)) { /* expanded set must be a full set */ /* it's a simple AMBIX! */ _ambix_info_set(ambix, AMBIX_EXTENDED, channels-ambix->matrix.cols, ambix->matrix.cols, ambix->matrix.rows); } else { /* ouch! matrix is not valid! */ _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); } } else { /* no uuid chunk found, it's probably a BASIC ambix file */ /* check whether channels are (N+1)^2 * if so, we have a simple-ambix file, else it is just an ordinary caf */ if(ambix_is_fullset(channels)) { /* expanded set must be a full set */ /* it's a simple AMBIX! */ _ambix_info_set(ambix, AMBIX_BASIC, 0, channels, channels); } else { /* it's an ordinary CAF file */ _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); } } } } else { /* it's not a CAF file.... */ _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); } haveformat=ambix->realinfo.fileformat; ambix->filemode=mode; memcpy(&ambix->info, &ambix->realinfo, sizeof(ambix->info)); if(0) { } else if(AMBIX_BASIC==wantformat && AMBIX_EXTENDED==haveformat) { ambix->info.fileformat=AMBIX_BASIC; ambix->use_matrix=1; ambix->info.ambichannels=ambix->matrix.rows; } else if(AMBIX_EXTENDED==wantformat && AMBIX_BASIC==haveformat) { ambix_matrix_init(ambix->realinfo.ambichannels, ambix->realinfo.ambichannels, &ambix->matrix); ambix_matrix_fill(&ambix->matrix, AMBIX_MATRIX_IDENTITY); ambix->info.fileformat=AMBIX_EXTENDED; ambix->use_matrix=0; } memcpy(ambixinfo, &ambix->info, sizeof(ambix->info)); if(_ambix_adaptorbuffer_resize(ambix, DEFAULT_ADAPTORBUFFER_SIZE, sizeof(float32_t)) == AMBIX_ERR_SUCCESS) return ambix; } ambix_close(ambix); return NULL; }
void datamul_4_2_tests(uint32_t chunksize, float32_t eps) { uint32_t r, c, rows, cols; float32_t errf; uint64_t frames=8; uint32_t rawchannels=2; uint32_t cokchannels=4; float32_t*inputdata; float32_t*outputdata; float32_t*targetdata; float32_t freq=500; ambix_matrix_t eye = {0, 0, NULL}; STARTTEST(""); inputdata =data_sine(frames, rawchannels, freq); targetdata=data_sine(frames, cokchannels, freq); outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*cokchannels); fail_if((NULL==outputdata), __LINE__, "couldn't allocate outputdata"); ambix_matrix_init(cokchannels, rawchannels, &eye); rows=eye.rows; cols=eye.cols; for(r=0; r<rows; r++) { for(c=0; c<cols; c++) { eye.data[r][c]=(1+r+c)%2; } } #if 0 matrix_print(&eye); printf("input\n"); data_print(inputdata, rawchannels*frames); #endif fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames), __LINE__, "data multilplication failed"); #if 0 printf("output\n"); data_print(outputdata, cokchannels*frames); printf("target\n"); data_print(targetdata, cokchannels*frames); #endif errf=data_diff(__LINE__, targetdata, outputdata, frames*cokchannels, eps); fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps); #if 0 printf("matrix:\n"); matrix_print(&eye); printf("input :\n"); data_print(inputdata, frames*channels); printf("output:\n"); data_print(outputdata,frames*channels); #endif ambix_matrix_deinit(&eye); free(inputdata); free(outputdata); free(targetdata); }
ambix_err_t _ambix_open (ambix_t*ambix, const char *path, const ambix_filemode_t mode, const ambix_info_t*ambixinfo) { int sfmode=0; int caf=0; ambix->private_data=calloc(1, sizeof(ambixsndfile_private_t)); ambix2sndfile_info(ambixinfo, &PRIVATE(ambix)->sf_info); if((mode & AMBIX_READ) & (mode & AMBIX_WRITE)) sfmode= SFM_RDWR; else if (mode & AMBIX_WRITE) sfmode= SFM_WRITE; else if (mode & AMBIX_READ) sfmode= SFM_READ; PRIVATE(ambix)->sf_file=sf_open(path, sfmode, &PRIVATE(ambix)->sf_info) ; if(!PRIVATE(ambix)->sf_file) return AMBIX_ERR_INVALID_FILE; memset(&ambix->realinfo, 0, sizeof(*ambixinfo)); sndfile2ambix_info(&PRIVATE(ambix)->sf_info, &ambix->realinfo); ambix->byteswap=(sf_command(PRIVATE(ambix)->sf_file, SFC_RAW_DATA_NEEDS_ENDSWAP, NULL, 0) == SF_TRUE); ambix->channels = PRIVATE(ambix)->sf_info.channels; caf=((SF_FORMAT_CAF == (SF_FORMAT_TYPEMASK & PRIVATE(ambix)->sf_info.format)) != 0); if(caf) { ambix->is_AMBIX=1; if(read_uuidchunk(ambix) == AMBIX_ERR_SUCCESS) { ambix->format=AMBIX_EXTENDED; } else { ambix->format=AMBIX_BASIC; } } else { // check whether this is an .amb file or the like... if(0) { } else if(sf_command(PRIVATE(ambix)->sf_file, SFC_WAVEX_GET_AMBISONIC, NULL, 0) == SF_AMBISONIC_B_FORMAT) { /* The four B-format signals are interleaved for each sample frame in the order W,X,Y,Z. If the extended six-channel B-Format is used, the U and V signals will occupy the fifth and sixth slots: W,X,Y,Z,U,V. If horizontal-only B-format is to be represented, a three or five-channel file will suffice, with signals interleaved as W,X,Y (First Order), or W,X,Y,U,V (Second-order). However, four and -six-channel files are also acceptable, with the Z channel empty. Higher-order configurations are possible in theory, but are not addressed here. A decoder program should either 'degrade gracefully', or reject formats it cannot handle. For all B-format configurations, the dwChannelMask field should be set to zero. Though strictly speaking an optional chunk, it is recommended that the PEAK chunk be used for all B-Format files. Apart from its general utility, it has the special virtue for B-format in that applications can determine from the peak value for the Z channel whether the file is indeed full periphonic B-format (with height information), or 'Horizontal-only' (Z channel present but empty). */ switch(ambix->channels) { case 3: /* h = 1st order 2-D */ ambix_matrix_init(ambix_order2channels(1), ambix->channels, &ambix->matrix); break; case 4: /* f = 1st order 3-D */ ambix_matrix_init(ambix_order2channels(1), ambix->channels, &ambix->matrix); break; case 5: /* hh = 2nd order 2-D */ ambix_matrix_init(ambix_order2channels(2), ambix->channels, &ambix->matrix); break; case 6: /* fh = 2nd order 2-D + 1st order 3-D (formerly called 2.5 order) */ ambix_matrix_init(ambix_order2channels(2), ambix->channels, &ambix->matrix); break; case 7: /* hhh = 3rd order 2-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; case 8: /* fhh = 3rd order 2-D + 1st order 3-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; case 9: /* ff = 2nd order 3-D */ ambix_matrix_init(ambix_order2channels(2), ambix->channels, &ambix->matrix); break; case 11: /* ffh = 3rd order 2-D + 2nd order 3-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; case 16: /* fff = 3rd order 3-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; } if(NULL != ambix_matrix_fill(&ambix->matrix, AMBIX_MATRIX_FUMA)) { ambix->is_AMBIX=1; ambix->format=AMBIX_EXTENDED; } else { ambix->is_AMBIX=0; ambix->format=AMBIX_NONE; } } else { ambix->is_AMBIX=0; ambix->format=AMBIX_NONE; } } if(0) { print_sfinfo( &PRIVATE(ambix)->sf_info); } return AMBIX_ERR_SUCCESS; }
void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps) { ambix_info_t info, rinfo, winfo; ambix_t*ambix=NULL; float32_t*orgambidata,*ambidata,*resultambidata; float32_t*orgotherdata,*otherdata,*resultotherdata; uint32_t framesize=441000; uint32_t ambichannels=4; uint32_t extrachannels=2; float32_t periods=20000; ambix_matrix_t eye={0,0,NULL}; const ambix_matrix_t*eye2=NULL; int64_t err64, gotframes; float32_t diff=0.; STARTTEST("\n"); printf("test using '%s' [%d] with chunks of %d and eps=%f\n", path, (int)format, (int)chunksize, eps); resultambidata=(float32_t*)calloc(ambichannels*framesize, sizeof(float32_t)); ambidata=(float32_t*)calloc(ambichannels*framesize, sizeof(float32_t)); resultotherdata=(float32_t*)calloc(extrachannels*framesize, sizeof(float32_t)); otherdata=(float32_t*)calloc(extrachannels*framesize, sizeof(float32_t)); ambix_matrix_init(ambichannels, ambichannels, &eye); ambix_matrix_fill(&eye, AMBIX_MATRIX_IDENTITY); memset(&winfo, 0, sizeof(winfo)); memset(&info, 0, sizeof(info)); info.fileformat=AMBIX_EXTENDED; info.ambichannels=ambichannels; info.extrachannels=extrachannels; info.samplerate=44100; info.sampleformat=format; memcpy(&rinfo, &info, sizeof(info)); ambix=ambix_open(path, AMBIX_WRITE, &rinfo); fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for writing", path); orgambidata=data_sine (FLOAT32, framesize, ambichannels, periods); orgotherdata=data_ramp(FLOAT32, framesize, extrachannels); //data_print(FLOAT32, orgdata, 100); fail_if((NULL==orgambidata), __LINE__, "couldn't create ambidata %dx%d sine @ %f", (int)framesize, (int)ambichannels, (float)periods); fail_if((NULL==orgotherdata), __LINE__, "couldn't create otherdata %dx%d sine @ %f", (int)framesize, (int)extrachannels, (float)periods); memcpy(ambidata, orgambidata, framesize*ambichannels*sizeof(float32_t)); memcpy(otherdata, orgotherdata, framesize*extrachannels*sizeof(float32_t)); fail_if((AMBIX_ERR_SUCCESS!=ambix_set_adaptormatrix(ambix, &eye)), __LINE__, "failed setting adaptor matrix"); if(chunksize>0) { uint32_t subframe=chunksize; uint32_t chunks = framesize/chunksize; uint32_t framesleft=framesize; uint32_t frame; printf("writing %d chunks of %d frames\n", (int)chunks, (int)chunksize); for(frame=0; frame<chunks; frame++) { err64=ambix_writef_float32(ambix, ambidata+ambichannels*frame*chunksize, otherdata+extrachannels*frame*chunksize, chunksize); fail_if((err64!=chunksize), __LINE__, "wrote only %d chunksize of %d", (int)err64, (int)chunksize); framesleft-=chunksize; } subframe=framesleft; printf("writing rest of %d frames\n", (int)subframe); err64=ambix_writef_float32(ambix, ambidata+ambichannels*frame*chunksize, otherdata+extrachannels*frame*chunksize, subframe); fail_if((err64!=subframe), __LINE__, "wrote only %d subframe of %d", (int)err64, (int)subframe); } else { err64=ambix_writef_float32(ambix, ambidata, otherdata, framesize); fail_if((err64!=framesize), __LINE__, "wrote only %d frames of %d", (int)err64, (int)framesize); } diff=data_diff(__LINE__, FLOAT32, orgambidata, ambidata, framesize*ambichannels, eps); fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps); diff=data_diff(__LINE__, FLOAT32, orgotherdata, otherdata, framesize*extrachannels, eps); fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps); fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix); ambix=NULL; /* read data back */ ambix=ambix_open(path, AMBIX_READ, &rinfo); fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for reading", path); fail_if((info.fileformat!=rinfo.fileformat), __LINE__, "fileformat mismatch %d!=%d", (int)info.fileformat, (int)rinfo.fileformat); fail_if((info.samplerate!=rinfo.samplerate), __LINE__, "samplerate mismatch %g!=%g", (float)info.samplerate, (float)rinfo.samplerate); fail_if((info.sampleformat!=rinfo.sampleformat), __LINE__, "sampleformat mismatch %d!=%d", (int)info.sampleformat, (int)rinfo.sampleformat); fail_if((info.ambichannels!=rinfo.ambichannels), __LINE__, "ambichannels mismatch %d!=%d", (int)info.ambichannels, (int)rinfo.ambichannels); fail_if((info.extrachannels!=rinfo.extrachannels), __LINE__, "extrachannels mismatch %d!=%d", (int)info.extrachannels, (int)rinfo.extrachannels); eye2=ambix_get_adaptormatrix(ambix); fail_if((NULL==eye2), __LINE__, "failed reading adaptor matrix"); diff=matrix_diff(__LINE__, &eye, eye2, eps); fail_if((diff>eps), __LINE__, "adaptormatrix diff %f > %f", diff, eps); gotframes=0; do { //err64=ambix_readf_float32(ambix, resultambidata, resultotherdata, framesize); err64=ambix_readf_float32(ambix, resultambidata +(gotframes*ambichannels ), resultotherdata+(gotframes*extrachannels), (framesize-gotframes)); fail_if((err64<0), __LINE__, "reading frames failed after %d/%d frames", (int)gotframes, (int)framesize); gotframes+=err64; } while(err64>0 && gotframes<framesize); diff=data_diff(__LINE__, FLOAT32, orgambidata, resultambidata, framesize*ambichannels, eps); fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps); diff=data_diff(__LINE__, FLOAT32, orgotherdata, resultotherdata, framesize*extrachannels, eps); fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps); fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix); ambix=NULL; free(resultambidata); free(ambidata); free(resultotherdata); free(otherdata); free(orgambidata); free(orgotherdata); ambix_matrix_deinit(&eye); ambixtest_rmfile(path); }
void mtxinverse_tests(float32_t eps) { float32_t errf; ambix_matrix_t *mtx=0, *testresult=0; float32_t*transposedata = (float32_t*)calloc(3*4, sizeof(float32_t)); STARTTEST("\n"); /* fill in some test data 4x4 */ STARTTEST("[4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill_data(mtx, leftdata_4_4); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill_data(testresult, resultpinv_4_4); mtxinverse_test(mtx, testresult, eps); /* fill in some test data 4x3 */ STARTTEST("[4x3]\n"); mtx=ambix_matrix_init(4, 3, mtx); ambix_matrix_fill_data(mtx, leftdata_4_3); testresult=ambix_matrix_init(3, 4, testresult); ambix_matrix_fill_data(testresult, resultpinv_4_3); mtxinverse_test(mtx, testresult, eps); /* fill in some test data 3x4 */ STARTTEST("[3x4]\n"); data_transpose(transposedata, leftdata_4_3, 4, 3); mtx=ambix_matrix_init(3, 4, mtx); ambix_matrix_fill_data(mtx, transposedata); data_transpose(transposedata, resultpinv_4_3, 3, 4); testresult=ambix_matrix_init(4, 3, testresult); ambix_matrix_fill_data(testresult, transposedata); mtxinverse_test(mtx, testresult, eps); /* fill in some test data 4x4 */ STARTTEST("[identity:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_IDENTITY); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_IDENTITY); mtxinverse_test(mtx, testresult, eps); STARTTEST("[one:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_ONE); mtxinverse_test(mtx, NULL, eps); STARTTEST("[zero:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_ZERO); mtxinverse_test(mtx, NULL, eps); STARTTEST("[SID:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_SID); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_SID); mtxinverse_test(mtx, testresult, eps); STARTTEST("[N3D:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_N3D); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_N3D); mtxinverse_test(mtx, testresult, eps); STARTTEST("[FUMA:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_FUMA); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_FUMA); mtxinverse_test(mtx, testresult, eps); ambix_matrix_destroy(mtx); ambix_matrix_destroy(testresult); free(transposedata); STOPTEST("\n"); }