/*
   F_SOUND.C

   Filters adapted from DeuTex by Olivier Montanuy
   Integrated into DEU by Mark Mathews
*/

#include "deu.h"
#include "d_misc.h"
#include "d_wads.h"
#include "f_sound.h"

/*
   this codes normally reads:
     WAVE files  8 bit PCM, 1 channel, no compression
       the useless data is skiped
       (WAV files are clean)
     VOC files 8 bit PCM 1 channel, no compression
       the comments, silences and such are NOT
       detected. if this is needed, I'll code it later.
       (VOC files are a mess, BTW.)
*/



/*
   DOOM/HERETIC sound header
*/

typedef struct
  {
    UInt16 type;
    UInt16 rate;
    UInt32 size;
  } SOUNDHEAD;


/******************  Start WAV ****************/


/*
    WAVE structures
*/
typedef struct
  {
    char  riff[4];
    Int32 length;
    char  wave[4];
  } RIFFHEAD;

typedef struct /*format*/
  {
    char  fmt[4];
    Int32 fmtsize;    /*0x10*/
    Int16 tag;        /*format tag. 1=PCM*/
    Int16 channel;    /*1*/
    Int32 smplrate;
    Int32 bytescnd;   /*average bytes per second*/
    Int16 align;      /*block alignment, in bytes*/
    Int16 nbits;      /*specific to PCM format*/
  } WAVEFMT;

typedef struct /*data*/
  {
    char data[4];
    Int32 datasize;
  } WAVEDATA;

/*
   Encapsulate a raw file in a PWAD file.
*/


/*
  convert a WAD in WAVE
*/
UInt32 WadToWav(FILE *wavfile, FILE *wadfile)
  {
    UInt32 size;
    UInt16 speed;
    UInt32 total;

    SOUNDHEAD Headd;
    RIFFHEAD  Headr;
    WAVEFMT   Headf;
    WAVEDATA  Headw;


    if (fread(&Headd, sizeof(Headd), 1, wadfile) != 1)
      {
        printf("[Error reading from WAD file.]\n");
        return 0;
      }
    if (Headd.type != 3)
      {
        printf("[Not a sound.]\n");
        return 0;
      }
    size = Headd.size;
    speed = Headd.rate;
    if(size > 0x10000L)
      {
        printf("[Sound too big.]\n");
        return 0;
      }
    strncpy(Headr.riff, "RIFF", 4);
    Headr.length = 4 + sizeof(Headf) + sizeof(WAVEDATA) + size;
    strncpy(Headr.wave, "WAVE", 4);
    WriteBytes(wavfile, &Headr, sizeof(Headr));
    total=sizeof(Headr);
    strncpy(Headf.fmt, "fmt ",4);
    Headf.fmtsize = sizeof(Headf) - 8;
    Headf.tag = 1;
    Headf.channel = 1;
    Headf.smplrate = speed;
    Headf.bytescnd = speed;
    Headf.align = 1;
    Headf.nbits = 8;
    WriteBytes(wavfile, &Headf, sizeof(Headf));
    total += sizeof(Headf);
    strncpy(Headw.data, "data", 4);
    Headw.datasize = size;
    WriteBytes(wavfile, &Headw, sizeof(WAVEDATA));
    total = sizeof(WAVEDATA);
    CopyBytes(wavfile, wadfile, size);
    total += size;
    /*shall I close?*/ /*! No */
    return total;
  }


/*
   convert a WAVE in WAD
*/

