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