package com.javadaw.audio;

import java.io.IOException;
import com.javadaw.gui.javaMain;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;

public class readAudio
{
  private javaMain parent;
  private AudioInputStream audioInputStream;
  private int productionRate;
  private float[][] inArray;
  private float[][] outArray;
  private int frameSizeInBytes;
  private int sampleSizeInBits;
  private float sampleRate;
  private int channels;
  private int bytesPerSample;
  private byte[] b = new byte[1];
  private float[][] floatArray = new float[1][1];
  public boolean isSupported = true;
  private int offset = 0;
  private int factor = 1;

  public readAudio(javaMain parent, String sourceURL)
    throws IOException {

    this.parent = parent;

    URL soundURL = new URL(sourceURL);

    openFileFromURL(soundURL);
  }

  private void openFileFromURL(URL soundURL) throws IOException {
    if (soundURL != null) { try {
        audioInputStream = AudioSystem.getAudioInputStream(soundURL);
      }
      catch (UnsupportedAudioFileException e) {
        throw new IOException("Unsupported AudioFile :" + e);
      }

    }

    if (audioInputStream == null) {
      throw new IOException("No loaded audio to play back");
    }

    AudioFormat origFormat = audioInputStream.getFormat();

    sampleRate = origFormat.getSampleRate();
    productionRate = (int)audioInputStream.getFrameLength();
    sampleSizeInBits = origFormat.getSampleSizeInBits();
    bytesPerSample = (sampleSizeInBits / 8);

    channels = origFormat.getChannels();
    

    boolean signed = true;
    boolean bigEndian = true;
    AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);

    try {
           audioInputStream = AudioSystem.getAudioInputStream(format, audioInputStream);
        
    } catch (Throwable t) { throw new IOException("Unsupported audio file format: " + t);
    }

    frameSizeInBytes = format.getFrameSize();
    
    outArray = new float[2][productionRate/factor];
    
    //System.out.println("--" + outArray[0].length);
  }
  public float GetFrameLengthInmSec() throws IllegalStateException {
    
    AudioFormat audioFormat = audioInputStream.getFormat();

    float T = (float)audioInputStream.getFrameLength() / audioFormat.getFrameRate();

    return T; 
  }
  public int getSize() throws IllegalStateException {
      return (int)audioInputStream.getFrameLength(); 
  }
  public int getBitsPerSample() throws IllegalStateException {
      return sampleSizeInBits; 
  }
  public float getSampleRate() throws IllegalStateException {
      return sampleRate; 
  }
  public int getChannels() throws IllegalStateException {
      return channels; 
  }
  public int getArrayLength() throws IllegalStateException {
      return outArray[0].length; 
  }
  public void setArrayLength(int factor) throws IllegalStateException {
      outArray = new float[2][productionRate/factor];
  }
  public void closeFile() throws IOException {
      audioInputStream.close();
  }
  public float[][] getSamples() throws IOException, IllegalStateException {
      
      int framesize = frameSizeInBytes;
      byte[] buffer = new byte[4 * parent.bufferSize * framesize]; 
      int numbytes = 0;  
      int bytesread = 0;
      
      for(;;) {
          
          bytesread=audioInputStream.read(buffer,numbytes,buffer.length-numbytes);
          if (bytesread == -1) break;
          numbytes += bytesread;
          
          int bytestowrite = (numbytes/framesize)*framesize;

          inArray = byteArrayToDoubleArray(buffer, bytesPerSample, channels);

          for (int channel = 0; channel < 2; ++channel) {
               for (int sample = 0; sample < 4 * parent.bufferSize * framesize; ++sample) {
                    if (offset+sample < outArray[0].length) outArray[channel][offset+sample] = inArray[channel][sample];
               }
          }
          
          if (offset < outArray[0].length) offset +=4*parent.bufferSize;
          
          int remaining = numbytes - bytestowrite;
          if (remaining > 0)
              System.arraycopy(buffer,bytestowrite,buffer,0,remaining);
          numbytes = remaining;
      }
      
      return outArray;
  }
  private float[][] byteArrayToDoubleArray(byte[] byteArray, int bytesPerSample, int channels)
  {
    float maxSampleReciprocal;

    int lengthInSamples = byteArray.length / bytesPerSample * channels;

    floatArray = new float[channels][lengthInSamples];

    if (bytesPerSample == 2)
    {
      maxSampleReciprocal = 3.051758E-005F;
    } else if (bytesPerSample == 1) {
      maxSampleReciprocal = 0.007813F;
    } else if (bytesPerSample == 3) {
      maxSampleReciprocal = 11920929.0F;
    } else if (bytesPerSample == 4) {
      maxSampleReciprocal = 4.655661E-010F;
    }
    else { maxSampleReciprocal = 0.0F; }

    int counter = 0;

    if (bytesPerSample != b.length) {
      b = new byte[bytesPerSample];
    }
    for (int currChannel = 0; currChannel < channels; ++currChannel) {
         for (int currSamp = 0; currSamp < lengthInSamples; ++currSamp) { 
           for (int i = 0; i < bytesPerSample; i += 1) { 
                counter = currSamp * bytesPerSample * channels + bytesPerSample * currChannel + i;
                if (counter < byteArray.length) b[i] = byteArray[counter];
           }
           int result = b[0] >> 7;
           for (int i = 0; i < bytesPerSample; i += 1) {
                result = (result << 8) + (b[i] & 0xFF);
           }
           floatArray[currChannel][currSamp] = (result * maxSampleReciprocal);
      }
    }
    return floatArray;
  }
}