UInt32 WavToWad(FILE *wadfile, FILE *wavfile)
  {
    Int32 size;
    Int16 speed;
    Int32 count;
    Int32 total;
    Int32 dummy;
    SOUNDHEAD Headd;
    RIFFHEAD  Headr;
    WAVEFMT   Headf;
    WAVEDATA  Headw;

    if (fread(&Headr, sizeof(Headr), 1, wavfile) != 1)
      {
        printf("[Can't read WAV file.]\n");
        return 0;
      }
    if (strncmp(Headr.riff, "RIFF", 4) != 0)
      {
        printf("[Bad WAV header.]\n");
        return 0;
      }
    if (strncmp(Headr.wave, "WAVE", 4) != 0)
      {
        printf("[Bad WAV header.]\n");
        return 0;
      }
    /*
      seek the format chunk
    */
    while(1)
      {
        if (fread(&Headf, 2 * sizeof(UInt32), 1, wavfile) != 1)
          {
            printf("[Can't read WAV file.]\n");
            return 0;
          }
        if (strncmp(Headf.fmt, "fmt ", 4) == 0)
          break;
        for (count = Headf.fmtsize; count > 0; count -= sizeof(UInt32))
          {
            fread(&dummy, sizeof(UInt32), 1, wavfile);
          }
      }
    fread(&Headf.tag, sizeof(Headf) - 2 * sizeof(UInt32), 1, wavfile);
    /*
      format supported:  8 bit PCM, 1 channel
    */
    if (Headf.tag != 1)
      {
        printf("[Not 8 bit PCM format.]\n");
        return 0;
      }
    if (Headf.channel > 1)
      {
        printf("[More than 1 channel.]\n");
        return 0;
      }
    speed = Headf.smplrate;
    /*
      seek the data chunk
    */
    while(1)
      {
        if (fread(&Headw, 2 * sizeof(UInt32), 1, wavfile) != 1)
          {
            printf("[Can't read WAV file.\n");
            return 0;
          }
        if (strncmp(Headw.data, "data", 4) == 0)
          break;
        for (count = Headw.datasize; count > 0; count -= sizeof(UInt32))
          {
            fread(&dummy, sizeof(UInt32), 1, wavfile);
          }
      }
    size=Headw.datasize;
    /*
      Write WAD data
    */
    Headd.type = 3;
    Headd.rate = speed;
    Headd.size = size;
    WriteBytes(wadfile, &Headd, sizeof(Headd));
    total = sizeof(Headd);
    CopyBytes(wadfile, wavfile, size);
    total = size;
    /*Shall I close?*/ /*! No */
    return total;
  }

UInt8 far * ReadWAV(FILE *wavfile, Int32 *size, Int32 *speed)
  {
    Int32 count;
    Int32 dummy;
    RIFFHEAD  Headr;
    WAVEFMT   Headf;
    WAVEDATA  Headw;
    UInt8 far *data;

    if (fread(&Headr, sizeof(Headr), 1, wavfile) != 1)
      {
        printf("[Can't read WAV file.]\n");
        return 0;
      }
    if (strncmp(Headr.riff, "RIFF", 4) != 0)
      {
        printf("[Bad WAV header.]\n");
        return 0;
      }
    if (strncmp(Headr.wave, "WAVE", 4) != 0)
      {
        printf("[Bad WAV header.]\n");
        return 0;
      }
    /*
      seek the format chunk
    */
    while(1)
      {
        if (fread(&Headf, 2 * sizeof(UInt32), 1, wavfile) != 1)
          {
            printf("[Can't read WAV file.]\n");
            return 0;
          }
        if (strncmp(Headf.fmt, "fmt ", 4) == 0)
          break;
        for (count = Headf.fmtsize; count > 0; count -= sizeof(UInt32))
          {
            fread(&dummy, sizeof(UInt32), 1, wavfile);
          }
      }
    fread(&Headf.tag, sizeof(Headf) - 2 * sizeof(UInt32), 1, wavfile);
    /*
      format supported:  8 bit PCM, 1 channel
    */
    if (Headf.tag != 1)
      {
        printf("[Not 8 bit PCM format.]\n");
        return 0;
      }
    if (Headf.channel > 1)
      {
        printf("[More than 1 channel.]\n");
        return 0;
      }
    *speed = Headf.smplrate;
    /*
      seek the data chunk
    */
    while(1)
      {
        if (fread(&Headw, 2 * sizeof(UInt32), 1, wavfile) != 1)
          {
            printf("[Can't read WAV file.\n");
            return 0;
          }
        if (strncmp(Headw.data, "data", 4) == 0)
          break;
        for (count = Headw.datasize; count > 0; count -= sizeof(UInt32))
          {
            fread(&dummy, sizeof(UInt32), 1, wavfile);
          }
      }
    *size=Headw.datasize;

    /*read data*/
    data=(UInt8 far *)GetMemory(*size);
    if(fread(data,1,*size,wavfile)!=*size)
      {
        FreeFarMemory(data);
        printf("[WAV: can't read data]\n");
        return 0;
      }

    return data;
  }

