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