/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package midi;

import abc.notation.BarLine;
import abc.notation.KeySignature;
import abc.notation.MultiNote;
import abc.notation.Note;
import abc.notation.TimeSignature;
import abc.notation.Tune;
import abc.ui.swing.JScoreComponent;
import data.Beat;
import data.NoteData;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import jm.music.data.Part;
import jm.music.data.Phrase;
import jm.music.data.Score;

/**
 *
 * @author Tom
 */
public class MidiToSheetMusic {
    ArrayList<ArrayList<Beat>> scoreInBeats = null;
    private int PartCount = 0;
    private String title = "";
    private int numerator = 4;
    private int denominator = 4;
    private static double BEATLENGTH = 4.0; //Laenge eines Taktes 4.0 = 4/4-Takt
    private boolean Major = true;
    private String Vorzeichen = "";
    
    public MidiToSheetMusic(ArrayList<ArrayList<Beat>> scoreInBeats, int numerator, int denominator, String title) {
        this.title = title;
        this.scoreInBeats = scoreInBeats;
        this.numerator = numerator;
        this.denominator = denominator;
        BEATLENGTH = (Double.valueOf(numerator)/Double.valueOf(denominator))*4;
    }

    /**
     * Konstruktor, welcher den Score gleich quantisiert
     * @param score der Score
     * @param quantize gibt an, ob der Score quantisiert werden soll
     */
    public MidiToSheetMusic(Score score, boolean quantize) {
        if (score != null){
            title = score.getTitle();
            numerator = score.getNumerator();
            denominator = score.getDenominator();
            BEATLENGTH = (Double.valueOf(numerator)/Double.valueOf(denominator))*4;

            if (quantize){
                MidiQuantizer mq = new MidiQuantizer();
                scoreInBeats = mq.getQuantizedScoreInBeats(score);
            } else {
                getScoreInBeats(score);
            }
        }
    }
    
    /**
     * Konstruktor, welcher den Score gleich quantisiert
     * @param score der Score
     * @param quantize gibt an, ob der Score quantisiert werden soll
     */
    public MidiToSheetMusic(Score score, boolean quantize, int numerator, int denominator, String key, boolean major) {
        if (score != null){
            title = score.getTitle();
            this.numerator = numerator;
            this.denominator = denominator;
            this.Major = major;
            this.Vorzeichen = key;
            BEATLENGTH = (Double.valueOf(numerator)/Double.valueOf(denominator))*4;

            if (quantize){
                MidiQuantizer mq = new MidiQuantizer();
                scoreInBeats = mq.getQuantizedScoreInBeats(score);
            } else {
                getScoreInBeats(score);
            }
        }
    }
    
    /**
     * Konstruktor, welcher den Score gleich quantisiert
     * und Infos zur Quantisierung in einer JTextPane ausgibt
     * @param score der Score
     * @param textPane TextPane fuer Log-Ausgaben
     */
    public MidiToSheetMusic(Score score, JTextPane textPane) {
        if (score != null){
            title = score.getTitle();
            numerator = score.getNumerator();
            denominator = score.getDenominator();
            BEATLENGTH = (Double.valueOf(numerator)/Double.valueOf(denominator))*4;

            MidiQuantizer mq = new MidiQuantizer(textPane);
            scoreInBeats = mq.getQuantizedScoreInBeats(score);
        }
    }
    
    /**
     * Konstruktor, welcher den Score gleich quantisiert
     * und Infos zur Quantisierung in einer JTextPane ausgibt
     * @param score der Score
     * @param textPane TextPane fuer Log-Ausgaben
     * @param numerator Numerator
     * @param denominator Denominator
     * @param key Tonart
     * @param major true wenn Major, false wenn Minor
     */
    public MidiToSheetMusic(Score score, JTextPane textPane, int numerator, int denominator, String key, boolean major) {
        if (score != null){
            title = score.getTitle();
            this.numerator = numerator;
            this.denominator = denominator;
            this.Major = major;
            this.Vorzeichen = key;
            BEATLENGTH = (Double.valueOf(numerator)/Double.valueOf(denominator))*4;

            MidiQuantizer mq = new MidiQuantizer(textPane);
            scoreInBeats = mq.getQuantizedScoreInBeats(score);
        }
    }
    
