Logo Search packages:      
Sourcecode: wavsplit version File versions  Download package

wavsplit.c

/* WavSplit by Tobias Weihmann  */
/* Licensed under GPL           */
/* Contact: tobias@fomalhaut.de */
/* Updated to version 1.0.0 by Alan Fitch, apfitch@ieee.org */
/* Version 1.1.0 - fixed bug in TokenOK, fps can be set to 12 */
#include "wavsplit.h"

int main (int argc, char *argv[])
{
  int optch, i, splits;
  int option_index = 0;
  char *strtokPtr;

  static struct option long_options[] = {
    {OPF_QUIET_LONG, no_argument, 0, OPF_QUIET},
    {OPF_HELP_LONG, no_argument, 0, OPF_HELP},
    {OPF_HOURS_LONG, no_argument, 0, OPF_HOURS},
    {OPF_SECONDS_LONG, no_argument, 0, OPF_SECONDS},
    {OPF_FRAMES_LONG, required_argument, 0, OPF_FRAMES},
    {0, 0, 0, 0}
  };

  unsigned int UseHours, UseFrames, UseSeconds, fps;
  char cmdopts[] =
    { OPF_QUIET, OPF_HELP, OPF_HOURS, OPF_SECONDS, OPF_FRAMES, ':' };

  timepos splitpos[argc - 1];

  verbose = DEFAULT_VERBOSE;
  UseHours = DEFAULT_HOURS;
  UseFrames = DEFAULT_FRAMES;
  UseSeconds = DEFAULT_SECONDS;
  fps = DEFAULT_FPS;

  if (verbose) {
    printf ("\nWAVSPLIT version %s (http://www.fomalhaut.de)\n", VERSION);
    printf ("Licensed under GPL by author Tobias Weihmann\n");
    printf ("Hour patch by Sacha Bartok (sacha@myrealbox.com)\n");
    printf
      ("Modified for frames, hours, seconds, decimal seconds by Alan Fitch\n\n");
  }
  while ((optch = getopt_long (argc, argv, cmdopts, long_options,
                               &option_index)) != -1) {
    switch (optch) {
    case OPF_QUIET:
    case 0:
      verbose = 0;
      Report ("Quiet option selected", "INFO", verbose);
      break;
    case OPF_HELP:
      usage ();
      return 1;
    case OPF_HOURS:
      UseHours = 1;
      Report ("Hours:mins:sec format selected", "INFO", verbose);
      break;
    case OPF_SECONDS:
      UseSeconds = 1;
      Report ("Seconds only option selected", "INFO", verbose);
      break;
    case OPF_FRAMES:
      UseFrames = 1;
      Report ("Frames options selected", "INFO", verbose);
      if (optarg) {
        fps = atoi (optarg);
        if (!checkfps (fps)) {
          Report ("Frames argument must be 12, 24, 25, or 30", "ERROR",
                  verbose);
        }
      }
      else {
        Report ("Missing argument to frames option 12, 24, 25, or 30 fps",
                "ERROR", verbose);
      }
      break;
    default:
      usage ();
      return 1;
    }
  }
  if (optind + 1 >= argc) {
    usage ();
    return 1;
  }

  if ((UseHours == 1) && (UseSeconds == 1)) {
    Report
      ("You selected time in just seconds, and in hours - only one is allowed",
       "ERROR", verbose);
  }

  strcpy (ifile, argv[optind]);
  strcpy (basename, ifile);
  if (strcmp (basename + strlen (basename) - 4, ".wav") == 0 ||
      strcmp (basename + strlen (basename) - 4, ".WAV") == 0)
    basename[strlen (basename) - 4] = '\0';

  for (i = 0; i < argc - (optind + 1); i++) {
    splitpos[i].hr = 0;
    splitpos[i].min = 0;
    splitpos[i].sek = 0.0;
    splitpos[i].seki = 0;
    splitpos[i].frames = 0;

    if (UseSeconds) {
      if (UseFrames) {
        strtokPtr = strtok (argv[optind + 1 + i], ":");
        splitpos[i].seki = atoi (strtokPtr);
        if (!TokenOK ("Frame Counter", &strtokPtr))
          return 1;
        splitpos[i].frames = atof (strtokPtr);
      }
      else {                    /* not using frames */
        splitpos[i].sek = atof (argv[optind + 1 + i]);
      }                         /* end if useframes */
    }
    else {                      /* not using seconds */
      strtokPtr = strtok (argv[optind + 1 + i], ":");
      if (UseHours) {
        splitpos[i].hr = atoi (strtokPtr);
        if (!TokenOK ("Minutes", &strtokPtr))
          return 1;
        splitpos[i].min = atoi (strtokPtr);
      }
      else {                    /* not usehours */
        splitpos[i].min = atoi (strtokPtr);
      }                         /* end if usehours */

      if (UseFrames) {
        /* expect integer seconds followed by floating point frames */
        if (!TokenOK ("Seconds", &strtokPtr))
          return 1;
        splitpos[i].seki = atoi (strtokPtr);

        if (!TokenOK ("Frame Counter", &strtokPtr))
          return 1;
        splitpos[i].frames = atof (strtokPtr);
      }                         /* not useframe */
      else {
        /* expect floating point seconds and no frames */
        if (!TokenOK ("Seconds", &strtokPtr))
          return 1;

        splitpos[i].sek = atof (strtokPtr);
      }                         /* end if useframes */
    }                           /* end if useseconds */

    /* Check that values are valid */
    if (UseFrames) {
      if (!((splitpos[i].frames > 0.0) && (splitpos[i].frames < (float) fps))) {
        Report
          ("When using frames, value must be >= 0.0  and < Frames Per Second",
           "ERROR", verbose);
      }
    }
    if (!UseSeconds) {
      if (!((splitpos[i].sek >= 0.0) && (splitpos[i].sek < 60.0))) {
        Report ("Seconds must be >= 0.0  and < 60.0", "ERROR", verbose);
      }
      if (!((splitpos[i].seki >= 0) && (splitpos[i].seki < 60))) {
        Report ("Seconds must be >= 0  and < 60", "ERROR", verbose);
      }
      if (UseHours && !((splitpos[i].min >= 0) && (splitpos[i].min < 60))) {
        Report ("When using Hours, minutes must be >= 0  and < 60", "ERROR",
                verbose);
      }
    }                           /* end if !useseconds */

  }                             /* end for */
  splits = i;

  if (mkdir (basename, 0777) == -1) {
    if (errno == EEXIST) {
      //if (verbose) fprintf(stderr,"Directory already exists, not creating.\n");
    }
    else {
      fprintf (stderr, "Could not create output directory.\n");
      return 1;
    }
  }

  ifd = open (ifile, O_RDONLY);
  if (ifd == -1) {
    fprintf (stderr, "Could not open file.\n");
    return 1;
  }
  if (readheader () > 0)
    return 1;
  if (split (UseHours, UseFrames, fps, splits, splitpos) > 0)
    return 1;
  close (ifd);

  return 0;
}

