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