package theGhastModding.tgmidi.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Transmitter;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;

import theGhastModding.synthesizer.main.MidiEvent;
import theGhastModding.synthesizer.main.TGMSynthesizer;
import theGhastModding.tgmidi.main.Settings;
import theGhastModding.tgmidi.main.Soundfont;
import theGhastModding.tgmidi.midi.LoopMidiReceiver;
import javax.swing.JSlider;
import javax.swing.JCheckBox;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;

@SuppressWarnings("serial")
public class TGMIDIPanel extends JPanel implements WindowListener {
	
	private TGMIDIPanel instance;
	private MidiDevice loopMidi = null;
	private Transmitter loopMidiTransmitter;
	private List<Soundfont> soundfonts;
	private int previousValue = 44100;
	private Settings s;
	private JLabel lblCurrentVoices;
	
	public TGMIDIPanel(){
		super();
		try {
			File folder = new File(System.getenv("appdata") + "\\TGMIDI\\");
			if(!folder.exists()){
				folder.mkdir();
			}
		} catch(Exception e){
			e.printStackTrace();
			JOptionPane.showMessageDialog(this, "Error creating settings folder", "Error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		try {
			soundfonts = Settings.loadSoundfonts();
		}catch(Exception e){
			e.printStackTrace();
			soundfonts = new ArrayList<Soundfont>();
			JOptionPane.showMessageDialog(this, "Error loading soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
		}
		try {
			s = Settings.loadSettings();
		}catch(Exception e){
			e.printStackTrace();
			s = new Settings(100,500,0,44100,false,false);
			JOptionPane.showMessageDialog(this, "Error loading settings", "Error", JOptionPane.ERROR_MESSAGE);
		}
		try {
			TGMSynthesizer.startSynth(s.getAudioFrequency());
		}catch(Exception e){
			e.printStackTrace();
			JOptionPane.showMessageDialog(null, "Error starting TGM's synthesizer", "Error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		try {
			TGMSynthesizer.setVolume(s.getVolume());
			TGMSynthesizer.setOnlyReleaseOnOverlapingInstances(s.isNoteOff());
			TGMSynthesizer.setUseFx(s.isDisableFx());
			TGMSynthesizer.setMaxVoices(s.getVoiceLimit());
			TGMSynthesizer.setRenderingLimit(s.getRenderingLimit());
		} catch(Exception e){
			e.printStackTrace();
			JOptionPane.showMessageDialog(instance, "Error applying settings", "Error", JOptionPane.ERROR_MESSAGE);
			return;
		}
		setBackground(Color.WHITE);
		instance = this;
		MidiDevice device = null;
		MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
		for (int i = 0; i < infos.length; i++) {
		    try {
		        device = MidiSystem.getMidiDevice(infos[i]);
		    	if(device.getMaxTransmitters() == 0){
		    		continue;
		    	}
		        String name = device.getDeviceInfo().getName();
		        if(name.equals("loopMIDI Port")){
		        	loopMidi = device;
		        	break;
		        }
		    } catch (Exception e) {
		          JOptionPane.showMessageDialog(null, "Error searching available MIDI input devices for loopMIDI", "Error", JOptionPane.ERROR_MESSAGE);
		          e.printStackTrace();
		          System.exit(1);
		    }
		}
		setPreferredSize(new Dimension(627,400));
		setLayout(null);
		
		JPanel soundfontsPanel = new JPanel();
		soundfontsPanel.setBackground(Color.WHITE);
		soundfontsPanel.setLayout(null);
		
		JTabbedPane soundfontsPane = new JTabbedPane(JTabbedPane.LEFT);
		soundfontsPane.setBounds(10, 11, 586, 278);
		soundfontsPane.setBackground(Color.WHITE);
		soundfontsPanel.add(soundfontsPane);
		int counter = 1;
		for(Soundfont sf:soundfonts){
			soundfontsPane.add(Integer.toString(counter), new JLabel("<html>" + sf.getLocation() + " (" + (sf.isEnabled() ? "enabled" : "disabled") + ")"));
			counter++;
		}
		
		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		tabbedPane.setBackground(Color.WHITE);
		tabbedPane.add("Soundfonts", soundfontsPanel);
		
		JFileChooser sfChooser = new JFileChooser();
		sfChooser.setDialogTitle("Select a soundfont");
		sfChooser.setFileFilter(new FileNameExtensionFilter("Soundfonts", "sf2", "SF2", "sfz", "SFZ"));
		
		JButton btnAdd = new JButton("Add");
		btnAdd.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if(sfChooser.showOpenDialog(instance) == JFileChooser.APPROVE_OPTION){
					if(!sfChooser.getSelectedFile().exists()){
						JOptionPane.showMessageDialog(instance, "The selected file doesnt exist", "Error", JOptionPane.ERROR_MESSAGE);
						return;
					}
					Soundfont sf = new Soundfont(sfChooser.getSelectedFile(), true);
					soundfonts.add(sf);
					soundfontsPane.add(Integer.toString(soundfonts.size()), new JLabel("<html>" + sf.getLocation() + " (" + (sf.isEnabled() ? "enabled" : "disabled") + ")"));
					JOptionPane.showMessageDialog(instance, "To apply changes to the soundfont list, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
					try {
						Settings.saveSoundfonts(soundfonts);
					}catch(Exception e2){
						e2.printStackTrace();
						JOptionPane.showMessageDialog(instance, "Error saving soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
					}
				}
			}
		});
		btnAdd.setBounds(10, 316, 89, 23);
		soundfontsPanel.add(btnAdd);
		
		JButton btnRemove = new JButton("Remove");
		btnRemove.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(soundfontsPane.getSelectedIndex() < 0){
					return;
				}
				soundfonts.remove(soundfontsPane.getSelectedIndex());
				soundfontsPane.remove(soundfontsPane.getSelectedIndex());
				JOptionPane.showMessageDialog(instance, "To apply changes to the soundfont list, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
				try {
					Settings.saveSoundfonts(soundfonts);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
				}
				for(int i = 0; i < soundfonts.size(); i++){
					soundfontsPane.setTabComponentAt(i, new JLabel(Integer.toString(i + 1)));
				}
			}
		});
		btnRemove.setBounds(109, 316, 89, 23);
		soundfontsPanel.add(btnRemove);
		
		JButton btnMoveUp = new JButton("Move up");
		btnMoveUp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(soundfontsPane.getSelectedIndex() < 1 || soundfonts.size() == 0){
					return;
				}
				int indx = soundfontsPane.getSelectedIndex();
				JLabel lbl = new JLabel("<html>" + soundfonts.get(indx - 1).getLocation() + " (" + (soundfonts.get(indx - 1).isEnabled() ? "enabled" : "disabled") + ")");
				Soundfont sf = soundfonts.get(indx - 1);
				JLabel lbl2 = new JLabel("<html>" + soundfonts.get(indx).getLocation() + " (" + (soundfonts.get(indx).isEnabled() ? "enabled" : "disabled") + ")");
				soundfontsPane.removeTabAt(indx - 1);
				soundfontsPane.insertTab(Integer.toString(indx + 1), null, lbl2, null, indx - 1);
				soundfonts.set(indx - 1, soundfonts.get(indx));
				soundfonts.set(indx, sf);
				soundfontsPane.removeTabAt(indx);
				soundfontsPane.insertTab(Integer.toString(indx), null, lbl, null, indx);
				soundfontsPane.repaint();
				JOptionPane.showMessageDialog(instance, "To apply changes to the soundfont list, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
				try {
					Settings.saveSoundfonts(soundfonts);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		btnMoveUp.setBounds(208, 316, 89, 23);
		soundfontsPanel.add(btnMoveUp);
		
		JButton btnMoveDown = new JButton("Move down");
		btnMoveDown.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if(soundfontsPane.getSelectedIndex() >= soundfonts.size() - 1 || soundfonts.size() < 2){
					return;
				}
				int indx = soundfontsPane.getSelectedIndex();
				JLabel lbl = new JLabel("<html>" + soundfonts.get(indx + 1).getLocation() + " (" + (soundfonts.get(indx + 1).isEnabled() ? "enabled" : "disabled") + ")");
				Soundfont sf = soundfonts.get(indx + 1);
				JLabel lbl2 = new JLabel("<html>" + soundfonts.get(indx).getLocation() + " (" + (soundfonts.get(indx).isEnabled() ? "enabled" : "disabled") + ")");
				soundfontsPane.removeTabAt(indx + 1);
				soundfontsPane.insertTab(Integer.toString(indx + 2), null, lbl2, null, indx + 1);
				soundfonts.set(indx + 1, soundfonts.get(indx));
				soundfonts.set(indx, sf);
				soundfontsPane.removeTabAt(indx);
				soundfontsPane.insertTab(Integer.toString(indx + 1), null, lbl, null, indx);
				soundfontsPane.repaint();
				JOptionPane.showMessageDialog(instance, "To apply changes to the soundfont list, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
				try {
					Settings.saveSoundfonts(soundfonts);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		btnMoveDown.setBounds(307, 316, 89, 23);
		soundfontsPanel.add(btnMoveDown);
		
		JButton btnEnableSf = new JButton("Enable SF");
		btnEnableSf.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Soundfont sf = soundfonts.get(soundfontsPane.getSelectedIndex());
				soundfonts.get(soundfontsPane.getSelectedIndex()).setEnabled(true);
				int indx = soundfontsPane.getSelectedIndex();
				soundfontsPane.removeTabAt(indx);
				soundfontsPane.insertTab(Integer.toString(indx + 1), null, new JLabel("<html>" + sf.getLocation() + " (" + (sf.isEnabled() ? "enabled" : "disabled") + ")"), null, indx);
				soundfontsPane.setSelectedIndex(indx);
				JOptionPane.showMessageDialog(instance, "To apply changes to the soundfont list, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
				try {
					Settings.saveSoundfonts(soundfonts);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		btnEnableSf.setBounds(406, 316, 89, 23);
		soundfontsPanel.add(btnEnableSf);
		
		JButton btnDisableSf = new JButton("Disable SF");
		btnDisableSf.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Soundfont sf = soundfonts.get(soundfontsPane.getSelectedIndex());
				soundfonts.get(soundfontsPane.getSelectedIndex()).setEnabled(false);
				int indx = soundfontsPane.getSelectedIndex();
				soundfontsPane.removeTabAt(indx);
				soundfontsPane.insertTab(Integer.toString(indx + 1), null, new JLabel("<html>" + sf.getLocation() + " (" + (sf.isEnabled() ? "enabled" : "disabled") + ")"), null, indx);
				soundfontsPane.setSelectedIndex(indx);
				JOptionPane.showMessageDialog(instance, "To apply changes to the soundfont list, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
				try {
					Settings.saveSoundfonts(soundfonts);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving soundfont list", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		btnDisableSf.setBounds(507, 316, 89, 23);
		soundfontsPanel.add(btnDisableSf);
		
		JPanel settingsPanel = new JPanel();
		settingsPanel.setLayout(null);
		settingsPanel.setBackground(Color.WHITE);
		
		tabbedPane.add("Settings", settingsPanel);
		
		JLabel lblVolume = new JLabel("Volume: 100%");
		lblVolume.setBounds(10, 12, 583, 14);
		settingsPanel.add(lblVolume);
		
		JSlider slider = new JSlider();
		slider.setMinorTickSpacing(2);
		slider.addChangeListener(new ChangeListener(){
			@Override
			public void stateChanged(ChangeEvent arg0) {
				lblVolume.setText("Volume: " + slider.getValue() + "%");
				s.setVolume(slider.getValue());
				try {
					TGMSynthesizer.setVolume(slider.getValue());
				} catch(Exception e){
					e.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error changing volume", "Error", JOptionPane.ERROR_MESSAGE);
				}
				try {
					Settings.saveSettings(s);
				}catch(Exception e){
					e.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving settings", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		slider.setMajorTickSpacing(10);
		slider.setValue(s.getVolume());
		slider.setPaintTicks(true);
		slider.setBackground(Color.WHITE);
		slider.setBounds(10, 37, 583, 26);
		settingsPanel.add(slider);
		
		JCheckBox chckbxDisableSoundEffects = new JCheckBox("Disable sound effects (can reduce CPU usage)");
		chckbxDisableSoundEffects.addChangeListener(new ChangeListener(){
			@Override
			public void stateChanged(ChangeEvent e) {
				s.setDisableFx(chckbxDisableSoundEffects.isSelected());
				try {
					TGMSynthesizer.setUseFx(chckbxDisableSoundEffects.isSelected());
				} catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error " + (chckbxDisableSoundEffects.isSelected() ? "enabling" : "disabling") + " sound effects", "Error", JOptionPane.ERROR_MESSAGE);
				}
				try {
					Settings.saveSettings(s);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving settings", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		chckbxDisableSoundEffects.setBackground(Color.WHITE);
		chckbxDisableSoundEffects.setBounds(10, 70, 247, 23);
		settingsPanel.add(chckbxDisableSoundEffects);
		chckbxDisableSoundEffects.setSelected(s.isDisableFx());
		
		JCheckBox chckbxOnlyReleaseThe = new JCheckBox("Only release the oldest instance upon a note off event when there are overlapping instances of that note");
		chckbxOnlyReleaseThe.addChangeListener(new ChangeListener(){
			@Override
			public void stateChanged(ChangeEvent e) {
				s.setNoteOff(chckbxOnlyReleaseThe.isSelected());
				try {
					TGMSynthesizer.setOnlyReleaseOnOverlapingInstances(chckbxOnlyReleaseThe.isSelected());
				} catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error " + (chckbxOnlyReleaseThe.isSelected() ? "enabling" : "disabling") + " that option", "Error", JOptionPane.ERROR_MESSAGE);
				}
				try {
					Settings.saveSettings(s);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving settings", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		chckbxOnlyReleaseThe.setBackground(Color.WHITE);
		chckbxOnlyReleaseThe.setBounds(10, 97, 583, 23);
		settingsPanel.add(chckbxOnlyReleaseThe);
		chckbxOnlyReleaseThe.setSelected(s.isNoteOff());
		
		JLabel lblSetVoiceLimit = new JLabel("Set voice limit:");
		lblSetVoiceLimit.setBounds(10, 129, 80, 14);
		settingsPanel.add(lblSetVoiceLimit);
		
		JSpinner spinner = new JSpinner();
		spinner.addChangeListener(new ChangeListener(){
			@Override
			public void stateChanged(ChangeEvent e) {
				s.setVoiceLimit(Integer.parseInt(spinner.getValue().toString()));
				try {
					TGMSynthesizer.setMaxVoices(Integer.parseInt(spinner.getValue().toString()));
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error changing voice limit", "Error", JOptionPane.ERROR_MESSAGE);
				}
				try {
					Settings.saveSettings(s);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving settings", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		spinner.setModel(new SpinnerNumberModel(500, 1, 100000, 1));
		spinner.setBounds(497, 126, 96, 20);
		settingsPanel.add(spinner);
		spinner.setValue(s.getVoiceLimit());
		
		JLabel lblSet = new JLabel("Set maximum rendering time percentage limit:");
		lblSet.setBounds(10, 154, 303, 14);
		settingsPanel.add(lblSet);
		
		JSpinner spinner_1 = new JSpinner();
		spinner_1.addChangeListener(new ChangeListener(){
			@Override
			public void stateChanged(ChangeEvent e) {
				s.setRenderingLimit(Integer.parseInt(spinner_1.getValue().toString()));
				try {
					TGMSynthesizer.setRenderingLimit(Integer.parseInt(spinner_1.getValue().toString()));
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error setting maximum rendering time percentage limit", "Error", JOptionPane.ERROR_MESSAGE);
				}
				try {
					Settings.saveSettings(s);
				}catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error saving settings", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		spinner_1.setModel(new SpinnerNumberModel(100, 1, 100, 1));
		spinner_1.setBounds(497, 151, 96, 20);
		settingsPanel.add(spinner_1);
		spinner_1.setValue(s.getRenderingLimit());
		
		JLabel lblSetAudioFrequency = new JLabel("Set audio frequency:");
		lblSetAudioFrequency.setBounds(10, 179, 174, 14);
		settingsPanel.add(lblSetAudioFrequency);
		
		previousValue = s.getAudioFrequency();
		
		JComboBox<Integer> comboBox = new JComboBox<Integer>();
		Integer[] values = new Integer[] {352800, 192000, 176400, 142180, 96000, 88200, 74750, 66150, 50400, 50000, 48000, 47250, 44100, 44056, 37800, 34750, 32000, 22050, 16000, 11025, 8000, 4000};
		comboBox.setModel(new DefaultComboBoxModel<Integer>(values));
		for(int i = 0; i < values.length; i++){
			if(values[i] == s.getAudioFrequency()){
				previousValue = values[i];
				comboBox.setSelectedIndex(i);
				break;
			}
		}
		comboBox.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if(Integer.parseInt(comboBox.getSelectedItem().toString()) != previousValue){
					System.out.println(previousValue + "," + Integer.parseInt(comboBox.getSelectedItem().toString()));
					s.setAudioFrequency(Integer.parseInt(comboBox.getSelectedItem().toString()));
					JOptionPane.showMessageDialog(instance, "To apply changes to this setting, restart TGMIDI", "Information", JOptionPane.INFORMATION_MESSAGE);
					previousValue = Integer.parseInt(comboBox.getSelectedItem().toString());
					try {
						Settings.saveSettings(s);
					}catch(Exception e2){
						e2.printStackTrace();
						JOptionPane.showMessageDialog(instance, "Error saving settings", "Error", JOptionPane.ERROR_MESSAGE);
					}
				}
			}
		});
		comboBox.setBackground(Color.WHITE);
		comboBox.setBounds(497, 176, 96, 20);
		settingsPanel.add(comboBox);
		
		JButton btnSendNoteoffTo = new JButton("Send NoteOff to all channels");
		btnSendNoteoffTo.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					for(int i = 0; i < 16; i++){
						TGMSynthesizer.sendEvent(new MidiEvent(MidiEvent.MIDI_EVENT_NOTESOFF, i, 0,0));
					}
				} catch(Exception e2){
					e2.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error sending NoteOff to all channels", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
		});
		btnSendNoteoffTo.setBounds(10, 204, 174, 23);
		settingsPanel.add(btnSendNoteoffTo);
		
		lblCurrentVoices = new JLabel("Current active voices: 0/" + s.getVoiceLimit());
		lblCurrentVoices.setBounds(10, 325, 219, 14);
		settingsPanel.add(lblCurrentVoices);
		
		tabbedPane.setSelectedIndex(0);
		tabbedPane.setBounds(10, 11, 608, 378);
		add(tabbedPane);
		if(loopMidi == null){
			JOptionPane.showMessageDialog(null, "Couldnt find loopMIDI port. Did you install loopMIDI and created a loopMIDI port?", "Error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		if(!soundfonts.isEmpty()){
			List<String> sfPaths = new ArrayList<String>();
			for(Soundfont sf:soundfonts){
				if(sf.getLocation().exists()){
					if(sf.isEnabled()){sfPaths.add(sf.getLocation().getPath());}
				}else{
					JOptionPane.showMessageDialog(this, "The soundfont " + sf.getLocation().getPath() + " was not found", "Error", JOptionPane.ERROR_MESSAGE);
				}
			}
			try {
				TGMSynthesizer.loadFonts(sfPaths);
			}catch(Exception e){
				e.printStackTrace();
				JOptionPane.showMessageDialog(this, "Error loading soundfonts", "Error", JOptionPane.ERROR_MESSAGE);
			}
		}
		try {
			if(!loopMidi.isOpen()){
				loopMidi.open();
			}
			loopMidiTransmitter = loopMidi.getTransmitter();
			loopMidiTransmitter.setReceiver(new LoopMidiReceiver());
		} catch(Exception e){
			e.printStackTrace();
			JOptionPane.showMessageDialog(instance, "Error starting loopMIDI port", "Error", JOptionPane.ERROR_MESSAGE);
			return;
		}
		new Thread(new DebugThread()).start();
	}
	
	private class DebugThread implements Runnable {
		
		private DebugThread(){
			
		}
		
		@Override
		public void run() {
			while(TGMSynthesizer.isSynthStarted()){
				try {
					lblCurrentVoices.setText("Current active voices: " + TGMSynthesizer.getActiveVoices() + "/" + TGMSynthesizer.getMaxVoices());
				}catch(Exception e){
					e.printStackTrace();
					JOptionPane.showMessageDialog(instance, "Error generating debug string", "Error", JOptionPane.ERROR_MESSAGE);
				}
				try {
					Thread.sleep(50);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
		
	}
	
	@Override
	public void windowActivated(WindowEvent arg0) {}
	
	@Override
	public void windowClosed(WindowEvent arg0) {}
	
	@Override
	public void windowClosing(WindowEvent arg0) {
		try {
			TGMSynthesizer.stopSynth();
		}catch(Exception e){
			e.printStackTrace();
			JOptionPane.showMessageDialog(this, "Error closing TGM's Synthesizer", "Error", JOptionPane.ERROR_MESSAGE);
		}
		try {
			loopMidi.close();
		}catch(Exception e){
			e.printStackTrace();
			JOptionPane.showMessageDialog(this, "Error closing loopMIDI port", "Error", JOptionPane.ERROR_MESSAGE);
		}
	}
	
	@Override
	public void windowDeactivated(WindowEvent arg0) {}
	
	@Override
	public void windowDeiconified(WindowEvent arg0) {}
	
	@Override
	public void windowIconified(WindowEvent arg0) {}
	
	@Override
	public void windowOpened(WindowEvent arg0) {}
}