Package instantbach.service.logic

Source Code of instantbach.service.logic.VoiceThread

package instantbach.service.logic;

// Custom I/O
import instantbach.service.Service;
// Custom Data
import instantbach.data.SymbolList;
import instantbach.data.Graph;
import instantbach.data.Chord;
import instantbach.data.ChordTemplate;
import instantbach.data.chord.ChordProperties;
import instantbach.data.chord.Voice;
import instantbach.data.Motion;
import instantbach.data.chord.Note;
// Standard Data
import java.util.ArrayList;

/**
* <p>Title: Voice Thread</p>
*
* <p>Description: Thread used to determine the voicing for the given progression</p>
*
* <p>Copyright: Copyright (c) 2007</p>
*
* <p>Company: </p>
*
* @author John Valentino II
* @version 1.0
*/
public class VoiceThread extends Thread implements ChordProperties {

    /** Reference to the parent controller */
    private Service parent;
    /** Represents the given progression */
    private SymbolList progression;
    /** Represents the progression graph */
    private Graph graph;

    private ArrayList<String> errors;

    /**
     *  Creates a class used to process the given progression
     * @param parent Service
     * @param graph Graph
     * @param progression SymbolList
     */
    public VoiceThread(Service parent, Graph graph, SymbolList progression) {
        this.parent = parent;
        this.progression = progression;
        this.graph = graph;
    }

    /**
     * Threaded operation for this class
     */
    public void run() {

        errors = new ArrayList<String>();

        if (progression.size() == 1) {
            errors.add("A progression must consist of two or more chords.");
        } else if (progression.size() > 12)
            errors.add("A progression cannot contain more than 12 chords.");

        for (int i = progression.size() - 2; i > -1; i--) {

            //get the next progression id
            String nextID = progression.getIdentifier(i + 1);

            //get the current id
            String currentID = progression.getIdentifier(i);

            graph.unweighted(nextID); //end
            graph.printPath(currentID); //start

            //resulting cost
            double cost = graph.getCost();

            if ((cost > 1.0) || (cost == 0.0)) {
                errors.add(currentID + " cannot go to "+nextID);
            }
        }

        //if no errors...
        if (errors.size() == 0) {
            voiceProgression();
        } else { //display the errors
            parent.displayErrors(errors);
        }

    }

