Esempio n. 1
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. 2
0
/* Create a soundfile header of the specified type. The usage msg above
   describes the kind of types you can create. (These are ones that
   sndlib can write and that can be useful to the average cmix user.
   There are other kinds of header sndlib can write -- for example,
   for 24-bit files -- but we want to keep the sfcreate syntax as
   simple as possible.

   We allocate a generous comment area, because expanding it after a
   sound has already been written would mean copying the entire file.
   (We use comments to store peak stats -- see sys/sndlibsupport.c.)
*/
int
main(int argc, char *argv[])
{
   int         i, fd, result, overwrite_file, old_format, old_header_type=0;
   int         data_location, old_data_location, old_nsamps, old_datum_size;
   int         force = FALSE;
   struct stat statbuf;

   /* get name of this program */
   progname = strrchr(argv[0], '/');
   if (progname == NULL)
      progname = argv[0];
   else
      progname++;

   if (argc < 2)
      usage();

   for (i = 1; i < argc; i++) {
      char *arg = argv[i];

      if (arg[0] == '-') {
         switch (arg[1]) {
            case 'c':
               if (++i >= argc)
                  usage();
               nchans = atoi(argv[i]);
               break;
            case 'r':
               if (++i >= argc)
                  usage();
               srate = atoi(argv[i]);
               break;
            case 'i':
               is_short = TRUE;
               break;
            case 'f':
               is_short = FALSE;
               break;
            case 'b':
               endian = CREATE_BIG_ENDIAN;
               break;
            case 'l':
               endian = CREATE_LITTLE_ENDIAN;
               break;
            case 't':
               if (++i >= argc)
                  usage();
               strncpy(format_name, argv[i], FORMAT_NAME_LENGTH - 1);
               format_name[FORMAT_NAME_LENGTH - 1] = 0; /* ensure termination */
               break;
            case '-':
               if (strcmp(arg, "--force") == 0)
                  force = TRUE;
               else
                  usage();
               break;
            default:  
               usage();
         }
      }
      else
         sfname = arg;
   }
   if (sfname == NULL)
      usage();

   if (check_params())
      usage();

   old_data_location = old_format = old_datum_size = old_nsamps = 0;

   /* Test for existing file. If there is one, and we can read and write it,
      and the force flag is set, then we'll overwrite its header.  Note that
      we slap on a header even if the file doesn't have one already, as 
      would be the case with a raw sound file (or a precious text file...).
      If there isn't an existing file, we'll create a new one.
   */
   overwrite_file = FALSE;
   result = stat(sfname, &statbuf);
   if (result == -1) {
      if (errno == ENOENT) {       /* file doesn't exist, we'll create one */
         fd = open(sfname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
         if (fd == -1) {
            fprintf(stderr, "Error creating file \"%s\" (%s)\n",
                                                      sfname, strerror(errno));
            exit(1);
         }
      }
      else {
         fprintf(stderr,
              "File \"%s\" exists, but there was an error accessing it (%s)\n",
                                                      sfname, strerror(errno));
         exit(1);
      }
   }
   else {
      int drastic_change;

      overwrite_file = TRUE;

      /* File exists and we could stat it. If it's a regular file, open
         it and see if it looks like a sound file.
      */
      if (!S_ISREG(statbuf.st_mode)) {
         fprintf(stderr, "\"%s\" exists, but it's not a regular file.\n",
                                                                      sfname);
         exit(1);
      }
      fd = open(sfname, O_RDWR);
      if (fd == -1) {
         fprintf(stderr, "Error opening file (%s)\n", strerror(errno));
         exit(1);
      }
      if (sndlib_read_header(fd) == -1) {
         fprintf(stderr, "Error reading header (%s)\n", strerror(errno));
         exit(1);
      }
      old_header_type = mus_header_type();
      old_format = mus_header_format();
      if (NOT_A_SOUND_FILE(old_header_type)
                                         || INVALID_DATA_FORMAT(old_format)) {
         fprintf(stderr, "\nWARNING: \"%s\" exists, but doesn't look like "
                         "a sound file.\n\n", sfname);
         drastic_change = TRUE;
         old_header_type = MUS_RAW;
      }
      else if (old_header_type != header_type || old_format != data_format)
         drastic_change = TRUE;
      else
         drastic_change = FALSE;

      if (drastic_change && !force) {
         fprintf(stderr, "%s\n", OVERWRITE_WARNING);
         exit(1);
      }

      old_data_location = mus_header_data_location();
      old_nsamps = mus_header_samples();         /* samples, not frames */
      old_datum_size = mus_header_data_format_to_bytes_per_sample();
   }

   result = sndlib_write_header(fd, 0, header_type, data_format, srate, nchans,
                                                        NULL, &data_location);
   if (result == -1) {
      fprintf(stderr, "Error writing header (%s)\n", strerror(errno));
      exit(1);
   }

   /* If we're overwriting a header, we have to fiddle around a bit
      to get the correct data_size into the header.
      (These will not likely be the same if we're changing header types.)
   */
   if (overwrite_file) {
      int loc_byte_diff, datum_size, sound_bytes;

      /* need to do this again */
      if (sndlib_read_header(fd) == -1) {
         fprintf(stderr, "Error re-reading header (%s)\n", strerror(errno));
         exit(1);
      }

      if (data_format != old_format && old_header_type != MUS_RAW)
        if (! FORMATS_SAME_BYTE_ORDER(data_format, old_format))
            printf("WARNING: Byte order changed!\n");

      datum_size = mus_header_data_format_to_bytes_per_sample();

      loc_byte_diff = data_location - old_data_location;

      /* If the data locations have changed, we're effectively adding or
         subtracting sound data bytes. Depending on the number of bytes
         added, this could result in swapped channels or worse. We can't
         do anything about this, because our scheme for encoding peak stats
         in the header comment requires a fixed comment allocation in the
         header. (Otherwise, we could shrink or expand this to make things
         right.) The best we can do is warn the user.
      */
      if (loc_byte_diff) {
         if (loc_byte_diff > 0)
            printf("Losing %d bytes of sound data\n", loc_byte_diff);
         else if (loc_byte_diff < 0)
            printf("Gaining %d bytes of sound data\n", -loc_byte_diff);

         if (loc_byte_diff % datum_size)
            printf("%s\n", WORD_INTEGRITY_WARNING);
         else if (loc_byte_diff % (nchans * datum_size))
            printf("%s\n", CHANNEL_SWAP_WARNING);
         /* else got lucky: no shifted words or swapping */

         sound_bytes = (old_nsamps * old_datum_size) - loc_byte_diff;  
      }
      else                               /* same number of bytes as before */
         sound_bytes = old_nsamps * old_datum_size;  

      result = sndlib_set_header_data_size(fd, header_type, sound_bytes);
      if (result == -1) {
         fprintf(stderr, "Error updating header\n");
         exit(1);
      }

      close(fd);
   }
   else
      close(fd);

   return 0;
}
Esempio n. 3
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);
}
static sound_file *fill_sf_record(const char *name, sound_file *sf)
{
  int i;

  sf->data_location = mus_header_data_location();
  sf->samples = mus_header_samples();
  sf->data_format = mus_header_format();
  sf->srate = mus_header_srate();
  /* if (sf->srate < 0) sf->srate = 0; */
  sf->chans = mus_header_chans();
  /* if (sf->chans < 0) sf->chans = 0; */
  sf->datum_size = mus_bytes_per_sample(sf->data_format);
  sf->header_type = mus_header_type();
  sf->original_sound_format = mus_header_original_format();
  sf->true_file_length = mus_header_true_length();

  sf->comment_start = mus_header_comment_start();
  sf->comment_end = mus_header_comment_end();
  if (((sf->header_type == MUS_AIFC) || 
       (sf->header_type == MUS_AIFF) || 
       (sf->header_type == MUS_RF64) || 
       (sf->header_type == MUS_RIFF)) &&
      (mus_header_aux_comment_start(0) != 0))

    {
      sf->aux_comment_start = (mus_long_t *)calloc(4, sizeof(mus_long_t));
      sf->aux_comment_end = (mus_long_t *)calloc(4, sizeof(mus_long_t));
      for (i = 0; i < 4; i++)
	{
	  sf->aux_comment_start[i] = mus_header_aux_comment_start(i);
	  sf->aux_comment_end[i] = mus_header_aux_comment_end(i);
	}
    }

  sf->type_specifier = mus_header_type_specifier();
  sf->bits_per_sample = mus_header_bits_per_sample();
  sf->fact_samples = mus_header_fact_samples();
  sf->block_align = mus_header_block_align();
  sf->write_date = local_file_write_date(name);

  if ((sf->header_type == MUS_AIFF) || (sf->header_type == MUS_AIFC))
    {
      int *marker_ids, *marker_positions;
      sf->markers = mus_header_mark_info(&marker_ids, &marker_positions);
      if (sf->markers > 0)
	{
	  sf->marker_ids = (int *)malloc(sf->markers * sizeof(int));
	  sf->marker_positions = (int *)malloc(sf->markers * sizeof(int));
	  memcpy((void *)(sf->marker_ids), (void *)marker_ids, sizeof(int) * sf->markers);
	  memcpy((void *)(sf->marker_positions), (void *)marker_positions, sizeof(int) * sf->markers);
	}
    }

  if (mus_header_loop_mode(0) > 0)
    {
      sf->loop_modes = (int *)calloc(2, sizeof(int));
      sf->loop_starts = (int *)calloc(2, sizeof(int));
      sf->loop_ends = (int *)calloc(2, sizeof(int));
      for (i = 0; i < 2; i++)
	{
	  sf->loop_modes[i] = mus_header_loop_mode(i);
	  if ((sf->header_type == MUS_AIFF) || 
	      (sf->header_type == MUS_AIFC))
	    {
	      sf->loop_starts[i] = mus_header_mark_position(mus_header_loop_start(i)); 
	      sf->loop_ends[i] = mus_header_mark_position(mus_header_loop_end(i));
	    }
	  else
	    {
	      sf->loop_starts[i] = mus_header_loop_start(i); 
	      sf->loop_ends[i] = mus_header_loop_end(i);
	    }
	}
      sf->base_detune = mus_header_base_detune();
      sf->base_note = mus_header_base_note();
    }

  return(sf);
}
Esempio n. 5
0
/* ----------------------------------------------------------------- main --- */
int
main(int argc, char *argv[])
{
   int         i, replace, result, inswap, outswap;
   int         infd, outfd, intype, outtype, inheadersize, outheadersize;
   int         inclass, outclass, nchans, informat, outformat, srate, nsamps;
   int         limiter, dither, inpeak_uptodate;
   int         nbytes, inbytes, outbytes, durbytes, readbytes, bufcount;
   float       inpeak, specified_peak, desired_peak, actual_peak;
   double      factor, inskip, outskip, dur, empty;
   long        inskipbytes, outskipbytes, len, seeds[2];
   short       outbuf[BUFSIZE];
   float       inbuf[BUFSIZE];
   short       *bufp;
   char        *insfname, *outsfname;
   SFComment   insfc, outsfc;
   struct stat statbuf;

   /* get name of this program */
   progname = strrchr(argv[0], '/');
   if (progname == NULL)
      progname = argv[0];
   else
      progname++;

   if (argc == 1)
      usage();

   insfname = outsfname = NULL;
   replace = dither = inpeak_uptodate = bufcount = 0;
   inskip = outskip = dur = empty = 0.0;
   factor = inpeak = specified_peak = desired_peak = 0.0;

   for (i = 1; i < argc; i++) {
      char *arg = argv[i];

      if (arg[0] == '-') {
         switch (arg[1]) {
            case 'P':
               if (++i >= argc)
                  usage();
               desired_peak = (float)atof(argv[i]);
               break;
            case 'p':
               if (++i >= argc)
                  usage();
               specified_peak = (float)atof(argv[i]);
               break;
            case 'f':
               if (++i >= argc)
                  usage();
               factor = atof(argv[i]);
               break;
            case 'r':
               replace = 1;
               break;
            case 't':
               dither = 1;
               break;
            case 's':
               if (++i >= argc)
                  usage();
               inskip = atof(argv[i]);
               if (inskip < 0.0) {
                  fprintf(stderr, "Input file skip must be >= 0.\n");
                  exit(1);
               }
               break;
            case 'o':
               if (++i >= argc)
                  usage();
               outskip = atof(argv[i]);
               if (outskip < 0.0) {
                  fprintf(stderr, "Output file skip must be >= 0.\n");
                  exit(1);
               }
               break;
            case 'd':
               if (++i >= argc)
                  usage();
               dur = atof(argv[i]);
               if (dur <= 0.0) {
                  fprintf(stderr, "Duration must be greater than zero.\n");
                  exit(1);
               }
               break;
            case 'e':
               if (++i >= argc)
                  usage();
               empty = atof(argv[i]);
               if (empty < 0.0) {
                  fprintf(stderr, "Silence at end must be >= 0.\n");
                  exit(1);
               }
               break;
            default:  
               usage();
         }
      }
      else {
         if (insfname == NULL)
            insfname = arg;
         else if (outsfname == NULL)
            outsfname = arg;
         else
            usage();
      }
   }

   if (insfname == NULL) {
      fprintf(stderr, "You haven't specified an input file.\n");
      exit(1);
   }

   /* Print out the specified options. */

   if (replace)
      printf("Writing over input file.\n");
   if (inskip > 0.0)
      printf("Input skip = %f\n", inskip);
   if (outskip > 0.0)
      printf("Output skip = %f\n", outskip);
   if (dur > 0.0)
      printf("Rescale duration = %f\n", dur);
   if (empty > 0.0)
      printf("Writing %g seconds of silence at end.\n", empty);
   if (factor != 0.0)
      printf("Specified rescale factor = %f\n", factor);
   if (specified_peak > 0.0)
      printf("Specified peak of input file = %f\n", specified_peak);
   if (desired_peak > 0.0) {
      if (factor > 0.0) {
         printf("You specified both a factor and a desired peak ...");
         printf(" ignoring your desired peak.\n");
      }
      else {
         if (desired_peak > 32767.0) {
            printf("Desired peak is out of range ... clamping to 32767.\n");
            desired_peak = 32767.0;
         }
         else
            printf("Desired peak = %f\n", desired_peak);
      }
   }
   else
      desired_peak = 32767.0;
   if (dither)
      printf("Dithering algorithm requested.\n");


   /************************************************************************/
   /* SET UP FILES AND PARAMETERS                                          */
   /************************************************************************/

   /*** Input File *********************************************************/

   infd = open(insfname, O_RDONLY);
   if (infd == -1) {
      perror(progname);
      exit(1);
   }
   if (fstat(infd, &statbuf) == -1) {
      perror(progname);
      exit(1);
   }
   if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
      fprintf(stderr, "%s is not a regular file or a link.\n", insfname);
      exit(1);
   }

   result = sndlib_read_header(infd);
   if (result == -1) {
      fprintf(stderr, "Can't read header of %s (%s)\n",
                                                  insfname, strerror(errno));
      exit(1);
   }

   intype = mus_header_type();
   informat = mus_header_format();
   nchans = mus_header_chans();
   srate = mus_header_srate();
   inheadersize = mus_header_data_location();
   inclass = mus_header_data_format_to_bytes_per_sample();

   if (NOT_A_SOUND_FILE(intype) || INVALID_DATA_FORMAT(informat)) {
      fprintf(stderr, "\"%s\" probably not a sound file.\n", insfname);
      exit(1);
   }

   if (sndlib_get_current_header_comment(infd, &insfc) == -1) {
      fprintf(stderr, "Can't read peak stats for input file\n");
      exit(1);
   }

   printf("Input: %s\n", insfname);
   printf("%s", sndlib_print_current_header_stats(infd, &insfc, 2));

   if (!IS_FLOAT_FORMAT(informat))
      printf("NOTE: Input file is not floating point.\n");

   /* Store overall peak, in case we need it later. */
   if (SFCOMMENT_PEAKSTATS_VALID(&insfc)) {
      for (i = 0, inpeak = 0.0; i < nchans; i++) 
         if (insfc.peak[i] > inpeak)
            inpeak = insfc.peak[i];

      /* See if peak stats are up-to-date (i.e., file not modified after
         peak stats timetag).
      */
      inpeak_uptodate = sfcomment_peakstats_current(&insfc, infd);
   }
   if (!inpeak_uptodate)
      printf(BAD_PEAK_LOC_WARNING);   /* output header peak locs unreliable */

   /* Limiter turned on ... unless the rescale factor (whether computed or
      specified by user) multiplied by the input peak is not greater than
      32767, AND we're using up-to-date header peak stats or the input file
      has shorts. (See below.)  ... whew!
   */
   limiter = 1;

   /* If user doesn't give a rescale factor, we need the file (or specified)
      peak to calculate the factor.
   */
   if (factor == 0.0) {
      if (specified_peak) {                  /* use instead of header peak */
         if (inclass == SF_SHORT && specified_peak > 32767) {
            printf("Specified peak exceeds range of input file");
            printf(" ... resetting to 32767.\n");
            specified_peak = 32767.0;
         }
         inpeak = specified_peak;

         /* need sfm for calculating output peak stats at end */
         for (i = 0; i < nchans; i++)
            insfc.peak[i] = specified_peak;
      }
      else {                                 /* use peak from header */
         if (inpeak_uptodate)
            limiter = 0;
         else {
            if (inpeak == 0.0) {
               fprintf(stderr, NO_PEAK_AMP_MSG, progname);
               exit(1);
            }
            printf(STALE_PEAK_STATS_WARNING);
         }
         printf("Peak amplitude of input file is %f.\n", inpeak);
      }
      factor = ((double)desired_peak / (double)inpeak) + DBL_EPSILON;
      printf("Computed rescale factor = %f\n", factor);
   }
   else {
      if (inpeak_uptodate && factor * inpeak <= 32767.0)
         limiter = 0;
   }

   if (inclass == SF_SHORT && factor <= 1.0)
      limiter = 0;

   if (limiter)
      printf("Might get samples out of range ... turning on limiter.\n");


   /*** Output File ********************************************************/

   outclass = SF_SHORT;           /* we always rescale to shorts */

   outformat = IS_BIG_ENDIAN_FORMAT(informat) ?  MUS_BSHORT : MUS_LSHORT;

   /* If input header is a type that sndlib can't write, output to AIFF. */
   if (WRITEABLE_HEADER_TYPE(intype))
      outtype = intype;
   else {
      outtype = MUS_AIFC;
      outformat = MUS_BSHORT;
   }
   if (outtype == MUS_AIFC)
      mus_header_set_aifc(0);                    /* we want AIFF, not AIFC */

   if (replace) {                 /* will open 2 descriptors for same file */
      int      fd;
      FILE     *stream;

      /* Only way to know for sure if headersize will change is to write
         a temp file with the header that would go on the input file when
         the rescale is finished. (Note that even with the same header
         type, the input file may not have the same comment allocation
         that sndlib-savvy cmix maintains.)
      */
      stream = tmpfile();
      fd = fileno(stream);
      if (fd == -1) {
         fprintf(stderr, "Trouble preparing output header\n");
         exit(1);
      }
      if (sndlib_write_header(fd, 0, outtype, outformat, srate, nchans,
                                               NULL, &outheadersize) == -1) {
         fprintf(stderr, "Trouble preparing output header\n");
         exit(1);
      }
      close(fd);
      fclose(stream);  /* deleted automatically, since created with tmpfile */

      outsfname = insfname;
   }
   else {                         /* need to create a new short int file */
      int   fd;

      if (outsfname == NULL) {    /* no filename specified */
         long  size;
         char  suffix[] = ".rescale";

         /* Build and allocate output file name. */
         size = strlen(insfname) + strlen(suffix) + 1;
         if (size > FILENAME_MAX) {
            fprintf(stderr, "Output file name is too long!\n");
            exit(1);
         }
         outsfname = (char *)malloc(size);
         if (!outsfname) {
            perror("Can't malloc output file name");
            exit(1);
         }
         strcpy(outsfname, insfname);
         strcat(outsfname, suffix);
      }

      /* Check that file doesn't exist. */
      result = stat(outsfname, &statbuf);
      if (result == 0 || errno != ENOENT) {
         fprintf(stderr, "\"%s\" already exists.\n", outsfname);
         exit(1);
      }

      /* Create file; prepare and write header. */

      fd = open(outsfname, O_RDWR | O_CREAT | O_TRUNC, 0644);
      if (fd == -1) {
         fprintf(stderr, "Can't create file %s (%s)\n",
                                                  outsfname, strerror(errno));
         exit(1);
      }

      if (sndlib_write_header(fd, 0, outtype, outformat, srate, nchans,
                                               NULL, &outheadersize) == -1) {
         fprintf(stderr, "Trouble writing output header\n");
         exit(1);
      }
      close(fd);                                 /* will reopen just below */
   }

   /* Open a file descriptor for the output file name (which might be the
      same as the input file name).
   */
   outfd = open(outsfname, O_RDWR);
   if (outfd == -1) {
      perror(progname);
      exit(1);
   }

   printf("Writing output to \"%s\"\n", outsfname);


   /*** Seek ***************************************************************/

   inskipbytes = (long)(inskip * srate * nchans * inclass);
   outskipbytes = (long)(outskip * srate * nchans * outclass);

   if (replace) {
      long outlead = (outskipbytes - inskipbytes)
                                           + (outheadersize - inheadersize);
      if ((BUFSIZE * outclass) + outlead > BUFSIZE * inclass) {
         fprintf(stderr, DANGEROUS_OVERWRITE_MSG);
         exit(1);
      }
      if (outskip > 0.0 && inheadersize > outheadersize)
         printf(OVERWRITE_CLICK_WARNING);
   }

   /* make sure it lands on sample block */
   inskipbytes -= inskipbytes % (inclass * nchans);
   if (lseek(infd, inskipbytes + inheadersize, SEEK_SET) == -1) {
      fprintf(stderr, "Bad skip on input file!\n");
      exit(1);
   }

   /* make sure it lands on sample block */
   outskipbytes -= outskipbytes % (outclass * nchans);
   if (lseek(outfd, outskipbytes + outheadersize, SEEK_SET) == -1) {
      fprintf(stderr, "Bad skip on output file!\n");
      exit(1);
   }

