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