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