#if MUS_LITTLE_ENDIAN
   inswap = IS_BIG_ENDIAN_FORMAT(informat);
   outswap = IS_BIG_ENDIAN_FORMAT(outformat);
#else
   inswap = IS_LITTLE_ENDIAN_FORMAT(informat);
   outswap = IS_LITTLE_ENDIAN_FORMAT(outformat);
#endif


   /************************************************************************/
   /* RESCALE LOOP                                                         */
   /************************************************************************/

   printf("Rescaling....\n");
   fflush(stdout);

#ifdef INPUT_PEAK_CHECK
   actual_peak = inpeak;
#endif

   readbytes = inbytes = BUFSIZE * inclass;
   durbytes = dur * inclass * nchans * srate;

   bufp = (short *)inbuf;

   seeds[0] = 17;      /* seeds for dither */
   seeds[1] = 31;

   while (1) {
      double dblsamp;

      if (dur) {
         if (durbytes <= readbytes)
            inbytes = durbytes;
         durbytes -= inbytes;
      }

      nbytes = read(infd, (char *)inbuf, inbytes);
      if (nbytes == -1) {
         fprintf(stderr, "Read on input file failed (%s)\n", strerror(errno));
         close(infd);
         close(outfd);
         exit(1);
      }
      if (nbytes == 0)                  /* reached EOF -- time to stop */
         break;

      nsamps = nbytes / inclass;
      outbytes = nsamps * outclass;

      if (inswap) {
         if (inclass == SF_FLOAT) {
            for (i = 0; i < nsamps; i++)
               byte_reverse4(&inbuf[i]);
         }
         else {
            for (i = 0; i < nsamps; i++)
               byte_reverse2(&bufp[i]);
         }
      }

      if (limiter) {
         int  samp, clipmax, numclipped;

         clipmax = numclipped = 0;

         if (inclass == SF_FLOAT) {
            for (i = 0; i < nsamps; i++) {
#ifdef INPUT_PEAK_CHECK
               float fabsamp = fabs(inbuf[i]);
               if (fabsamp > actual_peak)
                  actual_peak = fabsamp;
#endif
               /* NB: Assigning to dblsamp seems to be necessary for accuracy.
                  "samp = (int)((double)inbuf[i] * factor)" was NOT always.
               */
               dblsamp = (double)inbuf[i] * factor;
               if (dither)
                  dblsamp += (double)drandom(seeds);
               samp = (int)dblsamp;

               if (samp < -32767) {             /* not -32768 */
                  if (samp < -clipmax)
                     clipmax = -samp;
                  samp = -32767;
                  numclipped++;
               }
               else if (samp > 32767) {
                  if (samp > clipmax)
                     clipmax = samp;
                  samp = 32767;
                  numclipped++;
               }
               outbuf[i] = (short)samp;
            }
         }
         else {                                 /* SF_SHORT */
            for (i = 0; i < nsamps; i++) {
#ifdef INPUT_PEAK_CHECK
               int absamp = ABS(bufp[i]);
               if (absamp > (int)actual_peak)
                  actual_peak = (float)absamp;
#endif
               dblsamp = (double)bufp[i] * factor;
               if (dither)
                  dblsamp += (double)drandom(seeds);
               samp = (int)dblsamp;

               if (samp < -32767) {             /* not -32768 */
                  if (samp < -clipmax)
                     clipmax = -samp;
                  samp = -32767;
                  numclipped++;
               }
               else if (samp > 32767) {
                  if (samp > clipmax)
                     clipmax = samp;
                  samp = 32767;
                  numclipped++;
               }
               outbuf[i] = (short)samp;
            }
         }
         bufcount++;
         if (numclipped) {
            float loc1 = (float)(((bufcount - 1) * BUFSIZE) / nchans)
                                                                / (float)srate;
            float loc2 = (float)((bufcount * BUFSIZE) / nchans) / (float)srate;
            if (outskip > 0.0) {
               loc1 += outskip;
               loc2 += outskip;
            }
            printf("  CLIPPING: %4d samps, max: %d, output time: %f - %f\n",
                   numclipped, clipmax, loc1, loc2);
         }
      }

      else {                                   /* !limiter */
         if (inclass == SF_FLOAT) {
            for (i = 0; i < nsamps; i++) {
#ifdef INPUT_PEAK_CHECK
               float fabsamp = fabs(inbuf[i]);
               if (fabsamp > actual_peak)
                  actual_peak = fabsamp;
#endif
               dblsamp = (double)inbuf[i] * factor;
               if (dither)
                  dblsamp += (double)drandom(seeds);
               outbuf[i] = (short)dblsamp;
            }
         }
         else {                                /* SF_SHORT */
            for (i = 0; i < nsamps; i++) {
#ifdef INPUT_PEAK_CHECK
               int absamp = ABS(bufp[i]);
               if (absamp > (int)actual_peak)
                  actual_peak = (float)absamp;
#endif
               dblsamp = (double)bufp[i] * factor;
               if (dither)
                  dblsamp += (double)drandom(seeds);
               outbuf[i] = (short)dblsamp;
            }
         }
      }

      if (outswap) {
         for (i = 0; i < nsamps; i++)
            byte_reverse2(&outbuf[i]);
      }

      nbytes = write(outfd, (char *)outbuf, outbytes);
      if (nbytes != outbytes) {
         fprintf(stderr, "Write on output file failed  %s\n",
                                      (nbytes == -1) ? strerror(errno) : "");
         close(infd);
         close(outfd);
         exit(1);
      }
   }


   /************************************************************************/
   /* CLEANUP                                                              */
   /************************************************************************/

   close(infd);

   if (empty > 0.0) {                   /* write empty buffers */
      int bytesleft, bufbytes;

      for (i = 0; i < BUFSIZE; i++)
         outbuf[i] = 0;

      bufbytes = BUFSIZE * outclass;
      bytesleft = empty * srate * nchans * outclass;
      outbytes = MIN(bufbytes, bytesleft);

      for ( ; bytesleft > 0; bytesleft -= bufbytes) {
         if (bytesleft < outbytes)
            outbytes = bytesleft;
         if (write(outfd, (char *)outbuf, outbytes) != outbytes) {
            fprintf(stderr, "Bad write on output file!\n");
            close(outfd);
            exit(1);
         }
      }
   }

   if (replace) {
      long pos = lseek(outfd, 0L, SEEK_CUR);
      if (ftruncate(outfd, pos) < 0) 
         fprintf(stderr, "Bad truncation!\n");   /* but keep going */
   }

   for (i = 0; i < nchans; i++) {
      double opk = (double)insfc.peak[i];
#ifdef INPUT_PEAK_CHECK
      if (actual_peak != inpeak)
         opk += (double)(actual_peak - inpeak);
#endif
      opk *= factor;
      outsfc.peak[i] = (short)MIN(opk, 32767.0);
      outsfc.peakloc[i] = insfc.peakloc[i];
   }

   if (replace) {                             /* replace the input header */
      if (sndlib_write_header(outfd, 0, outtype, outformat, srate, nchans,
                                               NULL, &outheadersize) == -1) {
         fprintf(stderr, "Can't write header on \"%s\"\n", outsfname);
         close(outfd);
         exit(1);
      }
   }

   /* Make a text comment giving command line that wrote this file. */
   outsfc.comment[0] = '\0';
   nbytes = MAX_COMMENT_CHARS - 1;
   for (i = 0; i < argc && nbytes > 1; i++) {
      strncat(outsfc.comment, argv[i], nbytes - 1);
      strcat(outsfc.comment, " ");
      nbytes -= strlen(argv[i]);
   }
   outsfc.comment[MAX_COMMENT_CHARS - 1] = '\0';

   /* Write the peak stats and comment. */
   result = sndlib_put_header_comment(outfd, outsfc.peak, outsfc.peakloc,
                                                             outsfc.comment);
   if (result == -1) {
      fprintf(stderr, "Can't write peak stats for \"%s\"\n", outsfname);
      close(outfd);
      exit(1);
   }

   /* Update header for bytes of sound data written. */
   len = lseek(outfd, 0, SEEK_END);
   if (len == -1) {
      perror(progname);
      exit(1);
   }
   if (sndlib_set_header_data_size(outfd, outtype,
                                              len - outheadersize) == -1) {
      fprintf(stderr, "Can't update header data size for \"%s\"\n", outsfname);
      exit(1);
   }

   if (close(outfd) == -1) {
      fprintf(stderr, "Error closing output file (%s)\n", strerror(errno));
      exit(1);
   }

   printf("...done\n");