    /**
     * Attempts to voice the current progression
     */
    private synchronized void voiceProgression() {

        int startingNote = 0;

        boolean impossible = false;

        //represents all possible chords
        ChordTemplate fullSpectrum[] = new ChordTemplate[progression.size()];

        //represent the current chords
        Chord chordArray[] = new Chord[progression.size()];

        //allows the program to step back as many times as possible to revoice a progression
        ArrayList<Chord> backupVector[] = new ArrayList[progression.size()];

        //times that a current chord has been checked and has 0 voicings
        int times[] = new int[progression.size()];

        //initialize all times to zero
        for (int i = 0; i < times.length; i++)
            times[i] = 0;

        //For the entire progression....
        for (int i = progression.size() - 1; i > -1; i--) {

            parent.appendInfo("i = " + i + ", ");

            String currentSymbolID = progression.getIdentifier(i);
            String nextSymbolID = progression.getIdentifier(i+1);

            if (i != progression.size() - 1) {
                parent.appendInfo(nextSymbolID + " to " + currentSymbolID + " = ");
            } else {
                parent.appendInfo(currentSymbolID + " = ");
            }

            backupVector[i] = new ArrayList<Chord>();

            //get the starting note
            startingNote = getStartingNote(currentSymbolID);

            //get all the possible notes for that chord
            fullSpectrum[i] = new ChordTemplate();
            fullSpectrum[i] = createChord(currentSymbolID,
                                          startingNote,
                                          fullSpectrum[i]);

            //get all possible combinations of that chord (and doublings)
            Chord allChords[] = createAllChords(fullSpectrum[i],
                                                currentSymbolID);

            parent.appendInfo(allChords.length + " number of doublings, ");

            if (i != progression.size() - 1) {

                allChords = checkMotion(allChords, chordArray[i + 1]);
                parent.appendInfo(allChords.length + " correct motions");
                parent.appendInfo("\r\n");

            }

            if (allChords.length != 0) {

                //if the very last chord...
                if (i != progression.size() - 1) {
                    chordArray[i] = compareChords(allChords, chordArray[i + 1]);
                } else {

                    //create prefered last chord (For cadence)
                    Voice bassVoice = new Voice(NotePosition.ROOT, new Note("C2"));
                    Voice tenorVoice = new Voice(NotePosition.FIFTH, new Note("G2"));
                    Voice altoVoice = new Voice(NotePosition.THIRD, new Note("E3"));
                    Voice sopranoVoice = new Voice(NotePosition.ROOT, new Note("C4"));

                    //if the last chord is I....
                    if (progression.getIdentifier(i).equals("I")) {
                        chordArray[i] = new Chord("I", bassVoice, tenorVoice, altoVoice, sopranoVoice);
                        parent.appendInfo("\r\n");
                    } else {
                        chordArray[i] = compareChords(allChords,new Chord("I", bassVoice, tenorVoice, altoVoice, sopranoVoice));
                        parent.appendInfo("\r\n");
                    }
                }

                for (int j = 0; j < allChords.length; j++)
                    backupVector[i].add(allChords[j]);

            } else if (allChords.length == 0) {
                //if there are no motions of the chord...

                //if the next chord is already empty
                if (backupVector[i + 1].size() == 0) {

                    times[i]++;

                    //if i > then the progression, no where else to check
                    if ((i + times[i] + 1 >= progression.size())) {
                        errors.add("The following progression is impossible to voice:");
                        String text = "";

                        for (int k = 0; k < progression.size(); k++)
                           text += progression.getIdentifier(k) + " ";

                       errors.add(text);
                       impossible = true;
                    }

                    //go to the chord at the position of [times] and recheck
                    if (backupVector[i + times[i] + 1].size() != 0) {
                        chordArray[i + times[i] +
                                1] = (Chord) backupVector[i + times[i] +
                                     1].get(0);
                        backupVector[i + times[i] + 1].remove(0);
                        i = i + times[i] + 1;
                    }

                } else {
                    //look at the next backup chord, remove it so it is not checked again
                    //in this current setting of [i]
                    chordArray[i + 1] = (Chord) backupVector[i + 1].get(0);
                    backupVector[i + 1].remove(0);
                    i++;
                }
            }

        } // end for

        if (!impossible) {
            parent.displayChords(progression, chordArray);
        } else
            parent.displayErrors(errors);

    }

    /**
     * Returns the lowest possible note numeric value for the given chord symbol
     * @param chordSymbol String
     * @return int
     * @todo Remove functionality and put into an external rules file
     */
    private int getStartingNote(String chordSymbol) {

        int startingNote = 0;

        if ((chordSymbol.equals("I")) || (chordSymbol.equals("V/IV")) ||
            (chordSymbol.equals("7V/IV"))) {
            startingNote = 0;
        } else if ((chordSymbol.equals("ii")) || (chordSymbol.equals("V/V")) ||
                   (chordSymbol.equals("7V/V"))) {
            startingNote = 2;
        } else if (chordSymbol.equals("iii")) {
            startingNote = 4;
        } else if (chordSymbol.equals("IV")) {
            startingNote = 5;
        } else if ((chordSymbol.equals("V")) || (chordSymbol.equals("7V"))) {
            startingNote = 7;
        } else if (chordSymbol.equals("vi")) {
            startingNote = 9;
        } else if ((chordSymbol.equals("viio")) || (chordSymbol.equals("7vii0"))) {
            startingNote = 11;
        } else if (chordSymbol.equals("N6")) {
            startingNote = 1;
        } else if (chordSymbol.equals("7Fr+6")) {
            startingNote = 8;
        }

        return startingNote;

    }//end getStartingNote()

