1 2 3 /* 4 *This program interprets melodic lines given in ABC notation as a 5 * chromesthete might. 6 * 7 * A Pitch class will be defined, and will take center stage in the 8 * processing. 9 * 10 * Interpreting a melody in ABC notation will amount to flashing 11 * colored rectangles for prescribed durations, while sounding 12 * the pitch! The color of the rectangle will correspond to pitch 13 * class. The duration will correspond to the duration of the note. 14 * 15 * For this first version of the program, the duration will be held 16 * constant at 1 beat. 17 * 18 * Three sorts of images will appear on the screen, the chromesthetic 19 * output box, a text input box, and an error message box. Simplicity 20 * of design is rendered by permitting only one box to be on the screen 21 * at a time. 22 * 23 * ABC represents notes in a manner consistent with these examples: 24 * C, D, E, C D E c d e 25 * 26 * Google ABC music representation if you would like to know more about it 27 */ 28 29 package chromesthesia2; 30 31 import java.util.Scanner; 32 import javax.swing.JOptionPane; 33 import javax.swing.SwingUtilities; 34 import painter.SPainter; 35 36 37 public class Chromesthesia2 { 38 39 40 // INFRASTRUCTURE FOR THE PROGRAM -- LAUNCHING A "GRAPHICS" THREAD 41 42 public static void main(String[] args) { 43 SwingUtilities.invokeLater(new chromesthesia2.Chromesthesia2.ThreadForGUI()); 44 } 45 46 private static class ThreadForGUI implements Runnable { 47 @Override 48 public void run() { 49 new chromesthesia2.Chromesthesia2(); 50 } 51 } 52 53 public Chromesthesia2() { 54 interpreter(); 55 } 56 57 // FEATURED VARIABLES 58 59 private static SPainter miro; 60 private static Pitch[] pitches; 61 62 // THE INTERPRETER 63 64 public static void interpreter() { 65 66 initialization(); // miro and pitches 67 68 while ( true ) { 69 String input = getInput(); 70 if ( input.equalsIgnoreCase("EXIT") ) { 71 break; 72 } else { 73 try { 74 playMelody(input,pitches); 75 } catch (Exception ex) { 76 showErrorMessage(ex.toString()); 77 } 78 } 79 } 80 81 cleanup(); // miro has to go 82 } 83 84 // METHODS PERTAINING TO THE CHROMESTHETIC PITCHES 85 86 private static Pitch[] establishPitches(SPainter painter) { 87 Pitch[] pitches = new Pitch[21]; 88 89 Pitch pitchMiddleC = new Pitch("C", painter); 90 pitches[0] = pitchMiddleC; 91 92 Pitch pitchLowC = new Pitch("C,", painter); 93 pitches[1] = pitchLowC; 94 95 Pitch pitchHighC = new Pitch("c", painter); 96 pitches[2] = pitchHighC; 97 98 Pitch pitchMiddleD = new Pitch("D",painter); 99 pitches[3] = pitchMiddleD; 100 101 Pitch pitchLowD = new Pitch("D,",painter); 102 pitches[4] = pitchLowD; 103 104 Pitch pitchHighD = new Pitch("d",painter); 105 pitches[5] = pitchHighD; 106 107 Pitch pitchMiddleE = new Pitch("E",painter); 108 pitches[6] = pitchMiddleE; 109 110 Pitch pitchLowE = new Pitch("E,",painter); 111 pitches[7] = pitchLowE; 112 113 Pitch pitchHighE = new Pitch("e",painter); 114 pitches[8] = pitchHighE; 115 116 Pitch pitchMiddleF = new Pitch("F", painter); 117 pitches[9] = pitchMiddleF; 118 119 Pitch pitchLowF = new Pitch("F,", painter); 120 pitches[10] = pitchLowF; 121 122 Pitch pitchHighF = new Pitch( "f", painter); 123 pitches[11] = pitchHighF; 124 125 Pitch pitchMiddleG = new Pitch("G", painter); 126 pitches[12] = pitchMiddleG; 127 128 Pitch pitchLowG = new Pitch("G,", painter); 129 pitches[13] = pitchLowG; 130 131 Pitch pitchHighG = new Pitch( "g", painter); 132 pitches[14] = pitchHighG; 133 134 Pitch pitchMiddleA = new Pitch("A", painter); 135 pitches[15] = pitchMiddleA; 136 137 Pitch pitchLowA = new Pitch("A,", painter); 138 pitches[16] = pitchLowA; 139 140 Pitch pitchHighA = new Pitch( "a", painter); 141 pitches[17] = pitchHighA; 142 143 Pitch pitchMiddleB = new Pitch("B", painter); 144 pitches[18] = pitchMiddleB; 145 146 Pitch pitchLowB = new Pitch("B,", painter); 147 pitches[19] = pitchLowB; 148 149 Pitch pitchHighB = new Pitch( "b", painter); 150 pitches[20] = pitchHighB; 151 152 return pitches; 153 } 154 private static Pitch find(String token, Pitch[] pitches) throws Exception { 155 for ( int i = 0; i < pitches.length; i = i + 1 ) { 156 Pitch pitch = pitches[i]; 157 if ( pitch.abcName().equals(token) ) { 158 return pitch; 159 } 160 } 161 throw new Exception("### PITCH " + token + " NOT FOUND"); 162 } 163 164 private static void display(Pitch[] pitches) { 165 for ( int i = 0; i < pitches.length; i = i + 1 ) { 166 System.out.println(pitches[i].toString()); 167 } 168 } 169 170 private static void playMelody(String input, Pitch[] pitches) throws Exception { 171 Scanner scanner = new Scanner(input); 172 while ( scanner.hasNext() ) { 173 String token = scanner.next(); 174 String pitchName; 175 String duration = ""; 176 if ( token.indexOf(",") < 0 ) { 177 pitchName = token.substring(0,1); 178 duration = token.substring(1); 179 } else { 180 pitchName = token.substring(0,2); 181 duration = token.substring(2); 182 } 183 if ( duration.length() == 0 ) { duration = "1"; } 184 Pitch pitch = find(pitchName,pitches); 185 pitch.play(duration); 186 } 187 } 188 189 // INITIALIZATION, CLEANUP< GETTING INPUT< ERROR MESSAGING 190 191 static private void showErrorMessage(String message) { 192 miro.setVisible(false); 193 JOptionPane.showMessageDialog(null, message); 194 } 195 196 private static void initialization() { 197 // ESTABLISH THE PAINTER AND GIVE IT A SUBSTANTIAL BRUSH WIDTH 198 miro = new SPainter("Chromesthesia",500,500); 199 miro.setVisible(false); 200 miro.setBrushWidth(7); 201 // ESTABLISH THE CHROMESTITIC PITCH CLASS OBJECTS 202 pitches = establishPitches(miro); 203 display(pitches); 204 } 205 206 private static String getInput() { 207 miro.setVisible(false); 208 String label = "Please enter a melody in ABC notation, or EXIT ... "; 209 String input = JOptionPane.showInputDialog(null,label); 210 miro.setVisible(true); 211 if ( input == null ) { input = "";} 212 return input; 213 } 214 215 static private void cleanup() { 216 System.exit(0); 217 } 218 } 219 220 221