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