/*
 * @(#)EarTrain.java	1.1	Sept. 2002
 *
 * Copyright (c) 2002 Rainer Boettchers.  All Rights Are Wrongs.
 *
 * Just Chords grants you ("Licensee") a non-exclusive, royalty free, license to use,
 * modify and redistribute this software in source and binary code form,
 * provided that i) this copyright notice and license appear on all copies of
 * the software; and ii) Licensee does not utilize the software in a manner
 * which is disparaging to the author.
 *
 * This software is provided "AS IS," without a warranty of any kind. ALL
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. JUST CHORDS AND ITS LICENSORS SHALL NOT BE
 * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
 * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL JUST CHORDS OR ITS
 * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
 * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
 * OR INABILITY TO USE SOFTWARE, EVEN IF JUST CHORDS HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 * This software is not designed or intended for use in on-line control of
 * aircraft, air traffic, aircraft navigation or aircraft communications; or in
 * the design, construction, operation or maintenance of any nuclear
 * facility. Licensee represents and warrants that it will not use or
 * redistribute the Software for such purposes.
 */

     /* Der letzte Absatz lag mir besonders am Herzen!!! */

import java.lang.System;
import java.lang.Math;
import java.lang.Number;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.Random;
import javax.sound.midi.*;


public class EarTrain extends JApplet 
{
	final 		int PROGRAM = 192;
    	final 		int NOTEON = 144;
    	final 		int NOTEOFF = 128;
    	final 		int SUSTAIN = 64;
    	final 		int REVERB = 91;
    	final 		int ON = 0, OFF = 1;
	final 		int RANDOMINT = -1;
	int 		maxpattern0 = 0;
	int 		maxpattern1 = 0;
	int 		maxpattern2 = 0;
	int 		currentpattern = 0; // RANDOMINT == random pattern
	int 		tempo = 60;
	int 		midichannel = 35;
	int 		patternlevel = 0;
	int		workmode = 0;
	int		patternmode; // 0 = standard
	int		fretfontsize = 12;
	boolean		showfretboard = false;
    	Sequencer 	sequencer;
    	Synthesizer 	synthesizer;
    	Instrument 	instruments[];
    	ChannelData 	channels[];
    	ChannelData 	cc;
	Pattern 	patterns0[];
	Pattern 	patterns1[];
	Pattern 	patterns2[];
	Pattern 	randpattern;
	String		currentroot;
	RandomIntervals intgenerator;
	RandomRootNote	rootgenerator;
	Random 		rndgen;
	Container 	contentpane;
	JPanel 		dialogpanel;
	JPanel 		buttonflow;
	JPanel 		selectpanel;
	JPanel		centerpanel;
	FretBoardPanel	fretboard;
	JLabel 		hintlabel;
	JLabel 		sollabel;
	JLabel 		picturelabel;
	JComboBox 	randomize;
	JComboBox	modeselect;
	JComboBox	temposelect;
	JComboBox	playlevel;
	JComboBox	midilist;
	Font		solfont;
	Font		hintfont;
	Font		fretboardfont;
	Color		fbcolor;
	Color 		fwcolor;
	Color		markercolor;
	Color		intervalcolor;
	Color		rootcolor;

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~
	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