void usage ()
{
  printf ("Usage: wavsplit [options] wavfile split split split...\n\n");
  printf ("Options:\n");
  printf ("\t-%c\t--%s\t\tQuiet mode (no messages)\n", OPF_QUIET,
          OPF_QUIET_LONG);
  printf ("\t-%c\t--%s\t\tUse Hours\n", OPF_HOURS, OPF_HOURS_LONG);
  printf ("\t\t\t\twavsplit [options] wavfile hr:min:sec [hr:min:sec]...\n");
  printf ("\t-%c\t--%s FPS\tuse Frames\n", OPF_FRAMES, OPF_FRAMES_LONG);
  printf
    ("\t\t\t\tFPS (frames per second) must be either 12, 24, 25, or 30\n");
  printf ("\t\t\t\twavsplit [options] wavfile min:sec:fr [min:sec:fr]...\n");
  printf ("\t-%c\t--%s\tUse Seconds\n", OPF_SECONDS, OPF_SECONDS_LONG);
  printf ("\t\t\t\twavsplit [options] wavfile sec [sec]...\n");
  printf ("\t-%c\t--%s\t\tThis info\n", OPF_HELP, OPF_HELP_LONG);
  printf ("\nYou can combine both Hours and frames options\n");
  printf ("\nExamples:\n");
  printf ("\t\t\twavsplit --frames 30 file.wav 32:21:15 45:10:0\n");
  printf ("\t\t\twavsplit --Hours file.wav 1:32:21:59.2 1:45:10:0.3\n");
  printf ("\t\t\twavsplit --seconds file.wav 300.1 500.2\n\n");
}

void Report (const char *Message, const char *Severity, int Verbose)
{
  int IsError = !strcmp (Severity, "ERROR");
  int IsInfo = !strcmp (Severity, "INFO");
  assert (IsError || IsInfo);
  if ((IsInfo) && (Verbose))
    printf ("%s: %s\n", Severity, Message);
  if (IsError)
    fprintf (stderr, "%s: %s\n", Severity, Message);
  if (IsError)
    exit (1);
}