    /**
     * Creates a chord template for the given chord symbol
     * @param chord String
     * @param total int
     * @param template ChordTemplate
     * @return ChordTemplate
     * @todo Remove and bass chord template off an an external rules file
     */
    private ChordTemplate createChord(String chord, int total, ChordTemplate template) {

        int root = 0;
        int third = 0;
        int fifth = 0;

        //only used if a seventh chord
        int seventh = 0;
        int wrapper = 0;

        if ((chord.equals("I")) || (chord.equals("IV")) || (chord.equals("V")) ||
            (chord.equals("V/V"))
            || (chord.equals("N6")) || (chord.equals("V/IV"))) {
            //all major triads
            root = 4;
            third = 3;
            fifth = 5;
        } else if ((chord.equals("7V")) || (chord.equals("7V/V")) ||
                   (chord.equals("7V/IV"))) {
            //Dominant Seventh
            root = 4;
            third = 3;
            fifth = 5;
            seventh = 3;
            wrapper = 2;
        } else if ((chord.equals("ii")) || (chord.equals("iii")) ||
                   (chord.equals("vi"))) {
            //minor triads
            root = 3;
            third = 4;
            fifth = 5;
        } else if ((chord.equals("7vii0"))) {
            //half diminished seventh
            root = 3;
            third = 3;
            fifth = 3;
            seventh = 4;
            wrapper = 2;
        } else if (chord.equals("viio")) {
            //diminished triad
            root = 3;
            third = 3;
            fifth = 6;
        } else if (chord.equals("7Fr+6")) {
            //Fr+6 chord
            root = 4;
            third = 2;
            fifth = 4;
            seventh = 4;
            wrapper = 2;
        }

        if (total > 45) {
            //limit of the top range
            return template;

        } else {

            template.addVoice(NotePosition.ROOT, total);
            total = total + root;

            template.addVoice(NotePosition.THIRD, total);
            total = total + third;

            //seventh chords
            if (chord.charAt(0) == '7') {
                template.addVoice(NotePosition.FIFTH, total);
                total = total + seventh;

                template.addVoice(NotePosition.SEVENTH, total);
                total = total + wrapper;
            } else {
                //triads
                template.addVoice(NotePosition.FIFTH, total);
                total = total + fifth;
            }
            return createChord(chord, total, template);
        }
    } //end createChord

    /**
     * Creates all posible chords using the givne chord template
     * @param fullSpectrum ChordTemplate
     * @param symbol String
     * @return Chord[]
     */
    private Chord[] createAllChords(ChordTemplate fullSpectrum, String symbol) {

        ArrayList<Voice> bassVector = new ArrayList<Voice>();
        ArrayList<Voice> tenorVector = new ArrayList<Voice>();
        ArrayList<Voice> altoVector = new ArrayList<Voice>();
        ArrayList<Voice> sopranoVector = new ArrayList<Voice>();

        for (int i = 0; i < fullSpectrum.size(); i++) {

            //put chord members within in range into appropriate vectors
            int value = fullSpectrum.getNoteNumeric(i);

            Voice voice = fullSpectrum.getVoice(i);

            if ((value >= 4) && (value <= 24))
                bassVector.add(voice);
            if ((value >= 12) && (value <= 31))
                tenorVector.add(voice);
            if ((value >= 19) && (value <= 38))
                altoVector.add(voice);
            if ((value >= 24) && (value <= 43))
                sopranoVector.add(voice);
        }

        //find the maximum size out of all of the voices, build the combination
        int bass = bassVector.size();
        int tenor = tenorVector.size();
        int alto = altoVector.size();
        int soprano = sopranoVector.size();

        int maximum = 0;
        if (bass > maximum)
            maximum = bass;
        if (tenor > maximum)
            maximum = tenor;
        if (alto > maximum)
            maximum = alto;
        if (soprano > maximum)
            maximum = soprano;

        //build an alphabet consisting of [0,maximum]
        String alphabet = "abcdefghijklmnopqrstuvwxyz";
        String alpha = "";
        for (int i = 0; i < maximum; i++)
            alpha += alphabet.charAt(i);

        //convert the integer upper boundry for each voice to a letter
        String bletter = alpha.charAt(bass - 1) + "";
        String tletter = alpha.charAt(tenor - 1) + "";
        String aletter = alpha.charAt(alto - 1) + "";
        String sletter = alpha.charAt(soprano - 1) + "";

        //build a vector of all combinations within individual voice range
        ArrayList<String> temp = new ArrayList<String>();
        temp = combination("", alpha, 4, temp, bletter, tletter, aletter,
                           sletter);

        ArrayList<Chord> returnVector = new ArrayList<Chord>();

        parent.appendInfo(temp.size() + " note combinations, ");
        //convert to a vector of chords, check those chords for doubling
        for (int i = 0; i < temp.size(); i++) {
            char b = temp.get(i).charAt(0);
            char t = temp.get(i).charAt(1);
            char a = temp.get(i).charAt(2);
            char s = temp.get(i).charAt(3);

            int bloc = 0;
            int tloc = 0;
            int aloc = 0;
            int sloc = 0;
            for (int j = 0; j < maximum; j++) {

                if (alpha.charAt(j) == b)
                    bloc = j;
                if (alpha.charAt(j) == t)
                    tloc = j;
                if (alpha.charAt(j) == a)
                    aloc = j;
                if (alpha.charAt(j) == s)
                    sloc = j;
            }

            //build a chord with the converted number and location in the original voice Vector
            Chord tempC = new Chord(symbol,
                                    bassVector.get(bloc),
                                    tenorVector.get(tloc),
                                    altoVector.get(aloc),
                                    sopranoVector.get(sloc));
            //check doubling
            //if true add it to collection
            if (checkDouble(tempC))
                returnVector.add(tempC);

        }

        Chord returnArray[] = new Chord[returnVector.size()];
        for (int i = 0; i < returnVector.size(); i++) {
            returnArray[i] =  returnVector.get(i);
        }

        return returnArray;
    } //end createAllChords()

