/*
 * $Id: cdda2au.c,v 1.1 1997/10/14 07:39:51 jim Exp $
 * Convert .cdr to .au
 *
 * $Log: cdda2au.c,v $
 * Revision 1.1  1997/10/14 07:39:51  jim
 * Initial revision
 *
 * Revision 1.1  1997/10/14 06:47:47  jim
 * Initial revision
 *
 */

#include <sys/fcntl.h>
#include <stdio.h>

#define CDDABLKSIZE 2352

unsigned char *ulawmap;
unsigned char linear_to_ulaw();
int convert(unsigned char *);

/*
 * Audio file header format.
 */
typedef unsigned long	u_32;
struct auheader {
	u_32	magic;
	u_32	hdr_size;
	u_32	data_size;
	u_32	encoding;
	u_32	sample_rate;
	u_32	channels;
};

int
main(int argc, char **argv)
{
  unsigned char *in_buf, *out_buf, tmp, *ptr, *ptr2;
  int in_fd, out_fd, val, ctr;
  int num_read = 1, out_len;
  struct auheader hdr;
/*  
  ulawmap = (unsigned char *) malloc(65536);
  for(val = 0; val < 65536; val++)
    ulawmap[val] = linear_to_ulaw(val - 32768);
  ulawmap += 32768;
  */
  if(argc < 2)
    {
      fprintf(stderr, "Convert from CDDA format to 16bit Sun .au format\n");
      fprintf(stderr, "usage:\n");
      fprintf(stderr, "%s <infile> <outfile>\n", argv[0]);
      exit(1);
    }
  
  in_fd = open(argv[1], O_RDONLY);
  if(in_fd < 0)
    {
      fprintf(stderr, "can't open input file %s\n", argv[1]);
      exit(1);
    }

  out_fd = open(argv[2], O_WRONLY | O_CREAT, 0666);
  if(out_fd < 0)
    {
      fprintf(stderr, "can't create output file %s\n", argv[2]);
      exit(1);
    }
  
  hdr.magic = 0x2e736e64;
  hdr.hdr_size = sizeof(hdr) + 28;
  hdr.data_size = 16;
  hdr.encoding = 3;
  hdr.sample_rate = 44100;
  hdr.channels = 2;
  
  write(out_fd, hdr, sizeof(hdr));
  write(out_fd, "Recorded from CD by WorkMan", 28);
  
  in_buf = (unsigned char *) malloc(CDDABLKSIZE * 2);
  out_buf = (unsigned char *) malloc(CDDABLKSIZE * 2);
  

  while(num_read)
    {
      num_read = read(in_fd, in_buf, CDDABLKSIZE);
      if(num_read < 0)
	{
	  fprintf(stderr, "Error reading from file\n");
	  exit (1);
	}
      
      if(num_read > 0)
	{
/*	  
	  ptr = in_buf;
	  ptr2 = out_buf;

	  for(ctr = 0; ctr < num_read / 2; ctr++)
	    {
	      tmp = *ptr++;
	      *ptr2++ = *ptr++;
	      *ptr2++ = tmp;
	    }
*/
/*	  out_len = convert(out_buf);*/
	  write(out_fd, in_buf, num_read);
	}
    }
  
  close(in_fd);
  close(out_fd);
}

int
convert(unsigned char *buf)
{
  short *buf16 = (short *) buf;
  int ctr, ctr2, samples;
  int mono_value;
  unsigned char *bufend = buf + CDDABLKSIZE;
  
  for(ctr = 0; buf16 < (short *)(bufend); ctr++)
    {
      samples = (ctr & 1) ? ((ctr % 20) ? 10 : 12) : 12;
      
      if(buf16 + samples > (short *)(bufend))
	samples = ((short *)bufend) - buf16;
     
      mono_value = 0;
      for(ctr2 = 0; ctr2 < samples; ctr2++)
	mono_value += *buf16++;
      mono_value /= samples;
      buf[ctr] = ulawmap[mono_value];
    }
  
  return ctr;
}

	
	  
/*
** This routine converts from linear to ulaw.
**
** Craig Reese: IDA/Supercomputing Research Center
** Joe Campbell: Department of Defense
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711  (very difficult to follow)
** 2) "A New Digital Technique for Implementation of Any
**     Continuous PCM Companding Law," Villeret, Michel,
**     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
**     1973, pg. 11.12-11.17
** 3) MIL-STD-188-113,"Interoperability and Performance Standards
**     for Analog-to_Digital Conversion Techniques,"
**     17 February 1987
**
** Input: Signed 16 bit linear sample
** Output: 8 bit ulaw sample
*/
#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
#define BIAS 0x84               /* define the add-in bias for 16 bit samples */
#define CLIP 32635
 
unsigned char
linear_to_ulaw( sample )
int sample;
{
	static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
				   4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
				   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
				   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
				   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
				   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
				   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
				   6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
				   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
	int sign, exponent, mantissa;
	unsigned char ulawbyte;
 
	/* Get the sample into sign-magnitude. */
	sign = (sample >> 8) & 0x80;            /* set aside the sign */
	if ( sign != 0 ) sample = -sample;              /* get magnitude */
	if ( sample > CLIP ) sample = CLIP;             /* clip the magnitude */
 
	/* Convert from 16 bit linear to ulaw. */
	sample = sample + BIAS;
	exponent = exp_lut[( sample >> 7 ) & 0xFF];
	mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
	ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
#ifdef ZEROTRAP
	if ( ulawbyte == 0 ) ulawbyte = 0x02;   /* optional CCITT trap */
#endif
 
	return ulawbyte;
}
