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