int TokenOK (const char *Message, char **strPtr)
{
  *strPtr = strtok (NULL, ":");
  if (*strPtr == NULL) {
    fprintf (stderr, "ERROR: wavsplit: Argument error, expecting %s\n",
             Message);
    exit (1);
  }
  return 1;
}

int checkfps (unsigned int fps)
{
  return (fps == 12) || (fps == 24) || (fps == 25) || (fps == 30);
}

int split (unsigned int UseHours, unsigned int UseFrames,
           unsigned int fps, int splits, timepos * split)
{
  char *buf, *bp_out;
  long to_write, to_read, n_read, pos;
  int fnr = 0;
  unsigned long in_blk_size;
  struct stat stat_buf;

  /* Buffer reservieren */
  if (fstat (ifd, &stat_buf) < 0) {
    fprintf (stderr, "Could not read input file state.\n");
    return 1;
  }
  in_blk_size = stat_buf.st_blksize;
  buf = malloc (in_blk_size + 1);
  if (buf == NULL) {
    fprintf (stderr, "Could not allocate %ld bytes of memory.\n",
             in_blk_size + 1);
    return 1;
  }
  /* if (verbose) printf("Allocated %ld bytes for buffer.\n", in_blk_size+1); */

  /* Erste Datei öffnen */
  to_write = calcsplit (UseHours, UseFrames, fps, fnr, split);
  pos = to_write;
  if (createout (fnr + 1, to_write) > 0)
    return 1;

  do {
    n_read = (long) stdread (buf, in_blk_size + 1);
    if (n_read < 0) {
      fprintf (stderr, "Error while reading.\n");
      return 1;
    }
    bp_out = buf;
    to_read = n_read;
    for (;;) {
      if (to_read < to_write) {
        if (to_read) {          /* do not write 0 bytes! */
          if (write (ofd, bp_out, to_read) == -1) {
            fprintf (stderr, "Error while writing.\n");
            return 1;
          }
          to_write -= to_read;
        }
        break;
      }
      else {
        if (write (ofd, bp_out, to_write) == -1) {
          fprintf (stderr, "Error while writing.\n");
          return 1;
        }
        bp_out += to_write;
        to_read -= to_write;

        if (++fnr < splits) {
          to_write = calcsplit (UseHours, UseFrames, fps, fnr, split) - pos;
        }
        else {
          to_write = databytes - pos;
          if (to_write == 0) {
            /* Nothing to write any more */
            n_read = 0;
            break;
          }
          else {
            if (verbose)
              printf
                ("[%02d]\tuntil the end                %12ld   100.00%%\n",
                 fnr + 1, databytes);
          }
        }
        pos += to_write;
        close (ofd);
        if (to_write > 0) {
          if (createout (fnr + 1, to_write) > 0)
            return 1;
        }
      }
    }
  }
  while (n_read == in_blk_size + 1);

  if (verbose)
    printf ("Success.\n\n");
  close (ofd);

  free (buf);
  return 0;
}

void display (unsigned char avgleft, unsigned char avgright,
              unsigned char avgloud)
{
  int min, sec, percent;
  min = b / (waveformat.dwSamplesPerSec / 2 * 60);
  sec = b / (waveformat.dwSamplesPerSec / 2) - min * 60;
  percent = (b * 100) / (databytes / waveformat.wBlockAlign);
  printf ("\r[%d:%02d]\t%3d%%\tL=%3d%%\tR=%3d%%\tAVG=%3d%%   ", min, sec,
          percent, avgleft, avgright, avgloud);
  fflush (stdout);
}