    /**
     * Createa all possible combinations of the given string
     * @param str String
     * @param alpha String
     * @param length int
     * @param temp ArrayList
     * @param b String
     * @param t String
     * @param a String
     * @param s String
     * @return ArrayList
     */
    private ArrayList<String> combination(String str, String alpha, int length,
                                     ArrayList<String> temp, String b,
                                     String t, String a, String s) {

        if (str.length() == length) {

            if (((str.charAt(0) + "").compareTo(b) < 1) &&
                ((str.charAt(1) + "").compareTo(t) < 1) &&
                ((str.charAt(2) + "").compareTo(a) < 1) &&
                ((str.charAt(3) + "").compareTo(s) < 1)) {

                temp.add(str);
            }

        } else {

            for (int i = 0; i < alpha.length(); i++)
                combination(str + alpha.charAt(i), alpha, length, temp, b, t, a,
                            s);
        }

        return temp;
    } //end combination()

    /**
     * Returns true if the doubling of the given chord is correct
     * @param chord Chord
     * @return boolean
     * @todo Remove and place logic in an external rules file
     */
    private boolean checkDouble(Chord chord) {

        //the symbol is the same for each chord in this method
        String symbol = chord.getSymbol();

        boolean proceed = true;

        Voice bass = chord.getVoice(VoiceType.BASS);
        Voice tenor = chord.getVoice(VoiceType.TENOR);
        Voice alto = chord.getVoice(VoiceType.ALTO);
        Voice soprano = chord.getVoice(VoiceType.SOPRANO);

        int root = 0;
        int third = 0;
        int fifth = 0;
        int seventh = 0;

        ArrayList<Voice> voiceList = new ArrayList<Voice>();
        voiceList.add(bass);
        voiceList.add(tenor);
        voiceList.add(alto);
        voiceList.add(soprano);

        for (int i = 0; i < voiceList.size(); i++) {
            Voice voice = voiceList.get(i);
            NotePosition position = voice.getPosition();
            switch (position) {
            case ROOT:
                root++;
                break;
            case THIRD:
                third++;
                break;
            case FIFTH:
                fifth++;
                break;
            case SEVENTH:
                seventh++;
                break;
            }
        }

        //doubling for chords lacking the LT
        if ((symbol.equals("I")) || (symbol.equals("ii")) ||
            (symbol.equals("IV")) || (symbol.equals("vi")) ||
            (symbol.equals("N6"))) {

            if ((root > 2) || (root == 0)) {
                proceed = false;
            }
            if ((third > 2) || (third == 0)) {
                proceed = false;
            }
            if ((fifth > 1) || (fifth == 0)) {
                proceed = false;
            }
            if (bass.getPosition() == NotePosition.FIFTH) {
                proceed = false;
            }
            if (symbol.equals("N6")) {
                if (bass.getPosition() == NotePosition.ROOT)
                    proceed = false;
                if (third != 2)
                    proceed = false;
            }
            //doubling for the V and V/V, V/IV
        } else if ((symbol.equals("V")) || (symbol.equals("V/V")) ||
                   (symbol.equals("V/IV"))) {

            if ((root > 2) || (root == 0)) {
                proceed = false;
            }
            if ((third > 1) || (third == 0)) {
                proceed = false;
            }
            if ((fifth > 2) || (fifth == 0)) {
                proceed = false;
            }
            if (bass.getPosition() == NotePosition.FIFTH) {
                proceed = false;
            }
            //doubling for the iii
        } else if (symbol.equals("iii")) {

            if ((root > 2) || (root == 0)) {
                proceed = false;
            }
            if ((third > 2) || (third == 0)) {
                proceed = false;
            }
            if ((fifth > 1) || (fifth == 0)) {
                proceed = false;
            }
            if (bass.getPosition() == NotePosition.FIFTH) {
                proceed = false;
            }
            //doubling for the viio
        } else if (symbol.equals("viio")) {
            if ((root > 1) || (root == 0)) {
                proceed = false;
            }
            if ((third > 2) || (third == 0)) {
                proceed = false;
            }
            if ((fifth > 1) || (fifth == 0)) {
                proceed = false;
            }
            if (bass.getPosition() == NotePosition.FIFTH) {
                proceed = false;
            }
            if (bass.getPosition() == NotePosition.ROOT) {
                proceed = false;
            }
            //doubling for seventh chords
        } else if ((symbol.equals("7V")) || (symbol.equals("7vii0")) ||
                   (symbol.equals("7V/V"))
                   || (symbol.equals("7V/IV"))) {

            if ((root == 0) || (third == 0) || (fifth > 1) || (seventh == 0)) {
                proceed = false;
            }
            if ((third == 2) && (symbol.equals("7V")))
                proceed = false;
            if ((root == 2) && (symbol.equals("7vii0")))
                proceed = false;

        } else if (symbol.equals("7Fr+6")) {
            if ((root == 0) || (third == 0) || (fifth == 0) || (seventh == 0)) {
                proceed = false;
            }
        }

        return proceed;

    } //end checkDouble()

