package nxm.audio.lib;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/** A class that handles audio system data and writing out audio data */
public class AudioSystem {

  /** scale */  public static final int SCALE  = 32768;
  /** bias */   public static final int BIAS   = 132;
  /** clip */   public static final int CLIP   = 32635;
  /** offset */ public static final int OFFSET = 335;

  /** default constructor */
  public AudioSystem () {}

  /** Write out audio data to an output file
   *  @param stream   the audio input stream
   *  @param fileType the audio file format type
   *  @param out      the output file
   *  @param mulaw_f  true if mu-law format
   *  @return the amount of data written out
   *  @throws IOException on write error
   */
  public static int write(AudioInputStream stream,AudioFileFormat.Type fileType, File out,boolean mulaw_f) throws IOException {

    int nwrite = 0;
    AudioFormat format = stream.getFormat();

    long frameLength = stream.getFrameLength();
    byte [] data = new byte[(int) frameLength];
    int nread = stream.read(data);

    // Create AU file header
    int magic = 0x2e736e64;
    int dataLocation = 32;
    int dataSize = nread;

    int dataFormat = 0; // WGD was 1
    if (mulaw_f) {
      //System.out.println("Setting AU to MU");
      dataFormat = 1;   // MULAW Format
    } else {
      dataFormat = 2;   // None MULAW Format
    }

    int samplingRate = (int) format.getSampleRate();
    int channelCount = format.getChannels();

    byte [] info = new byte[4];
    for (int i=0; i<info.length; i++) {
      info[i] = (byte) '\0';
    }

    byte [] header_buf = new byte[32];
    intToIEEEBytes(header_buf, 0, magic);
    intToIEEEBytes(header_buf, 4, dataLocation);
    intToIEEEBytes(header_buf, 8, dataSize);
    intToIEEEBytes(header_buf, 12, dataFormat);
    intToIEEEBytes(header_buf, 16, samplingRate);
    intToIEEEBytes(header_buf, 20, channelCount);
    for (int i=0; i<info.length; i++) {
      header_buf[24+i] = info[i];
    }
    for(int i=28; i<32; i++) {
      header_buf[i] = 0;
    }

    // Convert data to mu-law
    byte [] ulaw_data = new byte[dataSize];
    /*
      double min_val = -128.0;
      double max_val = 127.0;
      double y, f;
      int e, sig;
      for (int i=0; i<ulaw_data.length; i++) {
        y = 2*(data[i] - min_val)/(max_val-min_val) - 1;
        y = SCALE * y;
        if (y >= 0)
          sig = 1;
        else
          sig = -1;

        if (Math.abs(y) < CLIP)
          y = Math.abs(y);
        else
          y = CLIP;
        e = (int) (Math.log(2*(y+BIAS))/Math.log(2) + .5);
        f = (y+BIAS) / Math.pow(2.0, e);
        ulaw_data[i] = (byte) (64*sig - 16*e - (int) (32*f) + OFFSET);
      }
     */

    // Write the file
    BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(out));
    fos.write(header_buf);

    //if (mulaw_f) {
    //  System.out.println("AudioSystem:Writting MULAW");
    //	fos.write(ulaw_data);
    //} else {
    //System.out.println("AudioSystem:Writting RAW");
    fos.write(data);
    //}
    fos.close();
    nwrite = header_buf.length + ulaw_data.length;
    return nwrite;
  }

  protected static void intToIEEEBytes(byte[] bytes, int offset, int intVal) {
    bytes[offset  ] = (byte) ((intVal>>24) & 0xFF);
    bytes[offset+1] = (byte) ((intVal>>16) & 0xFF);
    bytes[offset+2] = (byte) ((intVal>>8)  & 0xFF);
    bytes[offset+3] = (byte) ( intVal      & 0xFF);
  }

}