    /**
     * befuellt scoreInBeats mit dem Takt aus dem Score
     */
    private void getScoreInBeats(Score scr){
        scoreInBeats = new ArrayList<>();
        for (Part p : scr.getPartArray()){
            for (Phrase phr : p.getPhraseArray()){
                ArrayList<Beat> alb = new ArrayList<>();
                Beat b = new Beat();
                b.setPart(0);
                b.setPhrase(0);
                for (jm.music.data.Note n : phr.getNoteArray()){
                    NoteData nd = new NoteData(n.getPitch());
                    nd.setDuration(n.getDuration());
                    nd.setQuantizedDuration(n.getDuration());
                    b.addNote(nd);
                }
                alb.add(b);
                scoreInBeats.add(alb);
            }
        }
    }
    
    /**
     * gibt die Anzahl der Parts des aktuellen Scores zurueck
     * @return Anzahl der Parts
     */
    private int getPartCount(){
        if (scoreInBeats.size() > 0){
            if (scoreInBeats.get(scoreInBeats.size()-1).size() > 0){
                return scoreInBeats.get(scoreInBeats.size()-1).get(0).getPart()+1;
            }
        }
        return 0;
    }
    
    /**
    * liefert einen JFrame mit dem Midi-File als Notenblatt
    * @return Frame mit dem Midi-File als Notenblatt
    */
   public JFrame getNoteSheetFrame(){
        KeyFinder kf = new KeyFinder(getNoteDurationsForKeyFinding());
        String sKey = kf.getKey();
        KeySignature key = new KeySignature(Note.C, KeySignature.MAJOR);
        if (sKey.substring(0, sKey.indexOf(" ")).equalsIgnoreCase("Major")){
            Major = true;
            Vorzeichen = sKey.substring(sKey.indexOf(" ")+1, sKey.length());
            switch (Vorzeichen){
                case "C":
                    key = new KeySignature(Note.C, KeySignature.MAJOR);
                    break;
                case "C#":
                    key = new KeySignature(Note.C, KeySignature.MAJOR);
                    break;
                case "D":
                    key = new KeySignature(Note.D, KeySignature.MAJOR);
                    break;
                case "D#":
                    key = new KeySignature(Note.D, KeySignature.MAJOR);
                    break;
                case "E":
                    key = new KeySignature(Note.E, KeySignature.MAJOR);
                    break;
                case "F":
                    key = new KeySignature(Note.F, KeySignature.MAJOR);
                    break;
                case "F#":
                    key = new KeySignature(Note.F, KeySignature.MAJOR);
                    break;
                case "G":
                    key = new KeySignature(Note.G, KeySignature.MAJOR);
                    break;
                case "G#":
                    key = new KeySignature(Note.G, KeySignature.MAJOR);
                    break;
                case "A":
                    key = new KeySignature(Note.A, KeySignature.MAJOR);
                    break;
                case "A#":
                    key = new KeySignature(Note.A, KeySignature.MAJOR);
                    break;
                case "B":
                    key = new KeySignature(Note.B, KeySignature.MAJOR);
                    break;
            }
        } else { //Minor
            Major = false;
            Vorzeichen = sKey.substring(sKey.indexOf(" ")+1, sKey.length());
            switch (Vorzeichen){
                case "C":
                    key = new KeySignature(Note.C, KeySignature.MINOR);
                    break;
                case "C#":
                    key = new KeySignature(Note.C, KeySignature.MINOR);
                    break;
                case "D":
                    key = new KeySignature(Note.D, KeySignature.MINOR);
                    break;
                case "D#":
                    key = new KeySignature(Note.D, KeySignature.MINOR);
                    break;
                case "E":
                    key = new KeySignature(Note.E, KeySignature.MINOR);
                    break;
                case "F":
                    key = new KeySignature(Note.F, KeySignature.MINOR);
                    break;
                case "F#":
                    key = new KeySignature(Note.F, KeySignature.MINOR);
                    break;
                case "G":
                    key = new KeySignature(Note.G, KeySignature.MINOR);
                    break;
                case "G#":
                    key = new KeySignature(Note.G, KeySignature.MINOR);
                    break;
                case "A":
                    key = new KeySignature(Note.A, KeySignature.MINOR);
                    break;
                case "A#":
                    key = new KeySignature(Note.A, KeySignature.MINOR);
                    break;
                case "B":
                    key = new KeySignature(Note.B, KeySignature.MINOR);
                    break;
            }
        }

        //create Frame and return it
        JFrame j = new JFrame();
        JPanel p = new JPanel();
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        j.setTitle(title);
        
        PartCount = getPartCount();
        for (int i = 0; i<PartCount;i++){
            int midPitch = getMiddleNotePitch(i);
            
            Tune tune = new Tune();
            Tune.Music music = tune.getMusic();
            music.addElement(key);
            music.addElement(new TimeSignature(numerator, denominator));

            setNotes(music, i, midPitch);
            
            JScoreComponent jscore = new JScoreComponent();
            jscore.setJustification(true);
            jscore.setTune(tune);
            
            p.add(jscore);
        }
        
        JScrollPane jsp = new JScrollPane(p);
        j.add(jsp);
        j.pack();
        return j;
   }
   