void WriteWAV(FILE *wavfile, Int32 size, Int32 speed, UInt8 far *raw)
  {
    UInt32 total;

    RIFFHEAD  Headr;
    WAVEFMT   Headf;
    WAVEDATA  Headw;


    if(size > 0x10000L)
      {
        printf("[Sound too big.]\n");
        return;
      }
    strncpy(Headr.riff, "RIFF", 4);
    Headr.length = 4 + sizeof(Headf) + sizeof(WAVEDATA) + size;
    strncpy(Headr.wave, "WAVE", 4);
    WriteBytes(wavfile, &Headr, sizeof(Headr));
    total=sizeof(Headr);
    strncpy(Headf.fmt, "fmt ",4);
    Headf.fmtsize = sizeof(Headf) - 8;
    Headf.tag = 1;
    Headf.channel = 1;
    Headf.smplrate = speed;
    Headf.bytescnd = speed;
    Headf.align = 1;
    Headf.nbits = 8;
    WriteBytes(wavfile, &Headf, sizeof(Headf));
    total += sizeof(Headf);
    strncpy(Headw.data, "data", 4);
    Headw.datasize = size;
    WriteBytes(wavfile, &Headw, sizeof(WAVEDATA));
    total = sizeof(WAVEDATA);

    if(fwrite(raw,1,size,wavfile) != size)
      {
        printf("[VOC: write error]\n");
        return;
      }


    /* write data */
  }


/****************  End WAV ****************/


/****************  Start VOC **************/

/*
   VOC structures
*/
#define VOCIDLEN (0x13)

/*static char VocId[]="Creative Voice File";*/

typedef struct
  {
    char ident[VOCIDLEN];  /*0x13*/
    char eof;              /*0x1A*/
    UInt16 block1;         /*offset to block1=0x1A*/
    UInt16 version;        /*0x010A*/
    UInt16 version2;       /*0x2229*/
  } VOCHEAD;

typedef struct
  {
    char  type;   /*1=sound data.0=end block*/
    char  sizeL;  /*2+length of data*/
    char  sizeM;
    char  sizeU;
    char  rate;   /*rate = 256-(1000000/sample_rate)*/
    char  cmprs;  /*0=no compression*/
  } VOCBLOCK1;

static VOCBLOCK1 Blockv;

/*
   Convert a WAD in VOC
*/
UInt32 WadToVoc(FILE *vocfile, FILE *wadfile)
  {
    UInt32 size;
    UInt16 speed;
    UInt32 Sz;
    UInt32 total;
    SOUNDHEAD Headd;
    VOCHEAD Headv;
    char VocId[]="Creative Voice File";

    if (fread(&Headd, sizeof(Headd), 1, wadfile) != 1)
      {
        printf("[Error reading from WAD file.\n");
        return 0;
      }
    if (Headd.type != 3)
      {
        printf("[Not a sound.]\n");
        return 0;
      }
    size = Headd.size;
    speed = Headd.rate;
    if(size > 0x10000L)
      {
        printf("[Sound too big.]\n");
        return 0;
      }
    strncpy(Headv.ident,VocId,VOCIDLEN);
    Headv.eof      = 0x1A;
    Headv.block1   = 0x1A;
    Headv.version  = 0x10A;
    Headv.version2 = 0x2229;
    WriteBytes(vocfile,&Headv,sizeof(VOCHEAD));
    total = sizeof(VOCHEAD);
    Blockv.type = 0x1;
    Sz=(size+2)&0xFFFFFFL; /*char rate, char 0, then char[size]*/
    Blockv.sizeL = Sz&0xFFL;
    Blockv.sizeM = (Sz>>8)&0xFFL;
    Blockv.sizeU = (Sz>>16)&0xFFL;
    if(speed <= 4000)
      speed = 4000;
    Blockv.rate = (char)(256-(1000000L/((long)speed)));
    Blockv.cmprs = 0;
    WriteBytes(vocfile,&Blockv,sizeof(VOCBLOCK1));
    total += sizeof(VOCBLOCK1);
    CopyBytes(vocfile,wadfile,size);
    total += size;
    Blockv.type = 0;/*last block*/
    WriteBytes(vocfile,&Blockv,1);
    total += 1;
    return total;
  }


/*
   Convert a VOC in WAD
*/

