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