int _matrix_sid2acn(float32_t*data, uint32_t count) { float32_t*datap=data; int32_t order=ambix_channels2order(count); int32_t o; if(order<0)return 0; for(o=0; o<=order; o++) { uint32_t offset=o>0?ambix_order2channels(o-1):0; int32_t maxindex=ambix_order2channels(o)-offset; int32_t index; for(index=1; index<maxindex; index+=2) { *datap++=(float32_t)(index+offset); } for(index=maxindex-1; index>=0; index-=2) { *datap++=(float32_t)(index+offset); } } return 1; }
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; }
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; }
int main(int argc, char**argv) { uint32_t r, c, o; char name[64]; name[63]=0; for(r=1; r<16; r++) { for(c=1; c<16; c++) { snprintf(name, 63, "zero[%d, %d]", r, c); check_matrix(name, AMBIX_MATRIX_ZERO, r, c); snprintf(name, 63, "one[%d, %d]", r, c); check_matrix(name, AMBIX_MATRIX_ONE, r, c); snprintf(name, 63, "identity[%d, %d]", r, c); check_matrix(name, AMBIX_MATRIX_IDENTITY, r, c); } } check_matrix("FuMa[ 1, 1]", AMBIX_MATRIX_FUMA, 1, 1); check_matrix("FuMa[ 4, 3]", AMBIX_MATRIX_FUMA, 4, 3); check_matrix("FuMa[ 4, 4]", AMBIX_MATRIX_FUMA, 4, 4); check_matrix("FuMa[ 9, 5]", AMBIX_MATRIX_FUMA, 9, 5); check_matrix("FuMa[ 9, 6]", AMBIX_MATRIX_FUMA, 9, 6); check_matrix("FuMa[ 9, 9]", AMBIX_MATRIX_FUMA, 9, 9); check_matrix("FuMa[16, 7]", AMBIX_MATRIX_FUMA, 16, 7); check_matrix("FuMa[16, 8]", AMBIX_MATRIX_FUMA, 16, 8); check_matrix("FuMa[16,11]", AMBIX_MATRIX_FUMA, 16, 11); check_matrix("FuMa[16,16]", AMBIX_MATRIX_FUMA, 16, 16); check_inversion("FuMa[ 1, 1]", AMBIX_MATRIX_FUMA, 1, 1); check_inversion("FuMa[ 4, 3]", AMBIX_MATRIX_FUMA, 4, 3); check_inversion("FuMa[ 4, 4]", AMBIX_MATRIX_FUMA, 4, 4); check_inversion("FuMa[ 9, 5]", AMBIX_MATRIX_FUMA, 9, 5); check_inversion("FuMa[ 9, 6]", AMBIX_MATRIX_FUMA, 9, 6); check_inversion("FuMa[ 9, 9]", AMBIX_MATRIX_FUMA, 9, 9); check_inversion("FuMa[16, 7]", AMBIX_MATRIX_FUMA, 16, 7); check_inversion("FuMa[16, 8]", AMBIX_MATRIX_FUMA, 16, 8); check_inversion("FuMa[16,11]", AMBIX_MATRIX_FUMA, 16, 11); check_inversion("FuMa[16,16]", AMBIX_MATRIX_FUMA, 16, 16); for(o=1; o<6; o++) { uint32_t chan=ambix_order2channels(o); snprintf(name, 63, "n3d2snd3d[%d, %d]", chan, chan); check_matrix(name, AMBIX_MATRIX_N3D, chan, chan); snprintf(name, 63, "sn3d2n3d[%d, %d]", chan, chan); check_matrix(name, AMBIX_MATRIX_TO_N3D, chan, chan); snprintf(name, 63, "n3d[%d, %d]", chan, chan); check_inversion(name, AMBIX_MATRIX_N3D, 1, 1); snprintf(name, 63, "sid2acn[%d, %d]", chan, chan); check_matrix(name, AMBIX_MATRIX_SID, chan, chan); snprintf(name, 63, "acn2sid[%d, %d]", chan, chan); check_matrix(name, AMBIX_MATRIX_TO_SID, chan, chan); snprintf(name, 63, "sid[%d, %d]", chan, chan); check_inversion(name, AMBIX_MATRIX_SID, 1, 1); } pass(); return 0; }