    	public void init() 
	{
		int	i;

        	try {
            		if (synthesizer == null) {
                		if ((synthesizer = MidiSystem.getSynthesizer()) == null) {
                    			return;
                		}
            		} 
            		synthesizer.open();
        	} catch (Exception ex) { ex.printStackTrace(); return; }
		
        	Soundbank sb = synthesizer.getDefaultSoundbank();
		if (sb != null) {
            		instruments = synthesizer.getDefaultSoundbank().getInstruments();
	            	synthesizer.loadInstrument(instruments[midichannel - 1]);
        	}
        	MidiChannel midiChannels[] = synthesizer.getChannels();
        	channels = new ChannelData[midiChannels.length];
        	for (i = 0; i < channels.length; i++) {
            		channels[i] = new ChannelData(midiChannels[i], i);
        	}
        	cc = channels[0];
            	cc.channel.programChange(midichannel - 1);

		intgenerator = new RandomIntervals();
		rootgenerator = new RandomRootNote();

		randpattern = new Pattern('E', 2, "Root = E2", "1 5 8");

		setupPatterns();
		rndgen = new Random(System.currentTimeMillis());
		switch(patternlevel)
		{
			case 0: currentpattern = rndgen.nextInt(maxpattern0 + 1); break;
			case 1: currentpattern = rndgen.nextInt(maxpattern1 + 1); break;
			case 2: currentpattern = rndgen.nextInt(maxpattern2 + 1); break;
		}			

		// make GUI
		contentpane = getContentPane(); 
				
		buttonflow = new JPanel(new FlowLayout());
		picturelabel = new JLabel(new ImageIcon(getImage(getCodeBase(), "eartrain.gif")));
		buttonflow.add(picturelabel);
		JButton playButton = new JButton("  Play  "); 
		buttonflow.add(playButton);
		playButton.addActionListener(new playPattern());
		JButton nextButton = new JButton("  Neu  "); 
		buttonflow.add(nextButton);
		nextButton.addActionListener(new nextPattern());
		JButton solButton = new JButton("Zeigen"); 
		buttonflow.add(solButton);
		solButton.addActionListener(new showPattern());
		contentpane.add(buttonflow, BorderLayout.SOUTH);

		hintfont = new Font("Arial", Font.BOLD, 18);
		hintlabel = new JLabel("EarTrain v1.1", JLabel.CENTER);
		hintlabel.setSize(200,30);
		hintlabel.setFont(hintfont);
		switch(patternlevel)
		{
			case 0: hintlabel.setText(" " + patterns0[currentpattern].patterntext); break;
			case 1: hintlabel.setText(" " + patterns1[currentpattern].patterntext); break;
			case 2: hintlabel.setText(" " + patterns2[currentpattern].patterntext); break;
		}
		contentpane.add(hintlabel, BorderLayout.NORTH);

		centerpanel = new JPanel(new GridLayout(0, 1));
		fretboard = new FretBoardPanel();
		centerpanel.add(fretboard);
		sollabel = new JLabel("", JLabel.CENTER);
		sollabel.setSize(300, 30);
		solfont = new Font("Arial", Font.BOLD, 24);
		sollabel.setBorder(BorderFactory.createLineBorder(Color.black, 1));
		sollabel.setFont(solfont);
		centerpanel.add(sollabel);
		contentpane.add(centerpanel, BorderLayout.CENTER);

		selectpanel = new JPanel(new GridLayout(0, 1));
		String[] randdata = { "Standard-Patterns", "Zufalls-Patterns" };
		randomize =  new JComboBox(randdata);
		randomize.setSelectedIndex(0);
		randomize.addItemListener(new randChange());
                selectpanel.add(randomize);
		String[] modedata = { "Intervalle hören", "Intervalle spielen" };
		modeselect = new JComboBox(modedata);
		modeselect.setSelectedIndex(0);
		modeselect.setEnabled(true);
		workmode = 0;
		modeselect.addItemListener(new modeChange());
		selectpanel.add(modeselect);
		String[] tempodata = { "30bpm", "60bpm", "90bpm", "120bpm", "150bpm" };
		temposelect = new JComboBox(tempodata);
		temposelect.setSelectedIndex(1);
		temposelect.setEnabled(true);
		tempo = 60;
		temposelect.addItemListener(new tempoChange());
		selectpanel.add(temposelect);
		String[] instrumentdata = { "E-Bass (fingered)", "E-Bass (picked)", "Fretless Bass",
			"Acoustic Bass", "Contrabass", "Piano", "Cello" };
		midilist = new JComboBox(instrumentdata);
		midilist.setSelectedIndex(0);
		midilist.setEnabled(true);
		midilist.addItemListener(new midiChange());
		selectpanel.add(midilist);
		String[] playleveldata = { "Basic (3 Noten)", "Medium (4 Noten)", "Advanced (5 Noten)" };
		playlevel = new JComboBox(playleveldata);
		playlevel.setSelectedIndex(0);
		playlevel.setEnabled(true);
		playlevel.addItemListener(new levelChange());
		selectpanel.add(playlevel);
		contentpane.add(selectpanel, BorderLayout.WEST);

		fretboardfont = new Font("Arial", Font.PLAIN, fretfontsize);
		fbcolor = new Color(131, 109, 109);
		fwcolor = new Color(220, 220, 220);
		markercolor = new Color(180, 170, 160);
		intervalcolor = new Color(0, 0, 160);
		rootcolor = new Color(200, 0, 0);

		return;

    	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void start()
	{
		solfont = new Font("Arial", Font.BOLD, 16);
		sollabel.setText("EarTrain v1.1 (" + maxpattern0 + "/" + maxpattern1 + "/" + maxpattern2+ " patterns)");
		solfont = new Font("Arial", Font.BOLD, 24);
		return;
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void stop()
	{
		return;
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void destroy()
	{
		if (synthesizer != null) {
            		synthesizer.close();
        	}
        	synthesizer = null;
        	instruments = null;
        	channels = null;
        }

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void playString(char rootnote, int octave, String notes, long delay)
	{
		int		ind;
		int		midinote;
		int		hit;
		char		sint;
		StringBuffer 	interval;
		StringBuffer	compiledmidi;
		String		tmpinterval;
		
		compiledmidi = new StringBuffer();
		for (ind = 0; ind < notes.length(); ind++)
		{
			if (notes.charAt(ind) == ' ') { continue; }
			interval = new StringBuffer();
			while ((ind < notes.length()) && ((sint = notes.charAt(ind)) != ' ')) { 
				interval.append(sint);
				ind++;
			}
			midinote = 12 * octave;
			switch (rootnote) {
				case 'C': break;
				case 'D': midinote += 2; break;
				case 'E': midinote += 4; break;
				case 'F': midinote += 5; break;
				case 'G': midinote += 7; break;
				case 'A': midinote += 9; break;
				case 'B': midinote += 11; break;
			}

			tmpinterval = new String();
			tmpinterval = interval.toString();
			hit = 0;
			while (hit == 0) {
				if (tmpinterval.compareTo("1") == 0) { midinote += 0; hit = 1; continue; };			
				if (tmpinterval.compareTo("b2") == 0) { midinote += 1; hit = 1; continue; };
				if (tmpinterval.compareTo("2") == 0) { midinote += 2; hit = 1; continue; };
				if (tmpinterval.compareTo("b3") == 0) { midinote += 3; hit = 1; continue; };
				if (tmpinterval.compareTo("3") == 0) { midinote += 4; hit = 1; continue; };
				if (tmpinterval.compareTo("4") == 0) { midinote += 5; hit = 1; continue; };
				if (tmpinterval.compareTo("b5") == 0) { midinote += 6; hit = 1; continue; };
				if (tmpinterval.compareTo("#4") == 0) { midinote += 6; hit = 1; continue; };
				if (tmpinterval.compareTo("5") == 0) { midinote += 7; hit = 1; continue; };
				if (tmpinterval.compareTo("#5") == 0) { midinote += 8; hit = 1; continue; };
				if (tmpinterval.compareTo("b6") == 0) { midinote += 8; hit = 1; continue; };
				if (tmpinterval.compareTo("6") == 0) { midinote += 9; hit = 1; continue; };
				if (tmpinterval.compareTo("b7") == 0) { midinote += 10; hit = 1; continue; };
				if (tmpinterval.compareTo("7") == 0) { midinote += 11; hit = 1; continue; };
				if (tmpinterval.compareTo("8") == 0) { midinote += 12; hit = 1; continue; };
				if (tmpinterval.compareTo("b9") == 0) { midinote += 13; hit = 1; continue; };
				if (tmpinterval.compareTo("9") == 0) { midinote += 14; hit = 1; continue; };
				if (tmpinterval.compareTo("b10") == 0) { midinote += 15; hit = 1; continue; };
				if (tmpinterval.compareTo("10") == 0) { midinote += 16; hit = 1; continue; };
				if (tmpinterval.compareTo("b11") == 0) { midinote += 16; hit = 1; continue; };
				if (tmpinterval.compareTo("11") == 0) { midinote += 17; hit = 1; continue; };
				if (tmpinterval.compareTo("#11") == 0) { midinote += 18; hit = 1; continue; };
				if (tmpinterval.compareTo("12") == 0) { midinote += 18; hit = 1; continue; };
				if (tmpinterval.compareTo("b13") == 0) { midinote += 19; hit = 1; continue; };
				if (tmpinterval.compareTo("13") == 0) { midinote += 20; hit = 1; continue; };
				if (tmpinterval.compareTo("#13") == 0) { midinote += 21; hit = 1; continue; };
				hit = 1;
			}
			compiledmidi.append((char)midinote);
			
		}

		for (ind = 0; ind < compiledmidi.length(); ind++)
		{
			cc.channel.noteOn((int)compiledmidi.charAt(ind), 127);
			waitTicks(delay);
	        	cc.channel.noteOff((int)compiledmidi.charAt(ind));
		}

		return;
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void waitTicks(long ticks)
	{
		long	starttime, nowtime;

		starttime = System.currentTimeMillis();
		while ((nowtime = System.currentTimeMillis()) < (starttime + ticks)) { };
		return;
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void addPattern(int newlevel, char root, int offset, String text, String sequence)
	{
		switch(newlevel)
		{
		  	case 0:	maxpattern0++;
				patterns0[maxpattern0] = new Pattern(root, offset, text, sequence);
				break;
		  	case 1:	maxpattern1++;
				patterns1[maxpattern1] = new Pattern(root, offset, text, sequence);
				break;
		  	case 2:	maxpattern2++;
				patterns2[maxpattern2] = new Pattern(root, offset, text, sequence);
				break;
		}
		return;
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public void setupPatterns()
	{
		int	i;
		// E string:   E2
		// A string:   A2
		// D string:   D3
		// G string:   G3
		patterns0 = new Pattern[300];
		patterns1 = new Pattern[200];
		patterns2 = new Pattern[200];
		maxpattern0 = -1;
		maxpattern1 = -1;
		maxpattern2 = -1;

		addPattern(0, 'E', 2, "Root = E2", "1 2 b3");
		addPattern(0, 'G', 2, "Root = G2", "1 2 b3");
		addPattern(0, 'A', 2, "Root = A2", "1 b3 2");
		addPattern(0, 'C', 3, "Root = C3", "1 2 b3");
		addPattern(0, 'D', 3, "Root = D3", "1 2 b3");
		addPattern(0, 'E', 3, "Root = E3", "1 b3 2");

		addPattern(0, 'E', 2, "Root = E2", "1 2 3");
		addPattern(0, 'G', 2, "Root = G2", "1 2 3");
		addPattern(0, 'A', 2, "Root = A2", "1 3 2");
		addPattern(0, 'C', 3, "Root = C3", "1 2 3");
		addPattern(0, 'D', 3, "Root = D3", "1 3 2");
		addPattern(0, 'E', 3, "Root = E3", "1 2 3");

		addPattern(0, 'E', 2, "Root = E2", "1 b2 b3");
		addPattern(0, 'G', 2, "Root = G2", "1 b2 b3");
		addPattern(0, 'A', 2, "Root = A2", "1 b2 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 b2");
		addPattern(0, 'D', 3, "Root = D3", "1 b3 b2");
		addPattern(0, 'E', 3, "Root = E3", "1 b2 b3");

		addPattern(0, 'E', 2, "Root = E2", "1 b2 3");
		addPattern(0, 'G', 2, "Root = G2", "1 b2 3");
		addPattern(0, 'A', 2, "Root = A2", "1 3 b2");
		addPattern(0, 'C', 3, "Root = C3", "1 b2 3");
		addPattern(0, 'D', 3, "Root = D3", "1 b2 3");
		addPattern(0, 'E', 3, "Root = E3", "1 3 b2");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 4");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 4");
		addPattern(0, 'A', 2, "Root = A2", "1 4 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 4 b3");
		addPattern(0, 'D', 3, "Root = D3", "1 b3 4");
		addPattern(0, 'E', 3, "Root = E3", "1 b3 4");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 5");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 5 b3");
		addPattern(0, 'D', 3, "Root = D3", "1 b3 5");
		addPattern(0, 'E', 3, "Root = E3", "1 b3 5");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 #5");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 #5");
		addPattern(0, 'A', 2, "Root = A2", "1 #5 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 #5");
		addPattern(0, 'D', 3, "Root = D3", "1 b3 #5");
		addPattern(0, 'E', 3, "Root = E3", "1 #5 b3");

		addPattern(0, 'E', 2, "Root = E2", "1 3 5");
		addPattern(0, 'G', 2, "Root = G2", "1 3 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 3");
		addPattern(0, 'C', 3, "Root = C3", "1 3 5");
		addPattern(0, 'D', 3, "Root = D3", "1 5 3");
		addPattern(0, 'E', 3, "Root = E3", "1 3 5");

		addPattern(0, 'E', 2, "Root = E2", "1 2 5");
		addPattern(0, 'G', 2, "Root = G2", "1 2 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 2");
		addPattern(0, 'C', 3, "Root = C3", "1 2 5");
		addPattern(0, 'D', 3, "Root = D3", "1 5 2");
		addPattern(0, 'E', 3, "Root = E3", "1 2 5");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 b5");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 b5");
		addPattern(0, 'A', 2, "Root = A2", "1 b5 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 b5");
		addPattern(0, 'D', 3, "Root = D3", "1 b5 b3");
		addPattern(0, 'E', 3, "Root = E3", "1 b3 b5");

		addPattern(0, 'E', 2, "Root = E2", "1 4 5");
		addPattern(0, 'G', 2, "Root = G2", "1 4 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 4");
		addPattern(0, 'C', 3, "Root = C3", "1 4 5");
		addPattern(0, 'D', 3, "Root = D3", "1 4 5");
		addPattern(0, 'E', 3, "Root = E3", "1 5 4");

		addPattern(0, 'E', 2, "Root = E2", "1 5 6");
		addPattern(0, 'G', 2, "Root = G2", "1 5 6");
		addPattern(0, 'A', 2, "Root = A2", "1 6 5");
		addPattern(0, 'C', 3, "Root = C3", "1 5 6");
		addPattern(0, 'D', 3, "Root = D3", "1 5 6");
		addPattern(0, 'E', 3, "Root = E3", "1 5 6");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 b7 b3");
		addPattern(0, 'E', 3, "Root = E3", "1 b3 b7");

		addPattern(0, 'E', 2, "Root = E2", "1 5 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 b7 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 b7");
		addPattern(0, 'C', 3, "Root = C3", "1 5 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 5 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 b7 5");

		addPattern(0, 'E', 2, "Root = E2", "1 5 7");
		addPattern(0, 'G', 2, "Root = G2", "1 5 7");
		addPattern(0, 'A', 2, "Root = A2", "1 7 5");
		addPattern(0, 'C', 3, "Root = C3", "1 5 7");
		addPattern(0, 'D', 3, "Root = D3", "1 7 5");
		addPattern(0, 'E', 3, "Root = E3", "1 5 7");

		addPattern(0, 'E', 2, "Root = E2", "1 5 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 5 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 5");
		addPattern(0, 'C', 3, "Root = C3", "1 5 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 5 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 5 b7");

		addPattern(0, 'E', 2, "Root = E2", "1 5 8");
		addPattern(0, 'G', 2, "Root = G2", "1 8 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 8");
		addPattern(0, 'C', 3, "Root = C3", "1 8 5");
		addPattern(0, 'D', 3, "Root = D3", "1 5 8");
		addPattern(0, 'E', 3, "Root = E3", "1 8 5");

		addPattern(0, 'E', 2, "Root = E2", "1 6 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 6 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 6");
		addPattern(0, 'C', 3, "Root = C3", "1 6 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 6 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 b7 6");

		addPattern(0, 'E', 2, "Root = E2", "1 4 6");
		addPattern(0, 'G', 2, "Root = G2", "1 6 4");
		addPattern(0, 'A', 2, "Root = A2", "1 4 6");
		addPattern(0, 'C', 3, "Root = C3", "1 4 6");
		addPattern(0, 'D', 3, "Root = D3", "1 6 4");
		addPattern(0, 'E', 3, "Root = E3", "1 4 6");

		addPattern(0, 'E', 2, "Root = E2", "1 6 7");
		addPattern(0, 'F', 2, "Root = F2", "1 6 7");
		addPattern(0, 'G', 2, "Root = G2", "1 7 6");
		addPattern(0, 'A', 2, "Root = A2", "1 6 7");
		addPattern(0, 'B', 2, "Root = B2", "1 6 7");
		addPattern(0, 'C', 3, "Root = C3", "1 7 6");
		addPattern(0, 'D', 3, "Root = D3", "1 6 7");
		addPattern(0, 'E', 3, "Root = E3", "1 6 7");

		addPattern(0, 'E', 2, "Root = E2", "1 2 6");
		addPattern(0, 'F', 2, "Root = F2", "1 2 6");
		addPattern(0, 'G', 2, "Root = G2", "1 6 2");
		addPattern(0, 'A', 2, "Root = A2", "1 2 6");
		addPattern(0, 'B', 2, "Root = B2", "1 2 6");
		addPattern(0, 'C', 3, "Root = C3", "1 6 2");
		addPattern(0, 'D', 3, "Root = D3", "1 2 6");
		addPattern(0, 'E', 3, "Root = E3", "1 2 6");

		addPattern(0, 'E', 2, "Root = E2", "1 b5 b7");
		addPattern(0, 'F', 2, "Root = F2", "1 b5 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 b7 b5");
		addPattern(0, 'A', 2, "Root = A2", "1 b5 b7");
		addPattern(0, 'B', 2, "Root = B2", "1 b7 b5");
		addPattern(0, 'C', 3, "Root = C3", "1 b5 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 b5 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 b7 b5");

		addPattern(0, 'E', 2, "Root = E2", "1 2 7");
		addPattern(0, 'F', 2, "Root = F2", "1 2 7");
		addPattern(0, 'G', 2, "Root = G2", "1 7 2");
		addPattern(0, 'A', 2, "Root = A2", "1 2 7");
		addPattern(0, 'B', 2, "Root = B2", "1 7 2");
		addPattern(0, 'C', 3, "Root = C3", "1 2 7");
		addPattern(0, 'D', 3, "Root = D3", "1 7 2");
		addPattern(0, 'E', 3, "Root = E3", "1 2 7");

		addPattern(0, 'E', 2, "Root = E2", "1 4 b7");
		addPattern(0, 'F', 2, "Root = F2", "1 4 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 4 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 4 b7");
		addPattern(0, 'B', 2, "Root = B2", "1 4 b7");
		addPattern(0, 'C', 3, "Root = C3", "1 4 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 4 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 4 b7");

		addPattern(0, 'E', 2, "Root = E2", "1 7 5");
		addPattern(0, 'G', 2, "Root = G2", "1 7 5");
		addPattern(0, 'A', 2, "Root = A2", "1 7 5");
		addPattern(0, 'B', 2, "Root = B2", "1 7 5");
		addPattern(0, 'C', 3, "Root = C3", "1 7 5");

		addPattern(0, 'E', 2, "Root = E2", "1 5 2");
		addPattern(0, 'G', 2, "Root = G2", "1 2 5");
		addPattern(0, 'A', 2, "Root = A2", "1 5 2");
		addPattern(0, 'B', 2, "Root = B2", "1 2 5");
		addPattern(0, 'C', 3, "Root = C3", "1 5 2");

		addPattern(0, 'E', 2, "Root = E2", "1 5 b3");
		addPattern(0, 'G', 2, "Root = G2", "1 5 b3");
		addPattern(0, 'A', 2, "Root = A2", "1 5 b3");
		addPattern(0, 'B', 2, "Root = B2", "1 5 b3");
		addPattern(0, 'C', 3, "Root = C3", "1 5 b3");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 b6");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 b6");
		addPattern(0, 'A', 2, "Root = A2", "1 b3 b6");
		addPattern(0, 'B', 2, "Root = B2", "1 b3 b6");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 b6");

		addPattern(0, 'E', 2, "Root = E2", "1 b5 5");
		addPattern(0, 'G', 2, "Root = G2", "1 b5 5");
		addPattern(0, 'A', 2, "Root = A2", "1 b5 5");
		addPattern(0, 'B', 2, "Root = B2", "1 b5 5");
		addPattern(0, 'C', 3, "Root = C3", "1 b5 5");

		addPattern(0, 'E', 2, "Root = E2", "1 b2 #5");
		addPattern(0, 'G', 2, "Root = G2", "1 b2 #5");
		addPattern(0, 'A', 2, "Root = A2", "1 #5 b2");
		addPattern(0, 'B', 2, "Root = B2", "1 b2 #5");
		addPattern(0, 'C', 3, "Root = C3", "1 b2 #5");

		addPattern(0, 'E', 2, "Root = E2", "1 b7 8");
		addPattern(0, 'G', 2, "Root = G2", "1 8 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 8");
		addPattern(0, 'B', 2, "Root = B2", "1 b7 8");
		addPattern(0, 'C', 3, "Root = C3", "1 8 b7");

		addPattern(0, 'E', 2, "Root = E2", "1 b7 6");
		addPattern(0, 'F', 2, "Root = F2", "1 b7 6");
		addPattern(0, 'G', 2, "Root = G2", "1 6 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 6");
		addPattern(0, 'B', 2, "Root = B2", "1 b7 6");
		addPattern(0, 'C', 3, "Root = C3", "1 b7 6");
		addPattern(0, 'D', 3, "Root = D3", "1 6 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 b7 6");

		addPattern(0, 'E', 2, "Root = E2", "1 8 4");
		addPattern(0, 'G', 2, "Root = G2", "1 4 8");
		addPattern(0, 'A', 2, "Root = A2", "1 8 4");
		addPattern(0, 'B', 2, "Root = B2", "1 4 8");
		addPattern(0, 'C', 3, "Root = C3", "1 8 4");

		addPattern(0, 'E', 2, "Root = E2", "1 b7 2");
		addPattern(0, 'G', 2, "Root = G2", "1 2 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 2");
		addPattern(0, 'B', 2, "Root = B2", "1 2 b7");
		addPattern(0, 'C', 3, "Root = C3", "1 b7 2");

		addPattern(0, 'E', 2, "Root = E2", "1 b2 4");
		addPattern(0, 'G', 2, "Root = G2", "1 b2 4");
		addPattern(0, 'A', 2, "Root = A2", "1 b2 4");
		addPattern(0, 'B', 2, "Root = B2", "1 b2 4");
		addPattern(0, 'C', 3, "Root = C3", "1 b2 4");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 8");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 8");
		addPattern(0, 'A', 2, "Root = A2", "1 8 b3");
		addPattern(0, 'B', 2, "Root = B2", "1 b3 8");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 8");

		addPattern(0, 'E', 2, "Root = E2", "1 3 b6");
		addPattern(0, 'G', 2, "Root = G2", "1 3 b6");
		addPattern(0, 'A', 2, "Root = A2", "1 b6 3");
		addPattern(0, 'B', 2, "Root = B2", "1 3 b6");
		addPattern(0, 'C', 3, "Root = C3", "1 b6 3");

		addPattern(0, 'E', 2, "Root = E2", "1 7 3");
		addPattern(0, 'G', 2, "Root = G2", "1 7 3");
		addPattern(0, 'A', 2, "Root = A2", "1 3 7");
		addPattern(0, 'B', 2, "Root = B2", "1 3 7");
		addPattern(0, 'C', 3, "Root = C3", "1 7 3");

		addPattern(0, 'E', 2, "Root = E2", "1 7 2");
		addPattern(0, 'G', 2, "Root = G2", "1 7 2");
		addPattern(0, 'A', 2, "Root = A2", "1 2 7");
		addPattern(0, 'B', 2, "Root = B2", "1 7 2");
		addPattern(0, 'C', 3, "Root = C3", "1 2 7");

		addPattern(0, 'E', 2, "Root = E2", "1 b7 #5");
		addPattern(0, 'G', 2, "Root = G2", "1 b7 #5");
		addPattern(0, 'A', 2, "Root = A2", "1 b7 #5");
		addPattern(0, 'B', 2, "Root = B2", "1 b7 #5");
		addPattern(0, 'C', 3, "Root = C3", "1 b7 #5");

		addPattern(0, 'E', 2, "Root = E2", "1 b2 b7");
		addPattern(0, 'G', 2, "Root = G2", "1 b2 b7");
		addPattern(0, 'A', 2, "Root = A2", "1 b2 b7");
		addPattern(0, 'C', 3, "Root = C3", "1 b2 b7");
		addPattern(0, 'D', 3, "Root = D3", "1 b2 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 b2 b7");

		addPattern(0, 'E', 2, "Root = E2", "1 b2 7");
		addPattern(0, 'G', 2, "Root = G2", "1 7 b2");
		addPattern(0, 'A', 2, "Root = A2", "1 b2 7");
		addPattern(0, 'C', 3, "Root = C3", "1 7 b2");
		addPattern(0, 'D', 3, "Root = D3", "1 b2 b7");
		addPattern(0, 'E', 3, "Root = E3", "1 7 b2");

		addPattern(0, 'E', 2, "Root = E2", "1 5 b9");
		addPattern(0, 'G', 2, "Root = G2", "1 5 b9");
		addPattern(0, 'A', 2, "Root = A2", "1 b9 5");
		addPattern(0, 'C', 3, "Root = C3", "1 5 b9");
		addPattern(0, 'D', 3, "Root = D3", "1 b9 5");
		addPattern(0, 'E', 3, "Root = E3", "1 b9 5");

		addPattern(0, 'E', 2, "Root = E2", "1 6 9");
		addPattern(0, 'G', 2, "Root = G2", "1 6 9");
		addPattern(0, 'A', 2, "Root = A2", "1 9 6");
		addPattern(0, 'C', 3, "Root = C3", "1 6 9");
		addPattern(0, 'D', 3, "Root = D3", "1 6 9");
		addPattern(0, 'E', 3, "Root = E3", "1 9 6");

		addPattern(0, 'E', 2, "Root = E2", "1 5 9");
		addPattern(0, 'G', 2, "Root = G2", "1 5 9");
		addPattern(0, 'A', 2, "Root = A2", "1 9 5");
		addPattern(0, 'C', 3, "Root = C3", "1 5 9");
		addPattern(0, 'D', 3, "Root = D3", "1 5 9");
		addPattern(0, 'E', 3, "Root = E3", "1 9 5");

		addPattern(0, 'E', 2, "Root = E2", "1 3 9");
		addPattern(0, 'G', 2, "Root = G2", "1 3 9");
		addPattern(0, 'A', 2, "Root = A2", "1 3 9");
		addPattern(0, 'C', 3, "Root = C3", "1 3 9");
		addPattern(0, 'D', 3, "Root = D3", "1 3 9");
		addPattern(0, 'E', 3, "Root = E3", "1 3 9");

		addPattern(0, 'E', 2, "Root = E2", "1 b3 b9");
		addPattern(0, 'G', 2, "Root = G2", "1 b3 b9");
		addPattern(0, 'A', 2, "Root = A2", "1 b3 b9");
		addPattern(0, 'C', 3, "Root = C3", "1 b3 b9");
		addPattern(0, 'D', 3, "Root = D3", "1 b3 b9");
		addPattern(0, 'E', 3, "Root = E3", "1 b3 b9");

		addPattern(0, 'A', 3, "Root = A3", "1 b3 5");
		addPattern(0, 'A', 3, "Root = A3", "1 3 5");
		addPattern(0, 'A', 3, "Root = A3", "1 3 6");
		addPattern(0, 'A', 3, "Root = A3", "1 5 b7");
		addPattern(0, 'A', 3, "Root = A3", "1 5 7");
		addPattern(0, 'A', 3, "Root = A3", "1 b3 b7");
		addPattern(0, 'A', 3, "Root = A3", "1 5 8");
		addPattern(0, 'A', 3, "Root = A3", "1 5 9");


		// Pattern 1		

		addPattern(1, 'E', 2, "Root = E2", "1 2 b3 5");
		addPattern(1, 'F', 2, "Root = F2", "1 2 b3 5");
		addPattern(1, 'G', 2, "Root = G2", "1 2 b3 5");
		addPattern(1, 'A', 2, "Root = A2", "1 2 b3 5");
		addPattern(1, 'C', 3, "Root = C3", "1 2 b3 5");

		addPattern(1, 'E', 2, "Root = E2", "1 b3 4 5");
		addPattern(1, 'G', 2, "Root = G2", "1 b3 4 5");
		addPattern(1, 'A', 2, "Root = A2", "1 b3 4 5");
		addPattern(1, 'B', 2, "Root = B2", "1 b3 4 5");
		addPattern(1, 'C', 3, "Root = C3", "1 b3 4 5");

		addPattern(1, 'E', 2, "Root = E2", "1 4 5 b7");
		addPattern(1, 'F', 2, "Root = F2", "1 4 5 b7");
		addPattern(1, 'A', 2, "Root = A2", "1 4 5 b7");
		addPattern(1, 'B', 2, "Root = B2", "1 4 5 b7");
		addPattern(1, 'C', 3, "Root = C3", "1 4 5 b7");

		addPattern(1, 'E', 2, "Root = E2", "1 4 5 7");
		addPattern(1, 'G', 2, "Root = G2", "1 4 5 7");
		addPattern(1, 'A', 2, "Root = A2", "1 4 5 7");
		addPattern(1, 'B', 2, "Root = B2", "1 4 5 7");
		addPattern(1, 'C', 3, "Root = C3", "1 4 5 7");

		addPattern(1, 'E', 2, "Root = E2", "1 5 8 b7");
		addPattern(1, 'F', 2, "Root = F2", "1 5 8 b7");
		addPattern(1, 'G', 2, "Root = G2", "1 5 8 b7");
		addPattern(1, 'A', 2, "Root = A2", "1 5 8 b7");
		addPattern(1, 'B', 2, "Root = B2", "1 5 8 b7");

		addPattern(1, 'E', 2, "Root = E2", "1 b3 #5 b7");
		addPattern(1, 'F', 2, "Root = F2", "1 b3 #5 b7");
		addPattern(1, 'G', 2, "Root = G2", "1 b3 #5 b7");
		addPattern(1, 'A', 2, "Root = A2", "1 b3 #5 b7");
		addPattern(1, 'B', 2, "Root = B2", "1 b3 #5 b7");
		addPattern(1, 'C', 3, "Root = C3", "1 b3 #5 b7");

		addPattern(1, 'E', 2, "Root = E2", "1 3 6 8");
		addPattern(1, 'F', 2, "Root = F2", "1 3 6 8");
		addPattern(1, 'G', 2, "Root = G2", "1 3 6 8");
		addPattern(1, 'A', 2, "Root = A2", "1 3 6 8");
		addPattern(1, 'B', 2, "Root = B2", "1 3 6 8");
		addPattern(1, 'C', 3, "Root = C3", "1 3 6 8");

		addPattern(1, 'E', 2, "Root = E2", "1 2 5 8");
		addPattern(1, 'F', 2, "Root = F2", "1 2 5 8");
		addPattern(1, 'G', 2, "Root = G2", "1 2 5 8");
		addPattern(1, 'A', 2, "Root = A2", "1 2 5 8");
		addPattern(1, 'B', 2, "Root = B2", "1 2 5 8");
		addPattern(1, 'C', 3, "Root = C3", "1 2 5 8");

		addPattern(1, 'E', 2, "Root = E2", "1 3 5 9");
		addPattern(1, 'F', 2, "Root = F2", "1 3 5 9");
		addPattern(1, 'G', 2, "Root = G2", "1 3 5 9");
		addPattern(1, 'A', 2, "Root = A2", "1 3 5 9");
		addPattern(1, 'B', 2, "Root = B2", "1 3 5 9");
		addPattern(1, 'C', 3, "Root = C3", "1 3 5 9");

		addPattern(1, 'E', 2, "Root = E2", "1 b2 b5 b9");
		addPattern(1, 'F', 2, "Root = F2", "1 b2 b5 b9");
		addPattern(1, 'G', 2, "Root = G2", "1 b2 b5 b9");
		addPattern(1, 'A', 2, "Root = A2", "1 b2 b5 b9");
		addPattern(1, 'B', 2, "Root = B2", "1 b2 b5 b9");
		addPattern(1, 'C', 3, "Root = C3", "1 b2 b5 b9");

		addPattern(1, 'E', 2, "Root = E2", "1 b5 8 b9");
		addPattern(1, 'F', 2, "Root = F2", "1 b5 8 b9");
		addPattern(1, 'G', 2, "Root = G2", "1 b5 8 b9");
		addPattern(1, 'A', 2, "Root = A2", "1 b5 8 b9");
		addPattern(1, 'B', 2, "Root = B2", "1 b5 8 b9");
		addPattern(1, 'C', 3, "Root = C3", "1 b5 8 b9");

		addPattern(1, 'E', 2, "Root = E2", "1 b9 b6 5");
		addPattern(1, 'F', 2, "Root = F2", "1 b9 b6 5");
		addPattern(1, 'G', 2, "Root = G2", "1 b9 b6 5");
		addPattern(1, 'A', 2, "Root = A2", "1 b9 b6 5");
		addPattern(1, 'B', 2, "Root = B2", "1 b9 b6 5");
		addPattern(1, 'C', 3, "Root = C3", "1 b9 b6 5");

		addPattern(1, 'E', 2, "Root = E2", "1 b3 5 b7");
		addPattern(1, 'F', 2, "Root = F2", "1 b3 5 b7");
		addPattern(1, 'G', 2, "Root = G2", "1 b3 5 b7");
		addPattern(1, 'A', 2, "Root = A2", "1 b3 5 b7");
		addPattern(1, 'B', 2, "Root = B2", "1 b3 5 b7");
		addPattern(1, 'C', 3, "Root = C3", "1 b3 5 b7");

		addPattern(1, 'E', 2, "Root = E2", "1 b3 3 4");
		addPattern(1, 'F', 2, "Root = F2", "1 b3 3 4");
		addPattern(1, 'G', 2, "Root = G2", "1 b3 3 4");
		addPattern(1, 'A', 2, "Root = A2", "1 b3 3 4");
		addPattern(1, 'B', 2, "Root = B2", "1 b3 3 4");
		addPattern(1, 'C', 3, "Root = C3", "1 b3 3 4");

		addPattern(1, 'E', 2, "Root = E2", "1 5 b9 b7");
		addPattern(1, 'F', 2, "Root = F2", "1 5 b9 b7");
		addPattern(1, 'G', 2, "Root = G2", "1 5 b9 b7");
		addPattern(1, 'A', 2, "Root = A2", "1 5 b9 b7");
		addPattern(1, 'B', 2, "Root = B2", "1 5 b9 b7");
		addPattern(1, 'C', 3, "Root = C3", "1 5 b9 b7");

		addPattern(1, 'E', 2, "Root = E2", "1 7 8 5");
		addPattern(1, 'F', 2, "Root = F2", "1 7 8 5");
		addPattern(1, 'G', 2, "Root = G2", "1 7 8 5");
		addPattern(1, 'A', 2, "Root = A2", "1 7 8 5");
		addPattern(1, 'B', 2, "Root = B2", "1 7 8 5");
		addPattern(1, 'C', 3, "Root = C3", "1 7 8 5");

		addPattern(1, 'F', 2, "Root = F2", "1 10 b7 6");
		addPattern(1, 'G', 2, "Root = G2", "1 10 b7 6");
		addPattern(1, 'A', 2, "Root = A2", "1 10 b7 6");

		addPattern(1, 'F', 2, "Root = F2", "1 8 10 5");
		addPattern(1, 'G', 2, "Root = G2", "1 8 10 5");
		addPattern(1, 'A', 2, "Root = A2", "1 8 10 5");

		addPattern(1, 'F', 2, "Root = F2", "1 5 10 8");
		addPattern(1, 'G', 2, "Root = G2", "1 5 10 8");
		addPattern(1, 'A', 2, "Root = A2", "1 5 10 8");

		addPattern(1, 'F', 2, "Root = F2", "1 7 b7 5");
		addPattern(1, 'G', 2, "Root = G2", "1 7 b7 5");
		addPattern(1, 'A', 2, "Root = A2", "1 7 b7 5");

		addPattern(1, 'E', 2, "Root = E2", "1 5 b6 b3");
		addPattern(1, 'F', 2, "Root = F2", "1 5 b6 b3");
		addPattern(1, 'G', 2, "Root = G2", "1 5 b6 b3");
		addPattern(1, 'A', 2, "Root = A2", "1 5 b6 b3");
		addPattern(1, 'B', 2, "Root = B2", "1 5 b6 b3");
		addPattern(1, 'C', 3, "Root = C3", "1 5 b6 b3");

		addPattern(1, 'E', 2, "Root = E2", "1 b3 5 b7");
		addPattern(1, 'F', 2, "Root = F2", "1 b3 5 b7");
		addPattern(1, 'G', 2, "Root = G2", "1 b3 5 b7");
		addPattern(1, 'A', 2, "Root = A2", "1 b3 5 b7");
		addPattern(1, 'B', 2, "Root = B2", "1 b3 5 b7");
		addPattern(1, 'C', 3, "Root = C3", "1 b3 5 b7");

		addPattern(1, 'E', 2, "Root = E2", "1 7 5 b6");
		addPattern(1, 'F', 2, "Root = F2", "1 7 5 b6");
		addPattern(1, 'G', 2, "Root = G2", "1 7 5 b6");
		addPattern(1, 'A', 2, "Root = A2", "1 7 5 b6");
		addPattern(1, 'B', 2, "Root = B2", "1 7 5 b6");
		addPattern(1, 'C', 3, "Root = C3", "1 7 5 b6");

		addPattern(1, 'E', 2, "Root = E2", "8 7 5 1");
		addPattern(1, 'G', 2, "Root = G2", "8 7 5 1");
		addPattern(1, 'A', 2, "Root = A2", "8 7 5 1");
		addPattern(1, 'C', 3, "Root = C3", "8 7 5 1");

		addPattern(1, 'E', 2, "Root = E2", "4 5 3 1");
		addPattern(1, 'G', 2, "Root = G2", "4 5 3 1");
		addPattern(1, 'A', 2, "Root = A2", "4 5 3 1");
		addPattern(1, 'C', 3, "Root = C3", "4 5 3 1");

		addPattern(1, 'E', 2, "Root = E2", "1 8 9 5");
		addPattern(1, 'G', 2, "Root = G2", "8 1 9 5");
		addPattern(1, 'B', 2, "Root = B2", "1 8 9 5");
		addPattern(1, 'C', 3, "Root = C3", "1 9 8 5");

		addPattern(1, 'E', 2, "Root = E2", "1 #5 8 b3");
		addPattern(1, 'G', 2, "Root = G2", "1 #5 8 b3");
		addPattern(1, 'A', 2, "Root = A2", "1 #5 8 b3");
		addPattern(1, 'C', 3, "Root = C3", "1 #5 8 b3");

		addPattern(1, 'E', 2, "Root = E2", "1 b3 3 7");
		addPattern(1, 'G', 2, "Root = G2", "1 b3 3 7");
		addPattern(1, 'A', 2, "Root = A2", "1 b3 3 7");
		addPattern(1, 'C', 3, "Root = C3", "1 b3 3 7");

		addPattern(1, 'E', 2, "Root = E2", "1 7 8 3");
		addPattern(1, 'G', 2, "Root = G2", "1 7 8 3");
		addPattern(1, 'B', 2, "Root = B2", "1 7 8 3");
		addPattern(1, 'C', 3, "Root = C3", "1 7 8 3");

		addPattern(1, 'E', 2, "Root = E2", "1 4 2 5");
		addPattern(1, 'G', 2, "Root = G2", "1 4 2 5");
		addPattern(1, 'A', 2, "Root = A2", "1 4 2 5");
		addPattern(1, 'C', 3, "Root = C3", "1 4 2 5");

		// Pattern 2

		addPattern(2, 'E', 2, "Root = E2", "1 b3 3 4 b6");
		addPattern(2, 'F', 2, "Root = F2", "1 b3 3 4 b6");
		addPattern(2, 'G', 2, "Root = G2", "1 b3 3 4 b6");
		addPattern(2, 'A', 2, "Root = A2", "1 b3 3 4 b6");
		addPattern(2, 'B', 2, "Root = B2", "1 b3 3 4 b6");
		addPattern(2, 'C', 3, "Root = C3", "1 b3 3 4 b6");

		addPattern(2, 'E', 2, "Root = E2", "1 7 5 4 3");
		addPattern(2, 'F', 2, "Root = F2", "1 7 5 4 3");
		addPattern(2, 'G', 2, "Root = G2", "1 7 5 4 3");
		addPattern(2, 'A', 2, "Root = A2", "1 7 5 4 3");

		addPattern(2, 'E', 2, "Root = E2", "5 1 2 b3 b7");
		addPattern(2, 'F', 2, "Root = F2", "5 1 2 b3 b7");
		addPattern(2, 'G', 2, "Root = G2", "5 1 2 b3 b7");
		addPattern(2, 'A', 2, "Root = A2", "5 1 2 b3 b7");

		addPattern(2, 'E', 2, "Root = E2", "4 5 1 8 9");
		addPattern(2, 'F', 2, "Root = F2", "4 5 1 8 9");
		addPattern(2, 'G', 2, "Root = G2", "4 5 1 8 9");
		addPattern(2, 'A', 2, "Root = A2", "4 5 1 8 9");

		addPattern(2, 'E', 2, "Root = E2", "b6 1 b2 5 b7");
		addPattern(2, 'F', 2, "Root = F2", "b6 1 b2 5 b7");
		addPattern(2, 'G', 2, "Root = G2", "b6 1 b2 5 b7");
		addPattern(2, 'A', 2, "Root = A2", "b6 1 b2 5 b7");

		addPattern(2, 'E', 2, "Root = E2", "1 3 4 8 7");
		addPattern(2, 'F', 2, "Root = F2", "1 3 4 8 7");
		addPattern(2, 'G', 2, "Root = G2", "1 3 4 8 7");
		addPattern(2, 'A', 2, "Root = A2", "1 3 4 8 7");

		addPattern(2, 'E', 2, "Root = E2", "1 b10 8 4 5");
		addPattern(2, 'F', 2, "Root = F2", "1 b10 8 4 5");
		addPattern(2, 'G', 2, "Root = G2", "1 b10 8 4 5");

		addPattern(2, 'E', 2, "Root = E2", "8 5 1 b3 4");
		addPattern(2, 'F', 2, "Root = F2", "8 5 1 b3 4");
		addPattern(2, 'G', 2, "Root = G2", "8 5 1 b3 4");
		addPattern(2, 'A', 2, "Root = A2", "8 5 1 b3 4");

		addPattern(2, 'E', 2, "Root = E2", "b3 1 5 b6 2");
		addPattern(2, 'F', 2, "Root = F2", "b3 1 5 b6 2");
		addPattern(2, 'G', 2, "Root = G2", "b3 1 5 b6 2");
		addPattern(2, 'A', 2, "Root = A2", "b3 1 5 b6 2");

		addPattern(2, 'E', 2, "Root = E2", "1 2 b3 5 b7");
		addPattern(2, 'F', 2, "Root = F2", "1 2 b3 5 b7");
		addPattern(2, 'G', 2, "Root = G2", "1 2 b3 5 b7");
		addPattern(2, 'A', 2, "Root = A2", "1 2 b3 5 b7");

		return;
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class playPattern implements ActionListener 
	{
		public void actionPerformed(ActionEvent event) 
		{
			int	speed;
			Component c = (Component)event.getSource();

			repaint();

			speed = 60000 / tempo;

			if (currentpattern == RANDOMINT) // random mode
			{
				playString(randpattern.rootnote, randpattern.octaveoffset,
								randpattern.patternseq, speed);
				return;
			}

			switch(patternlevel)
			{
				case 0:
					playString(patterns0[currentpattern].rootnote,
						patterns0[currentpattern].octaveoffset,
						patterns0[currentpattern].patternseq, speed);
					break;
				case 1:
					playString(patterns1[currentpattern].rootnote,
						patterns1[currentpattern].octaveoffset,
						patterns1[currentpattern].patternseq, speed);
					break;
				case 2:
					playString(patterns2[currentpattern].rootnote,
						patterns2[currentpattern].octaveoffset,
						patterns2[currentpattern].patternseq, speed);
					break;
			}
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class nextPattern implements ActionListener 
	{
		public void actionPerformed(ActionEvent event) 
		{
			Component c = (Component)event.getSource();
			StringBuffer rootdata;
			Integer cint;
			showfretboard = false;
			repaint();

			if (patternmode == 1)  // random intervals
			{
				currentpattern = RANDOMINT;  // set random mode
				rootdata = new StringBuffer(rootgenerator.getRootNote());
				currentroot = rootdata.toString();
				randpattern.rootnote = rootdata.charAt(0);
				randpattern.octaveoffset = (int)(rootdata.charAt(1) - '0');
				if (patternlevel == 2)
				{
					randpattern.patternseq = intgenerator.getIntervals(5);
				}
				else
				{
					randpattern.patternseq = "1 " + intgenerator.getIntervals(patternlevel + 2);
				}
				randpattern.patterntext = "Root = " + rootdata;
				hintlabel.setText(" " + randpattern.patterntext);
				sollabel.setText("");
				if (workmode == 1)
				{
					sollabel.setText(randpattern.patternseq);
				}
				else
				{
					sollabel.setText("Neues Pattern ...");
				}
				return;
			}
	
			rootdata = new StringBuffer();
			switch(patternlevel)
			{
				case 0:
					currentpattern = rndgen.nextInt(maxpattern0 + 1);
					hintlabel.setText(" " + patterns0[currentpattern].patterntext);
					sollabel.setText("");
					if (workmode == 1)
					{
						sollabel.setText(patterns0[currentpattern].patternseq);
					}
					else
					{
						sollabel.setText("Neues Pattern ...");
					}
					rootdata.append(patterns0[currentpattern].rootnote);
					rootdata.append((char)(patterns0[currentpattern].octaveoffset + '0'));
					currentroot = rootdata.toString();
					break;
				case 1:
					currentpattern = rndgen.nextInt(maxpattern1 + 1);
					hintlabel.setText(" " + patterns1[currentpattern].patterntext);
					sollabel.setText("");
					if (workmode == 1)
					{
						sollabel.setText(patterns1[currentpattern].patternseq);
					}
					else
					{
						sollabel.setText("Neues Pattern ...");
					}
					rootdata.append(patterns1[currentpattern].rootnote);
					rootdata.append((char)(patterns1[currentpattern].octaveoffset + '0'));
					currentroot = rootdata.toString();
					break;
				case 2:
					currentpattern = rndgen.nextInt(maxpattern2 + 1);
					hintlabel.setText(" " + patterns2[currentpattern].patterntext);
					sollabel.setText("");
					if (workmode == 1)
					{
						sollabel.setText(patterns2[currentpattern].patternseq);
					}
					else
					{
						sollabel.setText("Neues Pattern ...");
					}
					rootdata.append(patterns2[currentpattern].rootnote);
					rootdata.append((char)(patterns2[currentpattern].octaveoffset + '0'));
					currentroot = rootdata.toString();
					break;
			}			
				
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class showPattern implements ActionListener 
	{
		public void actionPerformed(ActionEvent event) 
		{
			Component c = (Component)event.getSource();

			repaint();
			
			if (currentpattern == RANDOMINT)
			{
				sollabel.setText(randpattern.patternseq);
				showfretboard = true;
				repaint();
				return;
			}
			
			switch(patternlevel)
			{
				case 0:
					sollabel.setText(patterns0[currentpattern].patternseq);
					break;
				case 1:
					sollabel.setText(patterns1[currentpattern].patternseq);
					break;
				case 2:
					sollabel.setText(patterns2[currentpattern].patternseq);
					break;
			}
			showfretboard = true;
			repaint();
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class modeChange implements ItemListener 
	{
		public void itemStateChanged(ItemEvent event) 
		{
			workmode = modeselect.getSelectedIndex();
			showfretboard = false;
			repaint();
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class randChange implements ItemListener 
	{
		public void itemStateChanged(ItemEvent event) 
		{
			patternmode = randomize.getSelectedIndex();
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class tempoChange implements ItemListener 
	{
		public void itemStateChanged(ItemEvent event) 
		{
			int	selectedindex;

			selectedindex = temposelect.getSelectedIndex();
			tempo = 60;
			switch(selectedindex)
			{
				case 0: tempo = 30; break;
				case 1: tempo = 60; break;
				case 2: tempo = 90; break;
				case 3: tempo = 120; break;
				case 4: tempo = 150; break;
			}
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class midiChange implements ItemListener 
	{
		public void itemStateChanged(ItemEvent e) 
		{
			int	selectedindex;

			selectedindex = midilist.getSelectedIndex();
			midichannel = 1;
			switch(selectedindex)
			{
				case 0: midichannel = 35; break;
				case 1: midichannel = 34; break;
				case 2: midichannel = 36; break;
				case 3: midichannel = 33; break;
				case 4: midichannel = 44; break;
				case 5: midichannel = 1; break;
				case 6: midichannel = 43; break;
			}

			if (instruments != null) 
			{
                		synthesizer.loadInstrument(instruments[midichannel - 1]);
        		}
	            	cc.channel.programChange(midichannel - 1);
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class levelChange implements ItemListener 
	{
		public void itemStateChanged(ItemEvent e) 
		{
			patternlevel = playlevel.getSelectedIndex();
			return;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

    	class ChannelData 
	{
		MidiChannel channel;
        	boolean solo, mono, mute, sustain;
        	int velocity, pressure, bend, reverb;
        	int row, col, num;
 
        	public ChannelData(MidiChannel channel, int num) 
		{
            		this.channel = channel;
            		this.num = num;
            		velocity = pressure = bend = reverb = 64;
        	}
     	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	class Pattern
	{
		public	char	rootnote;
		public	int	octaveoffset;
		public	String	patterntext;
		public	String	patternseq;

		public Pattern(char aroot, int aoctave, String atext, String apattern)
		{
			this.rootnote = aroot;
			this.octaveoffset = aoctave;
			this.patterntext = atext;
			this.patternseq = apattern;
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	class RandomIntervals
	{
		private Random intervalrndgen;		
		private StringBuffer intervallist;
		private String[] possibleints0 = { "b2", "2", "b3", "3", "4", "b5", "5",
			"6", "b7", "7", "8" }; 
		private String[] possibleints1 = { "b2", "2", "b3", "3", "4", "b5", "5",
			"#5", "6", "b7", "7", "8", "b9", "9" }; 
		private String[] possibleints2 = { "1", "b2", "2", "b3", "3", "4", "b5", "5",
			"#5", "b6", "6", "b7", "7", "8", "b9", "9", "b10", "10" }; 
		private String[] selectints;
		
		public RandomIntervals()
		{
			intervalrndgen = new Random(System.currentTimeMillis());
		}

		public String getIntervals(int count)
		{
			int	i;
			int	p1;
			int	rand1;
			String anint;
			boolean[] used = new boolean[25];
			
			intervallist = new StringBuffer();
			selectints = possibleints0;
			switch(patternlevel)
			{
				case 1: selectints = possibleints1; break;
				case 2: selectints = possibleints2; break;
			}

			for (i = 0; i < 25; i++)
			{
				used[i] = false;
			}

			i = 0;
			while (i < count)
			{
				rand1 = intervalrndgen.nextInt(selectints.length);
				anint = new String();
				anint = selectints[rand1];
				// check unique-ness!
				if (used[rand1] == false)
				{
					intervallist.append(anint);
					used[rand1] = true;
					intervallist.append(" ");
					i++;
				}
			}
			intervallist.setLength(intervallist.length() - 1);
			return(intervallist.toString());
		}
	}
		
	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	class RandomRootNote
	{
		private Random rootrndgen;		
		private String[] possibleroots = { "E2", "F2", "G2", "A2", "B2", "C3" }; 

		public RandomRootNote()
		{
			rootrndgen = new Random(System.currentTimeMillis());
		}

		public String getRootNote()
		{

			return(possibleroots[rootrndgen.nextInt(possibleroots.length)].toString());
		}
	}

	// ~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~~-~-~

	public class FretBoardPanel extends JPanel 
	{
		Color 	bg = Color.lightGray;
   		Color 	fg = Color.black;
		Insets 	insets = getInsets();
        	int 	currentWidth = getWidth() - insets.left - insets.right;
        	int 	currentHeight = getHeight() - insets.top - insets.bottom;
		int	startx = insets.left + 20;
		int	starty = insets.top + 20;
		int	fretboardwidth = 90;
		int	fretboardlength = 500;
		int	fretdiststart = 24;
		int	markersize = 8;
		int	fretpos;
		int	stringdist = fretboardwidth / 3;
		int	fretdist = fretdiststart;


		public FretBoardPanel()
		{
			// setBackground(bg);
			setForeground(fg);
			setBorder(BorderFactory.createEtchedBorder());
		}
    
		public void paintComponent(Graphics g) 
		{
			int	i;
			
        		super.paintComponent(g); //paint background

			if (showfretboard == false)
			{
				return;
			}

			// Draw fretboard
			g.setColor(fbcolor);
			g.fill3DRect(startx, starty - 3, fretboardlength + 5, fretboardwidth + 8, true); 

        		//Draw zero-fret
			g.setColor(Color.black);
			g.fill3DRect(startx - 2, starty - 3, 4, fretboardwidth + 8, true);
			
			// draw frets
			g.setColor(fwcolor);
			fretpos = fretdiststart;
			while (fretpos < fretboardlength)
			{
				g.drawLine(startx + fretpos, starty - 3, startx + fretpos, starty + fretboardwidth + 5);
				fretpos += fretdiststart;
			}
			
			// draw markers;
			// singles
			setMarkers(2, 1, g);
			setMarkers(4, 1, g);
			setMarkers(8, 1, g);
			setMarkers(14, 1, g);
			setMarkers(16, 1, g);
			// doubles
			setMarkers(6, 2, g);
			setMarkers(11, 2, g);
			setMarkers(18, 2, g);

			// draw strings
			g.setColor(Color.gray);
			g.fill3DRect(startx, starty, fretboardlength, 2, true); 
			g.fill3DRect(startx, starty + stringdist - 1, fretboardlength, 3, true); 
			g.fill3DRect(startx, starty + (2 * stringdist) - 1, fretboardlength, 3, true); 
			g.fill3DRect(startx, starty + (3 * stringdist) - 2, fretboardlength, 4, true); 

			// Draw the intervals
			if (currentpattern == RANDOMINT) // random mode
			{
				drawIntervals(currentroot, randpattern.patternseq, g);
				return;
			}

			switch(patternlevel)
			{
				case 0:
					drawIntervals(currentroot, patterns0[currentpattern].patternseq, g);
					break;
				case 1:
					drawIntervals(currentroot, patterns1[currentpattern].patternseq, g);
					break;
				case 2:
					drawIntervals(currentroot, patterns2[currentpattern].patternseq, g);
					break;
			}

			return;
		}

		public void setMarkers(int markerposition, int marknum, Graphics graph)
		{
		
			if (marknum == 1)
			{
				graph.setColor(markercolor);
				graph.fillOval(startx + (markerposition * fretdist + (fretdist / 2)) - (markersize / 2),
					starty + (fretboardwidth / 2) - (markersize / 2),
					markersize, markersize);
			}
			else
			{
				graph.setColor(markercolor);
				graph.fillOval(startx + (markerposition * fretdist + (fretdist / 2)) - (markersize / 2),
					starty + (fretboardwidth / 2) - (markersize / 2) - markersize,
					markersize, markersize);
				graph.fillOval(startx + (markerposition * fretdist + (fretdist / 2)) - (markersize / 2),
					starty + (fretboardwidth / 2) - (markersize / 2) + markersize,
					markersize, markersize);
			}
			return;
		}

		public void drawIntervals(String root, String intervallist, Graphics g)
		{
			int		i;
			int		pch;
			int		stringindex; // E2 = 0
			int		fretindex = 0;
			int		rootindex = 0;
			int		stringshift = 0;
			int		drawstring = 0;
			int		drawfret = 0;
			int		hit = 0;
			int		ovaltype = 0; // 0 = filled, else circle
			int		ovalsize = 13;
			int		rectsize = 15;
			int		textlen;
			char		intchar;
			String[]	stringfinder = { "E2", "F2", "G2", "A2", "B2", "C3",
						"D3", "E3", "F3", "G3", "A3", "B3", "C4" };
			String		compinterval;
			StringBuffer	interval;
			FontMetrics	fm;


			g.setFont(fretboardfont);

			rootindex = -1;
			for (i = 0; i < 13; i++)
			{
				if (stringfinder[i].compareTo(root) == 0) 
				{
					rootindex = i;
					break;
				}
			}
			if (rootindex < 0) { return; }
			stringindex = 0;
			fretindex = 0;

			switch(rootindex)
			{
				case 0: stringindex = 0; fretindex = 0; break; // E2
				case 1: stringindex = 0; fretindex = 1; break; // F2
				case 2: stringindex = 0; fretindex = 3; break; // G2
				case 3: stringindex = 0; fretindex = 5; break; // A2
				case 4: stringindex = 1; fretindex = 2; break; // B2
				case 5: stringindex = 1; fretindex = 3; break; // C3
				case 6: stringindex = 1; fretindex = 5; break; // D3
				case 7: stringindex = 1; fretindex = 7; break; // E3
				case 8: stringindex = 1; fretindex = 8; break; // F3
				case 9: stringindex = 2; fretindex = 5; break; // G3
				case 10: stringindex = 2; fretindex = 7; break; // A3
				case 11: stringindex = 3; fretindex = 4; break; // B3
				case 12: stringindex = 3; fretindex = 5; break; // C4
			}

			// now stringindex/fretindex is the root note, scan interval list
			// calculate string and fret, watch out for string boundaries!

			for (i = 0; i < intervallist.length(); i++)
			{
				if (intervallist.charAt(i) == ' ') { continue; }
				interval = new StringBuffer();
				while ((i < intervallist.length()) && ((intchar = intervallist.charAt(i)) != ' ')) 
				{ 
					interval.append(intchar);
					i++;
				}

				compinterval = new String();
				compinterval = interval.toString();
				hit = 0;
				ovaltype = 1;
				drawstring = stringindex;
				drawfret = fretindex;
				// the bid Find-The-Interval-Position!!!
				while (hit == 0) 
				{
				   if (compinterval.compareTo("1") == 0) { 
					ovaltype = 0; // it's root note;
					break; };
			
				   if (compinterval.compareTo("b2") == 0) { 
					drawfret++;
					break; };

				   if (compinterval.compareTo("2") == 0) { 
					drawfret += 2;
					break; };

				   if (compinterval.compareTo("b3") == 0) {
					if ((drawfret > 1) && (drawstring < 3)) 
					{
					   drawfret -= 2;
					   drawstring++; 
					}
					else 
					{ 
					   drawfret += 3;
					}
					break; 
				   }

				   if (compinterval.compareTo("3") == 0) 
				   { 
					if ((drawfret > 1) && (drawstring < 3)) 
					{
					   drawfret--;
					   drawstring++; 
					}
					else 
					{ 
					   drawfret += 4;
					}
					break; 
				   }

				   if (compinterval.compareTo("4") == 0) 
				   { 
					if (drawstring < 3) 
					{
					   drawstring++; 
					}
					else 
					{
					   drawfret += 5; 
					}
					break; 
				   }

				   if (compinterval.compareTo("b5") == 0) 
				   { 
					if (drawstring < 3) 
					{
					   drawstring++;
					   drawfret++; 
				   	}
				   	else 
				   	{
					   drawfret += 6; 
				   	}
					break; 
				   }

				   if (compinterval.compareTo("#4") == 0) 
				   { 
					if (drawstring < 3) 
					{
					   drawstring++;
					   drawfret++; 
				   	}
				   	else 
				   	{
					   drawfret += 6; 
				   	}
					break; 
				   }

				   if (compinterval.compareTo("5") == 0) 
				   { 
					if (drawstring < 3) 
					{
					   drawstring++;
					   drawfret += 2; 
					}
					else 
					{
					   drawfret += 7; 
					}
					break; 
				   }

				   if (compinterval.compareTo("#5") == 0) 
				   { 
					if (drawstring < 3) 
					{
					   drawstring++;
					   drawfret += 3; 
					}
					else 
					{
					   drawfret += 8; 
					}
					break; 
				   }

				   if (compinterval.compareTo("b6") == 0) 
				   { 
					if (drawstring < 3) 
					{
					   drawstring++;
					   drawfret += 3; 
					}
					else 
					{
					   drawfret += 8; 
					}
					break; 
				   }

				   if (compinterval.compareTo("6") == 0) 
				   { 
					if ((drawfret > 0) && (drawstring < 2))
					{
					   drawfret--;
					   drawstring += 2; 
					}
					else 
					{ 
					   if (drawstring < 3) 
					   {
						drawstring++;
						drawfret += 4; 
					   }
					   else 
					   {
						drawfret += 9; 
					   }
					}
					break; 
				   }

				   if (compinterval.compareTo("b7") == 0) 
				   { 
					if (drawstring < 2) 
					{
					   drawstring += 2; 
					}
					else 
					{ 
					   if (drawstring < 3) 
					   {
						drawstring++; 
						drawfret += 5; 
					   }
					   else 
					   {
						drawfret += 10; 
					   }
					}
					break; 
				   }

				   if (compinterval.compareTo("7") == 0) 
				   { 
					if (drawstring < 2) 
					{
					   drawstring += 2;
					   drawfret++; 
					}
					else 
					{ 
					   if (drawstring < 3) 
					   {
						drawstring++; 
						drawfret += 6; 
					   }
					   else 
					   {
						drawfret += 11; 
					   }
	 				}
					break; 
				   }

				   if (compinterval.compareTo("8") == 0) 
				   { 
					if (drawstring < 2) 
					{
					   drawstring += 2; 
					   drawfret += 2;
					}
					else 
					{ 
					   if (drawstring < 3) 
					   {
						drawstring++; 
						drawfret += 7; 
					   }
					   else 
					   {
						drawfret += 12; 
					   }
					}
					break; 
				   }

				   if (compinterval.compareTo("b9") == 0) 
				   { 
					if (drawstring < 2) 
					{
					   drawstring += 2; 
					   drawfret += 3; 
					}
					else 
					{ 
					   if (drawstring < 3) 
					   {
						drawstring++; 
						drawfret += 8; 
					   }
					   else 
					   {
						drawfret += 13; 
					   }
					}
					break; 
				   }

				   if (compinterval.compareTo("9") == 0) 
				   { 
					if (drawstring < 2) 
					{
					   drawstring += 2; 
					   drawfret += 4; 
					}
					else 
					{ 
					   if (drawstring < 3) 
					   {
						drawstring++; 
						drawfret += 9; 
					   }
					   else 
					   {
						drawfret += 14; 
					   }
					}
					break; 
				   }

				   if (compinterval.compareTo("b10") == 0) 
				   { 
					if (drawstring == 0) 
					{ 
					   drawstring += 3;  
					   break;
					}
					if (drawstring == 1) 
					{ 
					   drawstring += 2; drawfret += 5; 
					   break;
					}
					if (drawstring == 2) 
					{ 
					   drawstring += 1; drawfret += 10;
					   break;
					}
					drawfret += 15;
					break; 
				   }

				   if (compinterval.compareTo("10") == 0) 
				   { 
					if (drawstring == 0) 
					{ 
					   drawstring += 3; drawfret += 1; 
					   break;
					}
					if (drawstring == 1) 
					{ 
					   drawstring += 2; drawfret += 6; 
					   break;
					}
					if (drawstring == 2) 
					{ 
					   drawstring += 1; drawfret += 11;
					   break;
					}
		 		      	drawfret += 16;
				   }
				   hit = 1; continue;
				}
			
				// drawstring is the string, drawfret is the fret to paint
				switch(drawstring)
				{
					case 0: drawstring = 3; break;
					case 1: drawstring = 2; break;
					case 2: drawstring = 1; break;
					case 3: drawstring = 0; break;
				}

				if (ovaltype != 0) // not root
				{
					g.setColor(Color.black);
					fm = g.getFontMetrics();
					textlen = 0;
					for (pch = 0; pch < interval.length(); pch++)
					{
						textlen += fm.charWidth(interval.charAt(pch));
					}
					g.setColor(intervalcolor);
					g.fillRoundRect(startx + (fretdist * drawfret) - ((textlen + 4) / 2),
						starty + (stringdist * drawstring) - (rectsize / 2),
						textlen + 4, rectsize, 2, 2);

					g.setColor(Color.yellow);
					g.drawString(interval.toString(),
						startx + (fretdist * drawfret) - (textlen / 2),
						starty + (stringdist * drawstring) + (fm.getAscent() / 2));
				}
				else
				{
					g.setColor(rootcolor);
					g.fillOval(startx + (fretdist * drawfret) - (ovalsize / 2),
						starty + (stringdist * drawstring) - (ovalsize / 2) - 1,
						ovalsize, ovalsize);
				}
			}
		return;
		}
	}
} 