   /**
    * liefert ein JScoreComponent mit dem Midi-File als Notenblatt
    * @return JScoreComponent mit dem Midi-File als Notenblatt
    */
   public JScoreComponent getNoteSheetJScoreComponent(){
        //create JScoreComponent and return it
        KeySignature key = new KeySignature(Note.C, KeySignature.MAJOR);
        
        if (Major){
            Major = true;
            switch (Vorzeichen){
                case "C":
                    key = new KeySignature(Note.C, KeySignature.MAJOR);
                    break;
                case "C#":
                    key = new KeySignature(Note.C, KeySignature.MAJOR);
                    break;
                case "D":
                    key = new KeySignature(Note.D, KeySignature.MAJOR);
                    break;
                case "D#":
                    key = new KeySignature(Note.D, KeySignature.MAJOR);
                    break;
                case "E":
                    key = new KeySignature(Note.E, KeySignature.MAJOR);
                    break;
                case "F":
                    key = new KeySignature(Note.F, KeySignature.MAJOR);
                    break;
                case "F#":
                    key = new KeySignature(Note.F, KeySignature.MAJOR);
                    break;
                case "G":
                    key = new KeySignature(Note.G, KeySignature.MAJOR);
                    break;
                case "G#":
                    key = new KeySignature(Note.G, KeySignature.MAJOR);
                    break;
                case "A":
                    key = new KeySignature(Note.A, KeySignature.MAJOR);
                    break;
                case "A#":
                    key = new KeySignature(Note.A, KeySignature.MAJOR);
                    break;
                case "B":
                    key = new KeySignature(Note.B, KeySignature.MAJOR);
                    break;
            }
        } else { //Minor
            Major = false;
            switch (Vorzeichen){
                case "C":
                    key = new KeySignature(Note.C, KeySignature.MINOR);
                    break;
                case "C#":
                    key = new KeySignature(Note.C, KeySignature.MINOR);
                    break;
                case "D":
                    key = new KeySignature(Note.D, KeySignature.MINOR);
                    break;
                case "D#":
                    key = new KeySignature(Note.D, KeySignature.MINOR);
                    break;
                case "E":
                    key = new KeySignature(Note.E, KeySignature.MINOR);
                    break;
                case "F":
                    key = new KeySignature(Note.F, KeySignature.MINOR);
                    break;
                case "F#":
                    key = new KeySignature(Note.F, KeySignature.MINOR);
                    break;
                case "G":
                    key = new KeySignature(Note.G, KeySignature.MINOR);
                    break;
                case "G#":
                    key = new KeySignature(Note.G, KeySignature.MINOR);
                    break;
                case "A":
                    key = new KeySignature(Note.A, KeySignature.MINOR);
                    break;
                case "A#":
                    key = new KeySignature(Note.A, KeySignature.MINOR);
                    break;
                case "B":
                    key = new KeySignature(Note.B, KeySignature.MINOR);
                    break;
            }
        }
        
        JScoreComponent jscore = new JScoreComponent();
        
        PartCount = getPartCount();
        for (int i = 0; i<PartCount;i++){
            int midPitch = getMiddleNotePitch(i);
            
            Tune tune = new Tune();
            Tune.Music music = tune.getMusic();
            music.addElement(key);
            music.addElement(new TimeSignature(numerator, denominator));

            setNotes(music, i, midPitch);
            
            jscore.setJustification(true);
            jscore.setTune(tune);
        }
        return jscore;
   }
   
