import java.io.IOException;

import javax.sound.sampled.UnsupportedAudioFileException;

import net.beadsproject.beads.core.AudioContext;
import net.beadsproject.beads.core.AudioUtils;
import net.beadsproject.beads.core.UGen;
import net.beadsproject.beads.data.AudioFile;


public class AudioFileTests {

	static public class AudioFileStreamer extends UGen
	{
		private AudioFile af;
		private byte[] byteData;
		private float[] interleaved;
		
		private float durationSum = 0;
		private int numDurationValues = 0;
		private final int totalDurationValues = 100; 
		
		public AudioFileStreamer(AudioContext ac, AudioFile af)
		{
			super(ac,af.nChannels);
			this.af = af;
			
			byteData = new byte[ac.getBufferSize()*af.nChannels*2];
			interleaved = new float[ac.getBufferSize()*af.nChannels];
		}
		
		@Override
		public void calculateBuffer()
		{
			try	{
				long before = System.currentTimeMillis();
				
				// test
				// split it up into two (just for testing purposes!)
				byte half1[] = new byte[bufferSize*af.nChannels*2/2];
				byte half2[] = new byte[bufferSize*af.nChannels*2/2];
				int nbytes = 0;
				nbytes += af.read(half1);
				nbytes += af.read(half2);
				System.arraycopy(half1, 0, byteData, 0, half1.length);
				System.arraycopy(half2, 0, byteData, half1.length, half2.length);
				
				// read data in a buffered fashion
				//int nbytes = af.read(byteData);
				int numFramesJustRead = nbytes / (2*this.getOuts());	
				if (numFramesJustRead < bufOut[0].length)
				{
					System.out.println("Couldn't get all the data I wanted!");
				}
				
				AudioUtils.byteToFloat(interleaved, byteData, af.getDecodedFormat().isBigEndian(),numFramesJustRead*af.nChannels);    		
				AudioUtils.deinterleave(interleaved,af.nChannels,numFramesJustRead,bufOut);
				
				duration(System.currentTimeMillis() - before);				
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		
		public void duration(long millis)
		{
			durationSum += (int)millis;
			numDurationValues++;
			if (numDurationValues >= totalDurationValues){
				System.out.println("Average read duration: " + (float)durationSum  / totalDurationValues + "ms");
				numDurationValues = 0;
				durationSum = 0;
				printHeapSize(".");
			}
		}
	}
	
	static Runtime rt;
	
	// returns the number of bytes used in the heap
	public static long heapSize()
	{
		return rt.totalMemory()-rt.freeMemory();
	}
	
	public static void printHeapSize(String s)
	{
		System.out.println("Memory used (" + s + ") = " + heapSize() + " bytes");
	}
	
	public static void main(String[] args)
	{
		rt = Runtime.getRuntime();
		
		printHeapSize("Starting");
		
		//final String FILE = "D:/audio/Jyske Rugkiks - Svartbag Remix M01.wav";
		//final String FILE = "D:/audio/Jyske Rugkiks - Svartbag Remix M01convert.wav";
		// final String FILE = "audio/gammaBrosTheme.mp3";
		final String FILE = "audio/minimal.ogg";
		//final String FILE = "audio/tada.wav"; // note that tada.wav is at a lower sample rate		
		 
		// AudioContext ac = new AudioContext(4096);  // This stuffs up, why?
		AudioContext ac = new AudioContext();
		AudioFile af = null;
		
		printHeapSize("After new AC");
		
		try {
			af = new AudioFile(FILE);
			//af.open();
			//System.out.println(af.info());
			
			/*
			System.out.println("channels: " + af.nChannels);
			System.out.println("frames: " + af.nFrames);
			System.out.println("total frames read:" + af.nTotalFramesRead);
			System.out.println("numbytes: " + af.byteDepth());
			*/
			
			/*
			af.reset();
			af.seek(44100*10);
			
			byte[] b = new byte[1024*1042];
			af.read(b);
			af.seek(44100*5);
			af.seek(44100*2);
			*/
		} catch (IOException e) {			
			e.printStackTrace();
		} catch (UnsupportedAudioFileException e) {
			System.out.println("Unsupported audio file!");
			e.printStackTrace();
		}
		
		printHeapSize("After new af");
		
		
		AudioFileStreamer afs = new AudioFileStreamer(ac,af);
		ac.out.addInput(afs);
				
		printHeapSize("After new afs");
		
		ac.start();
	}
	
}
