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