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