   /**
    * liefert ein Array mit den summierten Notenlaengen jeder Note (C-B)
    * @return Array mit summierter Laenge pro Note
    */
   private double[] getNoteDurationsForKeyFinding(){
        double[] noteDurations = {0,0,0,0,0,0,0,0,0,0,0,0};
        
        for (ArrayList<Beat> alb : scoreInBeats){
            for (Beat b : alb){
                for (NoteData nd : b.getBeat()){
                    switch (nd.getNote())
                    {
                        case "C":
                            noteDurations[0] += nd.getQuantizedDuration();
                            break;
                        case "C#":
                            noteDurations[1] += nd.getQuantizedDuration();
                            break;
                        case "D":
                            noteDurations[2] += nd.getQuantizedDuration();
                            break;
                        case "Eb":
                            noteDurations[3] += nd.getQuantizedDuration();
                            break;
                        case "E":
                            noteDurations[4] += nd.getQuantizedDuration();
                            break;
                        case "F":
                            noteDurations[5] += nd.getQuantizedDuration();
                            break;
                        case "F#":
                            noteDurations[6] += nd.getQuantizedDuration();
                            break;
                        case "G":
                            noteDurations[7] += nd.getQuantizedDuration();
                            break;
                        case "Ab":
                            noteDurations[8] += nd.getQuantizedDuration();
                            break;
                        case "A":
                            noteDurations[9] += nd.getQuantizedDuration();
                            break;
                        case "Bb":
                            noteDurations[10] += nd.getQuantizedDuration();
                            break;
                        case "B":
                            noteDurations[11] += nd.getQuantizedDuration();
                            break;
                    }
                }
            }
        }
        return noteDurations;
   }
   
   /**
    * liefert die mittlere Notenhoehe (Pitch) eines Parts
    * @param Part der Part, der untersucht werden soll
    * @return die mittlere Notenhoehe als Pitch
    */
   private int getMiddleNotePitch(int Part){
       int high=0, low=127;
       
       for (ArrayList<Beat> alb : scoreInBeats){
           if (alb.size() > 0 && alb.get(0).getPart() == Part){
               for (Beat b : alb){
                   for (NoteData nd : b.getBeat()){
                       if (nd.getPitch() != Integer.MIN_VALUE){
                           if (high < nd.getPitch()){
                               high = nd.getPitch();
                           }
                           if (low > nd.getPitch()){
                               low = nd.getPitch();
                           }
                       }
                   }
               }
           }
       }
       return (high+low)/2;
   }
   
   /**
    * Berechnet um wieviele Transpositionsstufen die Note vermindert/erhoeht werden muss
    * in Bezug auf das uebergebene C
    * @param Pitch aktuelle Note
    * @param C Referenz-C
    * @return Hoehe der Oktavenverschiebung (-3,-2,-1,0,1,2,3)
    */
   private int getOctaveHeightForNote(int Pitch, int C){
       int Oct;
       if (Pitch == Integer.MIN_VALUE){ //Pausen muessen nicht veraendert werden
           return 0;
       }
       if (Pitch < C){ //Pitches unter C werden herabgesetzt
           int i = 0;
           if (C-Pitch != 12){
               i = (C - Pitch)/12;
           }
           Oct = -i;
       } else if (Pitch - C >= 12){ //Pitches ueber C+11 (naechstes C) werden erhoeht
           int i = (Pitch - C)/12;
           if (i == 0){ //ausgleichen von Rundungsfehlern
               i = 1;
           }
           i++;
           Oct = i;
       } else { //keine Veraenderung (Pitches von C bis C + 11)
           Oct = 1;
       }
       return Oct;
   }
   
