]> ruin.nu Git - moosique.git/blob - Moosique.java
global keylistener..
[moosique.git] / Moosique.java
1 import javax.sound.midi.*;
2 import javax.swing.*;
3 import java.io.*;
4
5 /**
6  * Moosique - The MIDI Tracker
7  * 
8  * Main class that handles initiation, IO and sound.
9  * 
10  * @author  Einar Pehrson
11  */
12  
13 public class Moosique {
14
15         private static MooGUI gui;
16         private static Sequence seq;
17         private static Sequencer sequencer;
18         private static Synthesizer synthesizer;
19         private static MidiChannel[] channels;
20         private static MidiChannel activeChannel;
21
22         private static String filename, fileArg;
23         private static long position;
24         private static boolean makeGUI = true;
25         private static boolean playing = false;
26
27         /** 
28          * Starts the application.
29          */
30         public static void main (String[] args) {
31                 System.out.println("\nMoosique version 1.0\n");
32
33                 // Parses command-line arguments.
34                 for (int i = 0; i < args.length; i++) {
35                         if (args[i].equals("-n")) {makeGUI = false;}
36                         else if (fileArg == null) {fileArg = args[i];}
37                 }
38
39                 // Acquires MIDI devices and connects them.
40                 System.out.print("Initializing MIDI devices.");
41                 try {
42                         sequencer = MidiSystem.getSequencer();
43                         System.out.print(".");
44                         sequencer.open();
45                         synthesizer = MidiSystem.getSynthesizer();
46                         System.out.print(".");
47                         synthesizer.open();
48                         sequencer.getTransmitter().setReceiver(synthesizer.getReceiver());
49                         channels = synthesizer.getChannels();
50                         setActiveChannel(0);
51                 } catch (MidiUnavailableException e) {
52                         System.out.println("Failed, quitting.");
53                         quit();
54                 }
55                 System.out.println("Done");
56
57                 //If a filename is given as the command-line argument, attempts to load a sequence from the file.
58                 if (fileArg != null) {
59                         System.out.print("Loading MIDI sequence from " + fileArg + "...");
60                         if (!load(fileArg)) {
61                                 System.out.println("Failed");
62                                 clearSequence();
63                         } else {
64                                 System.out.println("Done");
65                         }
66                 } else {
67                         // Otherwise creates a new empty one.
68                         clearSequence();
69                 }
70
71                 // If n-flag is set, plays song and then exits. Otherwise builds GUI.
72                 if (makeGUI) {
73                         System.out.print("Building GUI...");
74                         gui = new MooGUI(seq);
75                         System.out.println("Done");
76                 } else {
77                         System.out.print("Playing...");
78                         play();
79                         while (sequencer.isRunning()) {}
80                         System.out.println("Done");
81                         quit();
82                 }
83         }
84
85         /** 
86          * Returns the GUI.
87          * @return the GUI
88          */
89         public static MooGUI getGUI() {
90                 return gui;
91         }
92
93         /** 
94          * Returns the current sequence.
95          * @return the current sequence
96          */
97         public static Sequence getSequence() {
98                 return seq;
99         }
100
101         /** 
102          * Returns the current sequencer.
103          * @return the current sequencer
104          */
105         public static Sequencer getSequencer() {
106                 return sequencer;
107         }
108
109         /** 
110          * Returns the MidiChannels of the selected synthesizer.
111          * @return the available MidiChannels
112          */
113         public static MidiChannel[] getChannels() {
114                 return channels;
115         }
116
117         /** 
118          * Returns the currently active MidiChannel.
119          * @return the active MidiChannel
120          */
121         public static MidiChannel getActiveChannel() {
122                 return activeChannel;
123         }
124
125         /** 
126          * Sets the currently active MidiChannel.
127          * @param channel       the number of the MidiChannel to activate
128          */
129         public static void setActiveChannel(int channel) {
130                 activeChannel = channels[channel];
131         }
132
133         /** 
134          * Replaces the current sequence with a new one, holding three empty tracks.
135          */
136         public static void clearSequence() {
137                 // Creates a new sequence and sends it to the sequencer.
138                 try {
139                         seq = new Sequence(Sequence.PPQ, 96, 3);
140                         sequencer.setSequence(seq);
141                 } catch (InvalidMidiDataException e) {}
142                 // Sends sequence to GUI.
143                 if (gui != null) gui.setSequence(seq);
144         }
145
146         /** 
147          * Starts playback of the current sequence.
148          */
149         public static void play() {
150                 playing = true;
151                 sequencer.setTickPosition(position);
152                 sequencer.start();
153         }
154
155         /** 
156          * Pauses playback of the current sequence.
157          */
158         public static void pause() {
159                 playing = false;
160                 sequencer.stop();
161         }
162
163         /** 
164          * Resumes playback of the current sequence.
165          */
166         public static void resume() {
167                 playing = true;
168                 sequencer.start();
169         }
170
171         /** 
172          * Stops playback of the current sequence.
173          */
174         public static void stop() {
175                 playing = false;
176                 sequencer.stop();
177                 sequencer.setTickPosition(position);
178         }
179
180         /**
181          * Pauses if playing and resumes if stopped.
182          */
183         public static void resumepause()
184         {
185                 if (playing)
186                         pause();
187                 else
188                         resume();
189         }
190
191         /** 
192          * Rewinds the current sequence the given number of measures.
193          * @param measures      the number of measures to rewind
194          */
195         public static long getPosition() {
196                 return position;
197         }
198
199         /** 
200          * Rewinds the current sequence the given number of measures.
201          * @param measures      the number of measures to rewind
202          */
203         public static void setPosition(long ticks) {
204                 position = ticks;
205         }
206
207         /** 
208          * Rewinds the current sequence the given number of measures.
209          * @param measures      the number of measures to rewind
210          */
211         public static void rewind(long ticks) {
212                 setPosition(position - ticks);
213         }
214
215         /** 
216          * Fast forwards the current sequence the given number of measures.
217          * @param measures      the number of measures to fast forward
218          */
219         public static void forward(long ticks) {
220                 setPosition(position + ticks);
221         }
222
223         /** 
224          * Loads the MooSequence in the given file.
225          * @param filename      the filename to use
226          */
227         public static boolean load(String file) {
228                 // Loads sequence from file
229                 filename = file;
230                 try {
231                         seq = MidiSystem.getSequence(new File(filename));
232                 } catch (InvalidMidiDataException e) {
233                         return false;
234                 } catch (IOException e) {
235                         JOptionPane.showMessageDialog(null, "Error 404", "File Not Found", JOptionPane.ERROR_MESSAGE); 
236                         return false;
237                 }
238
239                 // Sends sequence to GUI and sequencer
240                 if (gui != null) gui.setSequence(seq);
241                 try {
242                         sequencer.setSequence(seq);
243                 } catch (InvalidMidiDataException e) {}
244
245                 // Searches the sequence for NoteOn events
246                 Track[] tracks = seq.getTracks();
247                 MidiEvent noteOn, noteOff = null, nextEvent;
248                 MidiMessage nextMsg;
249                 ShortMessage shortMsg;
250                 for (int i = 0; i < tracks.length; i++) {
251                         for (int j = 0; j < tracks[i].size(); j++) {
252                                 noteOn = tracks[i].get(j);
253                                 if (noteOn.getMessage() instanceof ShortMessage) {
254                                         if (((ShortMessage)noteOn.getMessage()).getCommand() == ShortMessage.NOTE_ON) {
255                                                 // Finds the corresponding NoteOff event
256                                                 for (int k = j + 1; k < tracks[i].size(); k++) {
257                                                         nextEvent = tracks[i].get(k);
258                                                         nextMsg = nextEvent.getMessage();
259                                                         if (nextMsg instanceof ShortMessage) {
260                                                                 shortMsg = (ShortMessage) nextMsg;
261                                                                 if (shortMsg.getCommand() == ShortMessage.NOTE_OFF && shortMsg.getChannel() == ((ShortMessage)noteOn.getMessage()).getChannel() && shortMsg.getData1() == ((ShortMessage)noteOn.getMessage()).getData1()) {
262                                                                         noteOff = nextEvent;
263                                                                         break;
264                                                                 }
265                                                         }
266                                                 }
267                                                 // Replaces the NoteOn event with a MooNote, if possible with the corresponding NoteOff event
268                                                 tracks[i].remove(noteOn);
269                                                 if (noteOff != null) {
270                                                         tracks[i].add(new MooNote(noteOn, noteOff));
271                                                 } else {
272                                                         tracks[i].add(new MooNote(noteOn));
273                                                 }
274                                         }
275                                 }
276                         }
277                 }
278                 return true;
279         }
280
281         /** 
282          * Saves the current sequence to the given filename
283          * @param file  the filename to use
284          */
285         public static void saveAs(String file) {
286                 try {
287                         MidiSystem.write(seq, 1, new File(filename));
288                 } catch (IOException e) {}
289                 filename = file;
290         }
291
292         /** 
293          * Saves the current sequence to the previously given filename.
294          */
295         public static void save() {
296                 saveAs(filename);
297         }
298
299         /** 
300          * Releases all reserved devices and exits the program.
301          */
302         public static void quit() {
303                 if (sequencer.isOpen()) sequencer.close();
304                 if (synthesizer.isOpen()) synthesizer.close();
305                 System.exit(0);
306         }
307 }