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