import java.util.Vector; import jm.music.data.CPhrase; import jm.music.data.Note; import jm.constants.RhythmValues; /** * ChordProgression represents the sequence of chords that the piano will play. * @author Leslie Chong and Matthew Lipson */ public class ChordProgression extends CPhrase { // The chords that make up the progression private Vector chords; /** * ChordProgression will take in a vector of unvoiced chords. It will then set a voicing and offset for each chord. * Ultimately the voicings will be done by voice leading algorithms, and the offsets will be done probablistically. * @param chds The unvoiced chords. Cannot be null. * @throws ChordNotVoicedException */ public ChordProgression(Vector chds) throws ChordNotVoicedException{ assert chds != null; // Lead the chords VoiceLeading lead = new StandardStyleFactory().createVoiceLeading(); chords = lead.lead(chds); // Offset the chords try{ offset(); } catch (ChordNotVoicedException e){ // TODO: Is it acceptable for the program to continue if this exception occurs? System.out.println("Tried to offset an unvoiced chord"); } for (int x=0; x notes = c.getVoicedChord(); Note[] noteArray = new Note[notes.size()]; for(int i = 0; i < noteArray.length; i++){ noteArray[i] = notes.elementAt(i); } this.addChord(noteArray); } } /** * Offsets the chord progression * @throws ChordNotVoicedException if one of the chords is not voiced */ public void offset() throws ChordNotVoicedException{ double[] offsets = {0.0,1.0,0.0}; int pick = 1; // Initially set to offset directly on the beat. Should be picked anyway for(int i = 0; i < chords.size(); i++){ double prob = Math.random(); double increment = 0.0; double old = 0.0; Chord c = chords.get(i); for(int j = 0; j < offsets.length; j++){ increment = increment + offsets[j]; if(prob <= increment){ pick = j; old = offsets[j]; break; } } offsets[pick] = (Math.pow(offsets[pick],2.0))/2.0; double offsetIncrement = Math.abs(offsets[pick] - old)/2.0; switch(pick){ case 0: // Offset ahead by an eighth note c.setOffset(-RhythmValues.EIGHTH_NOTE); offsets[1] += offsetIncrement; offsets[2] += offsetIncrement; break; case 1: // Don't offset offsets[0] += offsetIncrement; offsets[2] += offsetIncrement; break; case 2: // Offset forward an eighth note c.setOffset(RhythmValues.EIGHTH_NOTE); offsets[0] += offsetIncrement; offsets[1] += offsetIncrement; } } } /** * Returns the size of the chord progression * @return the size of the chord progression */ public int getSize(){ return chords.size(); } }