1 /*************************************************************************
2 * musserver.c
3 *
4 * update to lxdoom, assorted features and bugfixes (see NOTES)
5 * Copyright (C) 1999 Rafael Reilova (rreilova@ececs.uc.edu)
6 *
7 * Copyright (C) 1995 Michael Heasley (mheasley@hmc.edu)
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *************************************************************************/
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <termios.h>
27 #include <unistd.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include "musserver.h"
31 #include "sequencer.h"
32
33 /* define for manual mode MUS playing - debugging use only */
34 #undef TESTING_CMDS
35
36 char *progname;
37 int verbose;
38 int has_opl3 = -1;
39 int dumpmus;
40
41 static synthdev_t pref_dev = USE_BEST_SYNTH;
42 static int num_dev = -1;
43
44 static FILE *musfile;
45 static FILE *oplfile;
46
47 /*
48 * try to leave the sequencer in a sane state before exiting
49 */
sig_hdlr(int snum)50 static void sig_hdlr(int snum __attribute__ ((unused)))
51 {
52 cleanup(CLEAN_EXIT, "signal caught, exiting");
53 }
54
show_help(void)55 static void show_help(void)
56 {
57 puts("Usage: musserver [options] [MUSfile [FM-patch file]]\n\n"
58 #ifdef ENABLE_AWE
59 " -a\t\tuse AWE32 synth device for music playback\n"
60 #endif
61 " -f\t\tuse FM synth device for music playback\n"
62 " -h\t\tprint this message and exit\n"
63 " -l\t\tlist detected music devices and exit\n"
64 " -m\t\tuse general midi device for music playback\n"
65 " -v\t\tverbose\n"
66 " -u number\tuse device [number] as reported by 'musserver -l'\n"
67 " -2\t\tforce dual voice mode when using FM synthesis\n"
68 " -1\t\tforce single voice mode when using FM synthesis\n"
69 " -B\t\tdo not increase pitch by one octave when using FM synthesis\n"
70 " -D\t\tdump playing songs and FM-patches to disk as mus-files\n"
71 "\t\tsongX.mus and raw_midi.patch respectively.\n");
72 }
73
cleanup(int error,const char * mesg)74 void cleanup(int error, const char *mesg)
75 {
76 if (seq_dev != -1)
77 cleanup_midi();
78
79 if (mesg)
80 printf("%s: %s\n", progname, mesg);
81
82 if (error == IO_ERROR && errno)
83 perror(progname);
84
85 exit(error);
86 }
87
parse_arguments(int argc,char * argv[])88 static void parse_arguments(int argc, char *argv[])
89 {
90 static const char opt_conflict[] =
91 "please specify only one of the -a -f -m -l options";
92 int x;
93
94 progname = argv[0];
95
96 musfile = stdin;
97 oplfile = stdin;
98
99 while ((x = getopt(argc, argv, "afhlmu:v12BD")) != -1)
100 switch (x)
101 {
102 case 'a':
103 if (pref_dev == USE_BEST_SYNTH) {
104 #ifdef ENABLE_AWE
105 pref_dev = USE_AWE_SYNTH;
106 #else
107 cleanup(MISC_ERROR,
108 "This program version wasn't compiled with AWE driver support\n");
109 #endif
110 }
111 else
112 cleanup(MISC_ERROR, opt_conflict);
113 break;
114
115 case 'f':
116 if (pref_dev == USE_BEST_SYNTH)
117 pref_dev = USE_FM_SYNTH;
118 else
119 cleanup(MISC_ERROR, opt_conflict);
120 break;
121
122 case 'm':
123 if (pref_dev == USE_BEST_SYNTH)
124 pref_dev = USE_MIDI_SYNTH;
125 else
126 cleanup(MISC_ERROR, opt_conflict);
127 break;
128
129 case 'h':
130 show_help();
131 exit(0);
132 break;
133
134 case 'l':
135 if (pref_dev == USE_BEST_SYNTH)
136 {
137 pref_dev = LIST_ONLY_SYNTH;
138 verbose = 1;
139 }
140 else
141 cleanup(MISC_ERROR, opt_conflict);
142 break;
143
144 case 'u':
145 if (pref_dev == USE_BEST_SYNTH || pref_dev == LIST_ONLY_SYNTH)
146 cleanup(MISC_ERROR,
147 "specify device type, -a -f -m, to use the -u option");
148
149 num_dev = atoi(optarg);
150 break;
151
152 case 'v':
153 verbose++;
154 break;
155 case '?': case ':':
156 show_help();
157 cleanup(MISC_ERROR, NULL);
158 break;
159
160 case '1': /* force use of only a single voice per instrument */
161 has_opl3 = 0;
162 break;
163
164 /*
165 * force use of dual voices instruments even on cards with
166 * limited set of voices (Adlib), not recommended
167 */
168 case '2':
169 has_opl3 = 1;
170 break;
171
172 case 'B': /* don't increase all notes by one octave */
173 voxware_octave_bug = 0;
174 break;
175
176 case 'D':
177 dumpmus = 1;
178 break;
179 }
180
181 if (argv[optind])
182 {
183 musfile = fopen(argv[optind], "r");
184 if (!musfile)
185 cleanup(IO_ERROR, "Can't open MUS file");
186
187 if (argv[++optind])
188 {
189 oplfile = fopen(argv[optind], "r");
190 if (!oplfile)
191 cleanup(IO_ERROR, "Can't open OPL instrument file");
192 }
193 else
194 oplfile = NULL;
195
196 if (dumpmus)
197 {
198 printf("%s: -D non-sensical when standalone, ignoring",progname);
199 dumpmus = 0;
200 }
201 }
202 }
203
204
main(int argc,char ** argv)205 int main(int argc, char **argv)
206 {
207 const MUSFILE *song = NULL;
208 const OPLFILE *midifile;
209 int vol;
210 int load_midi;
211 int looping = 0;
212 int playing_song = 0;
213 int paused = 0;
214 int ch;
215
216 parse_arguments(argc, argv);
217
218 load_midi = midi_setup(pref_dev, num_dev);
219
220 if (!oplfile && load_midi)
221 cleanup(MISC_ERROR, "FM synthesis requires an instrument patch file");
222
223 if (oplfile == stdin || load_midi)
224 {
225 midifile = read_genmidi(oplfile);
226 if (verbose)
227 printf("%s: got MIDI instrument info\n", progname);
228
229 if (load_midi)
230 {
231 fmload(midifile->opl_instruments);
232 if (verbose)
233 printf("%s: Loaded MIDI into synth device\n", progname);
234 }
235 }
236
237 signal(SIGINT, sig_hdlr);
238 signal(SIGTERM, sig_hdlr);
239
240 #ifndef TESTING_CMDS
241 if (musfile != stdin)
242 {
243 song = readmus(musfile);
244 vol_change(DFL_VOL);
245 midi_timer(MIDI_START);
246 playmus(song, MUS_NEWSONG, MUS_NOLOOP, STDIN_FILENO);
247 tcflush(STDIN_FILENO, TCIFLUSH);
248 cleanup(CLEAN_EXIT, NULL);
249 }
250 #endif
251
252 /* main loop */
253 while((ch = fgetc(stdin)) != EOF)
254 {
255 switch (ch)
256 {
257 /* volume change */
258 case 'V':
259 if (fscanf(stdin, "%d%*c", &vol) != 1)
260 cleanup(IO_ERROR, "error reading new volume");
261
262 vol_change(vol);
263 if (verbose > 1)
264 printf("%s: volume change to %d\n", progname, vol);
265 if (playing_song && !paused)
266 playmus(song, MUS_SAMESONG, looping, STDIN_FILENO);
267 break;
268
269 /* stop song */
270 case 'S':
271 if (playing_song)
272 {
273 midi_timer(MIDI_STOP);
274 playing_song = 0;
275 if (verbose > 1)
276 printf("%s: song stopped\n", progname);
277 }
278 break;
279
280 /* pause song */
281 case 'P':
282 if (playing_song && !paused)
283 {
284 midi_timer(MIDI_PAUSE);
285 paused = 1;
286 if (verbose > 1)
287 printf("%s: song paused\n", progname);
288 }
289 break;
290
291 /* resume song */
292 case 'R':
293 if (playing_song)
294 {
295 if (paused)
296 {
297 paused = 0;
298 midi_timer(MIDI_RESUME);
299 if (verbose > 1)
300 printf("%s: song resumed\n", progname);
301 }
302 playmus(song, MUS_SAMESONG, looping, STDIN_FILENO);
303 }
304 break;
305
306 /* new song */
307 case 'N':
308 if (fscanf(stdin, "%d%*c", &looping) != 1)
309 cleanup(IO_ERROR, "error reading \"looping\" flag");
310
311 song = readmus(musfile);
312 if (verbose > 1)
313 printf("%s: read new song, starting music\n", progname);
314
315 playing_song = 1;
316 paused = 0;
317 midi_timer(MIDI_START);
318 playmus(song, MUS_NEWSONG, looping, STDIN_FILENO);
319 break;
320
321 /* Quit command */
322 case 'Q':
323 cleanup(CLEAN_EXIT, (verbose) ? "received the quit command" : NULL);
324
325 case '\n': /* Ignore newline delimiters */
326 continue;
327
328 default:
329 cleanup(MISC_ERROR, "read unrecognized command");
330 }
331 }
332 cleanup(MISC_ERROR, "error reading mesg. pipe");
333 }
334