    /**
     * Returns an array of possible chords that meet motion rules
     * @param allChords Chord[]
     * @param chord Chord
     * @return Chord[]
     * @todo Remove logic and place rules in an external file
     */
    public Chord[] checkMotion(Chord[] allChords, Chord chord) {

        ArrayList<Integer> loc = new ArrayList<Integer>();

        for (int i = 0; i < allChords.length; i++) {

            boolean returner = true;

            Motion bass = new Motion(chord.getVoice(VoiceType.BASS),
                                     allChords[i].getVoice(VoiceType.BASS));
            Motion tenor = new Motion(chord.getVoice(VoiceType.TENOR),
                                      allChords[i].getVoice(VoiceType.TENOR));
            Motion alto = new Motion(chord.getVoice(VoiceType.ALTO),
                                     allChords[i].getVoice(VoiceType.ALTO));
            Motion soprano = new Motion(chord.getVoice(VoiceType.SOPRANO),
                                     allChords[i].getVoice(VoiceType.SOPRANO));

            //check for invlalid parallel motion
            if (bass.compareTo(tenor)) {
                if (tenor.isValidInterval(bass) == false)
                    returner = false;
            }
            if (bass.compareTo(alto)) {
                if (alto.isValidInterval(bass) == false)
                    returner = false;
            }
            if (bass.compareTo(soprano)) {
                if (soprano.isValidInterval(bass) == false)
                    returner = false;
            }

            if (tenor.compareTo(alto)) {
                if (alto.isValidInterval(tenor) == false)
                    returner = false;
            }
            if (tenor.compareTo(soprano)) {
                if (soprano.isValidInterval(tenor) == false)
                    returner = false;
            }

            if (alto.compareTo(soprano)) {
                if (soprano.isValidInterval(alto) == false)
                    returner = false;
            }

            //check for cross voicing
            int allChordBassNote = allChords[i].getNoteNumeric(VoiceType.BASS);
            int allChordTenorNote = allChords[i].getNoteNumeric(VoiceType.TENOR);
            int allChordAltoNote = allChords[i].getNoteNumeric(VoiceType.ALTO);
            int allChordSopranoNote = allChords[i].getNoteNumeric(VoiceType.SOPRANO);

            int bassNote = chord.getNoteNumeric(VoiceType.BASS);
            int tenorNote = chord.getNoteNumeric(VoiceType.TENOR);
            int altoNote = chord.getNoteNumeric(VoiceType.ALTO);
            int sopranoNote = chord.getNoteNumeric(VoiceType.SOPRANO);

            if (allChordBassNote > allChordTenorNote)
                returner = false;
            if (allChordTenorNote > allChordAltoNote)
                returner = false;
            if (allChordAltoNote > allChordSopranoNote)
                returner = false;

            //check for cross voicing in between chords
            if (allChordBassNote > tenorNote)
                returner = false;
            if (allChordTenorNote < bassNote)
                returner = false;
            if (allChordTenorNote > altoNote)
                returner = false;
            if (allChordAltoNote < tenorNote)
                returner = false;
            if (allChordAltoNote > sopranoNote)
                returner = false;
            if (allChordSopranoNote < altoNote)
                returner = false;

            //check for invalid skips
            if (bass.getDistance() > 7)
                returner = false;
            if (tenor.getDistance() > 4)
                returner = false;
            if (alto.getDistance() > 4)
                returner = false;
            if (soprano.getDistance() > 5)
                returner = false;

            //iii
            if (allChords[i].getSymbol().equals("iii")) {

                boolean correct = getLeadingToneMotion(NotePosition.FIFTH, allChords[i], chord);

                if (!correct) returner = false;
            }

            //check for leading tones in the V and 7V, V/V and 7V/V, V/IV, 7V/IV
            if ((allChords[i].getSymbol().equals("V")) ||
                (allChords[i].getSymbol().equals("7V"))
                || (allChords[i].getSymbol().equals("V/V")) ||
                (allChords[i].getSymbol().equals("7V/V"))
                || (allChords[i].getSymbol().equals("V/IV")) ||
                (allChords[i].getSymbol().equals("7V/IV"))) {

                //3 must move up 1 for the S or B, or the same or down 4 for the A or T
                boolean correct = getLeadingToneMotion(NotePosition.THIRD, allChords[i], chord);

                if (!correct) returner = false;

                //specific to sevenths
                if ((allChords[i].getSymbol().equals("7V")) ||
                    (allChords[i].getSymbol().equals("7V/V"))
                    || (allChords[i].getSymbol().equals("7V/IV"))) {

                    //7th must move down by 1
                    boolean correct2 = getStepwiseMotion(NotePosition.SEVENTH, allChords[i],
                            chord, -1);

                    if (!correct2) returner = false;

                }

            }
            //check for leading tones in the viio and 7vii0
            if ((allChords[i].getSymbol().equals("viio")) ||
                (allChords[i].getSymbol().equals("7vii0"))) {

                //viio can only go to V, where the LT is already present
                //thus no resolution is needed

                //specific to sevenths
                if (allChords[i].getSymbol().equals("7vii0")) {

                    //7th must move down by 2
                    boolean correct2 = getStepwiseMotion(NotePosition.SEVENTH, allChords[i],
                            chord, -2);

                    if (!correct2) returner = false;

                } //if a 7th

            } //if a viio

            //neopolitan
            if (allChords[i].getSymbol().equals("N6")) {

                //the root must move down by 2
                boolean correct = getStepwiseMotion(NotePosition.ROOT, allChords[i], chord,
                        -2);

                if (!correct) returner = false;
            }

            //Fr+6 chords
            if (allChords[i].getSymbol().equals("7Fr+6")) {

                //root must go down by 1
                boolean correct = getStepwiseMotion(NotePosition.ROOT, allChords[i], chord,
                        -1);

                if (!correct) returner = false;

                //get augmented sixths (7) must go up by 1
                boolean correct2 = getStepwiseMotion(NotePosition.SEVENTH, allChords[i], chord,
                        1);

                if (!correct2) returner = false;
            }

            //range between voices
            if (allChords[i].getSopranoNoteNumeric() - allChords[i].getAltoNoteNumeric() > 12)
                returner = false;

            if (allChords[i].getAltoNoteNumeric() - allChords[i].getTenorNoteNumeric() > 12)
                returner = false;

            if (returner == true)
                loc.add(new Integer(i));

        } //end huge loop

        Chord newChord[] = new Chord[loc.size()];

        for (int i = 0; i < loc.size(); i++) {
            newChord[i] = allChords[loc.get(i)];
        }

        return newChord;

    } //end checkMotion()