UInt32 VocToWad(FILE *wadfile, FILE *vocfile)
  {
    UInt32 size;
    UInt16 speed;
    UInt32 total;
    SOUNDHEAD Headd;
    VOCHEAD Headv;
    char VocId[]="Creative Voice File";

    if(fread(&Headv,1, sizeof(VOCHEAD),vocfile) != sizeof(VOCHEAD))
    {
      printf("[Can't read VOC file.]\n");
      return 0;
    }
    if(strncmp(VocId,Headv.ident,VOCIDLEN) != 0)
    {
      printf("[Bad VOC header.]\n");
      return 0;
    }
    if(fseek(vocfile,Headv.block1,0))
    {
      printf("[Bad VOC header.]\n");
      return 0;
    }
    if(fread(&Blockv,1,sizeof(VOCHEAD),vocfile) != sizeof(VOCHEAD))
    {
      printf("[Can't read VOC block.]\n");
      return 0;
    }
    /*
     Only the simplest VOC file is supported, but that could
     be unsuitable if the sound tool adds a comment block
    */
    if(Blockv.type != 1)
    {
      printf("[First VOC block is not sound.]\n");
      return 0;
    }
    size= ((Blockv.sizeU)<<16)&0xFF0000L;
    size+=((Blockv.sizeM)<<8)&0xFF00L;
    size+= (Blockv.sizeL)&0xFFL;
    /*size-= 2;*/ /*correction*/
    size-=22;
    if(size > 0x10000L)
    {
      printf("[VOC sound too long!]\n");
      return 0;
    }
    if(Blockv.cmprs != 0)
    {
      printf("[VOC compression not supported.]\n");
      return 0;
    }
    speed = (1000000L)/(256-(((int)Blockv.rate)&0xFF));
    /*
      Write WAD data
    */
    Headd.type = 3;
    Headd.rate = speed;
    Headd.size = size;
    WriteBytes(wadfile,&Headd,sizeof(Headd));
    total = sizeof(Headd);
    CopyBytes(wadfile,vocfile,size);
    total += size;
    return total;
  }

UInt8 far * ReadVOC(FILE *vocfile, Int32 *size, Int32 *speed)
  {

    VOCHEAD Headv;
    UInt8 far *data;
    char VocId[]="Creative Voice File";

    *size  = 0;
    *speed = 0;

    if(fread(&Headv,1, sizeof(VOCHEAD),vocfile) != sizeof(VOCHEAD))
      {
        printf("[Can't read VOC file.]\n");
        return 0;
      }
    if(strncmp(VocId,Headv.ident,VOCIDLEN) != 0)
      {
        printf("[Bad VOC header.]\n");
        return 0;
      }
    if(fseek(vocfile,Headv.block1,0))
      {
        printf("[Bad VOC header.]\n");
        return 0;
      }
    if(fread(&Blockv,1,sizeof(VOCHEAD),vocfile) != sizeof(VOCHEAD))
      {
        printf("[Can't read VOC block.]\n");
        return 0;
      }
    /*
     Only the simplest VOC file is supported, but that could
     be unsuitable if the sound tool adds a comment block
    */
    if(Blockv.type != 1)
      {
        printf("[First VOC block is not sound.]\n");
        return 0;
      }
    *size =  ((Blockv.sizeU)<<16)&0xFF0000L;
    *size += ((Blockv.sizeM)<<8)&0xFF00L;
    *size += (Blockv.sizeL)&0xFFL;
    /*size  -= 2;*/ /*correction*/
    *size-=22;
    if(*size > 0x100000L)
      {
        printf("[VOC sound too long!]\n");
        return 0;
      }
    if(Blockv.cmprs != 0)
      {
        printf("[VOC compression not supported.]\n");
        return 0;
      }
    /*read data*/
    data=(UInt8 far *)GetMemory(*size);
    if(fread(data,1,*size,vocfile) != *size)
      {
        FreeFarMemory(data);
        printf("[VOC: can't read data]\n");
        return 0;
      }

    *speed = (1000000L)/(256-(((int)Blockv.rate)&0xFF));

    return data;

  }


void WriteVOC(FILE *vocfile, Int32 size, Int32 speed, UInt8 far *raw)
  {
    UInt32 Sz;
    VOCHEAD Headv;
    char VocId[] = "Creative Voice File";

    if(size > 0x10000L)
      {
        printf("[Sound too big.]\n");
        return;
      }
    /* Write header */
    strncpy(Headv.ident,VocId,VOCIDLEN);
    Headv.eof      = 0x1A;
    Headv.block1   = 0x1A;
    Headv.version  = 0x10A;
    Headv.version2 = 0x2229;
    WriteBytes(vocfile,&Headv,sizeof(VOCHEAD));

    Blockv.type = 0x1;
    Sz = (size+2)&0xFFFFFFL; /*char rate, char 0, then char[size]*/
    Blockv.sizeL = Sz&0xFFL;
    Blockv.sizeM = (Sz>>8)&0xFFL;
    Blockv.sizeU = (Sz>>16)&0xFFL;
    if(speed <= 4000)
      speed = 4000;
    Blockv.rate = (char)(256-(1000000L/((long)speed)));
    Blockv.cmprs = 0;
    WriteBytes(vocfile,&Blockv,sizeof(VOCBLOCK1));

    /* write data */

    if(fwrite(raw,1,size,vocfile) != size)
      {
        printf("[VOC: write error]\n");
        return;
      }

    /* write last block */
    Blockv.type = 0;
    WriteBytes(vocfile,&Blockv,1);

  }


