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