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