   /**
    * liefert das C (als Pitch), das am naehesten zum Durchschnittspitch liegt
    * @param midPitch der mittlere Pitch
    * @return C als Pitch
    */
   private int getC(int midPitch){
       int[] Cs = {0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120}; //Pitches von C
       for (int i=0; i<Cs.length; i++){
           if (midPitch == Cs[i]){ //Durchschnitt ist genau C
               return Cs[i];
           } else if (midPitch < Cs[i]){
               if (i == 0){
                   return Cs[i];
               } else {
                   //das C, welches naeher am Durchschnittston liegt wird ausgewaehlt
                   if ((Cs[i] - midPitch) < (midPitch - Cs[i-1])){
                       return Cs[i];
                   } else {
                       return Cs[i-1];
                   }
               }
           }
       }
       return 60;
   }
   
   /**
    * gibt die maximale Anzahl der Noten eines Taktes innerhalb eines Part zurueck
    * @param part der zu durchsuchende Part
    * @param beat die ID des Takts
    * @return maximale Anzahl der Noten des Taktes im Part
    */
   private int getLongestBeatNoteCount(int part, int beat){
       int max = 0;
       for (ArrayList<Beat> ald : scoreInBeats){
           if (ald.size() > beat && ald.get(beat).getPart() == part){
               if (max < ald.get(beat).getNoteCount()){
                   max = ald.get(beat).getNoteCount();
               }
           }
       }
       return max;
   }
   
   /**
    * gibt an, ob der Part aus mehreren Phrasen besteht
    * @param Part der zu untersuchende Part
    * @return true, wenn mehrere Phrasen im Part, sonst false
    */
   private boolean hasMultiplePhrases(int Part){
       int Count = 0;
       for (ArrayList<Beat> ald : scoreInBeats){
           if (ald.size() > 0 && ald.get(0).getPart() == Part){
               Count++;
           }
       }
       if (Count > 1){
           return true;
       } else {
           return false;
       }
   }
   
   /**
    * erstellt eine Notenzeile des uebergebenen Parts
    * als Referenznote wird der Durchschnittspitch des Parts herangezogen
    * @param music Musikelement, welches zum Zeichnen verwendet wird
    * @param Part der Part, der als Notenzeile dargestellt werden soll
    * @param midPitch der mittlere Pitch in diesem Part als Referenzgroesse
    */
   private void setNotes(Tune.Music music, int Part, int midPitch){      
       int BigC = getC(midPitch);
       
       if (hasMultiplePhrases(Part)){
           for (ArrayList<Beat> alb : scoreInBeats){
               if (alb.size() > 0 && alb.get(0).getPart() == Part){
                   for (int beat = 0; beat<alb.size(); beat++){
                       int noteCount = getLongestBeatNoteCount(Part, beat);
                       if (noteCount == 0){
                            Note n = new Note(Note.REST);
                            NoteData nd = new NoteData();
                            nd.setQuantizedDuration(BEATLENGTH);
                            setNoteDuration(nd, n);
                            music.addElement(n);
                       } else {
                            for (int i=0; i<noteCount; i++){
                               music.addElement(new MultiNote(getMultiNote(Part, beat, i, BigC)));
                            }
                       }
                       music.addElement(new BarLine()); //Takttrennzeichen
                   }
                   break; //restlichen Phrasen in diesem Part ueberspringen, da schon in MultiNotes vorhanden
               }
           }
       } else {
           for (ArrayList<Beat> alb : scoreInBeats){
               if (alb.size() > 0 && alb.get(0).getPart() == Part){
                   for (Beat b : alb){
                       for (NoteData nd : b.getBeat()){
                            Note n = new Note(Note.C);
                            //Note setzen
                            setNote(nd,n);
                            //Notenhoehe/Oktave setzen
                            n.setOctaveTransposition(Byte.valueOf(getOctaveHeightForNote(nd.getPitch(), BigC) +""));
                            //Notendauer setzen
                            setNoteDuration(nd, n);
                            //Note hinzufuegen
                            music.addElement(n);
                       }
                       music.addElement(new BarLine()); //Takttrennzeichen
                   }
               }
           }
       }
   }
   
