public interface Internationalized
{
	/*
	public String getLicenseString() {
		return "This file is covered by the GNU GENERAL PUBLIC LICENSE, Version 2, June 1991";
	}
	*/

    /**
     * This method must by implemented were all the call to setText,setTitle methods and any
     * other method that involves a VISIBLE string are placed in here
     */
    public void setLangText() ; 
}
 public class ScrollText 
extends JFrame 
implements LicenseString

{ 
    String initial ;
    private int width = 500 ;
    private int height = 500 ;
    private Dimension screenSize ;
    private JPanel JPlogo ;
    private JLabel logo;

    public String getLicenseString() {
    	return "This file is covered by the GNU GENERAL PUBLIC LICENSE, Version 2, June 1991";
    }
    /** Creates new form ScrollText */
    public ScrollText() {
        super() ;
        initComponents();
    }
    public ScrollText(String init) {
        super() ;
        initComponents();
        this.initial = init ;
        this.STP.setText(this.initial) ;
    }
    public void setDisabledColor() {
        this.STP.setDisabledColor() ;
    }
    public void setSTPColor(java.awt.Color c) {
        this.STP.setBackground(c) ;
    }
    
    public void addLogo(String imageName) {
        JPlogo = new JPanel() ;
        logo = new javax.swing.JLabel();
        logo.setIcon(new javax.swing.ImageIcon(imageName));
        JPlogo.add(logo) ;
        getContentPane().add(JPlogo, java.awt.BorderLayout.NORTH);
        this.validate() ;
    }
    public void removeLogo() {
        getContentPane().remove(JPlogo) ;
        this.validate() ;
    }
    public void setEditable(boolean b) {
        this.STP.setEditable(b) ;
    }
    
    public void setText(String str) 
    {
        this.STP.setText(str) ;
    }
    public void append(String str)
    {
        this.STP.append(str) ;
    }
    public void displayFile(String file)
    {
        this.STP.displayFile(file) ;
    }   
    public void setWidth(int w) {
        if(w > 0) {
            this.width = w ;
            this.setBounds((screenSize.width-width)/2, (screenSize.height-height)/2, width, height);
        }
    }
    public void setHeight(int h) {
        if(h > 0) {
            this.height = h ;
            this.setBounds((screenSize.width-width)/2, (screenSize.height-height)/2, width, height);
        }
    }
    public void setClosable(boolean isClosable, boolean doExit) {
        if(isClosable) {
            if(doExit) {
                setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) ;
            } else {
                setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE) ;
            }
        }
        else {
            setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE) ;
        }
    }
    public ScrollTextPanel getScrollTextPanel() {
        return this.STP ;
    }
    public void addClearLog() {
        javax.swing.JPanel jPanel2 ;
        javax.swing.JButton clear ;


        jPanel2 = new javax.swing.JPanel();
        clear = new javax.swing.JButton();
        
        clear.setText("Clear Log");
        clear.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearActionPerformed(evt);
            }
        });
        jPanel2.add(clear);
        getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH);
    }
    private void clearActionPerformed(java.awt.event.ActionEvent e) {
        this.STP.setText(this.initial) ;
    }
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        STP = new common.ScrollTextPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("DGUITAR LOG");
        setFont(new java.awt.Font("Arial", 0, 12));
        getContentPane().add(jPanel1, java.awt.BorderLayout.SOUTH);

        getContentPane().add(jLabel1, java.awt.BorderLayout.NORTH);

        STP.setBackground(new java.awt.Color(255, 255, 255));
        STP.setEditable(true);
        getContentPane().add(STP, java.awt.BorderLayout.CENTER);

        screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-625)/2, (screenSize.height-327)/2, 625, 327);
    }//GEN-END:initComponents
    

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private common.ScrollTextPanel STP;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JPanel jPanel1;
    // End of variables declaration//GEN-END:variables
    
} public abstract class SwingWorker 
{
    private Object value;  // see getValue(), setValue()
    //private Thread thread; commented since never used

    public String getLicenseString() {
    	String res ;
    	
    	res = "" ;
    	res += "SwingWorder.java is released withe SUN Code sample License" ;
    	res += "\n\n" ;
    	res += "Copyright 1994-2005 Sun Microsystems, Inc. All Rights Reserved." ;
        res += "\n\n" ;
    	res += "see SwingWorker.java file for more details." ;
    		
    		return res ;
    }

    /** 
     * Class to maintain reference to current worker thread
     * under separate synchronization control.
     */
    private static class ThreadVar {
        private Thread thread;
        ThreadVar(Thread t) { thread = t; }
        synchronized Thread get() { return thread; }
        synchronized void clear() { thread = null; }
    }

    private ThreadVar threadVar;

    /** 
     * Get the value produced by the worker thread, or null if it 
     * hasn't been constructed yet.
     */
    protected synchronized Object getValue() { 
        return value; 
    }

    /** 
     * Set the value produced by worker thread 
     */
    private synchronized void setValue(Object x) { 
        value = x; 
    }

    /** 
     * Compute the value to be returned by the <code>get</code> method. 
     */
    public abstract Object construct();

    /**
     * Called on the event dispatching thread (not on the worker thread)
     * after the <code>construct</code> method has returned.
     */
    public void finished() {
    }

    /**
     * A new method that interrupts the worker thread.  Call this method
     * to force the worker to stop what it's doing.
     */
    public void interrupt() {
        Thread t = threadVar.get();
        if (t != null) {
            t.interrupt();
        }
        threadVar.clear();
    }

    /**
     * Return the value created by the <code>construct</code> method.  
     * Returns null if either the constructing thread or the current
     * thread was interrupted before a value was produced.
     * 
     * @return the value created by the <code>construct</code> method
     */
    public Object get() {
        while (true) {  
            Thread t = threadVar.get();
            if (t == null) {
                return getValue();
            }
            try {
                t.join();
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // propagate
                return null;
            }
        }
    }


    /**
     * Start a thread that will call the <code>construct</code> method
     * and then exit.
     */
    public SwingWorker() {
        final Runnable doFinished = new Runnable() {
           public void run() { finished(); }
        };

        Runnable doConstruct = new Runnable() { 
            public void run() {
                try {
                    setValue(construct());
                }
                finally {
                    threadVar.clear();
                }

                SwingUtilities.invokeLater(doFinished);
            }
        };

        Thread t = new Thread(doConstruct);
        threadVar = new ThreadVar(t);
    }

    /**
     * Start the worker thread.
     */
    public void start() {
        Thread t = threadVar.get();
        if (t != null) {
            t.start();
        }
    }
} public class GPAdaptor {
    private static String className = GPAdaptor.class.toString();

    private static Logger logger = Logger.getLogger(className);

    // The following definition of pulses per quarter note is for high
    // resolution,
    // supporting up to dotted 128th notes and all n-tuplet types up to 13.
    // Unfortunately you won't get this in a MIDI file. (Who would ever need
    // dotted 128th, 5, 7, 9, 11 and 13 n-tuplets in the same piece?).
    private static final int PPQ_HIGH_RESOLUTION = 2882880;

    // ...so we compromise. We internally run the adaptor at the high resultion
    // but in actual fact generate a score that's at a far more reasonable
    // scale.
    private static final int PPQ_SCALE_FACTOR = 286;

    /**
     * Create and return a regular SongMeasure from the current position of the
     * iterators.
     * 
     * @param itM
     *            an iterator over the measures collection. It must be pointing
     *            so that itM.next() returns the current measure, which will be
     *            marked as a repeatStart.
     * @param itMTP
     *            an iterator over the measure-track pairs collection. It must
     *            be pointing so that itMTP.next() returns the first track of
     *            the current measure
     * @param tracks
     *            The tracks definitions
     * @return a new filled-out SongMeasure
     * @throws GP4AdaptorException
     */
    private static RepeatedSongPhrase makeRepeatedSongPhrase(Song song,
            ListIterator<GPMeasure> itM, ListIterator<GPMeasureTrackPair> itMTP, List<GPTrack> tracks)
            throws GPFormatException {
        SongPhraseList spl = new SongPhraseListImpl();

        // read the first measure without testing for the repeat marker again.
        spl.addPhrase(makeSongMeasure(song, itM, itMTP, tracks));

        // look back at the last measure processed to see if we've done
        GPMeasure measure = itM.previous();
        itM.next();
        int repeatCount = measure.getNumberOfRepetitions();

        // keep calling the phrase factory until you find a measure
        // that's marked with a repeat count. If you run out of measures
        // (Corneille)
        // then assume the last measure has a repeat count of 1.
        while (repeatCount == 0) {
            if (!itM.hasNext()) {
                logger
                        .fine("Got to end of score before finding a closing repeat mark, assuming 1");
                repeatCount = 1;
                break;
            }
            SongPhrase phrase = phraseFactory(song, itM, itMTP, tracks);
            spl.addPhrase(phrase);
            measure = itM.previous();
            itM.next();
            repeatCount = measure.getNumberOfRepetitions();
            logger.fine("Repeat count measure at " + measure.getNumber()
                    + " is " + repeatCount);
        }

        return new RepeatedSongPhraseImpl(spl, repeatCount);
    }

    /**
     * Create and return a regular SongMeasure from the current position of the
     * iterators.
     * 
     * @param itM
     *            an iterator over the measures collection. It must be pointing
     *            so that itM.next() returns the current measure
     * @param itMTP
     *            an iterator over the measure-track pairs collection. It must
     *            be pointing so that itMTP.next() returns the first track of
     *            the current measure
     * @param tracks
     *            The tracks definitions
     * @return a new filled-out SongMeasure
     * @throws GP4AdaptorException
     */
    private static SongMeasure makeSongMeasure(Song song, ListIterator<GPMeasure> itM,
            ListIterator<GPMeasureTrackPair> itMTP, List<GPTrack> tracks) {
        GPMeasure measure = itM.next();

        int ending = measure.getNumberOfAlternateEnding();
        if (ending > 0) {
            logger.warning("Measure " + measure.getNumber()
                    + " is alternate ending " + ending);
        }

        // TODO getNumber
        // TODO getNumberOfAlternateEnding
        // TODO getNumberOfRepetitions
        // TODO getTonality
        int numerator = measure.getNumerator();
        int denominator = measure.getDenominator();

        int measureLength = PPQ_HIGH_RESOLUTION * 4 * numerator / denominator;
        //OLD MGG logger.finer("Measure "+measure.getNumber()+",
        // "+numerator+"/"+denominator+", length " + measureLength);
        TimeSignature ts = new TimeSignature(numerator, denominator);
        SongMeasure sm = new SongMeasureImpl(measure.getNumber(), measureLength
                / PPQ_SCALE_FACTOR, ts);

        for (int trackIndex = 1; trackIndex <= tracks.size(); trackIndex++) {
            GPTrack track = tracks.get(trackIndex - 1);
            // TODO is12StringedGuitarTrack
            // TODO isBanjoTrack
            // TODO getter/setter for isDrumsTrack

            // TODO getChannelEffects
            // TODO getColor
            // TODO getName
            // TODO getNumberOfFrets
            // TODO getPort
            int capo = track.getCapo();
            int strings = track.getNumberOfStrings();
            int stringTuning[] = new int[strings];
            for (int i = 0; i < strings; i++)
                stringTuning[i] = track.getStringsTuning(i);

            //OLD  MGG logger.finer("Measure " + measure.getNumber() + " Track "+
            // trackIndex);
            GPMeasureTrackPair mtp = itMTP.next();
            SongMeasureTrack smt = new SongMeasureTrackImpl(song
                    .getTrack(trackIndex));
            sm.addTrack(smt);

            List<GPBeat> beats = mtp.getBeats();
            int beatOffset = 0;
            for (Iterator<GPBeat> itBeat = beats.iterator(); itBeat.hasNext();) {
                GPBeat beat = itBeat.next();

                // TODO effects

                GPDuration duration = beat.getDuration();
                // TODO add getter and setter for GP4Beat.dottedNotes
                boolean dotted = beat.dottedNotes;
                int ntuplet = beat.getNTuplet();

                int beatDuration = calculateDuration(duration, dotted, ntuplet);

                if (beat.isNoteBeat()) {
                    List<GPNote> notes = beat.getNotes();
                    List<Integer> stringsPlayed = new LinkedList<Integer>();
                    // TODO suggest an easier way of returning the played
                    // string list
                    for (int i = 6; i >= 0; i--) {
                        if (beat.isStringPlayed(i)) {
                            stringsPlayed.add(new Integer(i));
                        }
                    }

                    Iterator<GPNote> itNotes = notes.iterator();
                    Iterator<Integer> itStrings = stringsPlayed.iterator();
                    
                    while (itNotes.hasNext()) {
                        
//						OLD MGG Integer stringObject = (Integer) itStrings.next();
// see TODO.TXT or NEWFEATURES.TXT
//						this lines were added to fix the GTP playing error - BEGIN
                        Integer stringObject;

                        if (!itStrings.hasNext()) 
                        {
                            //this error appears to happen when its *.GTP file
                            //TODO show a friendly error
                            break;

                        }
                        /*ELSE*/
//						END
                        
                        stringObject = itStrings.next();
                        // Note that the tuning array has the highest string
                        // at index 0
                        // but the track has the highest string at index 6.

                        // TODO find out if this is correct. What about a
                        // 4-string bass?
                        int stringID = 6 - stringObject.intValue();

                        GPNote note = itNotes.next();
                        int noteDuration = beatDuration;

                        // see if this note has time independent settings on
                        // it
                        // TODO getter/setter for GP4Note.duration
                        GPDuration tiDuration = note.duration;
                        if (tiDuration != null) {
                            // TODO getter/setter for GP4Note.isDotted
                            boolean tiDotted = note.isDotted;
                            int tiTriplet = note.getNTuplet();
                            noteDuration = calculateDuration(tiDuration,
                                    tiDotted, tiTriplet);
                        }

                        // TODO isDeadNote
                        // TODO isGhostNote
                        // TODO isTieNote
                        // TODO effects

                        // TODO Note effects are a little bit difficult.
                        // Remember these are guitar effects
                        // so we effectively need a 'virtual track' for
                        // every string, so when we playback we
                        // can assign a unique MIDI channel to that track
                        // and so we can apply a channel-wide
                        // controller to that effect (such as pitch bend).
                        // Even the simple effect (let ring)
                        // can't be done easily right now because we can't
                        // tell when to really kill the note.
                        // Of course if we don't need an effect, we should
                        // try to use as few MIDI channels as
                        // we can!

                        int virtualTrackID = stringID;
                        SongVirtualTrack svt = smt
                                .getVirtualTrack(virtualTrackID);
                        int noteStart = beatOffset / PPQ_SCALE_FACTOR;
                        int noteEnd = (beatOffset + noteDuration)
                                / PPQ_SCALE_FACTOR;

                        // FIXME cover the tie note case by grabbing the
                        // last fret
                        if (note.isTieNote()) {
                            svt.addEvent(new SongEventImpl(noteStart,
                                    new SongTieMessage(noteEnd - noteStart)));
                        } else {
                            int baseFret = note.getFretNumber();//OLD
                            // .getNumberOfFret();
                            int fret = baseFret + capo;
                            GPDynamic dynamic = note.getDynamic();
                            int velocity = DynamicsMap.velocityOf(dynamic);
                            int pitch = stringTuning[stringID] + fret;
                            svt.addEvent(new SongEventImpl(noteStart,
                                    new SongNoteOnMessage(pitch, velocity,
                                            noteEnd - noteStart, baseFret)));
                        }

                    }
                }
                beatOffset += beatDuration;
            }
            if (beatOffset != measureLength) {
                // an underfull one isn't fatal, but an overfull one is
                String reason = "Measure: " + measure.getNumber() + " track: "
                        + trackIndex + " length mismatch, expected "
                        + measureLength + ", got " + beatOffset;

                if (beatOffset > measureLength) {
                    logger.fine(reason);
                    System.err.println(reason);
                } else {
                    logger.fine(reason);
                }

            }
        }
        return sm;
    }

    /**
     * @param duration
     * @param dotted
     * @param ntuplet
     * @return the beat duration
     */
    private static int calculateDuration(GPDuration duration, boolean dotted,
            int ntuplet) {
        int durationIndex = duration.getIndex();
        int beatDuration = (PPQ_HIGH_RESOLUTION * 4) >> durationIndex;
        if (dotted) {
            beatDuration += (beatDuration >> 1);
        }
        if (ntuplet != 0) {
            TripletValue tv = TripletMap.getTriplet(ntuplet);
            beatDuration *= tv.getTimeOf();
            beatDuration /= tv.getNotes();
        }
        return beatDuration;
    }

    /**
     * Look ahead at the next measure, build and determine a suitable SongPhrase
     * to handle it.
     * 
     * @param itM
     *            an iterator over the measures collection. It must be pointing
     *            so that itM.next() returns the current measure, which will be
     *            marked as a repeatStart.
     * @param itMTP
     *            an iterator over the measure-track pairs collection. It must
     *            be pointing so that itMTP.next() returns the first track of
     *            the current measure
     * @param tracks
     *            The tracks definitions
     * @return the next SongPhrase
     */
    private static SongPhrase phraseFactory(Song song, ListIterator<GPMeasure> itM,
            ListIterator<GPMeasureTrackPair> itMTP, List<GPTrack> tracks) throws GPFormatException {
        SongPhrase sp = null;

        GPMeasure measure = itM.next(); // peek inside the measure
        // and dispatch to the right
        // factory
        itM.previous(); // rewind before calling the right factory method

        // TODO add getter and setter for GP4Measure.repeatStart
        logger.finer("Measure " + measure.getNumber() + " repeat start "
                + measure.repeatStart);
        logger.finer("Measure " + measure.getNumber() + " repeat count "
                + measure.getNumberOfRepetitions());

        // if it's the start of a repeat, then make a repeated phrase
        if (measure.repeatStart) {
            logger.fine("Creating a repeated phrase at " + measure.getNumber());
            sp = makeRepeatedSongPhrase(song, itM, itMTP, tracks);
        }

        // Failing everything else, just return a single measure
        if (sp == null) {
            logger.fine("Creating a measure phrase at " + measure.getNumber());
            sp = makeSongMeasure(song, itM, itMTP, tracks);
        }
        return sp;
    }

    /**
     * @param piece
     *            a loaded GP4 file
     * @return a representation of the piece that supports the Song interface
     * @throws GP4AdaptorException
     */
    public static Song makeSong(GPSong piece) throws GPFormatException {
        String methodName = "makeSong";
        logger.entering(className, methodName);

        int bpm = piece.getTempo();
        logger.finer("Tempo: " + bpm + "BPM");

        Tempo tempo = new Tempo();
        tempo.setBPM(bpm);

        Song song = new SongImpl(PPQ_HIGH_RESOLUTION / PPQ_SCALE_FACTOR, tempo);

        List<GPMeasure> measures = piece.getMeasures();
        logger.finer("Number of measures: " + measures.size());

        List<GPTrack> tracks = piece.getTracks();
        logger.finer("Number of tracks: " + tracks.size());

        //List fretStates = new LinkedList();

        int index = 1;
        for (Iterator<GPTrack> it = tracks.iterator(); it.hasNext(); index++) {
            GPTrack track = it.next();
            int port = track.getPort();
            int channel = track.getChannel();
            int channelEffects = track.getChannelEffects();

            logger.fine("Track " + index + " port " + port + " channels "
                    + channel + "," + channelEffects);

            int channelIndex = (port - 1) * 16 + (channel - 1);
            GPMIDIChannel mc = piece.getChannels(channelIndex);

            int strings = track.getNumberOfStrings();

            SongTrack st = new SongTrackImpl(index, strings); // channel is
            // 1-based
            st.setPrimaryDevice(new SongDeviceImpl(port, channel));
            if (channel != channelEffects) {
                st.setSecondaryDevice(new SongDeviceImpl(port, channelEffects));
            }

            st.setBendSensitivity(2);

            int instrument = mc.getInstrument();
            logger.fine("Instrument " + instrument);

            // Only set valid instruments. The drum track usually doesn't have
            // one.
            st.setProgram(instrument);

            // TODO Verify the volume setting is correct
            st.setVolume(8 * mc.getVolume());
            // TODO Verify the pan setting is correct
            st.setPan(8 * mc.getBalance());
            // TODO Verify the chorus setting is correct
            st.setChorus(8 * mc.getChorus());
            // TODO verify the reverb setting is correct
            st.setReverb(8 * mc.getReverb());
            // TODO Verify the tremolo setting is correct
            st.setTremolo(8 * mc.getTremolo());
            // TODO Verify the phaser setting is correct
            st.setPhaser(8 * mc.getPhaser());

            song.addTrack(st);
        }

        List<GPMeasureTrackPair> measureTrackPairs = piece.getMeasuresTracksPairs();
        logger.finer("Measure/Track pairs: " + measureTrackPairs.size());

        ListIterator<GPMeasureTrackPair> itMTP = measureTrackPairs.listIterator();
        ListIterator<GPMeasure> itM = measures.listIterator();

        while (itM.hasNext()) {
            SongPhrase sp = phraseFactory(song, itM, itMTP, tracks);
            song.addPhrase(sp);
        }

        logger.exiting(className, methodName, song);
        return song;
    }
} public abstract class CodecFormatException extends Exception {
   /**
	 * 
	 */
	private static final long serialVersionUID = 2890902020152189203L;
public CodecFormatException(String s) {
       super(s);
   }
   public CodecFormatException(String s, Throwable cause) {
       super(s, cause) ;
   }
}
 public abstract class GPFormatException extends CodecFormatException {
    /**
	 * 
	 */
	private static final long serialVersionUID = 485177597894441179L;

	/**
     * Creates a new GPFormatException described by s.
     * @param s the exception message.
     */
    public GPFormatException(String s) {
        super(s);
    }
    
    /**
     * Creates a new GPFormatException described by s, and cause.
     * @param s the exception message.
     * @param cause the exception cause.
     */
    public GPFormatException(String s, Throwable cause) {
        super(s, cause) ;
    }
} public class GPSong {
	public GPSong() {
		album = "";
        authorPiece = "";
        authorSong = "";
        channels = new GPMIDIChannel[64];
        //chordsDiagrams = new ArrayList(0);
        copyright = "";
        instruction = "";
        interpret = "";
        key = GPKey.G;
        lyrics = new GPTrackLyrics();
        measures = new ArrayList<GPMeasure>(0);
        measuresTracksPairs = new ArrayList<GPMeasureTrackPair>(0);
        note = "";
        octave = 8;
        subtitle = "";
        tempo = 100;
        title = "";
        tracks = new ArrayList<GPTrack>(0);
        tripletFeel = false;
        version = "unknown";
	}
    /** This class performs the actual loading of the file
	 *
	 */
	class StringImpl extends SwingWorker {
	    int i ;
	    int j ;
	    int numTracks ;
	    int numMeasures ;        
	    int deep ;
	    ScrollTextPanel STP ;
	    
	    public String res  ;
		private int tabsStrinImpl;
		//the number of \t to include
		/* (non-Javadoc)
		 * @see Common.SwingWorker#construct()
		 */
		public Object construct() {

	        return (this.toString()) ;
		}
	
	        
	    StringImpl(int howDeep, ScrollTextPanel stp) {
	    	STP = stp ;
	        this.tabsStrinImpl = 0 ;
	        this.deep = howDeep ;
	    }
	    /**Modifies the RES variable and Append to the ScrollTextPanel as necesary
	     * the number of tabs added depend on the tabsStrinImpl variable.
	     */
	    private void resAppend(String s) {
	        String aux ;
	        
	        aux = common.Util.tabs(tabsStrinImpl) + s ;
	        res += aux ;
	        if(this.STP != null) {
	            this.STP.append(aux) ;
	        }
	    }
	
	    
	    public String toString() {
	    	//DEBUG
	    	//System.err.println("TEXT VIEW!!") ;
	        
	    	res = "" ;
	        resAppend("GP - BEGIN\n") ;
	        
	        tabsStrinImpl++ ;
	        resAppend("HEADER - BEGIN\n") ;
	        resAppend("Version: " + version + "\n");
	        resAppend("Title: " + title + "\n") ;
	        resAppend("Subtitle: " + subtitle + "\n") ;
	        resAppend("Interpret: " + interpret + "\n") ;
	        resAppend("Album: " + album + "\n") ;
	        resAppend("Author of the song: " + authorSong + "\n");
	        resAppend("Copyright: " + copyright + "\n");
	        resAppend("Author of the piece: " + authorPiece + "\n");
	        resAppend("Instructions: " + instruction + "\n");
	        resAppend("Notes: " + note);
	        resAppend("Use triplet feel? " + tripletFeel + "\n");
	        resAppend(lyrics.toString());
	        resAppend("Tempo: " + tempo + "\n");
	        resAppend("Key: " + key + "\n");
	        resAppend("Octave: " + octave + "\n");
	        
	        numTracks =  tracks.size() ;            
	        resAppend("Number of measures: " + measures.size() + "\n");
	        resAppend("Number of tracks: " + tracks.size() + "\n");
	        resAppend("HEADER - END" + "\n") ;
	        tabsStrinImpl-- ;
	
	        
	        if(deep > 1) {
	            tabsStrinImpl++ ;
	            resAppend("MEASURES - BEGIN" + "\n") ;
	            for (i = 0; i < measures.size(); i++) {
	                resAppend("Measure #" + i + "\n") ;
	                resAppend(measures.get(i).toString() + "\n");
	            }
	            resAppend("MEASURES - END" + "\n") ;
	            tabsStrinImpl-- ;
	        }
	        
	        if(deep > 1) {
	            tabsStrinImpl++ ;
	            resAppend("TRACKS - BEGIN\n");
	            
	            for (i = 0; i < numTracks ; i++) {
	                resAppend("Track #" + (i+1) + "\n") ;
	                resAppend(tracks.get(i).toString() + "\n");
	            }
	            resAppend("TRACKS - END\n");
	            tabsStrinImpl-- ;
	        }
	        if(deep > 1) {
	            tabsStrinImpl++;
	            resAppend("MEASURE-TRACK PAIRS - BEGIN\n");
	            for (i = 0; i < measuresTracksPairs.size(); i++) {
	                resAppend("Measure #" + ((i/numTracks)+1) + " Track #" + (i%numTracks) + "\n") ;
	                resAppend(measuresTracksPairs.get(i).toString() + "\n");
	            }
	            resAppend("MEASURE-TRACK PAIRS - END\n");
	            tabsStrinImpl-- ;
	        }
	        if(deep > 1) {
	            tabsStrinImpl++ ;
	            resAppend("MIDI Channels - BEGIN\n");
	            for (i = 0; i < 4; i++) {
	                resAppend("Port: " + i + "\n" );
	                for (j = 0; j < 16; j++) {
	                    resAppend("Channel: " + j + "\n" );
	                    resAppend("" + channels[i*16+j] + "\n" ) ;
	                }
	            }
	            resAppend("MIDI Channels - END" + "\n");
	            tabsStrinImpl-- ;
	        }
	        tabsStrinImpl++ ;
	        resAppend("CHORD DIAGRAMS - BEGIN\n");
	        
	        resAppend("At this moment Chord Diagrams are not being read\n") ;
	        
	        resAppend("CHORD DIAGRAMS - END\n");
	        tabsStrinImpl-- ;
	        
	        resAppend("GP - END") ;
	        return res ;
	    }
	    /**
	     * this is called to find out how much work needd to be done to complete 
	     * the task of converting toString() ;
	     */
	    /*
	    public int getLengthOfTask() {
	        lengthOfTask = 10 ;
	        
	        return lengthOfTask;
	    }
	     */
	    
	    /**
	     * this is called to find how much progress has been made 
	     */
	    /*
	    public int getCurrent() {
	        return current;
	    }
	     */
	    /*
	     * Stops the toStringMethod
	     */
	    /*
	    public void stop() {
	        canceled = true;
	        statMessage = null;
	    }
	     */
	    
	    /**
	     * this is called to find out if the task has completed.
	     */
	    /*
	    public boolean isDone() {
	        return done;
	    }
	     */
	    
	    /**
	     * Returns the most recent status message, or null
	     * if there is no current status message.
	     */
	    /*
	    public String getMessage() {
	        return statMessage;
	    }
	     */
	}

	/**
     * The triplet feel.
     */
    public boolean tripletFeel;
    
    /**
     * The piece title.
     */
    protected String title;
    
    /**
     * The piece subtitle.
     */
    protected String subtitle;
    
    /**
     * The piece interpret.
     */
    protected String interpret;
    
    /**
     * The piece album.
     */
    protected String album;
    
    /**
     * The author of the song.
     */
    protected String authorSong;
    
    /**
     * The piece copyright.
     */
    protected String copyright;
    
    /**
     * The piece author.
     */
    protected String authorPiece;
    
    /**
     * The instructions to use with this piece.
     */
    protected String instruction;
    
    /**
     * Notes about the piece.
     */
    protected String note;
    
    /**
     * Lyrics associated with the tracks.
     */
    protected GPTrackLyrics lyrics;
    
    /**
     * The piece tempo.
     */
    protected int tempo;

	/**
	 * The MIDI channels used.
	 */
	protected GPMIDIChannel[] channels;

	/**
	 * A list of tracks present in this piece.
	 */
	protected List<GPTrack> tracks;

	/**
	 * A list of measures present in this piece.
	 */
	public List<GPMeasure> measures;

	/**
	 * A list of measures-tracks pairs containing data about the music.
	 */
	protected List<GPMeasureTrackPair> measuresTracksPairs;

	/**
	 * The version of the file the piece was loaded from.
	 */
	protected String version;

	SwingWorker worker ;

	/**
	 * A list of chords diagrams.
	 */
	//protected List chordsDiagrams;

	/**
	 * The key signature at the beginning of the piece.
	 */
	protected GPKey key;

	/**
	 * The octave (not used).
	 */
	protected int octave;

	/**
	 * @return Returns the album.
	 */
	public String getAlbum() {
	    return album;
	}

	/**
	 * @return Returns the authorPiece.
	 */
	public String getAuthorPiece() {
	    return authorPiece;
	}

	/**
	 * @return Returns the authorSong.
	 */
	public String getAuthorSong() {
	    return authorSong;
	}

	/**
	 * @return Returns the channels.
	 */
	public GPMIDIChannel getChannels(int i) {
	    return channels[i];
	}

	/**
	 * @return Returns the copyright.
	 */
	public String getCopyright() {
	    return copyright;
	}

	/**
	 * @return Returns the instruction.
	 */
	public String getInstruction() {
	    return instruction;
	}

	/**
	 * @return Returns the interpret.
	 */
	public String getInterpret() {
	    return interpret;
	}

	/**
	 * @return Returns the lyrics.
	 */
	public GPTrackLyrics getLyrics() {
	    return lyrics;
	}

	/**
	 * @return Returns the note.
	 */
	public String getNote() {
	    return note;
	}

	/**
	 * @return Returns the subtitle.
	 */
	public String getSubtitle() {
	    return subtitle;
	}

	/**
	 * @return Returns the tempo.
	 */
	public int getTempo() {
	    return tempo;
	}

	/**
	 * @return Returns the title.
	 */
	public String getTitle() {
	    return title;
	}
	
	public List<GPTrack> getTracks() {
        return tracks ;
	}

	/**
	 * @return Returns the version.
	 */
	public String getVersion() {
	    return version;
	}

	/**
	 * @return Returns the measures.
	 */
	public List<GPMeasure> getMeasures() {
	    return measures;
	}

	/**
	 * @return Returns the measuresTracksPairs.
	 */
	public List<GPMeasureTrackPair> getMeasuresTracksPairs() {
	    return measuresTracksPairs;
	}
	/**
	 * 
	 * @return Returns the number of Tracks of this Song
	 */
	public int getNumTracks() {
	    int res ;
	    
	    res = 0 ;
	    if(this.tracks != null) {
	        res = this.tracks.size() ;
	    }
	    
	    return res ;
	}
	/**
	 * 
	 * @return the number of measures of this Song
	 */
	public int getNumMeasures() {
	    int res ;
	    
	    res = 0 ;
	    if(this.measures != null) {
	        res = this.measures.size() ;
	    }
	    
	    return res ;
	}

	/**
	 * @return Returns a MeasureTrackPair
	 */
	public GPMeasureTrackPair getTrackMeasurePair(int track, int measure) {
	    return measuresTracksPairs.get(
	            (measure - 1) * tracks.size() + track - 1);
	}

	public void startDisplayString(final ScrollTextPanel stp) {
	    worker = new StringImpl(2,stp) ;
	    worker.start() ;
	    //DEBUG
	    //System.err.println("TEXT VIEW!!") ;
	}

	public void stopDisplayString() {
		if(worker != null) {
			worker.interrupt() ;
		}
	}

	/**
	 * Returns a string representation of this piece.
	 */
	public String toString() {
	    //the default DEEP is 100...in other words print every detail ;
	    //new StringImpl(100,null) ;
	    //return res ;
		return new StringImpl(100,null).toString() ;
	}

	/**
	 * @param album
	 *            The album to set.
	 */
	public void setAlbum(String album) {
	    this.album = album;
	}

	/**
	 * @param authorPiece
	 *            The authorPiece to set.
	 */
	public void setAuthorPiece(String authorPiece) {
	    this.authorPiece = authorPiece;
	}

	/**
	 * @param authorSong
	 *            The authorSong to set.
	 */
	public void setAuthorSong(String authorSong) {
	    this.authorSong = authorSong;
	}

	/**
	 * @param channels
	 *            The channels to set.
	 */
	public void setChannels(int i, GPMIDIChannel channels) {
	    this.channels[i] = channels;
	}

	/**
	 * @param copyright
	 *            The copyright to set.
	 */
	public void setCopyright(String copyright) {
	    this.copyright = copyright;
	}

	/**
	 * @param instruction
	 *            The instruction to set.
	 */
	public void setInstruction(String instruction) {
	    this.instruction = instruction;
	}

	/**
	 * @param interpret
	 *            The interpret to set.
	 */
	public void setInterpret(String interpret) {
	    this.interpret = interpret;
	}

	/**
	 * @param key
	 *            The key to set.
	 */
	public void setKey(GPKey key) {
	    this.key = key;
	}

	/**
	 * @param lyrics
	 *            The lyrics to set.
	 */
	public void setLyrics(GPTrackLyrics lyrics) {
	    this.lyrics = lyrics;
	}

	/**
	 * @param note
	 *            The note to set.
	 */
	public void setNote(String note) {
	    this.note = note;
	}

	/**
	 * @param octave
	 *            The octave to set.
	 */
	public void setOctave(int octave) {
	    this.octave = octave;
	}

	/**
	 * @param subtitle
	 *            The subtitle to set.
	 */
	public void setSubtitle(String subtitle) {
	    this.subtitle = subtitle;
	}

	/**
	 * @param tempo
	 *            The tempo to set.
	 */
	public void setTempo(int tempo) {
	    this.tempo = tempo;
	}

	/**
	 * @param title
	 *            The title to set.
	 */
	public void setTitle(String title) {
	    this.title = title;
	}

	/**
	 * @param version
	 *            The version to set.
	 */
	public void setVersion(String version) {
	    this.version = version;
	}

	/**
	 * @return Returns the chordsDiagrams.
	 */
	/*
	public List getChordsDiagrams() {
	    return chordsDiagrams;
	}
	 */
	/**
	 * @return Returns the key.
	 */
	public GPKey getKey() {
	    return key;
	}

	/**
	 * @return Returns a MeasureTrackPair
	 */
	public GPMeasureTrackPair getMeasureTrackPair(int measure, int track) {
	    return measuresTracksPairs.get(
	            (measure - 1) * tracks.size() + track - 1);
	}

	/**
	 * @return Returns the octave.
	 */
	public int getOctave() {
	    return octave;
	}

}
 public class GPStatsPiece extends GPStats {
    int numTracks ;
    int numMeasures ;
    GPStatsMeasureTrackPair MTPtotal ;
    String pieceName ;
    java.util.Vector<GPStatsMeasureTrackPair> MTPdetails ;
    int numTracksWithLyrics ;
    
    public GPStatsPiece() {
        numTracks = 0 ;
        numMeasures = 0 ;
        numTracksWithLyrics = 0 ;
        MTPtotal = new GPStatsMeasureTrackPair() ;
        MTPdetails = null ;
        pieceName = null ;
    }
    /**
     * this class gathers information about a single GPSong, you can dedicde
     * if you want detailed, The Sring pieceName contains the name to display.
     */
    public void getStats(GPSong p, String PieceName ) {
        int i ;
        int m ;
        int t ;
        int numMTPs ;
        List<GPMeasure> measures ;
        List<GPTrack> tracks ;
        List<GPMeasureTrackPair> MTPs ;
        GPStatsMeasureTrackPair detail ;
        GPMeasureTrackPair MTP ;
        
        this.pieceName = PieceName ;
        measures =  p.getMeasures() ;
        if(measures != null) {
            numMeasures = measures.size() ;
        }
        
        tracks = p.getTracks() ;
        if(tracks != null) {
            numTracks = tracks.size() ;
        }
        
        
        this.numTracksWithLyrics = (p.getLyrics() != null) ? 1 : 0 ;
        
        MTPs = p.getMeasuresTracksPairs() ;
        
        numMTPs = MTPs.size() ;
        MTPtotal = new GPStatsMeasureTrackPair() ;
        if(this.isDetailed()) {
            MTPdetails = new java.util.Vector<GPStatsMeasureTrackPair>(0,1) ;
        }
        for (i = 0; i < numMTPs; i++) {
            MTP = (GPMeasureTrackPair) MTPs.get(i) ;
            t = (i%numTracks) ;
            m = (i/numTracks)+1 ;
            detail = new GPStatsMeasureTrackPair(MTP, m, t) ;
            if( this.isDetailed() && (detail.nonZero()) ) {
                MTPdetails.add(detail) ;
            }
            MTPtotal.add(detail) ;
        }
    }
    public String toString() {
        String res ;
        String tabs ;
        GPStatsMeasureTrackPair MTPdetail ;
        int i ;
        
        tabs = common.Util.tabs(level) ;
        res = "" ;
        if( (pieceName != null) ) {
            res = tabs ;
            for(int j = 0 ; j < 6 ; j ++) {
                res += "--------------------------" ;
            }
            res +="\n" ;
            if (MTPdetails != null)  {
                res += tabs + "Statistics for piece \'" + pieceName + "\'\n" ;
            }
        }
        
    /* are there usefull statistics about number of repetitions, time signatures ??
    for (i = 0; i < numMeasures ; i++) {
        resAppend("\n\tMeasure #" + i) ;
        resAppend("\n\t" + measures.get(i).toString() + "\n");
    }*/
        
        
        //boolean isDrumsTrack;
        //boolean is12StringedGuitarTrack;
        //boolean isBanjoTrack;
    /*
            for (i = 0; i < numTracks ; i++) {
                resAppend("\n\tTrack #" + i) ;
                resAppend("\n\t" + tracks.get(i).toString() + "\n");
            }
     */
        //level++ ;
        if(MTPdetails != null) {
        	level ++ ;
            for (i = 0; i < MTPdetails.size() ; i++) {
                MTPdetail = MTPdetails.get(i) ;
                res += MTPdetail.toString() ;
            }
            level -- ;
            res += tabs ;
            for(int j = 0 ; j < 3 ; j ++) {
                res += "==========================" ;
            }
            res += "\n" ;
        }
        //level-- ;
        
        
        if(pieceName != null)  {
            
            res += tabs + "Totals for piece \'" + pieceName + "\'\n" ;
        }
        //level++ ;
        
        res += tabs + "\t" + numMeasures + " measures" + "\n" ;
        res += tabs + "\t" + numTracks +  " tracks" + "\n" ;
        res += "\t" + this.stringFor(numTracksWithLyrics,"track with lyrics",numTracks, "tracks" ) ;
        if(MTPtotal != null) {
            level++ ;
            res += MTPtotal.toString() ;
            level-- ;
        }
        //level-- ;
        
        
/*
            resAppend("\n\tMIDI Channels - BEGIN");
            for (i = 0; i < 4; i++) {
                resAppend("\n\t\tPort: " + i );
                for (j = 0; j < 16; j++) {
                    resAppend("\n\t\t\tChannel: " + j);
                    resAppend("\n\t\t\t" + channels[i*16+j]) ;
                }
            }
            resAppend("\n\tMIDI Channels - END");


        resAppend("\nCHORD DIAGRAMS - BEGIN\n");
        resAppend("At this moment Chord Diagrams are not being read") ;
        resAppend("\nCHORD DIAGRAMS - END\n");
*/
        
        return res ;
    }
    public void add(GPStatsPiece a) {
        if(a != null) {
            this.numTracks+= a.numTracks ;
            this.numMeasures += a.numMeasures ;
            this.numTracksWithLyrics += a.numTracksWithLyrics ;
            if(this.MTPtotal != null) {
                this.MTPtotal.add(a.MTPtotal) ;
            }
            
        }
    }
} public class MIDFileFilter extends CodecFileFilter {
    public String getDescription() {
        return "*.MID files" ;
    }


    /* (non-Javadoc)
     * @see dguitar.codecs.CodecFileFilter#getExtensions()
     */
    public Vector<String> getExtensions() {
        String []res = { ".MID"} ;
        Vector<String> vector ;
        int i ;
        
        vector = new Vector<String>() ;
        
        for(i = 0; i < res.length ; i++) {
            vector.add(res[i]) ;
        }
        return (vector);
    }


    /* (non-Javadoc)
     * @see dguitar.codecs.CodecFileFilter#accept(java.lang.String)
     */
    public boolean accept(String s) {
        boolean resp ;
        
        resp = false ;
        if(s != null) {
            resp = s.toUpperCase().endsWith(".MID") ; 
        }
        return (resp) ;
    }
    
} public class MidiOutputStream implements CodecOutputStream
{
    OutputStream out;

    public MidiOutputStream(OutputStream out)
    {
        this.out = out;
    }

    public void close() throws IOException
    {
        out.close();
    }

    /*
     * (non-Javadoc)
     * 
     * @see codecs.CodecOutputStream#write(java.lang.Object)
     */
    public int write(Object obj) throws IOException, CodecFormatException
    {
        if (obj instanceof GPSong)
        {
            writeGPSong((GPSong) obj);
        }
        else if (obj instanceof Song)
        {
            writeSong((Song) obj);
        }
        else if (obj instanceof PerformanceFile)
        {
            writePerformanceFile((PerformanceFile) obj);
        }
        else if (obj instanceof PerformanceLive)
        {
            writePerformanceLive((PerformanceLive) obj);
        }
        // TODO find out how the error codes work
        return 0;
    }

    /**
     * @param live
     * @throws IOException
     */
    private void writePerformanceLive(PerformanceLive live) throws IOException
    {
        Sequence sequence = live;
        // This sequence has an extra event track. ABout all we can do to make
        // this work is get everything off the track, delete the track, and
        // then recreate a new track with the same events in

        Track[] allTracks = sequence.getTracks();
        Track lastTrack = allTracks[allTracks.length - 1];

        int trackSize = lastTrack.size();
        List<MidiEvent> eventBuffer = new LinkedList<MidiEvent>();

        for (int i = 0; i < trackSize; i++)
        {
            eventBuffer.add(lastTrack.get(i));
        }
        sequence.deleteTrack(lastTrack);

        writeSequence(sequence);

        Track newTrack = sequence.createTrack();
        for (Iterator<MidiEvent> it = eventBuffer.iterator(); it.hasNext();)
        {
            MidiEvent event = it.next();
            newTrack.add(event);
        }
    }

    /**
     * @param file
     * @throws IOException
     */
    private void writePerformanceFile(PerformanceFile file) throws IOException
    {
        Sequence sequence = file;
        writeSequence(sequence);
    }

    /**
     * @param sequence
     * @throws IOException
     */
    private void writeSequence(Sequence sequence) throws IOException
    {
        MidiSystem.write(sequence,1,out);
    }

    /**
     * @param song
     * @throws IOException
     */
    private void writeSong(Song song) throws IOException
    {
        // Arrange the SOng into a PerformanceFile
        MasterPlayer player = new MasterPlayer();
        player.setSoundPlayer(new MidiFiler());
        PerformanceFile pf = (PerformanceFile) player.arrange(song, null);
        writePerformanceFile(pf);
    }

    /**
     * @param gpsong
     * @throws MidiFormatException
     * @throws IOException
     */
    private void writeGPSong(GPSong gpsong) throws MidiFormatException, IOException
    {
        Song song = null;
        try
        {
            song = GPAdaptor.makeSong(gpsong);
        }
        catch (GPFormatException e)
        {
            throw new MidiFormatException(
                    "Could not convert GPSong to Song format", e);
        }
        writeSong(song);
    }

    /*
     * (non-Javadoc)
     * 
     * @see codecs.Codec#supportedExtension(java.lang.String)
     */
    public boolean supportedExtension(String extension)
    {
        return (extension.toUpperCase().equals(".MID"));
    }

} public interface Arrangement
{
    /**
     * Gets the list of Integers which are zero-based measure numbers
     * into the song.
     * @return list, of Integer objects
     */
    List<Integer> getMeasureList();
}
 public class MasterPlayer implements RealtimeSoundPlayer, EventSoundPlayer
{
//UNUSED      private static String className = MasterPlayer.class.toString();
//UNUSED      private static Logger logger = Logger.getLogger(className);