    /**
     * Returns true if the leading tone motion is valid for the given note position for
     * the motion between the two given chords
     * @param s NotePosition
     * @param allChords Chord
     * @param chord Chord
     * @return boolean
     */
    private boolean getLeadingToneMotion(NotePosition s, Chord allChords, Chord chord) {

        boolean returner = true;

        //bass
        if (allChords.getNotePosition(VoiceType.BASS) == s) {

            if (chord.getNoteNumeric(VoiceType.BASS) !=
                allChords.getNoteNumeric(VoiceType.BASS) + 1)
                returner = false;
        }

        //soprano
        if (allChords.getNotePosition(VoiceType.SOPRANO) == s) {

            if (chord.getNoteNumeric(VoiceType.SOPRANO) !=
                allChords.getNoteNumeric(VoiceType.SOPRANO) + 1)
                returner = false;

        }

        //tenor
        if (allChords.getNotePosition(VoiceType.TENOR) == s) {

            if ((chord.getNoteNumeric(VoiceType.TENOR) !=
                allChords.getNoteNumeric(VoiceType.TENOR) + 1) &&
                (chord.getNoteNumeric(VoiceType.TENOR) !=
                allChords.getNoteNumeric(VoiceType.TENOR) - 4))
                returner = false;
        }
        //alto
        if (allChords.getNotePosition(VoiceType.ALTO) == s) {

            if ((chord.getNoteNumeric(VoiceType.ALTO) !=
                allChords.getNoteNumeric(VoiceType.ALTO) + 1) &&
                (chord.getNoteNumeric(VoiceType.ALTO) !=
                allChords.getNoteNumeric(VoiceType.ALTO) - 4))
                returner = false;

        }

        return returner;
    }