/***************** End VOC  **********************/

/***************** Start AU **********************/


typedef struct
{
  char snd[4];        /*.snd*/
  Int32 dataloc;
  Int32 datasize;
  Int32 format;
  Int32 smplrate;
  Int32 channel;
  char  info[4];
} AUHEAD;

#define MEMORYCACHE  (0x8000L)


UInt32 WadToAU(FILE *aufile, FILE *wadfile)
  {
    AUHEAD heada;
    Int32 i,wsize,sz=0, size;
    char far * buffer;
    SOUNDHEAD Headd;

    /* read sound header from WAD file */
    if (fread(&Headd, 1, sizeof(Headd), wadfile) != sizeof(Headd))
      {
        printf("[Error reading from WAD file.]\n");
        return 0;
      }
    /* check for sound type 3 */
    if (Headd.type != 3)
      {
        printf("[Not a sound.]\n");
        return 0;
      }
    size  = Headd.size;
    /* Is sound file > 64K? */
    if(size > 0x10000L)
      {
        printf("[Sound too big.]\n");
        return 0;
      }

    /* fill-in AU header */
    strncpy(heada.snd,".snd",4);
    heada.dataloc  = sizeof(heada);
    heada.datasize = size;
    heada.format   = 2L; /*8 bit linear*/
    heada.smplrate = Headd.rate;
    heada.channel  = 1L;
    heada.info[0]  ='\0';

    /* write AU header to AU file */
    if(fwrite(&heada,1,sizeof(heada),aufile) != sizeof(heada))
      {
        printf("[AU: write error]\n");
        return 0;
      }

    /* allocate sound buffer */
    buffer = (char far *) GetFarMemory(size);

    if (fread(buffer, 1, size, wadfile) != size)
      {
        FreeFarMemory(buffer);
        printf("[Error reading from WAD file.]\n");
        return 0;
      }

    for(i=0; i<size; i++)
      buffer[i] -= 0x80;

    for(wsize=0; wsize<size; wsize+=sz)
      {
        sz= (size-wsize > MEMORYCACHE) ? MEMORYCACHE : (size-wsize);
        if(fwrite((buffer+(wsize)),(size_t)sz,1,aufile) != 1)
          {
            FreeFarMemory(buffer);
            printf("[AU: write error]\n");
            return 0;
          }
      }

    FreeFarMemory(buffer);

    return size;

  }

UInt32 AUToWad(FILE *wadfile, FILE *aufile)
  {
    AUHEAD heada;
    Int32 wsize,sz=0,i,smplrate,datasize;
    char huge *data;
    SOUNDHEAD Headd;

    UInt32 total;


    /*read AU HEADER*/

    if(fread(&heada,1,sizeof(heada),aufile) != sizeof(heada))
      {
        printf("[AU: read error]\n");
        return 0;
      }

    /*check AU header*/
    if(strncmp(heada.snd,".snd",4)!=0)
      {
        printf("[AU: not an audio file]\n");
        return 0;
      }
    /*read RIFF HEADER*/
    if(heada.format!=2L)
      {
        printf("[AU: not linear 8 bit]\n");
        return 0;
      }
    if(heada.channel!=1L)
      {
        printf("[AU: not one channel]\n");
        return 0;
      }
    if(fseek(aufile,heada.dataloc,SEEK_SET))
      {
        printf("[AU: bad header]\n");
        return 0;
      }
    smplrate = heada.smplrate;
    datasize = heada.datasize;
    /*check AU header*/
    if(smplrate!=11025)
      printf("[AU: sample rate is %u instead of 11025]\n",smplrate);
    if(datasize>0x100000L)
      {
        printf("[AU: sample too long!]\n");
        return 0;
      }
    /*read data*/
    data = (char huge *)GetMemory(datasize);
    for(wsize=0; wsize < datasize; wsize += sz)
      {
        sz = (datasize-wsize>MEMORYCACHE)? MEMORYCACHE:(datasize-wsize);
        if(fread((data+(wsize)),1,(size_t)sz,aufile) != (size_t)sz)
          {
            FreeFarMemory(data);
            printf("[AU: can't read data]\n");
            return 0;
          }
      }

    /*convert from signed to unsigned char*/
    for(i=0;i<datasize;i++)
      data[i]+=0x80;

    /*
      Write WAD data
    */
    Headd.type=3;
    Headd.rate=smplrate;
    Headd.size=datasize;
    if(fwrite(&Headd,1,sizeof(Headd),wadfile) != sizeof(Headd))
      {
        FreeFarMemory(data);
        printf("[AU: write error]\n");
        return 0;
      }
    total = sizeof(Headd);


    if(fwrite(data,1,datasize,wadfile) != datasize)
      {
        FreeFarMemory(data);
        printf("[AU: write error]\n");
        return 0;
      }

    total += datasize;
    FreeFarMemory(data);

    return total;
  }