   /**
    * liefert eine MultiNote aller Phrasen im angegebenen Part zurueck
    * @param Part der gewuenschte Part
    * @param beat der aktuelle Takt
    * @param note die Position der Note im Takt
    * @param BigC Pitch der Referenznote C
    * @return die MultiNote
    */
   private Vector<Note> getMultiNote(int Part, int beat, int note, int BigC){
       ArrayList<Beat> al = new ArrayList<>(); //ArrayList mit dem aktuellen Takt der Phrasen
       
       for (ArrayList<Beat> alb : scoreInBeats){
            if (alb.size() > beat && alb.get(beat).getPart() == Part){
                al.add(alb.get(beat));
            }
       }
       
       boolean OnlyRest = true;
       Vector<Note> vn = new Vector<>();
       Vector<Note> restVector = new Vector<>();
       Note nRest = new Note(Note.REST);
       for (Beat b : al){
           NoteData nd = b.getNote(note);
           if (nd != null){
                //wenn eine der Noten eine Pause ist => nicht hinzufuegen
                if (!nd.getNote().equalsIgnoreCase("REST")){
                    OnlyRest = false;
                    Note n = new Note(Note.C);
                    //Note setzen
                    setNote(nd,n);
                    //Notenhoehe/Oktave setzen
                    n.setOctaveTransposition(Byte.valueOf(getOctaveHeightForNote(nd.getPitch(), BigC) +""));
                    //Notendauer setzen
                    setNoteDuration(nd, n);
                    vn.add(n);
                } else {
                    setNoteDuration(nd, nRest);
                }
           }
       }
       
       //pruefen, ob MultiNote nur aus Pausen besteht
       //wenn ja, dann ersetzen als Pause
       if (OnlyRest){           
           restVector.add(nRest);
           return restVector;
       } else {
           return vn;
       }
   }
   
   /**
    * setzt den Notenwert (SheetMusic)
    * @param nd die Note aus dem MIDI-File
    * @param n die Note als SheetMusic-Note
    */
   private void setNote(NoteData nd, Note n){
     switch (nd.getNote()){
        case "C":
            n.setHeight(Note.C);
            break;
        case "D":
            n.setHeight(Note.D);
            break;
        case "E":
            n.setHeight(Note.E);
            break;
        case "F":
            n.setHeight(Note.F);
            break;
        case "G":
            n.setHeight(Note.G);
            break;
        case "A":
            n.setHeight(Note.A);
            break;
        case "B":
            n.setHeight(Note.B);
            break;
        case "C#": //kann C# oder Des sein, je nach Tonart
            n.setHeight(getNoteForKey(nd));
            //n.setAccidental(AccidentalType.SHARP);
            break;
        case "F#": //kann F# oder Ges, je nach Tonart
            n.setHeight(getNoteForKey(nd));
            //n.setAccidental(AccidentalType.SHARP);
            break;
        case "Bb": //kann A# oder Bb sein, je nach Tonart
            n.setHeight(getNoteForKey(nd));
            //n.setAccidental(AccidentalType.FLAT);
            break;
        case "Ab": //kann G# oder As sein, je nach Tonart
            n.setHeight(getNoteForKey(nd));
            //n.setAccidental(AccidentalType.FLAT);
            break;
        case "Eb":
            n.setHeight(getNoteForKey(nd));
            //n.setAccidental(AccidentalType.FLAT);
            break;
        case "REST":
            n.setHeight(Note.REST);
            break;
        default:
            n.setHeight(Note.REST);
            break;
        }
   }
   
