Chromesthesia.java
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