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 chromesthesia0;
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[9];
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           return pitches;
90       }
91   
92       private static Pitch find(String token, Pitch[] pitches) throws Exception {
93           for (int i = 0; i < pitches.length; i = i + 1) {
94               Pitch pitch = pitches[i];
95               if (pitch.abcName().equals(token)) {
96                   return pitch;
97               }
98           }
99           throw new Exception("### PITCH " + token + " NOT FOUND");
100      }
101  
102      private static void display(Pitch[] pitches) {
103          for (int i = 0; i < pitches.length; i = i + 1) {
104              System.out.println(pitches[i].toString());
105          }
106      }
107  
108      private static void playMelody(String input, Pitch[] pitches) throws Exception {
109          Scanner scanner = new Scanner(input);
110          while (scanner.hasNext()) {
111              String token = scanner.next();
112              Pitch pitch = find(token,pitches);
113              pitch.play("1");
114          }
115      }
116  
117      // INITIALIZATION, CLEANUP, GETTING INPUT, ERROR MESSAGING
118  
119      static private void showErrorMessage(String message) {
120          miro.setVisible(false);
121          JOptionPane.showMessageDialog(null, message);
122      }
123  
124      private static void initialization() {
125          // ESTABLISH THE PAINTER AND GIVE IT A SUBSTANTIAL BRUSH WIDTH
126          miro = new SPainter("Chromesthesia", 500, 500);
127          miro.setVisible(false);
128          miro.setBrushWidth(7);
129          // ESTABLISH THE CHROMESTITIC PITCH CLASS OBJECTS
130          pitches = establishPitches(miro);
131          display(pitches);
132      }
133  
134      private static String getInput() {
135          miro.setVisible(false);
136          String label = "Please enter a melody in ABC notation, or EXIT...    ";
137          String input = JOptionPane.showInputDialog(null,label);
138          miro.setVisible(true);
139          if (input == null) {
140              input = "";
141          }
142          return input;
143      }
144  
145      static private void cleanup() {
146          System.exit(0);
147      }
148  }
149  
150  
151