   /**
    * gibt die richtige Tonhoehe einer Note je nach Tonart zurueck
    * Beispiel:
    * da es zB bei einer As-Dur ein Des gibt, aber kein C#, bei Midi
    * diese Note jedoch immer als C# gespeichert wird, muss sie am
    * Notenblatt trotzdem in der Zeile von "D" angezeigt werden.
    * 
    * @param nd aktuelle Note
    * @return richtige Tonhoehe
    */
   private byte getNoteForKey(NoteData nd){
       if ((Major && Vorzeichen.equalsIgnoreCase("G#")) || (!Major && Vorzeichen.equalsIgnoreCase("F"))){ //As-Dur oder f-Moll
           if (nd.getNote().equalsIgnoreCase("C#")){
               return Note.D; //Des
           }
       } else if ((Major && Vorzeichen.equalsIgnoreCase("C#")) || (!Major && Vorzeichen.equalsIgnoreCase("B")) //Des-Dur oder b-Moll
               || (Major && Vorzeichen.equalsIgnoreCase("F#")) || (!Major && Vorzeichen.equalsIgnoreCase("D#")) //Ges-Dur oder es-Moll
               || (Major && Vorzeichen.equalsIgnoreCase("B")) || (!Major && Vorzeichen.equalsIgnoreCase("G#"))) { //Ces-Dur oder as-Moll
           if (nd.getNote().equalsIgnoreCase("C#")){
               return Note.D; //Des
           } else if (nd.getNote().equalsIgnoreCase("F#")){
               return Note.G; //Ges
           }
       }
       
       if ((Major && Vorzeichen.equalsIgnoreCase("A")) || (!Major && Vorzeichen.equalsIgnoreCase("F#"))){ //A-Dur oder fis-Moll
           if (nd.getNote().equalsIgnoreCase("Ab")){
               return Note.G; //Gis
           }
       } else if ((Major && Vorzeichen.equalsIgnoreCase("E")) || (!Major && Vorzeichen.equalsIgnoreCase("C#"))){ //E-Dur oder cis-Moll
           if (nd.getNote().equalsIgnoreCase("Ab")){
               return Note.G; //Gis
           } else if (nd.getNote().equalsIgnoreCase("Eb")){
               return Note.D; //Dis
           }
       } else if ((Major && Vorzeichen.equalsIgnoreCase("E")) || (!Major && Vorzeichen.equalsIgnoreCase("C#"))){ //H-Dur oder gis-Moll
           if (nd.getNote().equalsIgnoreCase("Ab")){
               return Note.G; //Gis
           } else if (nd.getNote().equalsIgnoreCase("Eb")){
               return Note.D; //Dis
           } else if (nd.getNote().equalsIgnoreCase("Bb")){
               return Note.A; //Ais
           }
       }
       
       //kein Treffer => Note ohne Vorzeichen nehmen
       switch (nd.getNote()){
        case "C#":
            return Note.C;
        case "F#":
            return Note.F;
        case "Bb":
            return Note.B;
        case "Ab":
            return Note.A;
        case "Eb":
            return Note.E;
       }
       return 0; //sollte nie ausgeloest werden
   }
   
   /**
    * setzt die Dauer der Note (SheetMusic)
    * @param nd die Note aus dem MIDI-File
    * @param n die Note als SheetMusic-Note
    */
   private void setNoteDuration(NoteData nd, Note n){
        if (nd.getQuantizedDuration() == 4.0){
            n.setStrictDuration(Note.WHOLE);
        } else if (nd.getQuantizedDuration() == 2.0){
            n.setStrictDuration(Note.HALF);
        } else if (nd.getQuantizedDuration() == 1.0){
            n.setStrictDuration(Note.QUARTER);
        } else if (nd.getQuantizedDuration() == 0.5){
            n.setStrictDuration(Note.EIGHTH);
        } else if (nd.getQuantizedDuration() == 0.33){
            n.setStrictDuration(Note.EIGHTH); //Triplet
        } else if (nd.getQuantizedDuration() == 0.25){
            n.setStrictDuration(Note.SIXTEENTH);
        } else {
            n.setStrictDuration(Note.THIRTY_SECOND);
        }
   }
}
