package theGhastModding.mp3ToMidi.main;

import java.io.File;

import com.leff.midi.MidiFile;
import com.leff.midi.MidiTrack;
import com.leff.midi.event.MidiEvent;
import com.leff.midi.event.NoteOff;
import com.leff.midi.event.NoteOn;
import com.leff.midi.event.ProgramChange;
import com.leff.midi.event.meta.Tempo;
import com.leff.midi.event.meta.TimeSignature;

import WavFile.WavFile;

public class Mp3ToMidi {
	
	public static final int KEY = 44;
	
	public static void main(String[] args){
		try {
			//Step 1: loading the .wav
			WavFile wav = WavFile.openWavFile(new File("LTT original.wav"));
			//Step 2: creating MIDI:
			MidiFile midi = new MidiFile(800);
			//Step 3: millions BPM + the best instrument
			MidiTrack tempoTrack = new MidiTrack();
			Tempo tempo = new Tempo(0,0,(int) (60000000f / 1000000f));
			tempo.setBpm(600000f);
			tempoTrack.insertEvent(tempo);
			tempoTrack.insertEvent(new ProgramChange(0, 0, 0));
			TimeSignature sig = new TimeSignature(0,0,4,4,24,8);
			tempoTrack.insertEvent(sig);
			midi.addTrack(tempoTrack);
			//Step 4: creating track for the notes
			MidiTrack noteTrack = new MidiTrack();
			//Step 5: creating notedrum to force PFA to use 128 keys on "use song keys" setting
			for(int i = 0; i < 128; i++){
				NoteOn on = new NoteOn(0, 1, i, 1);
				NoteOff off = new NoteOff(100, 1, i, 0);
				noteTrack.insertEvent(on);
				noteTrack.insertEvent(off);
			}
			//Step 6: doing some math
			double TPS = (tempo.getBpm() / 60D) * (double)midi.getResolution();
			double lengthInSeconds = (double)wav.getNumFrames() / 8000D;
			long tickLength = (long)Math.ceil((lengthInSeconds * TPS));
			double sampleTime = 1D / 8000D;
			//Step 8: output shit to console
			System.out.println(Double.toString(TPS / 8000D / 256D) + " notes per sample");
			//Step 9: preparing shit
			long pos = 0;
			int currentSample = 0;
			double secondPos = 0;
			double lastSecondPos = 0;
			double[] nextFrame = new double[2];
			long progressTimer = System.currentTimeMillis();
			int noteCount = 0;
			MidiEvent.statusByteFix = true;
			//Step 10: actually converting
			while(pos <= tickLength){
				//Step 10.1: Print out progress information
				if(System.currentTimeMillis() - progressTimer >= 1000){
					progressTimer = System.currentTimeMillis();
					System.out.println(Double.toString((double)pos / (double)tickLength * 100D) + "% done");
				}
				//Step 10.2: Checking if sample needs to be updated and do so if necessary
				secondPos = pos / TPS;
				if(secondPos - lastSecondPos >= sampleTime){
					lastSecondPos = secondPos;
					wav.readFrames(nextFrame, 1);
					currentSample = (int) ((nextFrame[0] + 1D) / 2D * 255D);
					/*if(nextFrame[0] >= 0) currentSample = (int) ((nextFrame[0]) / 1D * 255D);
					if(nextFrame[0] < 0) currentSample = (int) ((-nextFrame[0]) / 1D * 255D);*/
				}
				//Step 10.3: Placing noets if a sample is currently supposed to play
				if(currentSample != 0){
					if(currentSample > 0){
						NoteOn on = new NoteOn(pos, 0, KEY, 100);
						NoteOff off = new NoteOff(pos + currentSample, 0, KEY, 0);
						noteTrack.insertEvent(on);
						noteTrack.insertEvent(off);
					}/*else if(currentSample < 0){
						NoteOn on = new NoteOn(pos - currentSample, 0, KEY, 100);
						NoteOff off = new NoteOff(pos - currentSample + (255 - (-currentSample)), 0, KEY, 0);
						noteTrack.insertEvent(on);
						noteTrack.insertEvent(off);
					}*/
					pos += 256;
					noteCount++;
				}else{
					pos+=256;
				}
			}
			midi.addTrack(noteTrack);
			//Step 11: Informing user about note count
			System.out.println("MIDI contains " + Integer.toString(noteCount) + " notes");
			//Step 12: Writing MIDI to file
			midi.writeToFile(new File("ltt.mid"));
			//Done
			System.out.println("Done.");
		}catch(Exception e){
			System.err.println("Error:");
			e.printStackTrace();
			System.exit(1);
		}
	}
	
}