]> ruin.nu Git - moosique.git/blob - Moosique.java
*** empty log message ***
[moosique.git] / Moosique.java
1 import javax.sound.midi.*;
2 import java.io.*;
3 import javax.swing.*;
4 import java.util.*;
5
6 /**
7  * Moosique - The MIDI Tracker
8  * 
9  * Main class that handles initiation, IO and sound.
10  * 
11  * @author  Einar Pehrson
12  */
13  
14 public class Moosique {
15
16         private static MooGUI gui;
17         private static Sequence seq;
18         private static Sequencer sequencer;
19         private static Synthesizer synthesizer;
20         private static MidiChannel[] channels;
21         private static MidiChannel activeChannel;
22
23         private static String filename, fileArg;
24         private static long position;
25         private static boolean makeGUI = true;
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 //                      System.exit(1);
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                 // Builds GUI, unless n-flag is set.
72                 if (makeGUI) {
73                         System.out.print("Building GUI...");
74                         try {
75                                 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
76                         } catch (Exception e) {}
77                         gui = new MooGUI(seq);
78                         System.out.println("Done");
79                 } else {
80                         System.out.print("Playing...");
81                         play();
82                         while (sequencer.isRunning()) {}
83                         System.out.println("Done");
84                         quit();
85                 }
86         }
87
88         /** 
89          * Returns the GUI.
90          * @return the GUI
91          */
92         public static MooGUI getGUI() {
93                 return gui;
94         }
95
96         /** 
97          * Returns the current sequence.
98          * @return the current sequence
99          */
100         public static Sequence getSequence() {
101                 return seq;
102         }
103
104         /** 
105          * Returns the current sequencer.
106          * @return the current sequencer
107          */
108         public static Sequencer getSequencer() {
109                 return sequencer;
110         }
111
112         /** 
113          * Returns the MidiChannels of the selected synthesizer.
114          * @return the available MidiChannels
115          */
116         public static MidiChannel[] getChannels() {
117                 return channels;
118         }
119
120         /** 
121          * Returns the currently active MidiChannel.
122          * @return the active MidiChannel
123          */
124         public static MidiChannel getActiveChannel() {
125                 return activeChannel;
126         }
127
128         /** 
129          * Sets the currently active MidiChannel.
130          * @param channel       the number of the MidiChannel to activate
131          */
132         public static void setActiveChannel(int channel) {
133                 activeChannel = channels[channel];
134         }
135
136         /** 
137          * Replaces the current sequence with a new one, holding three empty tracks.
138          */
139         public static void clearSequence() {
140                 // Creates a new sequence and sends it to the sequencer.
141                 try {
142                         seq = new Sequence(Sequence.PPQ, 96, 3);
143                         sequencer.setSequence(seq);
144                 } catch (InvalidMidiDataException e) {}
145                 // Sends sequence to GUI.
146                 if (gui != null) gui.setSequence(seq);
147         }
148
149         /** 
150          * Starts playback of the current sequence.
151          */
152         public static void play() {
153                 sequencer.setTickPosition(position);
154                 sequencer.start();
155         }
156
157         /** 
158          * Pauses playback of the current sequence.
159          */
160         public static void pause() {
161                 sequencer.stop();
162         }
163
164         /** 
165          * Resumes playback of the current sequence.
166          */
167         public static void resume() {
168                 sequencer.start();
169         }
170
171         /** 
172          * Stops playback of the current sequence.
173          */
174         public static void stop() {
175                 sequencer.stop();
176                 sequencer.setTickPosition(position);
177         }
178
179         /** 
180          * Rewinds the current sequence the given number of measures.
181          * @param measures      the number of measures to rewind
182          */
183         public static long getPosition() {
184                 return position;
185         }
186
187         /** 
188          * Rewinds the current sequence the given number of measures.
189          * @param measures      the number of measures to rewind
190          */
191         public static void setPosition(long ticks) {
192                 position = ticks;
193         }
194
195         /** 
196          * Rewinds the current sequence the given number of measures.
197          * @param measures      the number of measures to rewind
198          */
199         public static void rewind(long ticks) {
200                 setPosition(position - ticks);
201         }
202
203         /** 
204          * Fast forwards the current sequence the given number of measures.
205          * @param measures      the number of measures to fast forward
206          */
207         public static void forward(long ticks) {
208                 setPosition(position + ticks);
209         }
210
211         /** 
212          * Loads the MooSequence in the given file.
213          * @param filename      the filename to use
214          */
215         public static boolean load(String file) {
216                 // Loads sequence from file
217                 filename = file;
218                 try {
219                         seq = MidiSystem.getSequence(new File(filename));
220                 } catch (InvalidMidiDataException e) {
221                         return false;
222                 } catch (IOException e) {
223                         return false;
224                 }
225
226                 // Sends sequence to GUI and sequencer
227                 if (gui != null) gui.setSequence(seq);
228                 try {
229                         sequencer.setSequence(seq);
230                 } catch (InvalidMidiDataException e) {}
231
232                 // Searches the sequence for NoteOn events
233                 Track[] tracks = seq.getTracks();
234                 MidiEvent noteOn, noteOff = null, nextEvent;
235                 MidiMessage nextMsg;
236                 ShortMessage shortMsg;
237                 for (int i = 0; i < tracks.length; i++) {
238         /*
239                         Collections.sort(track[i].events, new Comparator() {
240                                 public int compare(Object o1, Object o2) {
241                                         return ((MidiEvent)o2).getTick() - ((MidiEvent)o1).getTick();
242                                 }
243                         });
244         */
245                         for (int j = 0; j < tracks[i].size(); j++) {
246                                 noteOn = tracks[i].get(j);
247                                 if (noteOn.getMessage() instanceof ShortMessage) {
248                                         if (((ShortMessage)noteOn.getMessage()).getCommand() == ShortMessage.NOTE_ON) {
249                                                 // Finds the corresponding NoteOff event
250                                                 for (int k = j + 1; k < tracks[i].size(); k++) {
251                                                         nextEvent = tracks[i].get(k);
252                                                         nextMsg = nextEvent.getMessage();
253                                                         if (nextMsg instanceof ShortMessage) {
254                                                                 shortMsg = (ShortMessage) nextMsg;
255                                                                 if (shortMsg.getCommand() == ShortMessage.NOTE_OFF && shortMsg.getChannel() == ((ShortMessage)noteOn.getMessage()).getChannel() && shortMsg.getData1() == ((ShortMessage)noteOn.getMessage()).getData1()) {
256                                                                         noteOff = nextEvent;
257                                                                         break;
258                                                                 }
259                                                         }
260                                                 }
261                                                 // Replaces the NoteOn event with a MooNote, if possible with the corresponding NoteOff event
262                                                 tracks[i].remove(noteOn);
263                                                 if (noteOff != null) {
264                                                         tracks[i].add(new MooNote(noteOn, noteOff));
265                                                 } else {
266                                                         tracks[i].add(new MooNote(noteOn));
267                                                 }
268                                         }
269                                 }
270                         }
271                 }
272                 return true;
273         }
274
275         /** 
276          * Saves the current sequence to the given filename
277          * @param file  the filename to use
278          */
279         public static void saveAs(String file) {
280                 try {
281                         MidiSystem.write(seq, 1, new File(filename));
282                 } catch (IOException e) {}
283                 filename = file;
284         }
285
286         /** 
287          * Saves the current sequence to the previously given filename.
288          */
289         public static void save() {
290                 saveAs(filename);
291         }
292
293         /** 
294          * Releases all reserved devices and exits the program.
295          */
296         public static void quit() {
297                 if (sequencer.isOpen()) sequencer.close();
298                 if (synthesizer.isOpen()) synthesizer.close();
299                 System.exit(0);
300         }
301 }