    int timerFrequency = 4;
    boolean noteEventsEnabled = false;

    SoundPlayer soundPlayer;

    /*
     * (non-Javadoc)
     * 
     * @see Player.TimerSettings#setTimerFrequency(int)
     */
    public void setTimerFrequency(int ppq)
    {
        timerFrequency = ppq;
    }

    /*
     * (non-Javadoc)
     * 
     * @see Player.EventSettings#enableNoteEvents(boolean)
     */
    public void enableNoteEvents(boolean enable)
    {
        noteEventsEnabled = enable;
    }

    public void setSoundPlayer(SoundPlayer soundPlayer)
    {
        this.soundPlayer = soundPlayer;
    }

    /**
     * @param listener
     */
    public void addEventListener(PerformanceEventListener listener)
    {
         ((EventSoundPlayer)soundPlayer).addEventListener(listener);
    }

    /**
     * @param listener
     */
    public void addTimerListener(PerformanceTimerListener listener)
    {
        ((RealtimeSoundPlayer)soundPlayer).addTimerListener(listener);
    }

    /**
     * @param song
     * @param passedArrangement
     */
    public Performance arrange(Song song, Arrangement passedArrangement)
    {
        Arrangement arrangement=null;
        if(passedArrangement==null)
        {
            arrangement=new DefaultArrangement(song);
        }
        else
        {
            arrangement=passedArrangement;
        }
        
        int tracks = song.getTrackCount();
        List<Integer> arrangedMeasures=arrangement.getMeasureList();
        int measures = arrangedMeasures.size();
        
        if(soundPlayer instanceof TimerSettings)
        {
            ((TimerSettings)soundPlayer).setTimerFrequency(timerFrequency);
        }
        if(soundPlayer instanceof EventSettings)
        {
            ((EventSettings)soundPlayer).enableNoteEvents(noteEventsEnabled);
        }

        Performance performance = soundPlayer.createPerformance(tracks, song.getTempo(),
                song.getResolution());
        
        performance.setTimerFrequency(timerFrequency);

        // add timing events to the performance
        TimeSignature lastTimeSignature=null;
        int location = 0;
        for (int m = 0; m < measures; m++)
        {
            Integer measureIndex=(Integer)arrangedMeasures.get(m);
            SongMeasure measure = song.getPerformanceMeasure(measureIndex.intValue());
            
            TimeSignature currentTimeSignature=measure.getTimeSignature();
            if((lastTimeSignature==null)||(!currentTimeSignature.equals(lastTimeSignature)))
            {
                performance.setTimeSignature(location,currentTimeSignature);
                lastTimeSignature=currentTimeSignature;
            }
            
            performance.addTimerEvents(measure, location);
            location += measure.getLength();
        }

        // loop for all tracks
        for (int t = 1; t <= tracks; t++)
        {
            SongTrack songTrack = song.getTrack(t);
            performance.initializeTrack(songTrack);

            int virtualTracks = songTrack.getVirtualTrackCount();

            // loop for all virtual tracks
            for (int v = 0; v < virtualTracks; v++)
            {
                EventStream es = new EventStream(songTrack, v);
                location = 0;
                for (int m = 0; m < measures; m++)
                {
                    Integer measureIndex=(Integer)arrangedMeasures.get(m);
                    SongMeasure measure = song.getPerformanceMeasure(measureIndex.intValue());

                    SongMeasureTrack smt = measure.getTrack(songTrack);
                    SongVirtualTrack svt = smt.getVirtualTrack(v);
                    List<SongEvent> events = svt.getEvents();
                    es.addEvents(events, location);
                    
                    location+=measure.getLength();
                }
                es.close();
                performance.addMusicalEvents(es);
            }
        }
        
        soundPlayer.setPerformance(performance);
        return performance;
    }

