package theGhastModding.midiConverter.main;

import java.io.File;

import WavFile.WavFile;

public class AdvancedMidiConverter {
	
	private WavFile wav;
	private double frameDuration;
	private double[] allSamples;
	private double volume;
	private int[] numNoets;
	private int polyphony;
	private boolean sawtooth;
	
	public AdvancedMidiConverter(int midiDuration, File f, int sampleRate, double volume, int polyphony, boolean sawtooth) throws Exception {
		long numFrames = (long)(midiDuration * sampleRate);
		wav = WavFile.newWavFile(f, 1, numFrames, 16, sampleRate);
		frameDuration = (double)midiDuration * 1000D / (double)numFrames;
		allSamples = new double[(int)numFrames];
		numNoets = new int[(int)numFrames];
		System.out.println("Preparing WAV");
		long timer = System.currentTimeMillis();
		for(int i = 0; i < numFrames; i++){
			if(System.currentTimeMillis() - timer >= 1000){
				timer = System.currentTimeMillis();
				double percent = (double)i / (double)(numFrames - 1) * 100D;
				System.out.println("Generating empty samples list: " + Double.toString(percent) + "%");
			}
			allSamples[i] = 0D;
		}
		this.volume = volume;
		this.polyphony = polyphony;
		this.sawtooth = sawtooth;
	}
	
	public void encodeNote(int note, int duration, int pos, int velocity, int channel) throws Exception {
		if(velocity < 5){
			return;
		}
		double frequency = Math.pow(2, ((double)note - 69D) / 12D) * 440D;
		double cycleLength = 1000D / frequency;
		int cycleLengthInFrames = (int) Math.round(cycleLength / frameDuration);
		int framePos = (int) Math.round((double)pos / frameDuration);
		if(numNoets[framePos] >= polyphony) return;
		double upStrength = (double)velocity / 127D * volume;
		double downStrength = -upStrength;
		int counter = 0;
		for(int i = 0; i < Math.round((double)duration / frameDuration); i++){
			if(framePos + i >= allSamples.length){
				return;
			}
			if(!sawtooth) {
				allSamples[framePos + i] += (counter <= (cycleLengthInFrames / 2) ? upStrength : downStrength);
			}else {
				allSamples[framePos + i] += (((double)counter / (double)cycleLengthInFrames) * upStrength - (0.5D * downStrength));
			}
			numNoets[framePos + i]++;
			counter++;
			if(counter == cycleLengthInFrames + 1){
				counter = 0;
			}
		}
	}
	
	public void finish() throws Exception {
		/*for(int i = 0; i < allSamples.length; i++) {
			allSamples[i] = Math.tanh(allSamples[i]);
		}*/
		wav.writeFrames(new double[][]{allSamples}, allSamples.length);
		wav.close();
	}
	
}