예제 #1
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;
}
예제 #2
0
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);
}
예제 #3
0
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);
}