/* sndcvt.c	-  Charles (nsa@link.xs4all.nl)
**
** convert 16bit sound of DOOM to 8bit ..
**
** (10sep94)
** (15sep94) update: added support for pcsp
*/

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/soundcard.h>

#define ERRMSG		  strerror(errno)
#define DSP_IN		  "/tmp/dsp"
#define DSP_OUT 	  "/dev/dsp"
#define PCSP_OUT	  "/dev/pcsp"

void do_dsp_stereo(int,int);
void do_dsp_mono(int,int);
void do_pcsp(int,int);
void usage(void);


void main(int argc, char **argv)
{
  char		 *dspin=DSP_IN;
  char		 *dspout=NULL;
  int		 ifd, ofd;
  int		 v, ret;
  int		 c;
  int		 Fs=0,Fm=0,Fp=0;

     if(argc<2)
      usage();

     while((c=getopt(argc, argv, "smpi:o:")) != -1)
      {
	switch(c)
	 {
	   case 's':
		Fs++;
		if(!dspout)
		 dspout=DSP_OUT;
		break;
	   case 'm':
		Fm++;
		if(!dspout)
		 dspout=DSP_OUT;
		break;
	   case 'p':
		Fp++;
		if(!dspout)
		 dspout=PCSP_OUT;
		break;
	   case 'i':
		dspin=optarg;
		break;
	   case 'o':
		dspout=optarg;
	   default:
		usage();
	 }
      }

     ifd = open(dspin, O_RDONLY);
     if(ifd < 0)
      {
	fprintf(stderr, "Can't open %s (rd): %s\n", dspin, ERRMSG);
	exit(1);
      }

     if(!dspout)
      dspout=DSP_OUT;
     ofd = open(dspout, O_WRONLY);
     if(ofd < 0)
      {
	fprintf(stderr, "Can't open %s (wr): %s\n", dspout, ERRMSG);
	exit(1);
      }

     if(Fm || Fs)
      {
	v = 131083;
	ret = ioctl(ofd, SNDCTL_DSP_SETFRAGMENT, &v);
	if(ret) perror("SNDCTL_DSP_SETFRAGMENT");
      }

     ret = ioctl(ofd, SNDCTL_DSP_RESET, 0);
     if(ret) perror("SNDCTL_DSP_RESET");

     v = 11025;
     ret = ioctl(ofd, SOUND_PCM_WRITE_RATE, &v);
     if(ret) perror("SOUND_PCM_WRITE_RATE");

     if(Fs) do_dsp_stereo(ifd, ofd);
     else
     if(Fm) do_dsp_mono(ifd, ofd);
     else
     if(Fp) do_pcsp(ifd, ofd);
}

void do_dsp_stereo(int ifd, int ofd)
{
  unsigned short s[1024];
  unsigned char  b[1024];
  int		 v, i, ret;

     v = 1;
     ret = ioctl(ofd, SNDCTL_DSP_STEREO, &v);
     if(ret) perror("SNDCTL_DSP_STEREO");

     while(read(ifd, &s, 2048) == 2048)
      {
	for(i=0;i<1024;i++)
	 {
	   s[i] ^= 0x8000;
	   b[i]  = (s[i]>>8);
	 }
	if(write(ofd, &b, 1024) != 1024)
	 {
	   fprintf(stderr, "sndcvt: short write: %s\n", ERRMSG);
	   exit(1);
	 }
      }

}

void do_dsp_mono(int ifd, int ofd)
{
  unsigned short s[1024];
  unsigned char  b[1024];
  int		 v, i, j, ret;

     v = 0;					/* set mono */
     ret = ioctl(ofd, SNDCTL_DSP_STEREO, &v);
     if(ret) perror("SNDCTL_DSP_STEREO");

     while(read(ifd, &s, 2048) == 2048)
      {
	for(i=0,j=0;i<1024;i++,j++)
	 {
	   s[i] = ((s[i] ^ 0x8000) + (s[++i] ^ 0x8000)) / 2;
	   b[j] = (s[i]>>8);
	 }
	if(write(ofd, &b, 512) != 512)
	 {
	   fprintf(stderr, "sndcvt: short write: %s\n", ERRMSG);
	   exit(1);
	 }
      }
}

void do_pcsp(int ifd, int ofd)
{
  unsigned short s[1024];
  unsigned char  b[1024];
  int		 i, j;

     while(read(ifd, &s, 2048) == 2048)
      {
	for(i=0,j=0;i<1024;i++,j++)
	 {
	   s[i] = ((s[i] ^ 0x8000) + (s[++i] ^ 0x8000)) / 2;
	   b[j] = (s[i]>>8);
	 }
	if(write(ofd, &b, 512) != 512)
	 {
	   fprintf(stderr, "sndcvt: short write: %s\n", ERRMSG);
	   exit(1);
	 }
      }
}

void usage(void)
{
  fprintf(stderr, "sndcvt - convert DOOM's 16bit sound to 8bit -  Charles (nsa@link.xs4all.nl)\n");
  fprintf(stderr, "usage: sndcvt <[-smp]> [-i] [-o]\n\n");
  fprintf(stderr, "      -s       stereo dsp\n");
  fprintf(stderr, "      -m       mono dsp\n");
  fprintf(stderr, "      -p       mono pcsp\n");
  fprintf(stderr, "      -i<dev>  input fifo\n");
  fprintf(stderr, "      -o<dev>  output device\n");
  exit(1);
}
