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 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 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"); }
/* * calculate the inverse of any (rectangular) real-valued matrix using cholesky decomposition */ ambix_matrix_t* _ambix_matrix_pinvert_cholesky(const ambix_matrix_t*input, ambix_matrix_t*inverse, float32_t tolerance) { /* (rows>cols)?(inv(x'*x)*x'):(x'*inv(x*x')) */ float32_t toler = tolerance; ambix_matrix_t*trans = _ambix_matrix_transpose(input, 0); ambix_matrix_t*chinv=0; ambix_matrix_t*result=0; do { if(!trans)break; if(input->rows > input->cols) { chinv=_ambix_matrix_multiply(trans, input, chinv); if(!chinv)break; _am_cholesky2_decomp(chinv, toler); _am_cholesky2_inverse(chinv); result=_ambix_matrix_multiply(chinv, trans, inverse); } else { chinv=_ambix_matrix_multiply(input, trans, chinv); if(!chinv)break; _am_cholesky2_decomp(chinv, toler); _am_cholesky2_inverse(chinv); result=_ambix_matrix_multiply(trans, chinv, inverse); } } while(0); if(trans)ambix_matrix_destroy(trans); if(chinv)ambix_matrix_destroy(chinv); return result; }
static void ambix_write_free(t_ambix_write *x) { /* request QUIT and wait for acknowledge */ void *threadrtn; pthread_mutex_lock(&x->x_mutex); x->x_requestcode = REQUEST_QUIT; /* post("stopping ambix_write thread..."); */ pthread_cond_signal(&x->x_requestcondition); while (x->x_requestcode != REQUEST_NOTHING) { /* post("signalling..."); */ pthread_cond_signal(&x->x_requestcondition); pthread_cond_wait(&x->x_answercondition, &x->x_mutex); } pthread_mutex_unlock(&x->x_mutex); if (pthread_join(x->x_childthread, &threadrtn)) error("ambix_write_free: join failed"); /* post("... done."); */ pthread_cond_destroy(&x->x_requestcondition); pthread_cond_destroy(&x->x_answercondition); pthread_mutex_destroy(&x->x_mutex); freebytes(x->x_buf, x->x_bufsize); if(x->x_matrix) ambix_matrix_destroy(x->x_matrix); x->x_matrix=NULL; }
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"); }
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*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"); }
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); }
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; }
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); }
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; }
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; }
static void *ambix_write_child_main(void *zz) { t_ambix_write *x = (t_ambix_write*)zz; ambix_t*ambix=NULL; pthread_mutex_lock(&x->x_mutex); while (1) { if (x->x_requestcode == REQUEST_NOTHING) { pthread_cond_signal(&x->x_answercondition); pthread_cond_wait(&x->x_requestcondition, &x->x_mutex); } else if (x->x_requestcode == REQUEST_OPEN) { int sysrtn, writeframes; ambix_info_t ainfo; /* copy file stuff out of the data structure so we can relinquish the mutex while we're in open_soundfile(). */ int64_t onsetframes = x->x_onsetframes; ambix_fileformat_t fileformat = x->x_fileformat; ambix_sampleformat_t sampleformat = x->x_sampleformat; uint32_t ambichannels = x->x_ambichannels; uint32_t xtrachannels = x->x_extrachannels; int localfifosize = x->x_fifosize; float32_t*ambibuf = NULL; float32_t*xtrabuf = NULL; double samplerate = x->x_samplerate; ambix_matrix_t*matrix=NULL; char *filename = strndup(x->x_filename, MAXPDSTRING); if(x->x_matrix) matrix=ambix_matrix_copy(x->x_matrix, matrix); /* alter the request code so that an ensuing "open" will get noticed. */ x->x_requestcode = REQUEST_BUSY; x->x_fileerror = 0; /* open the soundfile with the mutex unlocked */ pthread_mutex_unlock(&x->x_mutex); memset(&ainfo, 0, sizeof(ainfo)); ainfo.fileformat=fileformat; ainfo.ambichannels=ambichannels; ainfo.extrachannels=xtrachannels; ainfo.samplerate=samplerate; ainfo.sampleformat=sampleformat; /* if there's already a file open, close it. This should never happen since ambix_write_open() calls stop if needed and then waits until we're idle. */ if (ambix) ambix_close(ambix); ambix=ambix_open(filename, AMBIX_WRITE, &ainfo); free(filename); if(matrix) { if(ambix) ambix_set_adaptormatrix(ambix, matrix); ambix_matrix_destroy(matrix); matrix=NULL; } if(ambix && onsetframes) { ambix_seek(ambix, onsetframes, SEEK_SET); } if(ambix) { ambibuf = (float32_t*)calloc(localfifosize*ambichannels, sizeof(float32_t)); xtrabuf = (float32_t*)calloc(localfifosize*xtrachannels, sizeof(float32_t)); } pthread_mutex_lock(&x->x_mutex); if(NULL==ambix) { x->x_eof = 1; x->x_fileerror = errno; x->x_requestcode = REQUEST_NOTHING; continue; } /* check if another request has been made; if so, field it */ if (x->x_requestcode != REQUEST_BUSY) continue; x->x_fifotail = 0; /* in a loop, wait for the fifo to have data and write it to disk */ while (x->x_requestcode == REQUEST_BUSY || (x->x_requestcode == REQUEST_CLOSE && x->x_fifohead != x->x_fifotail)) { int fifosize = x->x_fifosize, fifotail; t_sample*buf = x->x_buf; /* if the head is < the tail, we can immediately write from tail to end of fifo to disk; otherwise we hold off writing until there are at least WRITESIZE bytes in the buffer */ if (x->x_fifohead < x->x_fifotail || x->x_fifohead >= x->x_fifotail + WRITFRAMES || (x->x_requestcode == REQUEST_CLOSE && x->x_fifohead != x->x_fifotail)) { writeframes = (x->x_fifohead < x->x_fifotail ? fifosize : x->x_fifohead) - x->x_fifotail; if (writeframes > READFRAMES) writeframes = READFRAMES; } else { pthread_cond_signal(&x->x_answercondition); pthread_cond_wait(&x->x_requestcondition, &x->x_mutex); continue; } fifotail = x->x_fifotail; pthread_mutex_unlock(&x->x_mutex); if(localfifosize<fifosize) { free(ambibuf); free(xtrabuf); localfifosize=fifosize; ambibuf = (float32_t*)calloc(localfifosize*ambichannels, sizeof(float32_t)); xtrabuf = (float32_t*)calloc(localfifosize*xtrachannels, sizeof(float32_t)); } split_samples(buf+fifotail*(ambichannels+xtrachannels), writeframes, ambibuf, ambichannels, xtrabuf, xtrachannels); sysrtn = ambix_writef_float32(ambix, ambibuf, xtrabuf, writeframes); pthread_mutex_lock(&x->x_mutex); if (x->x_requestcode != REQUEST_BUSY && x->x_requestcode != REQUEST_CLOSE) break; if (sysrtn < writeframes) { x->x_fileerror = errno; break; } else { x->x_fifotail += sysrtn; if (x->x_fifotail == fifosize) x->x_fifotail = 0; } /* signal parent in case it's waiting for data */ pthread_cond_signal(&x->x_answercondition); } free(ambibuf);free(xtrabuf); } else if (x->x_requestcode == REQUEST_CLOSE || x->x_requestcode == REQUEST_QUIT) { int quit = (x->x_requestcode == REQUEST_QUIT); if (ambix) { pthread_mutex_unlock(&x->x_mutex); ambix_close(ambix); ambix=NULL; pthread_mutex_lock(&x->x_mutex); } x->x_requestcode = REQUEST_NOTHING; pthread_cond_signal(&x->x_answercondition); if (quit) break; } else { } } pthread_mutex_unlock(&x->x_mutex); return (0); }
int main(int argc, char *argv[]) { const char*filename = "jtest.caf"; const char*myname=argv[0]; observe_signals (); struct recorder d; ambix_matrix_t*matrix=NULL; int32_t order = -1; d.buffer_frames = 4096; d.minimal_frames = 32; d.channels = 2; d.timer_seconds = -1.0; d.timer_counter = 0; d.sample_format = AMBIX_SAMPLEFORMAT_FLOAT32; d.file_format = AMBIX_BASIC; int c; while((c = getopt(argc, argv, "hVx:X:O:b:fhm:n:t:")) != -1) { switch(c) { case 'x': d.e_channels = (int) strtol(optarg, NULL, 0); d.file_format = AMBIX_EXTENDED; break; case 'X': matrix=matrix_read(optarg, matrix); if(!matrix) { eprintf("%s: couldn't read matrix-file '%s'\n", myname, optarg); FAILURE; } d.file_format = AMBIX_EXTENDED; break; case 'O': order = (uint32_t) strtol(optarg, NULL, 0); break; case 'b': d.buffer_frames = (int) strtol(optarg, NULL, 0); break; #if 0 case 'f': d.file_format = (int) strtol(optarg, NULL, 0); break; #endif case 'V': version (myname); break; case 'h': usage (myname); break; case 'm': d.minimal_frames = (int) strtol(optarg, NULL, 0); break; case 't': d.timer_seconds = (float) strtod(optarg, NULL); break; default: eprintf("%s: illegal option, %c\n", myname, c); usage (myname); break; } } if(optind == argc - 1) { filename=argv[optind]; } else { eprintf("opening default file '%s'\n", filename); //usage (myname); } /* Allocate channel based data. */ if(matrix) { if(order<0) { d.a_channels = matrix->cols; } else { if(ambix_order2channels(order) != matrix->rows) { eprintf("%s: ambisonics order:%d cannot use [%dx%d] adaptor matrix.\n", myname, order, matrix->rows, matrix->cols); FAILURE; } d.a_channels = matrix->cols; } } else { if(order<0) order=1; d.a_channels=ambix_order2channels(order); } switch(d.file_format) { case AMBIX_BASIC: //d.a_channels; d.e_channels=0; break; case AMBIX_EXTENDED: //d.a_channels; //d.e_channels; break; case AMBIX_NONE: default: d.a_channels=0; //d.e_channels; } d.channels = d.a_channels+d.e_channels; if(d.channels < 1) { eprintf("%s: illegal number of channels: %d\n", myname, d.channels); FAILURE; } d.in = (float**)xmalloc(d.channels * sizeof(float *)); d.input_port = (jack_port_t**)xmalloc(d.channels * sizeof(jack_port_t *)); /* Connect to JACK. */ jack_client_t *client = jack_client_unique_("ambix-jrecord"); jack_set_error_function(jack_client_minimal_error_handler); jack_on_shutdown(client, jack_client_minimal_shutdown_handler, 0); jack_set_process_callback(client, process, &d); d.sample_rate = jack_get_sample_rate(client); /* Setup timer. */ if(d.timer_seconds < 0.0) { d.timer_frames = -1; } else { d.timer_frames = d.timer_seconds * d.sample_rate; } /* Create sound file. */ ambix_info_t sfinfo; memset(&sfinfo, 0, sizeof(sfinfo)); sfinfo.samplerate = (int) d.sample_rate; sfinfo.frames = 0; sfinfo.fileformat = d.file_format; sfinfo.ambichannels = d.a_channels; sfinfo.extrachannels = d.e_channels; d.sound_file = ambix_open(filename, AMBIX_WRITE, &sfinfo); if(matrix) { ambix_err_t aerr = ambix_set_adaptormatrix(d.sound_file, matrix); if(AMBIX_ERR_SUCCESS != aerr) { eprintf("setting [%dx%d] matrix returned %d.\n", matrix->rows, matrix->cols, aerr); FAILURE; } } /* Allocate buffers. */ d.buffer_samples = d.buffer_frames * d.channels; d.buffer_bytes = d.buffer_samples * sizeof(float); d.a_buffer = (float32_t*)xmalloc(d.buffer_frames * d.a_channels * sizeof(float32_t)); d.e_buffer = (float32_t*)xmalloc(d.buffer_frames * d.e_channels * sizeof(float32_t)); d.d_buffer = (float*)xmalloc(d.buffer_bytes); d.j_buffer = (float*)xmalloc(d.buffer_bytes); d.u_buffer = (float*)xmalloc(d.buffer_bytes); d.ring_buffer = jack_ringbuffer_create(d.buffer_bytes); /* Create communication pipe. */ xpipe(d.pipe); /* Start disk thread. */ pthread_create (&(d.disk_thread), NULL, disk_thread_procedure, &d); /* Create input ports and activate client. */ #if 0 jack_port_make_standard(client, d.input_port, d.channels, false); jack_client_activate(client); #else do { int i=0, a, e; const char*format=(sfinfo.fileformat == AMBIX_BASIC)?"ACN_%d":"ambisonics_%d"; const int a_offset=(sfinfo.fileformat == AMBIX_BASIC)?0:1; for(a=0; a<d.a_channels; a++) { d.input_port[i] = _jack_port_register(client, JackPortIsInput, format, a+a_offset); i++; } for(e=0; e<d.e_channels; e++) { d.input_port[i] = _jack_port_register(client, JackPortIsInput, "in_%d", e+1); i++; } } while(0); if(jack_activate(client)) { eprintf("jack_activate() failed\n"); FAILURE; } #endif /* Wait for disk thread to end, which it does when it reaches the end of the file or is interrupted. */ pthread_join(d.disk_thread, NULL); /* Close sound file, free ring buffer, close JACK connection, close pipe, free data buffers, indicate success. */ jack_client_close(client); ambix_close(d.sound_file); jack_ringbuffer_free(d.ring_buffer); close(d.pipe[0]); close(d.pipe[1]); free(d.a_buffer); free(d.e_buffer); free(d.d_buffer); free(d.j_buffer); free(d.u_buffer); free(d.in); free(d.input_port); if(matrix)ambix_matrix_destroy(matrix); return EXIT_SUCCESS; }
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"); }
/* 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; }
ambix_matrix_t* ambix_matrix_fill(ambix_matrix_t*matrix, ambix_matrixtype_t typ) { int32_t rows=matrix->rows; int32_t cols=matrix->cols; int32_t r, c; float32_t**mtx=matrix->data; ambix_matrix_t*result=NULL; switch(typ) { default: return NULL; case (AMBIX_MATRIX_ZERO): for(r=0; r<rows; r++) { for(c=0; c<cols; c++) mtx[r][c]=0.; } break; case (AMBIX_MATRIX_ONE): for(r=0; r<rows; r++) { for(c=0; c<cols; c++) mtx[r][c]=1.; } break; case (AMBIX_MATRIX_IDENTITY): for(r=0; r<rows; r++) { for(c=0; c<cols; c++) mtx[r][c]=(float32_t)((r==c)?1.:0.); } break; case (AMBIX_MATRIX_FUMA): /* Furse Malham -> ACN/SN3D */ result=_matrix_fuma2ambix(cols); if(!result) return NULL; matrix=ambix_matrix_copy(result, matrix); break; case (AMBIX_MATRIX_TO_FUMA): /* Furse Malham -> ACN/SN3D */ result=_matrix_ambix2fuma(rows); if(!result) return NULL; matrix=ambix_matrix_copy(result, matrix); break; case (AMBIX_MATRIX_SID): /* SID -> ACN */ { float32_t*ordering=(float32_t*)malloc(rows*sizeof(float32_t)); if(!ordering) return NULL; if(!_matrix_sid2acn(ordering, rows)) { free(ordering); return NULL; } matrix=_matrix_router(matrix, ordering, rows, 0); free(ordering); } break; case (AMBIX_MATRIX_TO_SID): /* ACN -> SID */ { float32_t*ordering=(float32_t*)malloc(rows*sizeof(float32_t)); if(!_matrix_sid2acn(ordering, rows)) { free(ordering); return NULL; } matrix=_matrix_router(matrix, ordering, rows, 1); free(ordering); } break; case (AMBIX_MATRIX_N3D): /* N3D -> SN3D */ { float32_t*weights=NULL, *w_=NULL; int32_t counter=0; int32_t o=0, order=ambix_channels2order(rows); if(order<0) return NULL; weights=(float32_t*)malloc(rows*sizeof(float32_t)); w_=weights; for(o=0; o<=order; o++) { const float32_t w=(float32_t)(1./sqrt(2.*o+1.)); int32_t i; for(i=0; i<(2*o+1); i++) { *w_++=w; counter++; } } matrix=_matrix_diag(matrix, weights, rows); free(weights); } break; case (AMBIX_MATRIX_TO_N3D): /* SN3D -> N3D */ { float32_t*weights=NULL, *w_=NULL; int32_t counter=0; int32_t o, order=ambix_channels2order(rows); if(order<0) return NULL; weights=(float32_t*)malloc(rows*sizeof(float32_t)); w_=weights; for(o=0; o<=order; o++) { const float32_t w=(float32_t)(sqrt(2.*o+1.)); int32_t i; for(i=0; i<(2*o+1); i++) { *w_++=w; counter++; } } matrix=_matrix_diag(matrix, weights, rows); free(weights); } break; } if(result) ambix_matrix_destroy(result); return matrix; }
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"); }