/*
 * April 15, 1992
 * Copyright 1992 Rick Richardson
 * Copyright 1991 Lance Norskog And Sundry Contributors
 * This source code is freely redistributable and may be used for
 * any purpose.  This copyright notice must be maintained. 
 * Lance Norskog And Sundry Contributors are not responsible for 
 * the consequences of using this software.
 */

/*
 * Windows 3.0 .wav format driver
 */

#include "st.h"

/* Private data for .wav file */
typedef struct wavstuff {
      long     samples;
} *wav_t;

extern float volume, amplitude;
extern int summary, verbose;

/*
 * Do anything required before you start reading samples.
 * Read file header. 
 *    Find out sampling rate, 
 *    size and style of samples, 
 *    mono/stereo/quad.
 */
wavstartread(ft) 
ft_t ft;
{
      wav_t   wav = (wav_t) ft->priv;
      char    magic[4];
      long    len;

      /* If you need to seek around the input file. */
      if (0 && ! ft->seekable)
              fail(".wav input file must be a file, not a pipe");

      fread(magic, 4, 1, ft->fp);
      if (strncmp("RIFF", magic, 4))
              fail("Not a RIFF file");

      len = rllong(ft);

      fread(magic, 4, 1, ft->fp);
      if (strncmp("WAVE", magic, 4))
              fail("Not a WAVE file");

      fread(magic, 4, 1, ft->fp);
      if (strncmp("fmt ", magic, 4))
              fail("Missing fmt spec");

      len = rllong(ft);
      switch (rlshort(ft))
      {
      case 1:         ft->info.style = UNSIGNED; break;
      default:        fail("Don't understand format");
      }
      ft->info.channels = rlshort(ft);
      ft->info.rate = rllong(ft);
      rllong(ft);     /* Average bytes/second */
      rlshort(ft);    /* Block align */
      switch (rlshort(ft))
      {
      case 8:         ft->info.size = BYTE; break;
      case 16:        ft->info.size = WORD; break;
      case 32:        ft->info.size = LONG; break;
      default:        fail("Don't understand size");
      }
      len -= 16;
      while (len) getc(ft->fp);

      fread(magic, 4, 1, ft->fp);
      if (strncmp("data", magic, 4))
              fail("Missing data portion");

      wav->samples = rllong(ft);
}

/*
 * Read up to len samples from file.
 * Convert to signed longs.
 * Place in buf[].
 * Return number of samples read.
 */

wavread(ft, buf, len) 
ft_t ft;
long *buf, len;
{
      wav_t   wav = (wav_t) ft->priv;
      int     done;

      if (len > wav->samples) len = wav->samples;
      if (len == 0) return 0;
      done = rawread(ft, buf, len);
      wav->samples -= len;
      return done;
}

/*
 * Do anything required when you stop reading samples.  
 * Don't close input file! 
 */
wavstopread(ft) 
ft_t ft;
{
}

wavstartwrite(ft) 
ft_t ft;
{
      wav_t   wav = (wav_t) ft->priv;
      int     littlendian = 0;
      char    *endptr;

      if (! ft->seekable)
              fail("Output .wav file must be a file, not a pipe");

      endptr = (char *) &littlendian;
      *endptr = 1;
      if (!littlendian) ft->swap = 1;

      wav->samples = 0;
      wavwritehdr(ft);
}

wavwritehdr(ft) 
ft_t ft;
{
      wav_t   wav = (wav_t) ft->priv;
      int     samsize;
      long    datasize;

      switch (ft->info.size)
      {
      case BYTE:      samsize = 8; break;
      case WORD:      samsize = 16; break;
      default:
      case LONG:      ft->info.size = LONG; samsize = 32; break;
      }
      ft->info.style = UNSIGNED;

      datasize = samsize/8 * ft->info.channels * wav->samples;

      fputs("RIFF", ft->fp);
      wllong(ft, datasize + 8+16+12); /* Waveform chunk size: FIXUP(4) */
      fputs("WAVE", ft->fp);
      fputs("fmt ", ft->fp);
      wllong(ft, (long)16);                 /* fmt chunk size */
      wlshort(ft, 1);                 /* FormatTag: WAVE_FORMAT_PCM */
      wlshort(ft, ft->info.channels);
      wllong(ft, (long)ft->info.rate);      /* SamplesPerSec */
                                      /* Average Bytes/sec */
      wllong(ft,         ((long)ft->info.rate * ft->info.channels * samsize + 7) / 8 );
                                      /* nBlockAlign */
      wlshort(ft, (ft->info.channels * samsize + 7) / 8);
      wlshort(ft, samsize);           /* BitsPerSample */
      
      fputs("data", ft->fp);
      wllong(ft, datasize);           /* data chunk size: FIXUP(40) */
}

wavwrite(ft, buf, len) 
ft_t ft;
long *buf, len;
{
      wav_t   wav = (wav_t) ft->priv;

      wav->samples += len * ft->info.size;
      rawwrite(ft, buf, len);
}
void
wavstopwrite(ft) 
ft_t ft;
{
      /* All samples are already written out. */
      /* If file header needs fixing up, for example it needs the */
      /* the number of samples in a field, seek back and write them here. */
      wav_t   wav = (wav_t) ft->priv;

      if (!ft->seekable)
              return;
      if (fseek(ft->fp, 0L, 0) != 0)
              fail("Can't rewind output file to rewrite .wav header.");
      wavwritehdr(ft);
}
