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