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()
}