#ifdef INPUT_PEAK_CHECK
   if (actual_peak != inpeak)
      printf("Actual input peak different from expected: %f\n", actual_peak);
#endif

   return 0;
}
Esempio n. 6
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. 7
0
/* ------------------------------------------------------ open_sound_file --- */
int
open_sound_file(
      const char     *funcname,       // for error messages
      const char     *sfname,         // name of sound file to open
      int     		 *header_type,    // Remaining args are pointers to storage for
      int     		 *data_format,    //    various bits of file header info.  If
      int     		 *data_location,  //    pointer is NULL, it will be ignored.
      double   		 *srate,          //    Info is undefined on error return (-1).
      int     		 *nchans,
      long     		 *nsamps)
{
   // See if file exists and is a regular file or link.
   struct stat sfst;
   if (stat(sfname, &sfst) == -1) {
      rterror(funcname, "\"%s\": %s", sfname, strerror(errno));
      return -1;
   }
   if (!S_ISREG(sfst.st_mode) && !S_ISLNK(sfst.st_mode)) {
      rterror(funcname, "\"%s\" is not a regular file or a link.\n", sfname);
      return -1;
   }

   // Open the file and read its header.
   int fd = sndlib_open_read(sfname);
   if (fd == -1) {
      rterror(funcname, "Can't read header from \"%s\" (%s)\n",
		   sfname, strerror(errno));
      return -1;
   }

   // Now info is available from sndlib query functions.

   int type = mus_header_type();

   if (NOT_A_SOUND_FILE(type)) {
      rterror(funcname, "\"%s\" is probably not a sound file\n", sfname);
      sndlib_close(fd, 0, 0, 0, 0);
      return -1;
   }

   int format = mus_header_format();

   if (INVALID_DATA_FORMAT(format)) {
      rterror(funcname, "\"%s\" has invalid sound data format\n", sfname);
      sndlib_close(fd, 0, 0, 0, 0);
      return -1;
   }

   if (!SUPPORTED_DATA_FORMAT(format)) {
      rterror(funcname, "Can't open \"%s\": can read only 16-bit integer, "
                        "24-bit integer and 32-bit float files.", sfname);
      sndlib_close(fd, 0, 0, 0, 0);
	  return -1;
   }

   if (header_type)
      *header_type = type;
   if (data_format)
      *data_format = format;
   if (data_location)
      *data_location = mus_header_data_location();
   if (srate)
      *srate = (double) mus_header_srate();
   if (nchans)
      *nchans = mus_header_chans();
   if (nsamps)
      *nsamps = mus_header_samples();

   return fd;
}