UInt8 far * ReadAU(FILE *aufile, Int32 *size, Int32 *speed)
  {
    AUHEAD heada;
    Int32 wsize,sz=0,i,smplrate,datasize;
    UInt8 far *data;

    /*read AU HEADER*/

    if(fread(&heada,1,sizeof(heada),aufile) != sizeof(heada))
      {
        printf("[AU: read error]\n");
        return 0;
      }

    /*check AU header*/
    if(strncmp(heada.snd,".snd",4)!=0)
      {
        printf("[AU: not an audio file]\n");
        return 0;
      }
    /*read RIFF HEADER*/
    if(heada.format!=2L)
      {
        printf("[AU: not linear 8 bit]\n");
        return 0;
      }
    if(heada.channel!=1L)
      {
        printf("[AU: not one channel]\n");
        return 0;
      }
    if(fseek(aufile,heada.dataloc,SEEK_SET))
      {
        printf("[AU: bad header]\n");
        return 0;
      }
    smplrate = heada.smplrate;
    datasize = heada.datasize;
    /*check AU header*/
    if(smplrate!=11025)
      {
        printf("[AU: sample rate is %u instead of 11025]\n",smplrate);
      }
    if(datasize>0x100000L)
      {
        printf("[AU: sample too long!]\n");
        return 0;
      }
    /*read data*/
    data=(UInt8 far *)GetMemory(datasize);
    for(wsize=0;wsize<datasize;wsize+=sz)
      {
        sz = (datasize-wsize>MEMORYCACHE)? MEMORYCACHE:(datasize-wsize);
        if(fread((data+(wsize)),1,(size_t)sz,aufile)!=(size_t)sz)
          {
            FreeFarMemory(data);
            printf("[AU: can't read data]\n");
            return 0;
          }
      }

    /*convert from signed to unsigned char*/
    for(i=0;i<datasize;i++)
      data[i]+=0x80;

    *size=datasize;
    *speed=smplrate;

    return data;
  }

void WriteAU(FILE *aufile, Int32 size, Int32 speed, UInt8 far *raw)
  {
    AUHEAD heada;
    Int32 i,wsize,sz=0;

    /* Is sound file > 64K? */
    if(size > 0x10000L)
      {
        printf("[Sound too big.]\n");
        return;
     }

    /* fill-in AU header */
    strncpy(heada.snd,".snd",4);
    heada.dataloc  = sizeof(heada);
    heada.datasize = size;
    heada.format   = 2L; /*8 bit linear*/
    heada.smplrate = speed;
    heada.channel  = 1L;
    heada.info[0]  ='\0';

    /* write AU header to AU file */
    if(fwrite(&heada,1,sizeof(heada),aufile) != sizeof(heada))
      {
        printf("[AU: write error]\n");
        return;
      }

    for(i=0; i<size; i++)
      raw[i] -= 0x80;

    for(wsize=0; wsize<size; wsize+=sz)
      {
        sz= (size-wsize>MEMORYCACHE)? MEMORYCACHE:(size-wsize);
        if(fwrite((raw+(wsize)),(size_t)sz,1,aufile)!=1)
          {
            printf("[AU: write error]\n");
            /* restore data */
            for(i=0; i<size; i++)
              raw[i] += 0x80;
            return;
          }
      }
    /* restore data */
    for(i=0; i<size; i++)
      raw[i] += 0x80;

  }


/**************** End AU ******************/