int readheader ()
{
  char ibuffer[BUFFERSIZE];
  u_long offset;

  if (lseek (ifd, 0L, SEEK_SET)) {
    fprintf (stderr, "Could not locate beginning of input file\n");
    return 1;
  }

  read (ifd, ibuffer, BUFFERSIZE);
  if (findchunk (ibuffer, "RIFF", BUFFERSIZE) != ibuffer) {
    fprintf (stderr, "Bad format: Cannot find RIFF file marker\n");
    return 1;
  }
  if (!findchunk (ibuffer, "WAVE", BUFFERSIZE)) {
    fprintf (stderr, "Bad format: Cannot find WAVE file marker\n");
    return 1;
  }
  ptr = findchunk (ibuffer, "fmt ", BUFFERSIZE);
  if (!ptr) {
    fprintf (stderr, "Bad format: Cannot find 'fmt' file marker\n");
    return 1;
  }

#ifdef __powerpc__
  _ConvertHeaderToNative ((WAVE_HEADER *) ibuffer);
#endif

  ptr += 4;                     /* we move past fmt_ */
  memcpy (&waveformat, ptr, sizeof (WAVEFORMAT));

  if (waveformat.dwSize < (sizeof (WAVEFORMAT) - sizeof (u_long))) {
    fprintf (stderr, "Bad format: Bad fmt size\n");
    return 1;
  }

  if (waveformat.wFormatTag != PCM_WAVE_FORMAT) {
    fprintf (stderr, "Only supports PCM wave format\n");
    fprintf (stderr, "tag = %d, PCM = %x\n", waveformat.wFormatTag,
             PCM_WAVE_FORMAT);
    return 1;
  }

  ptr = findchunk (ibuffer, "data", BUFFERSIZE);

  if (!ptr) {
    fprintf (stderr, "Bad format: unable to find 'data' file marker");
    return 1;
  }

  ptr += 4;                     /* we move past data */
  memcpy (&databytes, ptr, sizeof (u_long));

  offset = (u_long) ptr + 4 - (u_long) ibuffer;
  if (lseek (ifd, offset, SEEK_SET) == -1) {
    fprintf (stderr, "Error seeking to WAV data at %lu\n", offset);
    return 1;
  }

  if (verbose) {
    printf ("Channels: %d\n", waveformat.wChannels);
    printf ("Samplerate: %ldHz\n", waveformat.dwSamplesPerSec);
    printf ("Samplebits: %d\n", waveformat.wBitsPerSample);
    printf ("Databytes: %ld\n\n", databytes);
    printf ("Split         Hours  Mins   Seconds         Bytes         %%\n");
    //printf("Blocks: %ld\n",databytes/waveformat.wBlockAlign);
  }

  if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec /
      waveformat.wBlockAlign) {
    fprintf (stderr, "Bad file format\n");
    return 1;
  }

  if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec /
      waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {
    fprintf (stderr, "Bad file format\n");
    return 1;
  }

  return 0;
}

char *findchunk (char *pstart, char *fourcc, size_t n)
{
  char *pend;
  int k, test;
  pend = pstart + n;
  while (pstart < pend) {
    if (*pstart == *fourcc) {   /* found match for first char */
      test = 1;
      for (k = 1; fourcc[k] != 0; k++)
        test = (test ? (pstart[k] == fourcc[k]) : 0);
      if (test)
        return pstart;
    };
    pstart++;
  };
  return NULL;
}

int createout (int num, long datasize)
{
  char ofile[MAX_PATH + 1];
  sprintf (ofile, "%s/%02d.wav", basename, num);
  ofd = creat (ofile, S_IRWXU);
  if (ofd == -1) {
    printf ("Could not create output file '%s'.\n", ofile);
    return 1;
  }
  waveheader.RiffSize = sizeof (WAVE_HEADER) + datasize - 8;
  waveheader.wFormatTag = PCM_WAVE_FORMAT;
  waveheader.nChannels = waveformat.wChannels;
  waveheader.nSamplesPerSec = waveformat.dwSamplesPerSec;
  waveheader.nAvgBytesPerSec = waveformat.dwAvgBytesPerSec;
  waveheader.nBlockAlign = waveformat.wBlockAlign;
  waveheader.wBitsPerSample = waveformat.wBitsPerSample;
  waveheader.nDataBytes = datasize;
#ifdef __powerpc__
  _ConvertHeaderFromNative (&waveheader);
#endif
  if (write (ofd, &waveheader, sizeof (WAVE_HEADER)) != sizeof (WAVE_HEADER)) {
    fprintf (stderr, "Could not write header.\n");
    return 1;
  }
#ifdef __powerpc__
  _ConvertHeaderToNative (&waveheader);
#endif
  return 0;
}

