/**********************************************************************
fix au files in place, or just report header info

$Id: fixau.c,v 1.2 2004/10/03 16:23:25 purnhage Exp $

(c) Heiko Purnhagen 2004
e-mail: purnhage@tnt.uni-hannover.de
WWW:    http://www.tnt.uni-hannover.de/~purnhage/

This program is available under the terms of the GNU General Public
License. See file COPYING for further details. All usual disclaimers
apply!

Authors:
HP    Heiko Purnhagen <purnhage@tnt.uni-hannover.de>

2004-10-03 HP      born

for file format info, see:
  http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/AU/AU.html
**********************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define uchar unsigned char
#define ulong unsigned long

#define buffersize 24

typedef struct {
  int i;
  char *s;
} iss;


static void be_putuint32(uchar *b, ulong x)
{
  *(b++) = (x>>24) & 255;
  *(b++) = (x>>16) & 255;
  *(b++) = (x>> 8) & 255;
  *(b++) =  x      & 255;
}

static ulong be_getuint32(uchar *b)
{
  ulong r,h;
  
  h  = *(b++);
  r  = h<<24;
  h  = *(b++);
  r |= h<<16;
  h  = *(b++);
  r |= h<< 8;
  h  = *(b++);
  r |= h;
  return r;
}


int main(int argc,char **argv)
{
  long sndMagic=0x2e736e64UL;
  iss sndFmt[] = {
    {1,"SND_FORMAT_MULAW_8"},
    {2,"SND_FORMAT_LINEAR_8"},
    {3,"SND_FORMAT_LINEAR_16"},
    {4,"SND_FORMAT_LINEAR_24"},
    {5,"SND_FORMAT_LINEAR_32"},
    {6,"SND_FORMAT_FLOAT"},
    {7,"SND_FORMAT_DOUBLE"},
    {27,"SND_FORMAT_ALAW_8"},
    {-1,"unkown"}
  };
  uchar  buffer[buffersize];
  FILE *f;
  long magic,hdr,data,fmt,fs,ch;
  long fileLen;
  long i;

  if ( argc==1 || strncmp(argv[1],"-h",2)==0 ) {
    fprintf(stderr,"usage: %s file.au [fs [ch [fmt [data [hdr]]]]]\n",argv[0]);
    fprintf(stderr,"  known fmt's:\n");
    i = 0;
    while (sndFmt[i].i!=-1) {
      fprintf(stderr,"  %2d %s\n",sndFmt[i].i,sndFmt[i].s),
      i++;
    }
    exit(0);
  }

  if (!(f = fopen(argv[1],"r+"))) {
    fprintf(stderr,"could not open <%s>\n",argv[1]);
    exit(-1);
  }

  i = fread(buffer,1,buffersize,f);
  if (i!=buffersize) {
    fprintf(stderr,"error, read only %ld of %d bytes\n",i,buffersize);
    exit(-1);
  }

  magic = be_getuint32(buffer   );
  hdr   = be_getuint32(buffer+ 4);
  data  = be_getuint32(buffer+ 8);
  fmt   = be_getuint32(buffer+12);
  fs    = be_getuint32(buffer+16);
  ch    = be_getuint32(buffer+20);

  i = 0;
  while (sndFmt[i].i!=fmt && sndFmt[i].i!=-1) {
    i++;
  }

  printf("HEADER INFO (read from %s)\n",argv[1]);
  printf("magic:       %8lx \"%c%c%c%c\" %s\n",magic,
	 *(buffer),*(buffer+1),*(buffer+2),*(buffer+3),
	 (magic==sndMagic)?"(OK)":"(should be \".snd\")");
  printf("hdr:      %11ld %s\n",hdr,(hdr<24)?"(should be >= 24)":"");
  printf("data:     %11ld %s\n",data,(data==-1)?"(until end of file)":"");
  printf("fmt:      %11ld (%s)\n",fmt,sndFmt[i].s);
  printf("fs:       %11ld\n",fs);
  printf("ch:       %11ld\n",ch);

  fseek(f,0,SEEK_END);
  fileLen = ftell(f);
  fseek(f,0,SEEK_SET);

  printf("filesize: %11ld\n",fileLen);
  printf(" ->data:  %11ld\n",fileLen-hdr);

  if (argc>=3) {
    {
      if (sscanf(argv[2],"%li",&ch)!=1) {
	fprintf(stderr,"error parsing ch (%s)\n",argv[2]);
	exit(-1);
      }
    }
    if (argc>=4) {
      if (sscanf(argv[3],"%li",&fs)!=1) {
	fprintf(stderr,"error parsing fs (%s)\n",argv[3]);
	exit(-1);
      }
    }
    if (argc>=5) {
      if (sscanf(argv[4],"%li",&fmt)!=1) {
	fprintf(stderr,"error parsing fmt (%s)\n",argv[4]);
	exit(-1);
      }
    }
    if (argc>=6) {
      if (sscanf(argv[5],"%li",&data)!=1) {
	fprintf(stderr,"error parsing data (%s)\n",argv[5]);
	exit(-1);
      }
    }
    if (argc>=7) {
      if (sscanf(argv[6],"%li",&hdr)!=1) {
	fprintf(stderr,"error parsing hdr (%s)\n",argv[6]);
	exit(-1);
      }
    }

    be_putuint32(buffer   ,sndMagic);
    be_putuint32(buffer+ 4,hdr);
    be_putuint32(buffer+ 8,data);
    be_putuint32(buffer+12,fmt);
    be_putuint32(buffer+16,fs);
    be_putuint32(buffer+20,ch);

    i = fwrite(buffer,1,buffersize,f);
    if (i!=buffersize) {
      fprintf(stderr,"error, wrote only %ld of %d bytes\n",i,buffersize);
      exit(-1);
    }

    i = 0;
    while (sndFmt[i].i!=fmt && sndFmt[i].i!=-1) {
      i++;
    }

    printf("HEADER INFO (written to from %s)\n",argv[1]);
    printf("magic:       %8lx \"%c%c%c%c\" %s\n",magic,
	   *(buffer),*(buffer+1),*(buffer+2),*(buffer+3),
	   (magic==sndMagic)?"(OK)":"(should be \".snd\")");
    printf("hdr:      %11ld %s\n",hdr,(hdr<24)?"(should be >= 24)":"");
    printf("data:     %11ld %s\n",data,(data==-1)?"(until end of file)":"");
    printf("fmt:      %11ld (%s)\n",fmt,sndFmt[i].s);
    printf("fs:       %11ld\n",fs);
    printf("ch:       %11ld\n",ch);
  }

  fclose(f);
  return 0;
}