    /**
     *  
     */
    public void start()
    {
        soundPlayer.start();
    }

    /**
     *  
     */
    public void stop()
    {
        ((RealtimeSoundPlayer)soundPlayer).stop();
    }

    /**
     *  
     */
    public void waitForCompletion()
    {
        ((RealtimeSoundPlayer)soundPlayer).waitForCompletion();
    }

    /**
     *  
     */
    public void close()
    {
        soundPlayer.close();
    }

    /* (non-Javadoc)
     * @see players.sound.SoundPlayer#createPerformance(int, adaptors.song.Tempo, int)
     */
    public Performance createPerformance(int tracks, Tempo tempo, int resolution)
    {
        // TODO Auto-generated method stub
        return null;
    }

    /* (non-Javadoc)
     * @see players.sound.SoundPlayer#setPerformance(players.sound.Performance)
     */
    public void setPerformance(Performance performance)
    {
        soundPlayer.setPerformance(performance);
    }
} public class MidiPlayer implements SoundPlayer, RealtimeSoundPlayer, EventSoundPlayer 
{
    private String className = MidiPlayer.class.toString();
    private Logger logger = Logger.getLogger(className);

    Sequencer sequencer = null;
    PerformanceLive live;
    List<MetaPerformer> listeners = new LinkedList<MetaPerformer>();
    private int timerFrequency;
    private boolean noteEventsEnabled;

    public Performance createPerformance(int tracks, Tempo tempo, int resolution)
    {
        try
        {
            PerformanceLive alive=new PerformanceLive(tracks, tempo, resolution);
            
            alive.enableNoteEvents(noteEventsEnabled);
            alive.setTimerFrequency(timerFrequency);
            
            return alive;
        }
        catch (InvalidMidiDataException e)
        {
            logger.severe("Could not create a performance object");
            return null;
        }
    }

    /**
     *  
     */
    public void start()
    {
        if (sequencer != null)
        {
            sequencer.close();
        }

        try
        {
            sequencer = MidiSystem.getSequencer();
            sequencer.open();
        }
        catch (MidiUnavailableException e)
        {
            // TODO decide on an exception throing mechanism
            sequencer = null;
        }

        for (Iterator<MetaPerformer> it = listeners.iterator(); it.hasNext();)
        {
            MetaPerformer mp = it.next();
            mp.setContainer(live);
            sequencer.addMetaEventListener((MetaEventListener) mp);
        }
        try
        {
            sequencer.setSequence(live);
        }
        catch (InvalidMidiDataException e1)
        {
            // TODO decide on an exception throing mechanism
            sequencer=null;
        }
        sequencer.start();
    }

    /**
     *  
     */
    public void stop()
    {
        if(sequencer.isOpen()) {
            sequencer.stop();
    	}
    }

    /**
     *  
     */
    public void waitForCompletion()
    {
        // TODO intercept the EOF notification message
        while (sequencer.isRunning())
        {
            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException e)
            {
            }
        }
    }

    /**
     * @param performance
     */
    public void setPerformance(Performance performance)
    {
        live = (PerformanceLive) performance;
    }

    /**
     *  
     */
    public void close()
    {
        if (sequencer != null)
        {
            sequencer.close();
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see players.sound.SoundPlayer#addTimerListener(players.sound.PerformanceTimerListener)
     */
    public void addTimerListener(PerformanceTimerListener listener)
    {
        MidiPerformanceTimerListenerProxy proxy = new MidiPerformanceTimerListenerProxy(
                listener);

        listeners.add(proxy);
    }

    /*
     * (non-Javadoc)
     * 
     * @see players.sound.SoundPlayer#addEventListener(players.sound.PerformanceEventListener)
     */
    public void addEventListener(PerformanceEventListener listener)
    {
        MidiPerformanceEventListenerProxy proxy = new MidiPerformanceEventListenerProxy(
                listener);

        listeners.add(proxy);
    }

    /* (non-Javadoc)
     * @see players.sound.TimerSettings#setTimerFrequency(int)
     */
    public void setTimerFrequency(int ppq)
    {
        timerFrequency=ppq;        
    }

    /* (non-Javadoc)
     * @see players.sound.EventSettings#enableNoteEvents(boolean)
     */
    public void enableNoteEvents(boolean enable)
    {
        noteEventsEnabled=enable;
    }
}

import i18n.Internationalized;
import java.awt.Container;
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.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.event.InternalFrameListener;
import common.ScrollText;
import common.SwingWorker;
import dguitar.adaptors.guitarPro.GPAdaptor;
import dguitar.adaptors.song.Song;
import dguitar.codecs.CodecFormatException;
import dguitar.codecs.guitarPro.GPFormatException;
import dguitar.codecs.guitarPro.GPInputStream;
import dguitar.codecs.guitarPro.GPSong;
import dguitar.codecs.guitarPro.statistics.GPStatsPiece;
import dguitar.codecs.midi.MIDFileFilter;
import dguitar.codecs.midi.MidiOutputStream;
import dguitar.players.gui.MusicCursorScroller;
import dguitar.players.sound.Arrangement;
import dguitar.players.sound.MasterPlayer;
import dguitar.players.sound.midi.MidiPlayer;
package dguitar.gui;

/*
 * SongInternalFrame.java
 *
 * Created on November 8, 2004, 11:28 PM
 */






/**
 * this class represents a JInternalFrame for any new of Open file
 * 
 * @author Mauricio Gracia 
 */
public class SongInternalFrame extends JInternalFrame 
implements			InternalFrameListener,
			Internationalized, 
			OptionsDisplay ,
			Playable
{

    /**
	 * 
	 */
	private static final long serialVersionUID = -5162064904973349576L;

	private boolean closeIt = true;

    private String songName;

    private DGuitar parent;

    private JSeparator jSeparator1;

    private JScrollPane JSP;

    private JMenuBar menuChild;

    private JMenu menuFile;

    private JMenuItem menuFileClose;

    private JMenuItem menuFileExportMidi;

    private JMenuItem menuFilePrint;

    private JMenuItem menuFileScoreInformation;

    private JMenuItem menuFileStats;

    private JMenuItem menuFileTextView;

    private JMenu menuView;

    private JMenuItem menuViewColorOptions;

    private JCheckBoxMenuItem menuViewMinPiece;

    private JCheckBoxMenuItem menuViewMultiTrack;

    private JCheckBoxMenuItem menuViewMusicCursors;

    private JCheckBoxMenuItem menuViewSingleMusicCursorsColor;

    private JCheckBoxMenuItem menuViewUnsupportedEffects;
    
    private JFileChooser fileChooser;

    private GPSong gpSong;

    MasterPlayer player;

    private short status;

    private SongPanel songPanel;

    private ScoreInformationDialog SID;

    private Song song;

    /**
     * Statistics are displayed using this object
     */
    private ScrollText STStats;

    /**
     * TextView of a song is displayed using this object
     */
    private ScrollText STTextView;

    private SwingWorker workerPlay;