    /**
     * Returns true if the stepwise motion is correct
     * @param s NotePosition
     * @param allChords Chord
     * @param chord Chord
     * @param value int
     * @return boolean
     */
    private boolean getStepwiseMotion(NotePosition s, Chord allChords, Chord chord, int value) {

        boolean returner = true;

        //bass
        if (allChords.getBassNotePosition() == s) {

            if (chord.getBassNoteNumeric() != allChords.getBassNoteNumeric() + value)
                returner = false;
        }
        //tenor
        if (allChords.getTenorNotePosition() == s) {

            if (chord.getTenorNoteNumeric() != allChords.getTenorNoteNumeric() + value)
                returner = false;
        }
        //alto
        if (allChords.getAltoNotePosition() == s) {

            if (chord.getAltoNoteNumeric() != allChords.getAltoNoteNumeric() + value)
                returner = false;
        }
        //soprano
        if (allChords.getSopranoNotePosition() == s) {

            if (chord.getSopranoNoteNumeric() != allChords.getSopranoNoteNumeric() + value)
                returner = false;
        }

        return returner;
    }

    /**
     * Returns the best possible chord
     * @param allChords Chord[]
     * @param chord Chord
     * @return Chord
     */
    private Chord compareChords(Chord allChords[], Chord chord) {

        int minDistance = 200;

        boolean chordFound = false;

        for (int i = 0; i < allChords.length; i++) {

            if (allChords[i].getBassNotePosition() == NotePosition.ROOT) {

                Motion tenor = new Motion(chord.getTenorVoice(), allChords[i].getTenorVoice());
                Motion alto = new Motion(chord.getAltoVoice(), allChords[i].getAltoVoice());
                Motion soprano = new Motion(chord.getSopranoVoice(), allChords[i].getSopranoVoice());

                int totalDistance = tenor.getDistance() + alto.getDistance() +
                                    soprano.getDistance();

                if (totalDistance < minDistance) {
                    chord = allChords[i];
                    minDistance = totalDistance;
                    chordFound = true;

                }
            }

        }

        if (!chordFound) {

            for (int i = 0; i < allChords.length; i++) {

                Motion tenor = new Motion(chord.getTenorVoice(), allChords[i].getTenorVoice());
                Motion alto = new Motion(chord.getAltoVoice(), allChords[i].getAltoVoice());
                Motion soprano = new Motion(chord.getSopranoVoice(), allChords[i].getSopranoVoice());

                int totalDistance = tenor.getDistance() + alto.getDistance() +
                                    soprano.getDistance();

                if (totalDistance < minDistance) {
                    chord = allChords[i];
                    minDistance = totalDistance;

                }
            }
        }

        return chord;
    } //end compareChord()



}
TOP

Related Classes of instantbach.service.logic.VoiceThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.