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