Esempio n. 1
0
File: tracker.c Progetto: bion/ats
/* ATS_SOUND *tracker (ANARGS *anargs, char *soundfile)
 * partial tracking function 
 * anargs: pointer to analysis parameters
 * soundfile: path to input file 
 * returns an ATS_SOUND with data issued from analysis
 */
ATS_SOUND *tracker (ANARGS *anargs, char *soundfile, char *resfile)
{
  int fd, M_2, first_point, filptr, n_partials = 0;
  int frame_n, k, sflen, *win_samps, peaks_size, tracks_size = 0;
  int i, frame, i_tmp;
  float *window, norm, sfdur, f_tmp;
  /* declare structures and buffers */
  ATS_SOUND *sound = NULL;
  ATS_PEAK *peaks, *tracks = NULL, cpy_peak;
  ATS_FRAME *ana_frames = NULL, *unmatched_peaks = NULL;
  mus_sample_t **bufs;
  ATS_FFT fft;
#ifdef FFTW
  fftw_plan plan;
  FILE *fftw_wisdom_file;
#endif

  /* open input file
     we get srate and total_samps in file in anargs */
  if ((fd = mus_sound_open_input(soundfile))== -1) {
    fprintf(stderr, "%s: %s\n", soundfile, strerror(errno));
    return(NULL);
  }
  /* warn about multi-channel sound files */
  if (mus_sound_chans(soundfile) > 1) {
    fprintf(stderr, "Error: file has %d channels, must be mono!\n",
	    mus_sound_chans(soundfile));
    return(NULL);
  }

  fprintf(stderr, "tracking...\n");

  /* get sample rate and # of frames from file header */
  anargs->srate = mus_sound_srate(soundfile);
  sflen = mus_sound_frames(soundfile);
  sfdur = (float)sflen/anargs->srate;
  /* check analysis parameters */
  /* check start time */
  if( !(anargs->start >= 0.0 && anargs->start < sfdur) ){
    fprintf(stderr, "Warning: start %f out of bounds, corrected to 0.0\n", anargs->start);
    anargs->start = (float)0.0;
  }
  /* check duration */
  if(anargs->duration == ATSA_DUR) {
    anargs->duration = sfdur - anargs->start;
  }
  f_tmp = anargs->duration + anargs->start;
  if( !(anargs->duration > 0.0 && f_tmp <= sfdur) ){
    fprintf(stderr, "Warning: duration %f out of bounds, limited to file duration\n", anargs->duration);
    anargs->duration = sfdur - anargs->start;
  }
  /* print time bounds */
  fprintf(stderr, "start: %f duration: %f file dur: %f\n", anargs->start, anargs->duration , sfdur);
  /* check lowest frequency */
  if( !(anargs->lowest_freq > 0.0 && anargs->lowest_freq < anargs->highest_freq)){
    fprintf(stderr, "Warning: lowest freq. %f out of bounds, forced to default: %f\n", anargs->lowest_freq, ATSA_LFREQ);
    anargs->lowest_freq = ATSA_LFREQ;
  }
  /* check highest frequency */
  if( !(anargs->highest_freq > anargs->lowest_freq && anargs->highest_freq <= anargs->srate * 0.5 )){
    fprintf(stderr, "Warning: highest freq. %f out of bounds, forced to default: %f\n", anargs->highest_freq, ATSA_HFREQ);
    anargs->highest_freq = ATSA_HFREQ;
  }
  /* frequency deviation */
  if( !(anargs->freq_dev > 0.0 && anargs->freq_dev < 1.0) ){
    fprintf(stderr, "Warning: freq. dev. %f out of bounds, should be > 0.0 and <= 1.0,  forced to default: %f\n", anargs->freq_dev, ATSA_FREQDEV);
    anargs->freq_dev = ATSA_FREQDEV;
  }
  /* window cycles */
  if( !(anargs->win_cycles >= 1 && anargs->win_cycles <= 8) ){
    fprintf(stderr, "Warning: windows cycles %d out of bounds, should be between 1 and 8, forced to default: %d\n", anargs->win_cycles, ATSA_WCYCLES);
    anargs->win_cycles = ATSA_WCYCLES;
  }
  /* window type */
  if( !(anargs->win_type >= 0 && anargs->win_type <= 3) ){
    fprintf(stderr, "Warning: window type %d out of bounds, should be between 0 and 3, forced to default: %d\n", anargs->win_type, ATSA_WTYPE);
    anargs->win_type = ATSA_WTYPE;
  }
  /* hop size */
  if( !(anargs->hop_size > 0.0 && anargs->hop_size <= 1.0) ){
    fprintf(stderr, "Warning: hop size %f out of bounds, should be > 0.0 and <= 1.0, forced to default: %f\n", anargs->hop_size, ATSA_HSIZE);
    anargs->hop_size = ATSA_HSIZE;
  }
  /* lowest mag */
  if( !(anargs->lowest_mag <= 0.0) ){
    fprintf(stderr, "Warning: lowest magnitude %f out of bounds, should be >= 0.0 and <= 1.0, forced to default: %f\n", anargs->lowest_mag, ATSA_LMAG);
    anargs->lowest_mag = ATSA_LMAG;
  }
  /* set some values before checking next set of parameters */
  anargs->first_smp = (int)floor(anargs->start * (float)anargs->srate);
  anargs->total_samps = (int)floor(anargs->duration * (float)anargs->srate);
  /* fundamental cycles */
  anargs->cycle_smp = (int)floor((double)anargs->win_cycles * (double)anargs->srate / (double)anargs->lowest_freq);
  /* window size */
  anargs->win_size = (anargs->cycle_smp % 2 == 0) ? anargs->cycle_smp+1 : anargs->cycle_smp;
  /* calculate hop samples */
  anargs->hop_smp = floor( (float)anargs->win_size * anargs->hop_size );
  /* compute total number of frames */
  anargs->frames = compute_frames(anargs);
  /* check that we have enough frames for the analysis */
  if( !(anargs->frames >= ATSA_MFRAMES) ){
    fprintf(stderr, "Error: %d frames are not enough for analysis, nead at least %d\n", anargs->frames , ATSA_MFRAMES);
    return(NULL);
  }
  /* check other user parameters */
  /* track length */
  if( !(anargs->track_len >= 1 && anargs->track_len < anargs->frames) ){
    i_tmp = (ATSA_TRKLEN < anargs->frames) ? ATSA_TRKLEN : anargs->frames-1;
    fprintf(stderr, "Warning: track length %d out of bounds, forced to: %d\n", anargs->track_len , i_tmp);
    anargs->track_len = i_tmp;
  }    
  /* min. segment length */
  if( !(anargs->min_seg_len >= 1 && anargs->min_seg_len < anargs->frames) ){
    i_tmp = (ATSA_MSEGLEN < anargs->frames) ? ATSA_MSEGLEN : anargs->frames-1;
    fprintf(stderr, "Warning: min. segment length %d out of bounds, forced to: %d\n", anargs->min_seg_len, i_tmp);
    anargs->min_seg_len = i_tmp;
  }
  /* min. gap length */
  if( !(anargs->min_gap_len >= 0 && anargs->min_gap_len < anargs->frames) ){
    i_tmp = (ATSA_MGAPLEN < anargs->frames) ? ATSA_MGAPLEN : anargs->frames-1;
    fprintf(stderr, "Warning: min. gap length %d out of bounds, forced to: %d\n", anargs->min_gap_len, i_tmp);
    anargs->min_gap_len = i_tmp;
  }
  /* SMR threshold */
  if( !(anargs->SMR_thres >= 0.0 && anargs->SMR_thres < ATSA_MAX_DB_SPL) ){
    fprintf(stderr, "Warning: SMR threshold %f out of bounds, shoul be >= 0.0 and < %f dB SPL, forced to default: %f\n", anargs->SMR_thres, ATSA_MAX_DB_SPL, ATSA_SMRTHRES);
    anargs->SMR_thres = ATSA_SMRTHRES;
  }
  /* min. seg. SMR */
  if( !(anargs->min_seg_SMR >= anargs->SMR_thres && anargs->min_seg_SMR < ATSA_MAX_DB_SPL) ){
    fprintf(stderr, "Warning: min. seg. SMR  %f out of bounds, shoul be >= %f and < %f dB SPL, forced to default: %f\n", anargs->min_seg_SMR, anargs->SMR_thres, ATSA_MAX_DB_SPL, ATSA_MSEGSMR);
    anargs->min_seg_SMR = ATSA_MSEGSMR;
  }
  /* last peak contibution */
  if( !(anargs->last_peak_cont >= 0.0 && anargs->last_peak_cont <= 1.0) ){
    fprintf(stderr, "Warning: last peak contibution %f out of bounds, should be >= 0.0 and <= 1.0, forced to default: %f\n", anargs->last_peak_cont, ATSA_LPKCONT);
    anargs->last_peak_cont = ATSA_LPKCONT;
  }
  /* SMR cont. */
  if( !(anargs->SMR_cont >= 0.0 && anargs->SMR_cont <= 1.0) ){
    fprintf(stderr, "Warning: SMR contibution %f out of bounds, should be >= 0.0 and <= 1.0, forced to default: %f\n", anargs->SMR_cont, ATSA_SMRCONT);
    anargs->SMR_cont = ATSA_SMRCONT;
  }
  /* continue computing parameters */
  /* fft size */
  anargs->fft_size = ppp2(2*anargs->win_size);

  /* allocate memory for sound, we read the whole sound in memory */
  bufs = (mus_sample_t **)malloc(sizeof(mus_sample_t*));
  bufs[0] = (mus_sample_t *)malloc(sflen * sizeof(mus_sample_t));
  /*  bufs = malloc(sizeof(mus_sample_t*));
      bufs[0] = malloc(sflen * sizeof(mus_sample_t)); */
  /* make our window */
  window = make_window(anargs->win_type, anargs->win_size);
  /* get window norm */
  norm = window_norm(window, anargs->win_size);
  /* fft mag for computing frequencies */
  anargs->fft_mag = (double)anargs->srate / (double)anargs->fft_size;
  /* lowest fft bin for analysis */
  anargs->lowest_bin = floor( anargs->lowest_freq / anargs->fft_mag );
  /* highest fft bin for analisis */
  anargs->highest_bin = floor( anargs->highest_freq / anargs->fft_mag );
  /* allocate an array analysis frames in memory */
  ana_frames = (ATS_FRAME *)malloc(anargs->frames * sizeof(ATS_FRAME));
  /* alocate memory to store mid-point window sample numbers */
  win_samps = (int *)malloc(anargs->frames * sizeof(int));
  /* center point of window */
  M_2 = floor((anargs->win_size - 1) / 2); 
  /* first point in fft buffer to write */
  first_point = anargs->fft_size - M_2;  
  /* half a window from first sample */
  filptr = anargs->first_smp - M_2;   
  /* read sound into memory */
  mus_sound_read(fd, 0, sflen-1, 1, bufs);     

  /* make our fft-struct */
  fft.size = anargs->fft_size;
  fft.rate = anargs->srate;
#ifdef FFTW
  fft.data = fftw_malloc(sizeof(fftw_complex) * fft.size);
  if(fftw_import_system_wisdom()) fprintf(stderr, "system wisdom loaded!\n");
  else fprintf(stderr, "cannot locate system wisdom!\n");
  if((fftw_wisdom_file = fopen("ats-wisdom", "r")) != NULL) {
    fftw_import_wisdom_from_file(fftw_wisdom_file);
    fprintf(stderr, "ats-wisdom loaded!\n");
    fclose(fftw_wisdom_file);
  } else fprintf(stderr, "cannot locate ats-wisdom!\n");
  plan = fftw_plan_dft_1d(fft.size, fft.data, fft.data, FFTW_FORWARD, FFTW_PATIENT);
#else
  fft.fdr = (double *)malloc(anargs->fft_size * sizeof(double));
  fft.fdi = (double *)malloc(anargs->fft_size * sizeof(double));
#endif

  /* main loop */
  for (frame_n=0; frame_n<anargs->frames; frame_n++) {
    /* clear fft arrays */
#ifdef FFTW
    for(k=0; k<fft.size; k++) fft.data[k][0] = fft.data[k][1] = 0.0f;
#else
    for(k=0; k<fft.size; k++) fft.fdr[k] = fft.fdi[k] = 0.0f;
#endif
    /* multiply by window */
    for (k=0; k<anargs->win_size; k++) {
      if ((filptr >= 0) && (filptr < sflen)) 
#ifdef FFTW
        fft.data[(k+first_point)%fft.size][0] = window[k] * MUS_SAMPLE_TO_FLOAT(bufs[0][filptr]);
#else
        fft.fdr[(k+first_point)%anargs->fft_size] = window[k] * MUS_SAMPLE_TO_FLOAT(bufs[0][filptr]);
#endif
      filptr++;
    }
    /* we keep sample numbers of window midpoints in win_samps array */
    win_samps[frame_n] = filptr - M_2 - 1;
    /* move file pointer back */
    filptr = filptr - anargs->win_size + anargs->hop_smp;
    /* take the fft */
#ifdef FFTW
    fftw_execute(plan);
#else
    fft_slow(fft.fdr, fft.fdi, fft.size, 1);
#endif
    /* peak detection */
    peaks_size = 0;
    peaks = peak_detection(&fft, anargs->lowest_bin, anargs->highest_bin, anargs->lowest_mag, norm, &peaks_size); 
    /* peak tracking */
    if (peaks != NULL) {
      /* evaluate peaks SMR (masking curves) */
      evaluate_smr(peaks, peaks_size);
      if (frame_n) {
	/* initialize or update tracks */
	if ((tracks = update_tracks(tracks, &tracks_size, anargs->track_len, frame_n, ana_frames, anargs->last_peak_cont)) != NULL) {
	  /* do peak matching */
          unmatched_peaks = peak_tracking(tracks, &tracks_size, peaks, &peaks_size,  anargs->freq_dev, 2.0 * anargs->SMR_cont, &n_partials);
	  /* kill unmatched peaks from previous frame */
          if(unmatched_peaks[0].peaks != NULL) {
	    for(k=0; k<unmatched_peaks[0].n_peaks; k++) {
	      cpy_peak = unmatched_peaks[0].peaks[k];
	      cpy_peak.amp = cpy_peak.smr = 0.0;
	      peaks = push_peak(&cpy_peak, peaks, &peaks_size);
             }
             free(unmatched_peaks[0].peaks);
           }
           /* give birth to peaks from new frame */
           if(unmatched_peaks[1].peaks != NULL) {
             for(k=0; k<unmatched_peaks[1].n_peaks; k++) {
               tracks = push_peak(&unmatched_peaks[1].peaks[k], tracks, &tracks_size);
               unmatched_peaks[1].peaks[k].amp = unmatched_peaks[1].peaks[k].smr = 0.0;
               ana_frames[frame_n-1].peaks = push_peak(&unmatched_peaks[1].peaks[k], ana_frames[frame_n-1].peaks, &ana_frames[frame_n-1].n_peaks);
             }
             free(unmatched_peaks[1].peaks);
           }
         } else {
           /* give number to all peaks */
           qsort(peaks, peaks_size, sizeof(ATS_PEAK), peak_frq_inc);
           for(k=0; k<peaks_size; k++) peaks[k].track = n_partials++;
         }
      } else {
        /* give number to all peaks */
        qsort(peaks, peaks_size, sizeof(ATS_PEAK), peak_frq_inc);
        for(k=0; k<peaks_size; k++) peaks[k].track = n_partials++;
      }
      /* attach peaks to ana_frames */
      ana_frames[frame_n].peaks = peaks;
      ana_frames[frame_n].n_peaks = n_partials;
      ana_frames[frame_n].time = (double)(win_samps[frame_n] - anargs->first_smp) / (double)anargs->srate;
      /* free memory */
      free(unmatched_peaks);
    } else {
      /* if no peaks found, initialize empty frame */
      ana_frames[frame_n].peaks = NULL;
      ana_frames[frame_n].n_peaks = 0;
      ana_frames[frame_n].time = (double)(win_samps[frame_n] - anargs->first_smp) / (double)anargs->srate;
    }
  }
  /* free up some memory */
  free(window);
  free(tracks);
#ifdef FFTW
  fftw_destroy_plan(plan);
  fftw_free(fft.data);
#else
  free(fft.fdr);
  free(fft.fdi);
#endif
  /* init sound */
  fprintf(stderr, "Initializing ATS data...");
  sound = (ATS_SOUND *)malloc(sizeof(ATS_SOUND));
  init_sound(sound, anargs->srate, (int)(anargs->hop_size * anargs->win_size), 
             anargs->win_size, anargs->frames, anargs->duration, n_partials,
             ((anargs->type == 3 || anargs->type == 4) ? 1 : 0));
  /* store values from frames into the arrays */
  for(k=0; k<n_partials; k++) {
    for(frame=0; frame<sound->frames; frame++) {
      sound->time[k][frame] = ana_frames[frame].time;
      for(i=0; i<ana_frames[frame].n_peaks; i++) 
        if(ana_frames[frame].peaks[i].track == k) {
	  sound->amp[k][frame] = ana_frames[frame].peaks[i].amp;
          sound->frq[k][frame] = ana_frames[frame].peaks[i].frq;
          sound->pha[k][frame] = ana_frames[frame].peaks[i].pha;
          sound->smr[k][frame] = ana_frames[frame].peaks[i].smr;
        }
    }
  }
  fprintf(stderr, "done!\n");
  /* free up ana_frames memory */
  /* first, free all peaks in each slot of ana_frames... */
  for (k=0; k<anargs->frames; k++) free(ana_frames[k].peaks);  
  /* ...then free ana_frames */
  free(ana_frames);                                            
  /* optimize sound */
  optimize_sound(anargs, sound);
  /* compute  residual */
  if( anargs->type == 3 || anargs->type == 4 ) {
    fprintf(stderr, "Computing residual...");
    compute_residual(bufs, sflen, resfile, sound, win_samps, anargs->srate);
    fprintf(stderr, "done!\n");
  }
  /* free the rest of the memory */
  free(win_samps);
  free(bufs[0]);
  free(bufs);
  /* analyze residual */
  if( anargs->type == 3 || anargs->type == 4 ) {
    fprintf(stderr, "Analyzing residual...");
    residual_analysis(ATSA_RES_FILE, sound);
    fprintf(stderr, "done!\n");
  }
#ifdef FFTW
  fftw_wisdom_file = fopen("ats-wisdom", "w");
  fftw_export_wisdom_to_file(fftw_wisdom_file);
  fclose(fftw_wisdom_file);
#endif
  fprintf(stderr, "tracking completed.\n");
  return(sound);
}
Esempio n. 2
0
File: sndplay.c Progetto: huangjs/cl
static int main_not_alsa(int argc, char *argv[])
{
  int fd, afd, i, j, n, k, chans, srate;
  off_t frames, m;
  mus_sample_t **bufs;
  OutSample *obuf;
  int use_multi_card_code = 0, use_volume = 0;
  int afd0, afd1, buffer_size = BUFFER_SIZE, curframes, sample_size, out_chans, outbytes;
  mus_sample_t **qbufs;
  short *obuf0, *obuf1;
  char *name = NULL;
  off_t start = 0, end = 0;
  double begin_time = 0.0, end_time = 0.0, volume = 1.0;

  for (i = 1; i < argc; i++)
    {
      if (strcmp(argv[i], "-describe") == 0) 
	{
	  mus_audio_describe(); 
	  exit(0);
	}
      else
	{
	  if (strcmp(argv[i], "-buffers") == 0) 
	    {
	      set_buffers(argv[i + 1]); 
	      i++;
	    }
	  else
	    {
	      if (strcmp(argv[i], "-bufsize") == 0) 
		{
		  buffer_size = atoi(argv[i + 1]);
		  i++;
		}
	      else
		{
		  if (strcmp(argv[i], "-start") == 0) 
		    {
		      begin_time = atof(argv[i + 1]);
		      i++;
		    }
		  else
		    {
		      if (strcmp(argv[i], "-end") == 0) 
			{
			  end_time = atof(argv[i + 1]);
			  i++;
			}
		      else 
			{ 
			  if (strcmp(argv[i], "-volume") == 0)
			    { 
			      volume = atof(argv[i + 1]);
			      use_volume = 1;
			      i++; 
			    } 
			  else name = argv[i];
			}}}}}}
  if (name == NULL) 
    {
      printf("usage: sndplay file [-start 1.0] [-end 1.0] [-bufsize %d] [-buffers 2x12] [-volume 1.0] [-describe]\n", BUFFER_SIZE); 
      exit(0);
    }

  afd = -1;
  afd0 = -1;
  afd1 = -1;
  if (!(MUS_HEADER_TYPE_OK(mus_sound_header_type(name))))
    {
      fprintf(stderr, "can't play %s (header type: %s?)\n",
	      name,
	      mus_header_type_name(mus_header_type()));
      exit(0);
    }
  if (!(MUS_DATA_FORMAT_OK(mus_sound_data_format(name))))
    {
      fprintf(stderr, "can't play %s (data format: %s (%s)?)\n",
	      name,
	      mus_data_format_name(mus_sound_data_format(name)),
	      mus_header_original_format_name(mus_sound_original_format(name), 
					      mus_sound_header_type(name)));
      exit(0);
    }
  fd = mus_sound_open_input(name);
  if (fd != -1)
    {
      chans = mus_sound_chans(name);
      if (chans > 2)
	{
	  float val[8];
	  mus_audio_mixer_read(MUS_AUDIO_DEFAULT, MUS_AUDIO_CHANNEL, 0, val);
	  if (val[0] < chans)
	    {
	      if (mus_audio_systems() > 1)
		use_multi_card_code = 1;
	      /* I suppose we could count up all the channels here */
	      else
		{
		  fprintf(stderr, "%s has %d channels, but we can only handle %d\n", name, chans, (int)(val[0]));
		  exit(1);
		}
	    }
	}
      out_chans = chans;
      srate = mus_sound_srate(name);
      frames = mus_sound_frames(name);
      sample_size = mus_bytes_per_sample(MUS_AUDIO_COMPATIBLE_FORMAT);
      start = (off_t)(begin_time * srate);
      if (start > 0)
	mus_file_seek_frame(fd, start);
      if (end_time > 0.0)
	end = (off_t)(end_time * srate);
      else end = frames;
      if ((end - start) < frames)
	frames = end - start;
      if (!use_multi_card_code)
	{
	  bufs = (mus_sample_t **)calloc(chans, sizeof(mus_sample_t *));
	  for (i = 0; i < chans; i++) bufs[i] = (mus_sample_t *)calloc(buffer_size, sizeof(mus_sample_t));
	  obuf = (OutSample *)calloc(buffer_size * out_chans, sizeof(OutSample));
	  outbytes = buffer_size * out_chans * sample_size;
	  for (m = 0; m < frames; m += buffer_size)
	    {
	      if ((m + buffer_size) <= frames)
		curframes = buffer_size;
	      else curframes = frames - m;
	      mus_file_read(fd, 0, curframes - 1, chans, bufs); 
	      /* some systems are happier if we read the file before opening the dac */
	      /* at this point the data is in separate arrays of mus_sample_t's */
	      if (use_volume) 
		set_volume(bufs, chans, curframes, volume); 
	      if (chans == 1)
		{
		  for (k = 0; k < curframes; k++) 
		    obuf[k] = MUS_CONVERT(bufs[0][k]);
		}
	      else
		{
		  if (chans == 2)
		    {
		      for (k = 0, n = 0; k < curframes; k++, n += 2) 
			{
			  obuf[n] = MUS_CONVERT(bufs[0][k]); 
			  obuf[n + 1] = MUS_CONVERT(bufs[1][k]);
			}
		    }
		  else
		    {
		      for (k = 0, j = 0; k < curframes; k++, j += chans)
			{
			  for (n = 0; n < chans; n++) 
			    obuf[j + n] = MUS_CONVERT(bufs[n][k]);
			}
		    }
		}
	      if (afd == -1)
		{
#if defined(MUS_LINUX) && defined(PPC)
		  afd = mus_audio_open_output(MUS_AUDIO_DEFAULT, srate, chans, MUS_AUDIO_COMPATIBLE_FORMAT, 0);
#else
		  afd = mus_audio_open_output(MUS_AUDIO_DEFAULT, srate, out_chans, MUS_AUDIO_COMPATIBLE_FORMAT, outbytes);
#endif
		  if (afd == -1) break;
		}
	      outbytes = curframes * out_chans * sample_size;
	      mus_audio_write(afd, (char *)obuf, outbytes);
	    }
	  if (afd != -1) mus_audio_close(afd);
	  mus_sound_close_input(fd);
	  for (i = 0; i < chans; i++) free(bufs[i]);
	  free(bufs);
	  free(obuf);
	}
      else
	{
	  /* code is essentially the same as above, but since this is supposed
	   *   to be a working example of sndlib, I didn't want the basic stuff
	   *   to be complicated by one special case.
	   *
	   * in my test case, I was using a Sound Blaster and an Ensoniq clone.
	   * they had slightly different start-up latencies (not really audible),
	   * and the Ensoniq's dac was running ca. 1 sample per second faster than
	   * the SB's, so by 5 minutes into a sound, the stereo pairs had drifted
	   * .01 seconds apart -- this is probably acceptable in many cases.
	   * In a second test, with two Ensoniq's in one machine, they started
	   * together and drifted apart at about 1 sample per 8 seconds -- about
	   * .001 secs apart after 5 minutes.  ("Ensoniq" was SoundWave Pro PCI
	   * from SIIG Inc -- some sort of clone.)
	   */
	  buffer_size = 256;   /* 128 probably better */
	  outbytes = buffer_size * 2 * 2; 
	  qbufs = (mus_sample_t **)calloc(chans, sizeof(mus_sample_t *));
	  for (i = 0; i < chans; i++) qbufs[i] = (mus_sample_t *)calloc(buffer_size, sizeof(mus_sample_t));
	  obuf0 = (short *)calloc(buffer_size * 2, sizeof(short));
	  obuf1 = (short *)calloc(buffer_size * 2, sizeof(short));
	  for (m = 0; m < frames; m += buffer_size)
	    {
	      if ((m + buffer_size) <= frames)
		curframes = buffer_size;
	      else curframes = frames - m;
	      mus_file_read(fd, 0, curframes - 1, chans, qbufs); 
	      if (use_volume) 
		set_volume(qbufs, chans, curframes, volume); 
	      for (k = 0, n = 0; k < buffer_size; k++, n += 2) 
		{
		  obuf0[n] = MUS_SAMPLE_TO_SHORT(qbufs[0][k]); 
		  obuf0[n + 1] = MUS_SAMPLE_TO_SHORT(qbufs[1][k]);
		  obuf1[n] = MUS_SAMPLE_TO_SHORT(qbufs[2][k]); 
		  obuf1[n + 1] = MUS_SAMPLE_TO_SHORT(qbufs[3][k]);
		}
	      if (afd0 == -1)
		{
		  afd0 = mus_audio_open_output(MUS_AUDIO_PACK_SYSTEM(0) | MUS_AUDIO_DEFAULT, srate, 2, MUS_AUDIO_COMPATIBLE_FORMAT, outbytes);
		  afd1 = mus_audio_open_output(MUS_AUDIO_PACK_SYSTEM(1) | MUS_AUDIO_DEFAULT, srate, 2, MUS_AUDIO_COMPATIBLE_FORMAT, outbytes);
		  if ((afd0 == -1) || (afd1 == -1)) break;
		}
	      mus_audio_write(afd0, (char *)obuf0, outbytes);
	      mus_audio_write(afd1, (char *)obuf1, outbytes);
	    }
	  mus_audio_close(afd0);
	  mus_audio_close(afd1);
	  mus_sound_close_input(fd);
	  for (i = 0; i < chans; i++) free(qbufs[i]);
	  free(qbufs);
	  free(obuf0);
	  free(obuf1);
	}
    }
  return(0);
}
Esempio n. 3
0
int main(int argc, char *argv[])
{
  int fd, afd, i, j, n, k, chans, srate;
  mus_long_t frames, m;
  mus_sample_t **bufs;
  OutSample *obuf;
  int buffer_size = BUFFER_SIZE, curframes, sample_size, out_chans, outbytes;
  char *name = NULL;
  mus_long_t start = 0, end = 0;
  double begin_time = 0.0, end_time = 0.0;
  int mutate = 1, include_mutate = 0;

  if (argc == 1) 
    {
      printf("usage: sndplay file [-start 1.0] [-end 1.0] [-bufsize %d] [-buffers 2x12] [-describe]\n", BUFFER_SIZE); 
      exit(0);
    }
  mus_sound_initialize();

  for (i = 1; i < argc; i++)
    {
      if (strcmp(argv[i], "-buffers") == 0) 
	{
#if (HAVE_OSS || HAVE_ALSA)
	  static char x_string[2] = {'x','\0'};
	  char *arg;
	  int a, b;
	  arg = strtok(argv[i + 1], x_string);
	  a = atoi(arg);
	  arg = strtok(NULL, x_string);
	  b = atoi(arg);
	  mus_oss_set_buffers(a, b);
#endif
	  i++;
	}
      else
	{
	  if (strcmp(argv[i], "-bufsize") == 0) 
	    {
	      buffer_size = atoi(argv[i + 1]);
	      i++;
	    }
	  else
	    {
	      if (strcmp(argv[i], "-start") == 0) 
		{
		  begin_time = atof(argv[i + 1]);
		  i++;
		}
	      else
		{
		  if (strcmp(argv[i], "-end") == 0) 
		    {
		      end_time = atof(argv[i + 1]);
		      i++;
		    }
		  else 
		    {
		      if (strcmp(argv[i], "-mutable") == 0) 
			{
			  mutate = atoi(argv[i + 1]);
			  include_mutate = 1;
			  i++;
			}
		      else name = argv[i];
		    }}}}}

  if (name == NULL) 
    {
      printf("usage: sndplay file [-start 1.0] [-end 1.0] [-bufsize %d] [-buffers 2x12] [-mutable 1]\n", BUFFER_SIZE); 
      exit(0);
    }

  afd = -1;

  if (!(mus_header_type_p(mus_sound_header_type(name))))
    {
      fprintf(stderr, "can't play %s (header type: %s?)\n",
	      name,
	      mus_header_type_name(mus_header_type()));
      exit(0);
    }

  if (!(mus_data_format_p(mus_sound_data_format(name))))
    {
      fprintf(stderr, "can't play %s (data format: %s (%s)?)\n",
	      name,
	      mus_data_format_name(mus_sound_data_format(name)),
	      mus_header_original_format_name(mus_sound_original_format(name), 
					      mus_sound_header_type(name)));
      exit(0);
    }

  fd = mus_sound_open_input(name);
  if (fd != -1)
    {
      chans = mus_sound_chans(name);
      if (chans > 2)
	{
	  int available_chans;
	  available_chans = mus_audio_device_channels(MUS_AUDIO_DEFAULT);
	  if (available_chans < chans)
	    {
	      fprintf(stderr, "%s has %d channels, but we can only handle %d\n", name, chans, available_chans);
	      exit(1);
	    }
	}

      out_chans = chans;
      srate = mus_sound_srate(name);
      frames = mus_sound_frames(name);
      sample_size = mus_bytes_per_sample(MUS_AUDIO_COMPATIBLE_FORMAT);
      start = (mus_long_t)(begin_time * srate);
      if (start > 0)
	mus_file_seek_frame(fd, start);
      if (end_time > 0.0)
	end = (mus_long_t)(end_time * srate);
      else end = frames;
      if ((end - start) < frames)
	frames = end - start;

      bufs = (mus_sample_t **)calloc(chans, sizeof(mus_sample_t *));
      for (i = 0; i < chans; i++) bufs[i] = (mus_sample_t *)calloc(buffer_size, sizeof(mus_sample_t));
      obuf = (OutSample *)calloc(buffer_size * out_chans, sizeof(OutSample));
      outbytes = buffer_size * out_chans * sample_size;

      for (m = 0; m < frames; m += buffer_size)
	{
	  if ((m + buffer_size) <= frames)
	    curframes = buffer_size;
	  else curframes = frames - m;
	  mus_file_read(fd, 0, curframes - 1, chans, bufs); 
	  /* some systems are happier if we read the file before opening the dac */
	  /* at this point the data is in separate arrays of mus_sample_t's */

	  if (chans == 1)
	    {
	      for (k = 0; k < curframes; k++) 
		obuf[k] = MUS_CONVERT(bufs[0][k]);
	    }
	  else
	    {
	      if (chans == 2)
		{
		  for (k = 0, n = 0; k < curframes; k++, n += 2) 
		    {
		      obuf[n] = MUS_CONVERT(bufs[0][k]); 
		      obuf[n + 1] = MUS_CONVERT(bufs[1][k]);
		    }
		}
	      else
		{
		  for (k = 0, j = 0; k < curframes; k++, j += chans)
		    {
		      for (n = 0; n < chans; n++) 
			obuf[j + n] = MUS_CONVERT(bufs[n][k]);
		    }
		}
	    }
#if MUS_MAC_OSX
	  if (include_mutate == 1)
	    mus_audio_output_properties_mutable(mutate);
#endif
	  if (afd == -1)
	    {
	      afd = mus_audio_open_output(MUS_AUDIO_DEFAULT, srate, out_chans, MUS_AUDIO_COMPATIBLE_FORMAT, outbytes);
	      if (afd == -1) break;
	    }
	  outbytes = curframes * out_chans * sample_size;
	  mus_audio_write(afd, (char *)obuf, outbytes);
	}
      if (afd != -1) mus_audio_close(afd);
      mus_sound_close_input(fd);
      for (i = 0; i < chans; i++) free(bufs[i]);
      free(bufs);
      free(obuf);
    }
  return(0);
}
Esempio n. 4
0
File: sndplay.c Progetto: huangjs/cl
static int main_alsa(int argc, char *argv[])
{
  int fd, i, chans, srate;
  off_t frames, ioff;
  mus_sample_t **read_bufs;
  int afd[MAX_SLOTS];
  short *out_buf[MAX_SLOTS];
  float val[MAX_SLOTS];
  int ival[MAX_SLOTS];
  int afd0, afd1;
  char *name;
  int base, curframes;
  int allocated;
  int out_devs[MAX_SLOTS];
  int out_chans[MAX_SLOTS];
  int out_format[MAX_SLOTS];
  int out_bytes[MAX_SLOTS];
  int samples_per_chan;
  int last_device;
  int devices[MAX_SLOTS];
  int available_chans[MAX_SLOTS];
  int min_chans[MAX_SLOTS];
  int max_chans[MAX_SLOTS];
  int alloc_chans;
  off_t start = 0, end = 0;
  double begin_time = 0.0, end_time = 0.0, volume = 1.0;
  int use_volume = 0;

  /* -describe => call mus_audio_describe and exit
   * -buffers axb => set OSS fragment numbers 
   */
  for (i = 1; i < argc; i++)
    {
      if (strcmp(argv[i], "-describe") == 0)
	{
	  mus_audio_describe(); 
	  exit(0);
	}
      else 
	{
	  if (strcmp(argv[i], "-buffers") == 0) 
	    {
	      set_buffers(argv[i+1]); 
	      i++;
	    }
	  else
	    {
	      if (strcmp(argv[i], "-start") == 0) 
		{
		  begin_time = atof(argv[i + 1]);
		  i++;
		}
	      else
		{
		  if (strcmp(argv[i], "-end") == 0) 
		    {
		      end_time = atof(argv[i + 1]);
		      i++;
		    }
		  else
		    {
		      if (strcmp(argv[i], "-volume") == 0)
			{ 
			  volume = atof(argv[i + 1]);
			  use_volume = 1;
			  i++; 
			} 
		      else name = argv[i];
		    }}}}}
  afd0 = -1;
  afd1 = -1;
  if (!(MUS_HEADER_TYPE_OK(mus_sound_header_type(name))))
    {
      fprintf(stderr, "can't play %s (header type: %s?)\n",
	      name,
	      mus_header_type_name(mus_header_type()));
      exit(0);
    }
  if (!(MUS_DATA_FORMAT_OK(mus_sound_data_format(name))))
    {
      fprintf(stderr, "can't play %s (data format: %s (%s)?)\n",
	      name,
	      mus_data_format_name(mus_sound_data_format(name)),
	      mus_header_original_format_name(mus_sound_original_format(name), 
					      mus_sound_header_type(name)));
      exit(0);
    }
  fd = mus_sound_open_input(name);
  if (fd != -1)
    {
      /* try to select proper device */
      float dir;
      int cards, card;
      int sysdev, devs, dev, d, i, im;
      int first_samples_per_chan = -1;
      cards = mus_audio_systems();
      /* deselect all devices */
      for (d = 0; d < MAX_SLOTS; d++) 
	{
	  out_devs[d] = -1;
	  afd[d] = -1;
	}
      /* Scan all cards and build a list of available output devices.
	 This is evil because it second guesses the intentions of the
	 user, best would be to have a command line parameter that
	 points to the device or devices to be used. For things to 
	 work under alsa .5 and multichannel cards it has to be here.
	 Hopefully the need will go away (in alsa .6 it will definitely
	 not be needed).
      */
      i = 0;
      im = 0;
      for (card = 0; card < cards; card++) 
	{
	  /* get the list of all available devices */
	  mus_audio_mixer_read(MUS_AUDIO_PACK_SYSTEM(card), MUS_AUDIO_PORT, MAX_SLOTS, val);
	  devs = (int)(val[0]);
	  for (d = 0; d < devs; d++) 
	    {
	      dev = (int)(val[d + 1]);
	      sysdev = MUS_AUDIO_PACK_SYSTEM(card)|dev;
	      mus_audio_mixer_read(sysdev, MUS_AUDIO_DIRECTION, 0, &dir);
	      /* only consider output devices */
	      if ((int)dir == 0) 
		{
		  float ch[4];
		  /* get the number of channels the device supports */
		  mus_audio_mixer_read(sysdev, MUS_AUDIO_CHANNEL, 4, ch);
		  available_chans[i] = (int)(ch[0]);
		  if ((int)ch[2] != 0) /* alsa also sets min and max channels */
		    {
		      min_chans[i] = (int)(ch[1]);
		      max_chans[i] = (int)(ch[2]);
		    }
		  if (max_chans[i] > max_chans[im]) im = i;
		  /* find out what format we can use with the device */
		  out_format[i] = mus_audio_compatible_format(sysdev);
		  /* find out what buffer size the device wants */
		  mus_audio_mixer_read(sysdev, MUS_AUDIO_SAMPLES_PER_CHANNEL, 2, ch);
		  samples_per_chan = (int)ch[0];
		  /* skip device if it has different buffer size, all must match */
		  if (first_samples_per_chan == -1) 
		    first_samples_per_chan = samples_per_chan;
		  else
		    if (samples_per_chan != first_samples_per_chan) 
		      continue;
		  devices[i++] = sysdev;
		  if (i >= MAX_SLOTS) 
		    goto NO_MORE_DEVICES;
		}
	    }
	}
    NO_MORE_DEVICES:
      last_device = i;
      chans = mus_sound_chans(name);
      allocated = 0;
      if (available_chans[im] >= chans)
	{
	  /* the widest device is wide enough to play all channels so we use it */
	  out_devs[allocated] = im;
	  out_chans[allocated] = chans;
	  if (chans < min_chans[im])
	    out_chans[allocated] = min_chans[im];
	  alloc_chans = out_chans[allocated];
	  allocated++;
	}
      else
	{
	  alloc_chans = 0;
	  if (use_one_device == 0) 
	    {
	      /* allocate devices until all channels can be played */
	      for (i = 0; i < last_device; i++) 
		{
		  out_devs[allocated] = i;
		  out_chans[allocated] = available_chans[i];
		  alloc_chans += available_chans[out_devs[allocated]];
		  allocated++;
		  if (alloc_chans >= chans) 
		    break;
		}
	    }
	  if (alloc_chans < chans)
	    {
	      /* FOR NOW, fail the program, not enough channels... */

	      fprintf(stderr, "not enough channels, %d available, %d needed\n", 
		      available_chans[0], chans);
	      exit(1);

	      /* either not enough channels found or have to use just
		 one device and the widest can't do it, so fold all of
		 them into whatever the first device can do */
	      allocated = 0;
	      out_devs[allocated] = 0;
	      out_chans[allocated] = available_chans[0];
	      alloc_chans = out_chans[allocated];
	      allocated++;
	    }
	}
      srate = mus_sound_srate(name);
      frames = mus_sound_frames(name);
      base = 0;
      start = (off_t)(begin_time * srate);
      if (start > 0)
	mus_file_seek_frame(fd, start);
      if (end_time > 0.0)
	end = (off_t)(end_time * srate);
      else end = frames;
      if ((end - start) < frames)
	frames = end - start;
      /* allocate the list of read buffers, each buffer will hold one channel
	 of the input soundfile, each sample is going to be mus_sample_t
      */
      read_bufs = (mus_sample_t **)calloc(alloc_chans, sizeof(mus_sample_t *));
      for (d = 0; d < allocated; d++)
	{
	  int dev = out_devs[d];
	  for (i = 0; i < out_chans[d]; i++) 
	    read_bufs[base + i] = (mus_sample_t *)calloc(samples_per_chan, sizeof(mus_sample_t));
	  base += out_chans[d];
	  out_bytes[dev] = samples_per_chan * out_chans[d] * mus_bytes_per_sample(out_format[dev]);
	  out_buf[dev] = (short *)calloc(out_bytes[dev], 1);
	}
      for (ioff = 0; ioff < frames; ioff += samples_per_chan)
	{
	  mus_sample_t **dev_bufs = read_bufs;
	  if ((ioff + samples_per_chan) <= frames)
	    curframes = samples_per_chan;
	  else 
	    {
	      curframes = frames - ioff;
	      for (d = 0; d < allocated; d++)
		{
		  int f, dev = out_devs[d];
#if 1
		  /* try to kludge around an ALSA bug... */
		  for (f = 0; f < chans; f++) 
		    memset(read_bufs[f], 0, samples_per_chan * sizeof(mus_sample_t));
#endif
		  out_bytes[dev] = curframes * out_chans[d] * mus_bytes_per_sample(out_format[dev]);
		}
	    }
	  mus_file_read(fd, 0, curframes - 1, chans, read_bufs); 
	  if (use_volume) 
	    set_volume(read_bufs, chans, curframes, volume); 
	  /* some systems are happier if we read the file before opening the dac */
	  /* at this point the data is in separate arrays of mus_sample_t */
	  for (d = 0; d < allocated; d++)
	    {
	      int dev = out_devs[d];
	      mus_file_write_buffer(out_format[dev],
				    0, curframes - 1,
				    out_chans[d],
				    dev_bufs,
				    (char *)(out_buf[dev]),
				    0);
	      if (afd[dev] == -1)
		{
#if defined(PPC)
		  afd[dev] = mus_audio_open_output(devices[dev], srate, out_chans[d], out_format[dev], 0);
#else
		  afd[dev] = mus_audio_open_output(devices[dev], srate, out_chans[d], out_format[dev], out_bytes[dev]);
#endif
		  if (afd[dev] == -1) break; 
		}
	      mus_audio_write(afd[dev], (char *)out_buf[dev], out_bytes[dev]);
	      dev_bufs += out_chans[d];
	    }
	}
      for (d = 0; d < allocated; d++)
	{
	  int dev = out_devs[d];
	  if (afd[dev] != -1) mus_audio_close(afd[dev]);
	}
      mus_sound_close_input(fd);
      for (i = 0; i < alloc_chans; i++) free(read_bufs[i]);
      free(read_bufs);
      for (d = 0; d < allocated; d++)
	{
	  int dev = out_devs[d];
	  free(out_buf[dev]);
	}
    }
  return(0);
}
Esempio n. 5
0
int main(int argc, char *argv[])
{
  int chans, srate, ctr;
  mus_sample_t samp_type;
  mus_header_t type;
  mus_long_t samples;
  float length = 0.0;
  time_t date;
  int *loops = NULL;
  char *comment, *header_name;
  char *samp_type_info = NULL, *samp_type_name, *ampstr = NULL;
  char timestr[64];
  if (argc == 1) {printf("usage: sndinfo file\n"); exit(0);}
  mus_sound_initialize();
  for (ctr = 1; ctr < argc; ctr++)
    {
      if (mus_file_probe(argv[ctr])) /* see if it exists */
	{
	  date = mus_sound_write_date(argv[ctr]);
	  srate = mus_sound_srate(argv[ctr]);
	  if (srate == MUS_ERROR)
	    {
	      fprintf(stdout, "%s: not a sound file?\n", argv[ctr]);
	      continue;
	    }
	  chans = mus_sound_chans(argv[ctr]);
	  samples = mus_sound_samples(argv[ctr]);
	  comment = mus_sound_comment(argv[ctr]); 
	  if ((chans > 0) && (srate > 0))
	    length = (float)((double)samples / (double)(chans * srate));
	  loops = mus_sound_loop_info(argv[ctr]);
	  type = mus_sound_header_type(argv[ctr]);
	  header_name = (char *)mus_header_type_name(type);
	  samp_type = mus_sound_sample_type(argv[ctr]);
	  if (samp_type != MUS_UNKNOWN_SAMPLE)
	    samp_type_info = (char *)mus_sample_type_name(samp_type);
	  else
	    {
	      int orig_type;
	      if (samp_type_info == NULL) samp_type_info = (char *)calloc(64, sizeof(char));
	      orig_type = mus_sound_original_sample_type(argv[ctr]);
	      samp_type_name = (char *)mus_header_original_sample_type_name(orig_type, type);
	      if (samp_type_name)
		snprintf(samp_type_info, 64, "%d (%s)", orig_type, samp_type_name);
	      else snprintf(samp_type_info, 64, "%d", orig_type);
	    }
	  fprintf(stdout, "%s:\n  srate: %d\n  chans: %d\n  length: %f",
		  argv[ctr], srate, chans, length);
	  if (length < 10.0)
	    {
	      int samps;
	      samps = mus_sound_framples(argv[ctr]);
	      fprintf(stdout, " (%d sample%s)", samps, (samps != 1) ? "s" : "");
	    }
	  fprintf(stdout, "\n");
	  fprintf(stdout, "  header type: %s\n  sample type: %s\n  ",
		  header_name,
		  samp_type_info);

	  strftime(timestr, 64, "%a %d-%b-%Y %H:%M %Z", localtime(&date));
	  fprintf(stdout, "written: %s", timestr);

	  if ((chans > 0) && (mus_sound_maxamp_exists(argv[ctr])))
	    {
	      ampstr = display_maxamps(argv[ctr], chans);
	      if (ampstr) fprintf(stdout, "%s", ampstr);
	    }
	  fprintf(stdout, "\n");
	  if (comment) fprintf(stdout, "  comment: %s\n", comment);
	  if (loops)
	    {
	      fprintf(stdout, "  loop: %d to %d\n", loops[0], loops[1]);
	      if (loops[2] != 0)
		fprintf(stdout, "  loop: %d to %d\n", loops[2], loops[3]);
	      if (loops[0] != 0)
		fprintf(stdout, "    base: %d, detune: %d\n", loops[4], loops[5]);
	    }
	}
      else
	fprintf(stderr, "%s: %s\n", argv[ctr], strerror(errno));
      if (ctr < argc - 1) fprintf(stdout, "\n");
    }
  return(0);
}