/* Calculate split point in samples as follows
UseHours =0, UseFrames = 0:
    TimeFloat min * 60.0 + sek;
    
UseHours = 0, UseFrames= 1:
    TimeFloat = min * 60.0 + sek + (frames/fps);

UseHours = 1, UseFrames =0:
    TimeFloat = hr* 3600.0 + min * 60.0 + sek;

UseHours = 1, UseFrames =1:
    TimeFloat = hr* 3600.0 + min * 60.0 + sek + (frames/fps);

*/
long calcsplit (unsigned int UseHours, unsigned int UseFrames,
                unsigned int fps, int splitnr, timepos * split)
{
  double TimeFloat = 0.0;
  long pos;
  unsigned int Opt = 2 * UseHours + UseFrames;

  switch (Opt) {
  case 0:                      /* UseHours =0, UseFrames = 0 */
    TimeFloat = (double) split[splitnr].min * 60.0 + split[splitnr].sek;
    break;                      /* UseHours =0, UseFrames = 1 */
  case 1:
    TimeFloat = (double) split[splitnr].min * 60.0 +
      (double) split[splitnr].seki +
      (double) split[splitnr].frames / (double) fps;
    break;
  case 2:                      /* UseHours = 1, UseFrames = 0 */
    TimeFloat = (double) split[splitnr].hr * 3600.0 +
      (double) split[splitnr].min * 60.0 + split[splitnr].sek;
    break;
  case 3:                      /* UseHours = 1, UseFrames = 1 */
    TimeFloat = (double) split[splitnr].hr * 3600.0 +
      (double) split[splitnr].min * 60.0 +
      (double) split[splitnr].seki +
      (double) split[splitnr].frames / (double) fps;
    break;
  default:
    break;
  }

  /* first calculate to the nearest sample, then scale by the  */
  /* block size to avoid getting e.g. half a block */

  pos = (long) ((TimeFloat * (double) waveformat.dwSamplesPerSec));
  pos = pos * waveformat.wBlockAlign;

  if (verbose)
    printf ("[%02d]\tuntil %5d ", splitnr + 1, split[splitnr].hr);
  if (UseFrames)
    printf ("%5d  %8.3f  %12ld    %3.2f%%\n",
            split[splitnr].min,
            (double) split[splitnr].seki +
            ((double) split[splitnr].frames / (double) fps), pos,
            (float) pos / (float) databytes * 100);

  else
    printf ("%5d  %8.3f  %12ld    %3.2f%%\n",
            split[splitnr].min,
            split[splitnr].sek, pos, (float) pos / (float) databytes * 100);

  return pos;
}

long stdread (char *buf, long nchars)
{
  int n_read;
  int to_be_read = nchars;

  while (to_be_read) {
    n_read = read (ifd, buf, to_be_read);
    if (n_read < 0)
      return -1;
    if (n_read == 0)
      break;
    to_be_read -= n_read;
    buf += n_read;
  }
  return nchars - to_be_read;
}


#ifdef __powerpc__

static _ConvertHeaderToNative (WAVE_HEADER * hdr)
{
  /* Convert fields */
  hdr->FmtSize = _LE_long ((unsigned char *) &hdr->FmtSize);
  hdr->wFormatTag = _LE_short ((unsigned char *) &hdr->wFormatTag);
  hdr->nChannels = _LE_short ((unsigned char *) &hdr->nChannels);
  hdr->nSamplesPerSec = _LE_long ((unsigned char *) &hdr->nSamplesPerSec);
  hdr->nAvgBytesPerSec = _LE_long ((unsigned char *) &hdr->nAvgBytesPerSec);
  hdr->nBlockAlign = _LE_short ((unsigned char *) &hdr->nBlockAlign);
  hdr->wBitsPerSample = _LE_short ((unsigned char *) &hdr->wBitsPerSample);
  hdr->nDataBytes = _LE_long ((unsigned char *) &hdr->nDataBytes);
}

static _ConvertHeaderFromNative (WAVE_HEADER * hdr)
{
  /* Convert fields */
  hdr->FmtSize = _LE_long ((unsigned char *) &hdr->FmtSize);
  hdr->wFormatTag = _LE_short ((unsigned char *) &hdr->wFormatTag);
  hdr->nChannels = _LE_short ((unsigned char *) &hdr->nChannels);
  hdr->nSamplesPerSec = _LE_long ((unsigned char *) &hdr->nSamplesPerSec);
  hdr->nAvgBytesPerSec = _LE_long ((unsigned char *) &hdr->nAvgBytesPerSec);
  hdr->nBlockAlign = _LE_short ((unsigned char *) &hdr->nBlockAlign);
  hdr->wBitsPerSample = _LE_short ((unsigned char *) &hdr->wBitsPerSample);
  hdr->nDataBytes = _LE_long ((unsigned char *) &hdr->nDataBytes);
}

#endif

Generated by  Doxygen 1.6.0   Back to index