1 /*
2  * Program XBLAST V2.5.15 or higher
3  * (C) by Oliver Vogel (e-mail: vogel@ikp.uni-koeln.de)
4  * March 21nd, 1997
5  * started August 1993
6  *
7  * File: xbsndsrv.c
8  * sound server and sound processing
9  *
10  * Author: Norbert Nicolay, e-mail: nicolay@ikp.uni-koeln.de
11  *         July 30th 1996
12  *
13  * $Id: xbsndsrv.c,v 1.23 2006/06/12 11:06:36 fzago Exp $
14  *
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public Licences as published
18  * by the Free Software Foundation; either version 2; or (at your option)
19  * any later version
20  *
21  * This program is distributed in the hope that it will entertaining,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
24  * Publis License for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, write to the Free Software Foundation, Inc.
28  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  *
30  */
31 
32 #include "config.h"
33 
34 #if defined(XBLAST_SOUND)
35 
36 #define _SOUND_C_
37 
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/fcntl.h>
45 #include <sys/stat.h>
46 #include <sys/ioctl.h>
47 #include <sys/time.h>
48 
49 #ifdef __sun__
50 
51 /* format for pids on sun */
52 #define PID_FORMAT "%lu"
53 /* needed for bzero(), open()*/
54 #include <strings.h>
55 #include <fcntl.h>
56 /* sun-specific audio includes */
57 #ifdef HAVE_SYS_AUDIO_H
58 #include <sys/audio.h>
59 #else
60 #include <sys/audioio.h>
61 #include <sys/stropts.h>
62 #endif
63 
64 #else
65 
66 /* format for pids, non-sun */
67 #define PID_FORMAT "%u"
68 /* non-sun audio includes */
69 #ifdef HAVE_SYS_SOUNDCARD_H
70 #include <sys/soundcard.h>
71 #endif
72 #ifdef HAVE_MACHINE_SOUNDCARD_H
73 #include <machine/soundcard.h>
74 #endif
75 #ifdef HAVE_LINUX_SOUNDCARD_H
76 #include <linux/soundcard.h>
77 #endif
78 
79 #endif
80 
81 #include <signal.h>
82 
83 #include "xblast.h"
84 
85 #if !defined(TRUE)
86 #define TRUE 1
87 #endif
88 
89 #if !defined(FALSE)
90 #define FALSE 0
91 #endif
92 
93 /*
94  * play at least 5 sounds simultaneously regardless of machine power
95  */
96 #define DEFAULT_MAX_SIM_SOUNDS 10
97 
98 #define ABS_MAX_SIM_SOUNDS    250
99 #define MAX_CPU_LOAD_ADJUST    10
100 
101 /* client/server commands */
102 #define SND_LOAD_SOUND      0
103 #define SND_PLAY_SOUND      1
104 #define SND_STOP_SOUND      2
105 #define SND_UNLOAD_SOUND    3
106 
107 /* values to be used in acknowledge pipe */
108 #define SND_ACK_OK      0
109 #define SND_ACK_ERROR   1
110 
111 static const char rcs_id[] = "$Id: xbsndsrv.c,v 1.23 2006/06/12 11:06:36 fzago Exp $";
112 
113 typedef unsigned char u8;
114 typedef short s16;
115 
116 typedef struct _xbsound
117 {
118 	int id;
119 	int repeat;
120 	int mono;
121 	int position;
122 	u8 *samples;
123 	int length;
124 	struct _xbsound *next;
125 } XBSOUND;
126 
127 static int max_sim_sounds = DEFAULT_MAX_SIM_SOUNDS;
128 static int next_free_sound = 0;
129 static int sounds_playing = 0;
130 static XBSOUND *sound_table;
131 static volatile int calibration_ready;
132 
133 /*
134  * sound sample table
135  */
136 static struct _sound_name
137 {
138 	int sound_id;				/* the sound's id to refer to it */
139 	const char *name;			/* raw samples data file name */
140 	u8 *samples;				/* pointer to samples memory */
141 	int length;					/* length in samples of the sound */
142 	int repeat;					/* repeat flag to play sound endlessly */
143 	int mono;					/* mono flag indicating mono sounds */
144 } sound_name[] = {
145 	{
146 	SND_BAD, "xb_bad.raw", NULL, 0, FALSE, FALSE},	/* got a skull */
147 	{
148 	SND_DROP, "xb_drop.raw", NULL, 0, FALSE, TRUE},	/* dropped a bomb */
149 	{
150 	SND_NEWBOMB, "xbnbmb.raw", NULL, 0, FALSE, TRUE},	/* got an extra bomb */
151 	{
152 	SND_NEWKICK, "xbnkick.raw", NULL, 0, FALSE, TRUE},	/* got kick extra */
153 	{
154 	SND_NEWPUMP, "xbnpmp.raw", NULL, 0, FALSE, TRUE},	/* got pump extra */
155 	{
156 	SND_NEWRC, "xbnrc.raw", NULL, 0, FALSE, TRUE},	/* got rem. control */
157 	{
158 	SND_MOREFIRE, "xbfire.raw", NULL, 0, FALSE, TRUE},	/* got more range */
159 	{
160 	SND_DEAD, "xb_dead.raw", NULL, 0, FALSE, FALSE},	/* player died */
161 	{
162 	SND_EXPL, "xb_expl.raw", NULL, 0, FALSE, TRUE},	/* normal explosion */
163 	{
164 	SND_KICK, "xb_kick.raw", NULL, 0, FALSE, TRUE},	/* kick a bomb */
165 	{
166 	SND_PUMP, "xb_pump.raw", NULL, 0, FALSE, TRUE},	/* pump a bomb */
167 	{
168 	SND_OUCH, "xb_ouch.raw", NULL, 0, FALSE, FALSE},	/* player lost life */
169 	{
170 	SND_INTRO, "xb_intro.raw", NULL, 0, FALSE, FALSE},	/* intro fanfare */
171 	{
172 	SND_APPL, "xb_appl.raw", NULL, 0, FALSE, FALSE},	/* applause */
173 	{
174 	SND_APPL2, "xb_app2.raw", NULL, 0, FALSE, FALSE},	/* applause */
175 	{
176 	SND_BUTT, "xb_butt.raw", NULL, 0, FALSE, TRUE},	/* triggered button */
177 	{
178 	SND_SHOOT, "xb_shoot.raw", NULL, 0, FALSE, FALSE},	/* using rem. ctrl. */
179 	{
180 	SND_INVIS, "xb_nvis.raw", NULL, 0, FALSE, FALSE},	/* player invisible */
181 	{
182 	SND_INVINC, "xb_nvnc.raw", NULL, 0, FALSE, FALSE},	/* player invincible */
183 	{
184 	SND_NEWTELE, "xbntel.raw", NULL, 0, FALSE, TRUE},	/* player got telep. */
185 	{
186 	SND_TELE, "xbtele.raw", NULL, 0, FALSE, TRUE},	/* player uses tele. */
187 	{
188 	SND_INJ, "xbinj.raw", NULL, 0, FALSE, FALSE},	/* player got junkie */
189 	{
190 	SND_MINIBOMB, "xbmbmb.raw", NULL, 0, FALSE, TRUE},	/* small bomb expl. */
191 	{
192 	SND_WON, "xb_won.raw", NULL, 0, FALSE, FALSE},	/* player won */
193 	{
194 	SND_HAUNT, "xb_haunt.raw", NULL, 0, FALSE, FALSE},	/* haunting bomb */
195 	{
196 	SND_SPIRAL, "xb_spir.raw", NULL, 0, FALSE, TRUE},	/* spiral shrinking */
197 	{
198 	SND_SPBOMB, "xb_spbmb.raw", NULL, 0, FALSE, TRUE},	/* got special bomb */
199 	{
200 	SND_SLIDE, "xbslide.raw", NULL, 0, FALSE, TRUE},	/* bomb slide sound */
201 	{
202 	SND_FINALE, "xbfin.raw", NULL, 0, FALSE, FALSE},	/* final fanfare */
203 	{
204 	SND_WARN, "xb_warn.raw", NULL, 0, FALSE, FALSE},	/* shrink warn sound */
205 	{
206 	SND_STUN, "xb_stun.raw", NULL, 0, FALSE, FALSE},	/* player stun sound */
207 	{
208 	SND_WHIRL, "xb_whrl.raw", NULL, 0, TRUE, FALSE},	/* intro whirl */
209 	{
210 	SND_COMPOUND, "xb_cmpnd.raw", NULL, 0, FALSE, FALSE},	/* compound shrink */
211 	{
212 	SND_TELE1, "xbtele1.raw", NULL, 0, FALSE, TRUE},	/* teleport start */
213 	{
214 	SND_TELE2, "xbtele2.raw", NULL, 0, FALSE, TRUE},	/* teleport end */
215 	{
216 	SND_HOLY, "xbholy.raw", NULL, 0, FALSE, FALSE},	/* holy grail extra */
217 	{
218 	SND_ENCLOAK, "xbcloak.raw", NULL, 0, FALSE, TRUE},	/* encloak sound */
219 	{
220 	SND_DECLOAK, "xbdcloak.raw", NULL, 0, FALSE, TRUE},	/* decloak sound */
221 	{
222 	SND_FAST, "xbfast.raw", NULL, 0, FALSE, TRUE},	/* speed up extra */
223 	{
224 	SND_SLOW, "xbslow.raw", NULL, 0, FALSE, TRUE},	/* slow down extra */
225 	{
226 	SND_SLAY, "xbslay.raw", NULL, 0, FALSE, TRUE},	/* slay extra */
227 	{
228 	SND_LIFE, "xblife.raw", NULL, 0, FALSE, TRUE},	/* extra life */
229 	{
230 	SND_NEWCLOAK, "xbcloakx.raw", NULL, 0, FALSE, TRUE},	/* new cloak extra */
231 	{
232 	SND_BOMBMORPH, "xb_bombmorph.raw", NULL, 0, FALSE, TRUE},	/* bomb morph */
233 	{
234 	SND_STEP1, "xbstep1.raw", NULL, 0, FALSE, TRUE},	/* Backgr. song #1 */
235 	{
236 	SND_STEP2, "xbstep2.raw", NULL, 0, FALSE, TRUE},	/* Backgr. song #2 */
237 	{
238 	SND_STEP3, "xbstep3.raw", NULL, 0, FALSE, TRUE},	/* Backgr. song #3 */
239 	{
240 	SND_STEP4, "xbstep4.raw", NULL, 0, FALSE, TRUE},	/* Backgr. song #4 */
241 	{
242 	SND_STEP5, "xbstep5.raw", NULL, 0, FALSE, TRUE},	/* Backgr. song #5 */
243 	{
244 	SND_STEP6, "xbstep6.raw", NULL, 0, FALSE, TRUE},	/* Backgr. song #6 */
245 	{
246 	SND_SNG1, "xbsng1.raw", NULL, 0, TRUE, FALSE},	/* Backgr. song #1 */
247 	{
248 	SND_SNG2, "xbsng2.raw", NULL, 0, TRUE, FALSE},	/* Backgr. song #2 */
249 	{
250 	SND_SNG3, "xbsng3.raw", NULL, 0, TRUE, FALSE},	/* Backgr. song #3 */
251 	{
252 	SND_SNG4, "xbsng4.raw", NULL, 0, TRUE, FALSE},	/* Backgr. song #4 */
253 	{
254 	SND_SNG5, "xbsng5.raw", NULL, 0, TRUE, FALSE},	/* Backgr. song #5 */
255 	{
256 	SND_SNG6, "xbsng6.raw", NULL, 0, TRUE, FALSE},	/* Backgr. song #6 */
257 	{
258 	SND_MAX, NULL, NULL, 0}
259 };
260 
261 #ifdef __sun__
262 #define SOUND_DEVICE "/dev/audio"
263 #define SAMPLE_CHANNELS     2
264 #define SAMPLE_SIZE         16
265 #define SUN_AUDIO_REF 0
266 #else
267 #define SOUND_DEVICE "/dev/dsp"
268 #define SAMPLE_CHANNELS     1
269 #define SAMPLE_SIZE         8
270 #endif
271 
272 #define SAMPLE_RATE     22050
273 #define SUBSIZE          2048
274 #define FRAGSIZE         0x0004000a
275 
276 static s16 sumbuff[SUBSIZE];
277 static u8 playbuff[SUBSIZE];
278 
279 static int mono_mode = FALSE;
280 
281 static int fragsize = FRAGSIZE;
282 static int sample_rate = SAMPLE_RATE;
283 static int sample_channels = SAMPLE_CHANNELS;
284 static int sample_size = SAMPLE_SIZE;
285 
286 /*
287  * outcomment the following line to suppress server statistics
288  */
289 #define SERVER_STATISTICS
290 
291 #if defined(SERVER_STATISTICS)
292 static double total_samples = 0.0;
293 static int total_played = 0;
294 static int total_skipped = 0;
295 static int total_loaded = 0;
296 static int total_unloaded = 0;
297 #endif
298 
299 /*
300  * Abort signal handler
301  */
302 static void
server_abort(int signnum)303 server_abort (int signnum)
304 {
305 #if defined(SERVER_STATISTICS)
306 	fprintf (stderr, "XBlast sound server statistics:\n");
307 	fprintf (stderr, "\tloaded %d sounds,\n", total_loaded);
308 	fprintf (stderr, "\tfreed %d sounds,\n", total_unloaded);
309 	fprintf (stderr, "\tplayed %d sounds,\n", total_played);
310 	fprintf (stderr, "\tskipped %d sounds,\n", total_skipped);
311 	fprintf (stderr, "\tprocessed %10.3f Mega samples on sound device.\n",
312 			 total_samples / 1000000.0);
313 #endif
314 	fprintf (stderr, "XBlast sound server terminated.\n");
315 	fflush (stderr);
316 	exit (0);
317 }
318 
319 /*
320  * alarm signal handler for sound server calibration
321  */
322 static void
calibration_stop(int signum)323 calibration_stop (int signum)
324 {
325 	calibration_ready = TRUE;
326 }
327 
328 /*
329  * initialize sound device
330  */
331 #if defined(__STDC__)
332 static void
init_dsp(int dsp)333 init_dsp (int dsp)
334 #else
335 static void
336 init_dsp (dsp)
337 	 int dsp;
338 #endif
339 {
340 
341 #ifdef __sun__
342 	struct audio_info au;
343 
344 	bzero (&au, sizeof (struct audio_prinfo));
345 
346 	fprintf (stderr, "Solaris audio device initialisation beginning.\n");
347 
348 	if (ioctl (dsp, AUDIO_GETINFO, &au) < 0) {
349 		fprintf (stderr, "XBlast sound server: " "could not read audio device settings\n");
350 	}
351 	au.play.sample_rate = sample_rate;
352 	au.play.precision = sample_size;
353 	au.play.channels = sample_channels;
354 	if (sample_channels == 0)
355 		au.play.channels = 1;
356 	au.play.buffer_size = fragsize;
357 	au.play.encoding = AUDIO_ENCODING_LINEAR;	/* ULAW, ALAW, LINEAR */
358 	au.play.balance = AUDIO_MID_BALANCE;
359 	au.play.pause = 0;
360 	au.record.pause = 1;
361 	au.output_muted = 0;
362 	if (ioctl (dsp, AUDIO_SETINFO, &au) < 0) {
363 		fprintf (stderr, "XBlast sound server: " "could not read audio device settings\n");
364 	}
365 	if (ioctl (dsp, AUDIO_GETINFO, &au) < 0) {
366 		fprintf (stderr, "XBlast sound server: " "could not read audio device settings\n");
367 	}
368 
369 	fprintf (stderr, "Audio device initialised: %d channels, %d bits, %dHz.\n",
370 			 au.play.channels, au.play.precision, au.play.sample_rate);
371 	fprintf (stderr, "  (wanted %d channels, %d bits, %dHz)\n",
372 			 sample_channels, sample_size, sample_rate);
373 
374 #else
375 
376 	if (ioctl (dsp, SNDCTL_DSP_SETFRAGMENT, &fragsize) < 0) {
377 		fprintf (stderr, "XBlast sound server: could not set fragment size %8x on sound device\n",
378 				 fragsize);
379 	}
380 	if (ioctl (dsp, SNDCTL_DSP_STEREO, &sample_channels) < 0) {
381 		fprintf (stderr, "XBlast sound server: could not set %d sample channels on sound device\n",
382 				 sample_channels);
383 	}
384 	if (ioctl (dsp, SNDCTL_DSP_SPEED, &sample_rate) < 0) {
385 		fprintf (stderr, "XBlast sound server: could not set sample rate %d on sound device\n",
386 				 sample_rate);
387 	}
388 	if (ioctl (dsp, SNDCTL_DSP_SETFMT, &sample_size) < 0) {
389 		fprintf (stderr, "XBlast sound server: could not set sample size %d on sound device\n",
390 				 sample_size);
391 	}
392 	if (ioctl (dsp, SNDCTL_DSP_GETBLKSIZE, &fragsize) < 0) {
393 		fprintf (stderr, "XBlast sound server: could not get block size of sound device\n");
394 	}
395 #endif
396 }
397 
398 /*
399  * resync sound device
400  */
401 #if defined(__STDC__)
402 static void
resync(int dsp)403 resync (int dsp)
404 #else
405 static void
406 resync (dsp)
407 	 int dsp;
408 #endif
409 {
410 	/* clear sample sum buffer */
411 	register int i;
412 	register u8 *s = playbuff;
413 
414 	for (i = 0; i < SUBSIZE; i++) {
415 		*s++ = 128;
416 	}
417 
418 #ifdef __sun__
419 	ioctl (dsp, I_FLUSH, NULL);
420 	fprintf (stderr, "\nsync\n");
421 #else
422 	/* resync sound device to correct any channel flipping */
423 	write (dsp, playbuff, SUBSIZE);
424 	write (dsp, playbuff, SUBSIZE);
425 	write (dsp, playbuff, SUBSIZE);
426 	(void)ioctl (dsp, SNDCTL_DSP_SYNC, NULL);
427 #endif
428 }
429 
430 /*
431  * load sound samples into server memory
432  */
433 #if defined(__STDC__)
434 static int
server_load_sound(int number)435 server_load_sound (int number)
436 #else
437 static int
438 server_load_sound (number)
439 	 int number;
440 #endif
441 {
442 	char fname[1000];
443 	int i, f;
444 	static char *path_list[3] = {
445 		NULL,
446 		GAME_DATADIR "/",
447 		".",
448 	};
449 
450 	/* check environment for xblast search path */
451 	path_list[0] = getenv ("XBLASTDIR");
452 
453 	for (i = 0; i < 3; i++) {
454 		if (path_list[i] != NULL) {
455 			sprintf (fname, "%s/%s/%s", path_list[i], "sounds", sound_name[number].name);
456 			//      fprintf(stderr," opening %s \n",fname);
457 			if ((f = open (fname, O_RDONLY)) >= 0) {
458 				int sound_size;
459 				u8 *sb;
460 				struct stat snd_stat;
461 
462 #ifdef DEBUG
463 				fprintf (stderr, "Opened file \"%s\".\n", fname);
464 #endif
465 				(void)fstat (f, &snd_stat);
466 				sound_size = snd_stat.st_size / sizeof (u8);
467 				if (sound_name[number].samples != NULL) {
468 					free (sound_name[number].samples);
469 					sound_name[number].samples = NULL;
470 					sound_name[number].length = 0;
471 				}
472 
473 				if ((sb = (u8 *) malloc (sound_size * sizeof (u8))) == NULL) {
474 					close (f);
475 					return (-1);
476 				}
477 				else {
478 					read (f, sb, sound_size * sizeof (u8));
479 					sound_name[number].samples = sb;
480 					sound_name[number].length = sound_size;
481 					close (f);
482 #if defined(SERVER_STATISTICS)
483 					total_loaded++;
484 #endif
485 					/*
486 					 * convert stereo samples to mono if running in mono mode
487 					 */
488 					if (mono_mode == TRUE && sound_name[number].mono == FALSE) {
489 						int i;
490 						u8 *m, *s;
491 						s16 sum;
492 
493 						m = s = sound_name[number].samples;
494 
495 						sound_name[number].length >>= 1;
496 						for (i = 0; i < sound_name[number].length; i++) {
497 							sum = *s + *(s + 1);
498 							*m++ = sum >> 1;
499 							s += 2;
500 						}
501 					}
502 					return (0);
503 				}
504 			}
505 		}
506 	}
507 	fprintf (stderr, "could not open sound data file %s\n", sound_name[number].name);
508 	return (-1);
509 }
510 
511 /*
512  * free sample memory of a given sound
513  */
514 #if defined(__STDC__)
515 static void
server_unload_sound(int id)516 server_unload_sound (int id)
517 #else
518 static void
519 server_unload_sound (id)
520 	 int id;
521 #endif
522 {
523 	if (sound_name[id].samples != NULL) {
524 		free (sound_name[id].samples);
525 		sound_name[id].samples = NULL;
526 		sound_name[id].length = 0;
527 #if defined(SERVER_STATISTICS)
528 		total_unloaded++;
529 #endif
530 	}
531 }
532 
533 static int
RunningInstances(void)534 RunningInstances (void)
535 {
536 	FILE *ptr;
537 	static char userPath[1024];
538 	char tmp[1024];
539 	unsigned int pid;
540 
541 	char *home;
542 	/* set private xblast path */
543 	home = getenv ("HOME");
544 	if (NULL == home) {
545 		strcpy (userPath, "./user/xbsndsrv.pid");
546 	}
547 	else {
548 		sprintf (userPath, "%s/.xblast_tnt/xbsndsrv.pid", home);
549 	}
550 	ptr = fopen (userPath, "r+");
551 	if (ptr == NULL) {
552 		ptr = fopen (userPath, "w+");
553 		sprintf (tmp, PID_FORMAT, getpid ());
554 		fwrite (tmp, 1, strlen (tmp), ptr);
555 		fclose (ptr);
556 		return 0;
557 
558 	}
559 	fscanf (ptr, PID_FORMAT, &pid);
560 	fprintf (stderr, " " PID_FORMAT " \n", pid);
561 	if (kill (pid, 0) == -1 || pid <= 0) {
562 		fseek (ptr, 0, SEEK_SET);
563 		sprintf (tmp, PID_FORMAT, getpid ());
564 		fwrite (tmp, 1, strlen (tmp), ptr);
565 		fclose (ptr);
566 		return 0;
567 	}
568 	else {
569 		return 1;
570 	}
571 
572 }
573 
574 /*
575  * main function
576  */
577 #if defined(__STDC__)
578 int
main(int argc,char ** argv)579 main (int argc, char **argv)
580 #else
581 int
582 main (argc, argv)
583 	 int argc;
584 	 char **argv;
585 #endif
586 {
587 	int dsp;
588 	int do_sync = TRUE;
589 	int did_sync = FALSE;
590 	int ack_val;
591 
592 #ifdef __sun__
593 	int samples_to_play = 0;
594 	int samples_played = 0;
595 #endif
596 
597 	if (RunningInstances ()) {
598 		fprintf (stderr, "xbsndsrv already running\n");
599 		return 1;
600 	}
601 	/*
602 	 * open and prepare sound device
603 	 */
604 	if ((dsp = open (SOUND_DEVICE, O_WRONLY)) < 0) {
605 		fprintf (stderr, "XBlast sound server: could not open sound device %s\n", SOUND_DEVICE);
606 		ack_val = SND_ACK_ERROR;
607 		write (1, &ack_val, sizeof (ack_val));
608 		exit (-1);
609 	}
610 	ack_val = SND_ACK_OK;
611 	write (1, &ack_val, sizeof (ack_val));
612 
613 	while (--argc > 0) {
614 		++argv;
615 		if (!strcmp ("-mono", *argv)) {
616 			mono_mode = TRUE;
617 		}
618 		else {
619 			fprintf (stderr, "XBlast sound server: unknown option %s ignored\n", *argv);
620 		}
621 	}
622 
623 	if (mono_mode == TRUE) {
624 #ifdef __sun__
625 		sample_channels = 1;
626 #else
627 		sample_channels = 0;
628 #endif
629 	}
630 
631 	init_dsp (dsp);
632 	/*
633 	 * install server abort signal handler
634 	 */
635 	signal (SIGINT, server_abort);
636 
637 	fprintf (stderr, "XBlast sound server $Revision: 1.23 $ running in %s mode.\n",
638 			 (mono_mode == TRUE) ? "mono" : "stereo");
639 
640 	/*
641 	 * calibrate sound server to CPU power
642 	 */
643 	signal (SIGALRM, calibration_stop);
644 	{
645 		unsigned long l = 0;
646 		int d1, d2, d3, d4, d5;
647 		calibration_ready = FALSE;
648 		alarm (1);
649 		while (calibration_ready == FALSE) {
650 			l++;
651 			/* do something similar to the "place a sample" loop */
652 #ifdef __sun__
653 			d5 = d2++ - SUN_AUDIO_REF;
654 #else
655 			d5 = d2++ - 128;
656 #endif
657 			d1 = (d2 * (d3 + 1)) >> 4;
658 			d4 = (d2 * (d3 - MAX_SOUND_POSITION + 1)) >> 4;
659 			d2 += d1;
660 			d3 += d4;
661 		}
662 		max_sim_sounds = l / (SAMPLE_RATE * MAX_CPU_LOAD_ADJUST);
663 		l = d4 + d5;			/* hope to fake C optimizer */
664 
665 		/* calc. max playable sounds to something reasonable... */
666 		if (max_sim_sounds > ABS_MAX_SIM_SOUNDS) {
667 			max_sim_sounds = ABS_MAX_SIM_SOUNDS;
668 		}
669 		else if (max_sim_sounds < DEFAULT_MAX_SIM_SOUNDS) {
670 			max_sim_sounds = DEFAULT_MAX_SIM_SOUNDS;
671 		}
672 	}
673 
674 	/*
675 	 * allocate memory for playing sounds table
676 	 */
677 	fprintf (stderr, "Xblast Sound Server: playing at most %d sounds simultaneously\n",
678 			 max_sim_sounds);
679 	fflush (stderr);
680 	if ((sound_table = (XBSOUND *) malloc (max_sim_sounds * sizeof (XBSOUND)))
681 		== NULL) {
682 		fprintf (stderr, "XBlast Sound Server: not enough memory to allocate sound table\n");
683 		exit (-1);
684 	}
685 	else {
686 		/* initialze sound table */
687 		XBSOUND *s = sound_table;
688 		int i;
689 		for (i = 0; i < max_sim_sounds; i++, s++) {
690 			s->length = 0;
691 		}
692 	}
693 
694 	/*
695 	 * loop forever (or SIGINT)
696 	 */
697 	while (1) {
698 		/* clear sample sum buffer */
699 		{
700 			register int i;
701 			register s16 *s = sumbuff;
702 
703 			for (i = 0; i < SUBSIZE; i++) {
704 				*s++ = 128;
705 			}
706 		}
707 
708 		if (sounds_playing <= 0) {
709 			/* no sound to play, may sync */
710 			do_sync = TRUE;
711 		}
712 		else {
713 			do_sync = FALSE;
714 			did_sync = FALSE;
715 		}
716 
717 		/* sum samples in sumup buffer */
718 		if (mono_mode == TRUE) {
719 			/*
720 			 * process sounds in mono mode
721 			 */
722 			XBSOUND *xs = sound_table;
723 			int as;
724 
725 			for (as = 0; as < max_sim_sounds; as++) {
726 				if (xs->length > 0) {
727 					int i;
728 					register s16 *s = sumbuff;
729 
730 					for (i = 0; i < SUBSIZE && xs->length > 0; i++, xs->length--) {
731 #ifdef __sun__
732 						*s++ += ((s16) * xs->samples++) - SUN_AUDIO_REF;
733 #else
734 						*s++ += ((s16) * xs->samples++) - 128;
735 #endif
736 					}
737 
738 #if defined(SERVER_STATISTICS)
739 					total_samples += (double)i;
740 #endif
741 					/* repeat a sound if this is required */
742 					if (xs->length <= 0) {
743 						if (xs->repeat == TRUE) {
744 							int id = xs->id;
745 							xs->length = sound_name[id].length;
746 							xs->samples = sound_name[id].samples;
747 						}
748 						else {
749 							next_free_sound = as;
750 							sounds_playing--;
751 						}
752 					}
753 				}
754 				xs++;
755 			}
756 
757 			/* correct clipping */
758 			{
759 				register int i;
760 				register s16 *s = sumbuff;
761 				for (i = 0; i < SUBSIZE; i++) {
762 					if (*s > 255) {
763 						*s = 255;
764 					}
765 					else if (*s < 0) {
766 						*s = 0;
767 					}
768 					s++;
769 				}
770 			}
771 
772 			/* copy sum buffer to playback buffer and play it */
773 			{
774 				register u8 *d = playbuff;
775 				register s16 *s = sumbuff;
776 				register int i;
777 
778 				for (i = 0; i < SUBSIZE; i++) {
779 					*d++ = (u8) * s++;
780 				}
781 
782 				/* play buffer */
783 				write (dsp, playbuff, SUBSIZE);
784 			}
785 		}
786 		else {
787 			/*
788 			 * process sounds in stereo  mode
789 			 */
790 			XBSOUND *xs = sound_table;
791 			int as;
792 
793 			for (as = 0; as < max_sim_sounds; as++) {
794 				if (xs->length > 0) {
795 					int i;
796 					register s16 *s = sumbuff;
797 
798 					for (i = 0; i < SUBSIZE && xs->length > 0; i++, xs->length--) {
799 						if (xs->mono == TRUE) {
800 							/* calc. position of mono sounds and add to sumup buffer */
801 							int pos = xs->position;
802 #ifdef __sun__
803 							s16 sample = ((s16) * xs->samples++) - SUN_AUDIO_REF;
804 #else
805 							s16 sample = ((s16) * xs->samples++) - 128;
806 #endif
807 							s16 sr, sl;
808 
809 							sr = (sample * (pos + 1)) >> 4;
810 							sl = (sample * (pos - MAX_SOUND_POSITION + 1)) >> 4;
811 							*s++ += sl;
812 							*s++ += sr;
813 							i++;
814 						}
815 						else {
816 #ifdef __sun__
817 							*s++ += ((s16) * xs->samples++) - SUN_AUDIO_REF;
818 #else
819 							*s++ += ((s16) * xs->samples++) - 128;
820 #endif
821 						}
822 					}
823 #if defined(SERVER_STATISTICS)
824 					total_samples += (double)i;
825 #endif
826 					/* repeat a sound if this is required */
827 #ifdef __sun__
828 					samples_to_play = i;
829 #endif
830 					if (xs->length <= 0) {
831 						if (xs->repeat == TRUE) {
832 							int id = xs->id;
833 							xs->length = sound_name[id].length;
834 							xs->samples = sound_name[id].samples;
835 						}
836 						else {
837 							sounds_playing--;
838 							next_free_sound = as;
839 						}
840 					}
841 				}
842 				xs++;
843 			}
844 
845 			/* correct clipping */
846 			switch (sample_size) {
847 			case 8:
848 				{
849 					register int i;
850 					register s16 *s = sumbuff;
851 					for (i = 0; i < SUBSIZE; i++) {
852 						if (*s > 255) {
853 							*s = 255;
854 						}
855 						else if (*s < 0) {
856 							*s = 0;
857 						}
858 						s++;
859 					}
860 				}
861 				break;
862 			case 16:
863 				{
864 					register int i;
865 					register s16 *s = sumbuff;
866 					for (i = 0; i < SUBSIZE; i++) {
867 						if (*s > 8191) {
868 							*s = 8191;
869 						}
870 						(*s) = (*s) << 5;
871 						if (*s < -8191) {
872 							*s = -8191;
873 						}
874 						s++;
875 					}
876 				}
877 			}
878 
879 			/* copy sum buffer to playback buffer and play it */
880 			{
881 				register u8 *d = playbuff;
882 				register s16 *s = sumbuff;
883 				register int i;
884 
885 				for (i = 0; i < SUBSIZE; i++) {
886 					*d++ = (u8) * s++;
887 				}
888 
889 				/* play buffer */
890 
891 #ifdef __sun__
892 				switch (sample_size) {
893 				case 8:
894 					write (dsp, playbuff, samples_to_play);
895 					samples_played += samples_to_play;
896 					break;
897 				case 16:
898 					write (dsp, sumbuff, samples_to_play * 2);
899 					samples_played += samples_to_play >> 1;
900 					break;
901 				}
902 
903 				/* Wait for output to mostly finish playing */
904 				{
905 					struct audio_info au;
906 
907 					/* ioctl(dsp,AUDIO_GETINFO,&au);
908 					   au.play.pause=0;
909 					   au.play.error=0;
910 					   ioctl(dsp,AUDIO_SETINFO,&au); */
911 					ioctl (dsp, AUDIO_GETINFO, &au);
912 
913 					/*
914 					   fprintf(stderr,
915 					   "\rsamples_played = %10d, played = %10d, error=%d",
916 					   samples_played,au.play.samples,au.play.error);
917 
918 					   fflush(stdout);
919 					 */
920 
921 					while ((samples_played - au.play.samples) > (SAMPLE_RATE >> 4)) {
922 
923 						if (ioctl (dsp, AUDIO_GETINFO, &au) < 0) {
924 							fprintf (stderr, "XBlast sound server: "
925 									 "could not read audio device settings\n");
926 						}
927 						/* if (au.play.error) break; */
928 					}
929 				}
930 
931 #else
932 				switch (sample_size) {
933 				case 8:
934 					write (dsp, playbuff, SUBSIZE);
935 					break;
936 				case 16:
937 					write (dsp, sumbuff, SUBSIZE * 2);
938 					break;
939 				}
940 
941 #endif
942 			}
943 
944 		}
945 #if 1
946 		/* resync sound device to correct any channel flipping */
947 		if (do_sync == TRUE && did_sync == FALSE) {
948 
949 #ifdef __sun__
950 			/* ioctl(dsp,AUDIO_DRAIN,NULL); */
951 			ioctl (dsp, I_FLUSH, NULL);
952 			fprintf (stderr, "\nsync\n");
953 #else
954 			(void)ioctl (dsp, SNDCTL_DSP_SYNC, NULL);
955 #endif
956 			did_sync = TRUE;
957 		}
958 #endif
959 
960 		/* check for new commands in input pipe */
961 		{
962 			int command_buff[1024];
963 			int *cmd;
964 			int n;
965 			struct timeval tv;
966 			fd_set rs;
967 
968 			while (1) {
969 
970 				tv.tv_sec = tv.tv_usec = 0;
971 				FD_ZERO (&rs);
972 				FD_SET (0, &rs);
973 
974 				if (select (1, &rs, NULL, NULL, &tv) > 0 && FD_ISSET (0, &rs)) {
975 					n = read (0, command_buff, 8);
976 					if ((n == 0) || (n < 0 && errno != EINTR && errno != EAGAIN)) {
977 						fprintf (stderr, "Parent was killed, bailing out ...\n");
978 						exit (0);
979 					}
980 					cmd = command_buff;
981 					/* there are commands in the pipe */
982 					while (n > 0) {
983 						if (*cmd == SND_PLAY_SOUND) {
984 							int id = *++cmd;
985 
986 							if (sounds_playing < max_sim_sounds) {
987 								XBSOUND *xs = sound_table + next_free_sound;
988 								/* append new sound to play to play list */
989 #if defined(SERVER_STATISTICS)
990 								total_played++;
991 #endif
992 								while (xs->length > 0) {
993 									next_free_sound++;
994 									if (next_free_sound >= max_sim_sounds) {
995 										next_free_sound = 0;
996 									}
997 									xs = sound_table + next_free_sound;
998 								}
999 								xs->id = id & 0xffff;
1000 								xs->position = (id >> 16) & 0xffff;
1001 								id &= 0xffff;
1002 								xs->repeat = sound_name[id].repeat;
1003 								xs->mono = sound_name[id].mono;
1004 								xs->samples = sound_name[id].samples;
1005 								xs->length = sound_name[id].length;
1006 								xs->next = NULL;
1007 								sounds_playing++;
1008 							}
1009 							else {
1010 								total_skipped++;
1011 							}
1012 						}
1013 						else if (*cmd == SND_STOP_SOUND) {
1014 							int stop_id = *++cmd;
1015 
1016 							if (stop_id == 0 || stop_id == STOP_ALL_SOUNDS) {
1017 								XBSOUND *s = sound_table;
1018 								int i;
1019 								for (i = 0; i < max_sim_sounds; i++, s++) {
1020 									s->length = 0;
1021 									s->repeat = 0;
1022 								}
1023 								sounds_playing = 0;
1024 								resync (dsp);
1025 							}
1026 							else {
1027 								XBSOUND *s = sound_table;
1028 								int i;
1029 								for (i = 0; i < max_sim_sounds; i++, s++) {
1030 									if (s->id == stop_id) {
1031 										s->length = 0;
1032 										s->repeat = 0;
1033 										sounds_playing--;
1034 									}
1035 								}
1036 							}
1037 							write (1, cmd, 1);
1038 						}
1039 						else if (*cmd == SND_LOAD_SOUND) {
1040 							server_load_sound (*++cmd);
1041 							write (1, cmd, 1);
1042 						}
1043 						else if (*cmd == SND_UNLOAD_SOUND) {
1044 							server_unload_sound (*++cmd);
1045 							write (1, cmd, 1);
1046 						}
1047 						n -= 2 * sizeof (int);
1048 						cmd++;
1049 					}
1050 				}
1051 				else {
1052 					break;
1053 				}
1054 			}
1055 		}
1056 	}
1057 }
1058 
1059 #endif
1060