1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_sound.c 1471 2019-10-04 08:59:55Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (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 //
20 // $Log: i_sound.c,v $
21 // Revision 1.13 2004/05/13 11:09:38 andyp
22 // Removed extern int errno references for Linux
23 //
24 // Revision 1.12 2004/04/17 12:55:27 hurdler
25 // now compile with gcc 3.3.3 under Linux
26 //
27 // Revision 1.11 2003/07/13 13:16:15 hurdler
28 // go RC1
29 //
30 // Revision 1.10 2003/01/19 21:24:26 bock
31 // Make sources buildable on FreeBSD 5-CURRENT.
32 //
33 // Revision 1.9 2002/07/01 19:59:59 metzgermeister
34 // *** empty log message ***
35 //
36 // Revision 1.8 2001/08/20 20:40:42 metzgermeister
37 // *** empty log message ***
38 //
39 // Revision 1.7 2001/05/16 22:33:35 bock
40 // Initial FreeBSD support.
41 //
42 // Revision 1.6 2000/08/11 19:11:07 metzgermeister
43 // *** empty log message ***
44 //
45 // Revision 1.5 2000/04/30 19:47:38 metzgermeister
46 // iwad support
47 //
48 // Revision 1.4 2000/03/28 16:18:42 linuxcub
49 // Added a command to the Linux sound-server which sets a master volume.
50 // Someone needs to check that this isn't too much of a performance drop
51 // on slow machines. (Works for me).
52 //
53 // Added code to the main parts of doomlegacy which uses this command to
54 // implement volume control for sound effects.
55 //
56 // Added code so the (really cool) cd music works for me. The volume didn't
57 // work for me (with a Teac 532E drive): It always started at max (31) no-
58 // matter what the setting in the config-file was. The added code "jiggles"
59 // the volume-control, and now it works for me :-)
60 // If this code is unacceptable, perhaps another solution is to periodically
61 // compare the cd_volume.value with an actual value _read_ from the drive.
62 // Ie. not trusting that calling the ioctl with the correct value actually
63 // sets the hardware-volume to the requested value. Right now, the ioctl
64 // is assumed to work perfectly, and the value in cd_volume.value is
65 // compared periodically with cdvolume.
66 //
67 // Updated the spec file, so an updated RPM can easily be built, with
68 // a minimum of editing. Where can I upload my pre-built (S)RPMS to ?
69 //
70 // Erling Jacobsen, linuxcub@email.dk
71 //
72 // Revision 1.3 2000/03/12 23:21:10 linuxcub
73 // Added consvars which hold the filenames and arguments which will be used
74 // when running the soundserver and musicserver (under Linux). I hope I
75 // didn't break anything ... Erling Jacobsen, linuxcub@email.dk
76 //
77 // Revision 1.2 2000/02/27 00:42:11 hurdler
78 // fix CR+LF problem
79 //
80 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
81 // Initial import into CVS (v1.29 pr3)
82 //
83 //
84 // DESCRIPTION:
85 // System interface for sound.
86 //
87 //-----------------------------------------------------------------------------
88
89 #include "doomincl.h"
90 // stdio, stdlib
91
92 #include <stdio.h>
93 #include <stdlib.h>
94 #include <stdarg.h>
95
96 #include <math.h>
97
98 #include <sys/time.h>
99 #include <sys/types.h>
100
101 #if !defined(LINUX) && !defined(SCOOS5) && !defined(_AIX)
102 #include <sys/filio.h>
103 #endif
104
105 #include <fcntl.h>
106 #include <unistd.h>
107 #include <sys/ioctl.h>
108 #include <sys/msg.h>
109
110 // Linux voxware output.
111 #ifdef LINUX
112 #ifdef FREEBSD
113 #include <sys/soundcard.h>
114 #else
115 #include <linux/soundcard.h>
116 #endif
117 #endif
118
119 // SCO OS5 and Unixware OSS sound output
120 #if defined(SCOOS5) || defined(SCOUW2) || defined(SCOUW7)
121 #include <sys/soundcard.h>
122 #endif
123
124 // Timer stuff. Experimental.
125 #include <time.h>
126 #include <signal.h>
127
128 // for IPC between xdoom and musserver
129 #include <sys/ipc.h>
130
131 #include <errno.h>
132
133 #include "doomstat.h"
134 // nomusic
135 // nosoundfx
136 // Flags for the -nosound and -nomusic options
137
138 #include "i_system.h"
139 #include "i_sound.h"
140 #include "s_sound.h"
141 #include "m_argv.h"
142 #include "m_misc.h"
143 #include "w_wad.h"
144
145 #include "searchp.h"
146 #include "d_main.h"
147 #include "z_zone.h"
148
149 #include "musserv/musserver.h"
150
151
152 // #define DEBUG_SFX_PIPE
153
154 // Master hardware sound volume.
155 static int hw_sndvolume = 31;
156
157 // UNIX hack, to be removed.
158 #ifdef SNDSERV
159 #include "sndserv/soundsrv.h"
160
161 static FILE * sndserver = 0;
162 static uint16_t handle_cnt = 0;
163
164 #elif SNDINTR
165
166 // Update all 30 millisecs, approx. 30fps synchronized.
167 // Linux resolution is allegedly 10 millisecs,
168 // scale is microseconds.
169 #define SOUND_INTERVAL 10000
170
171 #else
172 // None?
173 #endif
174
175 // UNIX hack too, unlikely to be removed.
176 #ifdef MUSSERV
177 static int musserver = -1;
178 static int msg_id = -1;
179 #endif
180
181
182 // Flag to signal CD audio support to not play a title
183 //int playing_title;
184
185
186 // The number of internal mixing channels,
187 // the samples calculated for each mixing step,
188 // the size of the 16bit, 2 hardware channel (stereo)
189 // mixing buffer, and the samplerate of the raw data.
190
191 // Needed for calling the actual sound output.
192 #define NUM_CHANNELS 16
193 #define CHANNEL_NUM_MASK (NUM_CHANNELS-1)
194
195
196 #ifndef SNDSERV
197
198 #define SAMPLECOUNT 1024
199 #define SAMPLERATE 11025 // Hz
200 #define SAMPLESIZE 2 // 16bit
201 // It is 2 for 16bit, and 2 for two channels.
202 #define BUFMUL 4
203 #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL)
204
205
206 // The actual output device and a flag for using 8bit samples.
207 static int audio_fd;
208 static byte audio_8bit_flag;
209
210
211
212 typedef struct {
213 // the channel data, current position
214 byte * data; // NULL=inactive
215 // the channel data end pointer
216 byte * data_end;
217 // the channel step amount
218 unsigned int step;
219 // 0.16 bit remainder of last step
220 unsigned int remainder;
221 // volumes
222 int left_volume, right_volume;
223 // the channel volume lookup, modifed by master volume
224 int * left_vol_tab, * right_vol_tab;
225 // Time/gametic that the channel started playing,
226 // used to determine oldest, which automatically has lowest priority.
227 // In case number of active sounds exceeds available channels.
228 int start_time;
229 // The channel handle, determined on registration,
230 // might be used to unregister/stop/modify.
231 // Lowest bits are the channel num.
232 int handle;
233 // SFX id of the playing sound effect.
234 // Used to catch duplicates (like chainsaw).
235 uint16_t id;
236
237 #ifdef SURROUND_SOUND
238 byte invert_right;
239 #endif
240
241 } channel_info_t;
242
243 static channel_info_t channel[NUM_CHANNELS];
244
245 // The global mixing buffer.
246 // Basically, samples from all active internal channels
247 // are modifed and added, and stored in the buffer
248 // that is submitted to the audio device.
249 static int16_t mixbuffer[MIXBUFFERSIZE];
250
251
252 // Pitch to stepping lookup, unused.
253 static int steptable[256];
254
255 // Volume lookups.
256 static int vol_lookup[128][256];
257
258 #endif
259
260 #ifndef SNDSERV
261 //
262 // Safe ioctl, convenience.
263 //
myioctl(int fd,int command,int * arg)264 void myioctl(int fd, int command, int *arg)
265 {
266 static byte ioctl_err_count = 0;
267 static byte ioctl_err_off = 0;
268 int rc;
269
270 if( ioctl_err_off )
271 {
272 ioctl_err_off--;
273 return;
274 }
275
276 rc = ioctl(fd, command, arg);
277 if (rc < 0)
278 {
279 GenPrintf(EMSG_error, "ioctl(dsp,%d,arg) failed\n", command);
280 GenPrintf(EMSG_error, "errno=%d\n", errno);
281 // [WDJ] No unnecessary fatal exits, let the player savegame.
282 if( ioctl_err_count < 254 )
283 ioctl_err_count++;
284 if( ioctl_err_count > 10 )
285 ioctl_err_off = 20;
286
287 // exit(-1);
288 }
289 }
290 #endif
291
292
293 // Interface
294 // This function loads the sound data from the WAD lump,
295 // for single sound.
296 //
I_GetSfx(sfxinfo_t * sfx)297 void I_GetSfx(sfxinfo_t * sfx)
298 {
299 byte *dssfx;
300 int size;
301
302
303 S_GetSfxLump( sfx ); // lump to sfx
304 // Linked sounds will reuse the data.
305 // Can set data to NULL, but cannot change its format.
306
307 dssfx = (byte *) sfx->data;
308 if( ! dssfx ) return;
309
310 // Sound data header format.
311 // 0,1: 03
312 // 2,3: sample rate (11,2B)=11025, (56,22)=22050
313 // 4,5: number of samples
314 // 6,7: 00
315 size = sfx->length;
316 if( size <= 8 )
317 {
318 size = 8;
319 GenPrintf( EMSG_warn, "GetSfx, short sound: %s\n", sfx->name );
320 }
321
322 #ifdef SNDSERV
323 // write data to llsndserv 19990201 by Kin
324 if (sndserver)
325 {
326 server_load_sound_t sls;
327 // Send sound data to server.
328 sls.flags = sfx->flags;
329 // The sound server does not need padded sound, and if it did
330 // it could more easily do that itself.
331 sls.snd_len = size - 8;
332 // [WDJ] No longer send volume with load, as it interferes with
333 // the automated volume update.
334 sls.id = sfx - S_sfx;
335
336 #ifdef DEBUG_SFX_PIPE
337 GenPrintf( EMSG_debug," Command L: Sfx size=%x\n", sfx->length );
338 GenPrintf( EMSG_debug," Load sound, sfx=%i, snd_len=%i flagx=%x\n ", sls.id, sls.snd_len, sls.flags );
339 #endif
340 // sfx data loaded to sound server at sfx id.
341 fputc('l', sndserver);
342 fwrite((byte*)&sls, sizeof(sls), 1, sndserver); // sfx id, flags, size
343 fwrite(&dssfx[8], 1, sls.snd_len, sndserver);
344 fflush(sndserver);
345 }
346 #else
347 #ifdef HAVE_ALLEGRO
348 // convert raw data and header from Doom sfx to a SAMPLE for Allegro
349 // Linked sound will already be padded.
350 int sampsize = ((size - 8 + (SAMPLECOUNT - 1)) / SAMPLECOUNT) * SAMPLECOUNT;
351 int reqsize = sampsize + 8;
352 if( reqsize > size )
353 {
354 // Only reallocate when necessary.
355 byte *paddedsfx = (byte *) Z_Malloc(reqsize, PU_STATIC, 0);
356 memcpy(paddedsfx, dssfx, size);
357 for (i = size; i < reqsize; i++)
358 paddedsfx[i] = 128;
359 sfx->data = (void *) paddedsfx;
360 sfx->length = reqsize;
361 // Remove the cached lump.
362 Z_Free(dssfx);
363 dssfx = paddedsfx;
364 }
365 *((uint32_t *) dssfx) = sampsize;
366 #endif
367 #endif
368 }
369
I_FreeSfx(sfxinfo_t * sfx)370 void I_FreeSfx(sfxinfo_t * sfx)
371 {
372 // normal free
373 }
374
375
376 #ifndef SNDSERV
377 //
378 // This function adds a sound to the
379 // list of currently active sounds,
380 // which is maintained as a given number
381 // (eight, usually) of internal channels.
382 // Returns a handle.
383 //
384 // vol : volume, 0..255
385 // sep : separation, +/- 127, SURROUND_SEP special operation
386 static
addsfx_ch(int sfxid,int vol,int step,int sep)387 int addsfx_ch(int sfxid, int vol, int step, int sep)
388 {
389 channel_info_t * chp, * chp2;
390 int i, oldest;
391 int slot;
392 int leftvol, rightvol;
393
394 // Chainsaw troubles.
395 // Play these sound effects only one at a time.
396 if (S_sfx[sfxid].flags & SFX_single)
397 {
398 // Loop all channels, check.
399 for( chp2 = &channel[0]; chp2 < &channel[cv_numChannels.value]; chp2++ )
400 {
401 // Active, and using the same SFX?
402 if (chp2->data && (chp2->id == sfxid))
403 {
404 if( S_sfx[sfxid].flags & SFX_id_fin )
405 return chp2->handle; // already have one
406 // Kill, Reset.
407 chp2->data = NULL; // close existing channel
408 break;
409 }
410 }
411 }
412
413 // Find inactive channel, or oldest channel.
414 chp = &channel[0]; // default
415 oldest = INT_MAX;
416 for ( chp2 = &channel[0]; chp2 < &channel[cv_numChannels.value]; chp2++ )
417 {
418 if( chp2->data == NULL )
419 {
420 chp = chp2; // Inactive channel
421 break;
422 }
423 if( chp2->start_time < oldest )
424 {
425 chp = chp2; // older channel
426 oldest = chp->start_time;
427 }
428 }
429
430 // Okay, in the less recent channel,
431 // we will handle the new SFX.
432 // Preserve sound SFX id,
433 // e.g. for avoiding duplicates of chainsaw.
434 chp->id = sfxid;
435 // Set pointer to raw data.
436 chp->data = & S_sfx[sfxid].data[8]; // after header
437 // Set pointer to end of raw data.
438 chp->data_end = chp->data + S_sfx[sfxid].length - 8; // without header
439
440 // Set stepping
441 // Kinda getting the impression this is never used.
442 chp->step = step;
443 chp->remainder = 0;
444 // Should be gametic, I presume.
445 chp->start_time = gametic;
446
447 // Per left/right channel.
448 // x^2 seperation,
449 // adjust volume properly.
450
451 #ifdef SURROUND_SOUND
452 chp->invert_right = 0;
453 if( sep == SURROUND_SEP )
454 {
455 // Use a normal sound data for the left channel (with pan left)
456 // and an inverted sound data for the right channel (with pan right)
457 leftvol = rightvol = (vol * (224 * 224)) >> 16; // slight reduction going through panning
458 chp->invert_right = 1; // invert right channel
459 }
460 else
461 #endif
462 {
463 // Separation, that is, orientation/stereo.
464 // sep : +/- 127, <0 is left, >0 is right
465 sep += 129; // 129 +/- 127 ; ( 1 - 256 )
466 leftvol = vol - ((vol * sep * sep) >> 16);
467 sep = 258 - sep; // 129 +/- 127
468 rightvol = vol - ((vol * sep * sep) >> 16);
469 }
470
471 // Sanity check, clamp volume.
472 if (rightvol < 0 || rightvol > 127)
473 {
474 I_SoftError("rightvol out of bounds\n");
475 rightvol = ( rightvol < 0 ) ? 0 : 127;
476 }
477
478 if (leftvol < 0 || leftvol > 127)
479 {
480 I_SoftError("leftvol out of bounds\n");
481 leftvol = ( leftvol < 0 ) ? 0 : 127;
482 }
483
484 // Get the proper lookup table for this volume level.
485 chp->left_volume = leftvol;
486 chp->left_vol_tab = &vol_lookup[(leftvol * hw_sndvolume / 31)][0];
487 chp->right_volume = rightvol;
488 chp->right_vol_tab = &vol_lookup[(rightvol * hw_sndvolume / 31)][0];
489
490 // Assign current handle number.
491 // Preserved so sounds could be stopped (unused).
492 chp->handle = slot | ((chp->handle + NUM_CHANNELS) & ~CHANNEL_NUM_MASK);
493 return chp->handle;
494 }
495 #endif
496
497 #ifndef SNDSERV
498 //
499 // SFX API
500 // Note: this was called by S_Init.
501 // However, whatever they did in the old DPMS based DOS version, this
502 // were simply dummies in the Linux version.
503 // See soundserver initdata().
504 //
I_SetChannels()505 void I_SetChannels()
506 {
507 // Init internal lookups (raw data, mixing buffer, channels).
508 // This function sets up internal lookups used during
509 // the mixing process.
510 int i;
511 int j;
512
513
514 int *steptablemid = steptable + 128;
515
516 memset( channel, 0, sizeof(channel) );
517
518 // This table provides step widths for pitch parameters.
519 // I fail to see that this is currently used.
520 for (i = -128; i < 128; i++)
521 steptablemid[i] = (int) (pow(2.0, (i / 64.0)) * 65536.0);
522
523 // Generates volume lookup tables
524 // which also turn the unsigned samples
525 // into signed samples.
526 for (i = 0; i < 128; i++)
527 {
528 for (j = 0; j < 256; j++)
529 {
530 if (!audio_8bit_flag)
531 vol_lookup[i][j] = (i * (j - 128) * 256) / 127;
532 else
533 vol_lookup[i][j] = (i * (j - 128) * 256) / 127 * 4;
534 }
535 }
536 }
537 #endif
538
539
540 // new_volume : 0..31
I_SetSfxVolume(int volume)541 void I_SetSfxVolume(int volume)
542 {
543 // Identical to DOS.
544 // Basically, this should propagate the menu/config file setting
545 // to the state variable used in the mixing.
546
547 #ifdef DEBUG_SFX_PIPE
548 GenPrintf( EMSG_debug," Testing: volume=%i\n", hw_sndvolume );
549 #endif
550 #ifdef SNDSERV
551 hw_sndvolume = volume;
552
553 if (sndserver)
554 {
555 #ifdef DEBUG_SFX_PIPE
556 GenPrintf( EMSG_debug," Command V: volume=%i\n", hw_sndvolume );
557 #endif
558 fputc('v', sndserver);
559 fputc((byte) hw_sndvolume, sndserver);
560 fflush(sndserver);
561 }
562 #else
563
564 if( volume == hw_sndvolume )
565 return;
566
567 if( volume > 31 ) volume = 31;
568 hw_sndvolume = volume;
569
570 // Update existing channel volumes.
571 register channel_info_t * chp;
572 for( chp = &channel[0]; chp < &channel[cv_numChannels.value]; chp++ )
573 {
574 if( chp->data )
575 {
576 chp->left_vol_tab = &volume_lookup[(chp->left_volume * volume)/31][0];
577 chp->right_vol_tab = &volume_lookup[(chp->right_volume * volume)/31][0];
578 }
579 }
580 }
581 #endif
582 }
583
584
585
586 //
587 // Starting a sound means adding it
588 // to the current list of active sounds
589 // in the internal channels.
590 // As the SFX info struct contains
591 // e.g. a pointer to the raw data,
592 // it is ignored.
593 // As our sound handling does not handle
594 // priority, it is ignored.
595 // Pitching (that is, increased speed of playback)
596 // is set, but currently not used by mixing.
597 //
598 // Starts a sound in a particular sound channel.
599 // vol : 0..255
600 // Return a handle to the sound.
601 int I_StartSound ( sfxid_t sfxid, int vol, int sep, int pitch, int priority )
602 {
603 // UNUSED
604 priority = 0;
605 vol = vol >> 4; // xdoom only accept 0-15 19990124 by Kin
606
607 if (nosoundfx)
608 return 0;
609
610 #ifdef SNDSERV
611 if (sndserver)
612 {
613 server_play_sound_t sps;
614
615 sps.sfxid = sfxid;
616 sps.vol = vol;
617 sps.pitch = pitch;
618 sps.sep = sep;
619 sps.handle = handle_cnt++;
620
621 #ifdef DEBUG_SFX_PIPE
622 GenPrintf( EMSG_debug," Command P:" );
623 GenPrintf( EMSG_debug," Play sound, sfx=%i, vol=%i, pitch=%i, sep=%i, handle=%i\n ", sps.sfxid, sps.vol, sps.pitch, sps.sep, sps.handle );
624 #endif
625 // play sound
626 fputc('p', sndserver);
627 fwrite((byte*)&sps, sizeof(sps), 1, sndserver);
628 fflush(sndserver);
629 return sps.handle;
630 }
631 return 0;
632 #else
633 // Debug.
634 //GenPrintf(EMSG_debug, "starting sound %d", id );
635
636 // Returns a handle.
637 int handle = addsfx_ch(id, vol, steptable[pitch], sep);
638
639 //GenPrintf(EMSG_debug, "/handle is %d\n", id );
640
641 return handle;
642 #endif
643 }
644
645 // You need the handle returned by StartSound.
646 void I_StopSound(int handle)
647 {
648 #ifdef SNDSERV
649 uint16_t handle16 = handle;
650
651 #ifdef DEBUG_SFX_PIPE
652 GenPrintf( EMSG_debug," Command S: Stop handle=%i\n", handle );
653 #endif
654
655 // Send stop sound.
656 fputc('s', sndserver);
657 fwrite(&handle16, sizeof(uint16_t), 1, sndserver); // handle
658 fflush(sndserver);
659 #else
660 int slot = handle & CHANNEL_NUM_MASK;
661 if (channel[slot].handle == handle)
662 {
663 channel[i].data = NULL;
664 }
665 #endif
666 }
667
668 int I_SoundIsPlaying(int handle)
669 {
670 #ifdef SNDSERV
671 return (handle_cnt - ((uint16_t)handle)) < 8; // guess
672 #else
673 int slot = handle & CHANNEL_NUM_MASK;
674 if (channel[slot].handle == handle)
675 {
676 #if 1
677 return ( channel[chan].data != NULL );
678
679 #else
680 // old code
681 return 1;
682 #endif
683 }
684 return 0;
685 #endif
686 }
687
688
689
690 #ifdef SNDINTR
691 // Get the interrupt. Set duration in millisecs.
692 int I_SoundSetTimer(int duration_of_tick);
693 void I_SoundDelTimer(void);
694 #endif
695
696 #ifndef SNDSERV
697 // A quick hack to establish a protocol between
698 // synchronous mix buffer updates and asynchronous
699 // audio writes. Probably redundant with gametic.
700 volatile static int mix_cnt = 0;
701
702 //
703 // This function loops all active (internal) sound
704 // channels, retrieves a given number of samples
705 // from the raw sound data, modifies it according
706 // to the current (internal) channel parameters,
707 // mixes the per channel samples into the global
708 // mixbuffer, clamping it to the allowed range,
709 // and sets up everything for transferring the
710 // contents of the mixbuffer to the (two)
711 // hardware channels (left and right, that is).
712 //
713 void I_UpdateSound(void)
714 {
715 // Debug. Count buffer misses with interrupt.
716 static int misses = 0;
717
718 // Flag. Will be set if the mixing buffer really gets updated.
719 byte updated = 0;
720
721 channel_info_t * chp;
722
723 // Mix current sound data.
724 // Data, from raw sound, for right and left.
725 register unsigned int sample;
726 register int dl, dr;
727 uint16_t sdl, sdr;
728
729 // Pointers in global mixbuffer, left, right, end.
730 int16_t * leftout;
731 int16_t * rightout;
732 int16_t * leftend;
733 byte * bothout;
734
735 // Step in mixbuffer, left and right, thus two.
736 int step;
737
738
739 if (dedicated)
740 return;
741
742 // Left and right channel
743 // are in global mixbuffer, alternating.
744 leftout = mixbuffer;
745 rightout = mixbuffer + 1;
746 bothout = (byte *) mixbuffer;
747 step = 2;
748
749 // Determine end, for left channel only
750 // (right channel is implicit).
751 leftend = mixbuffer + SAMPLECOUNT * step;
752
753 // Mix sounds into the mixing buffer.
754 // Loop over step*SAMPLECOUNT.
755 while (leftout != leftend)
756 {
757 // Reset left/right value.
758 dl = 0;
759 dr = 0;
760
761 // Love thy L2 chache - made this a loop.
762 // Now more channels could be set at compile time
763 // as well. Thus loop those channels.
764 for( chp = &channel[0]; chp < &channel[cv_numChannels.value]; chp++ )
765 {
766 // Check channel, if active.
767 if (chp->data)
768 {
769 // we are updating the mixer buffer, set flag
770 updated = 1;
771 // Get the raw data from the channel.
772 sample = * chp->data;
773 // Add left and right part for this channel (sound)
774 // to the current data.
775 // Adjust volume accordingly.
776 dl += chp->left_vol_tab[sample];
777 #ifdef SURROUND_SOUND
778 if( chp->invert_right )
779 dr -= chp->right_vol_tab[sample];
780 else
781 dr += chp->right_vol_tab[sample];
782 #else
783 dr += chp->right_vol_tab[sample];
784 #endif
785 // Increment fixed point index
786 chp->remainder += chp->step;
787 // MSB is next sample
788 chp->data += chp->remainder >> 16;
789 // Keep the fractional index part
790 chp->remainder &= 0xFFFF;
791
792 // Check whether we are done.
793 if (chp->data >= chp->data_end)
794 chp->data = NULL;
795 }
796 }
797
798 // Clamp to range. Left hardware channel.
799 // Has been char instead of int16.
800 // if (dl > 127) *leftout = 127;
801 // else if (dl < -128) *leftout = -128;
802 // else *leftout = dl;
803
804 if (!audio_8bit_flag)
805 {
806 if (dl > 0x7fff)
807 *leftout = 0x7fff;
808 else if (dl < -0x8000)
809 *leftout = -0x8000;
810 else
811 *leftout = dl;
812
813 // Same for right hardware channel.
814 if (dr > 0x7fff)
815 *rightout = 0x7fff;
816 else if (dr < -0x8000)
817 *rightout = -0x8000;
818 else
819 *rightout = dr;
820 }
821 else
822 {
823 if (dl > 0x7fff)
824 dl = 0x7fff;
825 else if (dl < -0x8000)
826 dl = -0x8000;
827 sdl = dl ^ 0xfff8000;
828
829 if (dr > 0x7fff)
830 dr = 0x7fff;
831 else if (dr < -0x8000)
832 dr = -0x8000;
833 sdr = dr ^ 0xfff8000;
834
835 *bothout++ = (((sdr + sdl) / 2) >> 8);
836 }
837
838 // Increment current pointers in mixbuffer.
839 leftout += step;
840 rightout += step;
841 }
842
843 if (updated)
844 {
845 // Debug check.
846 if (mix_cnt)
847 {
848 misses += mix_cnt;
849 mix_cnt = 0;
850 }
851
852 if (misses > 10)
853 {
854 GenPrintf(EMSG_warn, "I_SoundUpdate: missed 10 buffer writes\n");
855 misses = 0;
856 }
857
858 // Increment mix_cnt for update.
859 mix_cnt++;
860 }
861 }
862 #endif
863
864 #ifdef SNDSERV
865 // [WDJ] Fix this in d_main.c
866 void I_SubmitSound(void)
867 {
868 }
869 #else
870 // This is used to write out the mixbuffer
871 // during each game loop update.
872 //
873 void I_SubmitSound(void)
874 {
875 if (dedicated)
876 return;
877
878 // Write it to DSP device.
879 if (mix_cnt)
880 {
881 if (!audio_8bit_flag)
882 write(audio_fd, mixbuffer, SAMPLECOUNT * BUFMUL);
883 else
884 write(audio_fd, mixbuffer, SAMPLECOUNT);
885 mix_cnt = 0;
886 }
887 }
888 #endif
889
890
891
892 // Interface
893 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
894 {
895 // I fail too see that this is used.
896 // Would be using the handle to identify
897 // on which channel the sound might be active,
898 // and resetting the channel parameters.
899
900 // UNUSED.
901 handle = vol = sep = pitch = 0;
902 }
903
904
905 static
906 void LX_ShutdownSound(void)
907 {
908 #ifdef SNDSERV
909 if (sndserver)
910 {
911 #ifdef DEBUG_SFX_PIPE
912 GenPrintf( EMSG_debug," Command Q:\n" );
913 #endif
914 // Send a "quit" command.
915 fputc('q', sndserver);
916 fflush(sndserver);
917 }
918
919 #else
920
921 // Wait till all pending sounds are finished.
922 int done = 0;
923 int i;
924
925 if (nosoundfx)
926 return;
927
928 #ifdef SNDINTR
929 I_SoundDelTimer();
930 #endif
931
932 while (!done)
933 {
934 for (i = 0; i < cv_numChannels.value; i++)
935 if( channel[i].data ) break; // any busy channel
936 if (i == cv_numChannels.value)
937 done++;
938 else
939 {
940 I_UpdateSound();
941 I_SubmitSound();
942 }
943 }
944
945 // Cleaning up -releasing the DSP device.
946 close(audio_fd);
947 #endif
948
949 // Done.
950 return;
951 }
952
953
954 static
955 void LX_InitSound()
956 {
957 #ifdef SNDSERV
958 char buffer[2048];
959 char *fn_snd;
960
961 fn_snd = searchpath(cv_sndserver_cmd.string);
962
963 // start sound process
964 if (!access(fn_snd, X_OK))
965 {
966 sprintf(buffer, "%s %s", fn_snd, cv_sndserver_arg.string);
967 sndserver = popen(buffer, "w");
968 #ifdef DEBUG_SFX_PIPE
969 GenPrintf( EMSG_debug," Started Sound Server:\n" );
970 #endif
971 }
972 else
973 GenPrintf(EMSG_error, "Could not start sound server [%s]\n", fn_snd);
974 #else
975
976 int i;
977
978 if (nosoundfx)
979 return;
980
981 // Secure and configure sound device first.
982 GenPrintf(EMSG_info, "LX_InitSound: ");
983
984 audio_fd = open("/dev/dsp", O_WRONLY);
985 if (audio_fd < 0)
986 {
987 GenPrintf(EMSG_error, "Could not open /dev/dsp\n");
988 nosoundfx++;
989 return;
990 }
991
992 #ifdef SOUND_RESET
993 myioctl(audio_fd, SNDCTL_DSP_RESET, 0);
994 #endif
995
996 audio_8bit_flag = 1; // default
997 if (getenv("DOOM_SOUND_SAMPLEBITS") == NULL)
998 {
999 myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i);
1000 if (i &= AFMT_S16_LE)
1001 {
1002 audio_8bit_flag = 0;
1003 myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i);
1004 i = 11 | (2 << 16);
1005 myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);
1006 i = 1;
1007 myioctl(audio_fd, SNDCTL_DSP_STEREO, &i);
1008 }
1009 }
1010
1011 if( audio_8bit_flag ) // default
1012 {
1013 i = AFMT_U8;
1014 myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i);
1015 i = 10 | (2 << 16);
1016 myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);
1017 }
1018
1019 i = SAMPLERATE;
1020 myioctl(audio_fd, SNDCTL_DSP_SPEED, &i);
1021
1022 GenPrintf(EMSG_info, " configured %dbit audio device\n", (audio_8bit_flag) ? 8 : 16);
1023
1024 #ifdef SNDINTR
1025 GenPrintf(EMSG_info, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL);
1026 I_SoundSetTimer(SOUND_INTERVAL);
1027 #endif
1028
1029 // Initialize external data (all sounds) at start, keep static.
1030 GenPrintf(EMSG_info, "LX_InitSound: ");
1031
1032 // Do we have a sound lump for the chaingun?
1033 if (W_CheckNumForName("dschgun") == -1)
1034 {
1035 // No, so link it to the pistol sound
1036 //S_sfx[sfx_chgun].link = &S_sfx[sfx_pistol];
1037 //S_sfx[sfx_chgun].pitch = 150;
1038 //S_sfx[sfx_chgun].volume = 0;
1039 //S_sfx[sfx_chgun].data = 0;
1040 GenPrintf(EMSG_info, "linking chaingun sound to pistol sound,");
1041 }
1042 else
1043 {
1044 GenPrintf(EMSG_info, "found chaingun sound,");
1045 }
1046
1047 GenPrintf(EMSG_info, " pre-cached all sound data\n");
1048
1049 // Now initialize mixbuffer with zero.
1050 for (i = 0; i < MIXBUFFERSIZE; i++)
1051 mixbuffer[i] = 0;
1052
1053 // Finished initialization.
1054 GenPrintf(EMSG_info, "LX_InitSound: sound module ready\n");
1055
1056 #endif
1057 }
1058
1059
1060 // --- Music
1061 //#define DEBUG_MUSSERV
1062
1063 #ifdef MUSSERV
1064 mus_msg_t msg_buffer;
1065
1066 void send_val_musserver( char command, char sub_command, int val )
1067 {
1068 if( msg_id < 0 ) return;
1069
1070 msg_buffer.mtype = 5;
1071 memset(msg_buffer.mtext, 0, MUS_MSG_MTEXT_LENGTH);
1072 snprintf(msg_buffer.mtext, MUS_MSG_MTEXT_LENGTH-1, "%c%c%i",
1073 command, sub_command, val);
1074 msg_buffer.mtext[MUS_MSG_MTEXT_LENGTH-1] = 0;
1075 #ifdef DEBUG_MUSSERV
1076 GenPrintf( EMSG_debug, "Send musserver: %s\n", msg_buffer.mtext );
1077 #endif
1078 msgsnd(msg_id, MSGBUF(msg_buffer), 12, IPC_NOWAIT);
1079 usleep(2); // just enough for musserver to respond promptly.
1080 }
1081 #endif
1082
1083 // Music volume may be set before calling LX_InitMusic.
1084 static int music_volume = 0;
1085
1086 //
1087 // MUSIC API.
1088 // Music done now, we'll use Michael Heasley's musserver.
1089 //
1090 static
1091 void LX_InitMusic(void)
1092 {
1093 #ifdef MUSSERV
1094 char buffer[MAX_WADPATH];
1095 char *fn_mus;
1096
1097 fn_mus = searchpath(cv_musserver_cmd.string);
1098
1099 // Try to start the music server process.
1100 if ( access(fn_mus, X_OK) < 0)
1101 {
1102 GenPrintf(EMSG_error, "Could not find music server [%s]\n", fn_mus);
1103 return;
1104 }
1105
1106 // [WDJ] Use IPC for settings, not command line.
1107 snprintf(buffer, MAX_WADPATH-1, "%s %s &", fn_mus, cv_musserver_arg.string);
1108 buffer[MAX_WADPATH-1] = 0;
1109
1110 GenPrintf( EMSG_info, "Starting music server [%s]\n", buffer);
1111 // Sys call "system()" seems to work, and does not need \n.
1112 // It returns 0 on success.
1113 musserver = system(buffer);
1114 if( musserver < 0 )
1115 {
1116 GenPrintf( EMSG_error, "Could not start music server [%s]\n", fn_mus);
1117 return;
1118 }
1119
1120 msg_id = msgget(MUSSERVER_MSG_KEY, IPC_CREAT | 0777);
1121 if( verbose > 1 )
1122 GenPrintf( EMSG_info, "Started Musicserver = %i, IPC = %i\n", musserver, msg_id );
1123 send_val_musserver( 'v', ' ', music_volume );
1124 // [WDJ] Starting with system() gives the process a PPID of 1, which is Init.
1125 // When DoomLegacy is killed, it is not detected by musserver.
1126 send_val_musserver( 'I', ' ', getpid() ); // our pid
1127 // Send this again because it was too early at configure time.
1128 I_SetMusicOption();
1129 #endif
1130 }
1131
1132 void LX_ShutdownMusic(void)
1133 {
1134 if (nomusic)
1135 return;
1136
1137 #ifdef MUSSERV
1138 // [WDJ] It is a race between the quit command and the queue destruction.
1139 // Rely upon one or the other.
1140 #if 1
1141 // send a "quit" command.
1142 send_val_musserver( 'Q', 'Q', 0 );
1143 #else
1144 if (musserver > -1)
1145 {
1146 // Close the queue.
1147 if (msg_id != -1)
1148 msgctl(msg_id, IPC_RMID, (struct msqid_ds *) NULL);
1149 }
1150 #endif
1151 #endif
1152 }
1153
1154
1155 // MUSIC API
1156 void I_SetMusicVolume(int volume)
1157 {
1158 // Internal state variable.
1159 music_volume = volume;
1160 // Now set volume on output device.
1161 // Whatever( snd_MusciVolume );
1162
1163 if (nomusic)
1164 return;
1165
1166 #ifdef MUSSERV
1167 send_val_musserver( 'v', ' ', volume );
1168 #endif
1169 }
1170
1171 // MUSIC API
1172
1173 char * mus_ipc_opt_tab[] = {
1174 "-dd", // Default
1175 "-da", // Search 1
1176 "-db", // Search 2
1177 "-dc", // Search 3
1178 "-dM", // Midi
1179 "-dT", // TiMidity
1180 "-dL", // FluidSynth
1181 "-dE", // Ext Midi
1182 "-dS", // Synth
1183 "-dF", // FM Synth
1184 "-dA", // Awe32 Synth
1185 "-dg", // Dev6
1186 "-dh", // Dev7
1187 "-dj", // Dev8
1188 "-dk" // Dev9
1189 };
1190
1191 void I_SetMusicOption(void)
1192 {
1193 byte bi = cv_musserver_opt.value;
1194
1195 if( msg_id < 0 ) return;
1196 if( bi > 16 ) return;
1197
1198 msg_buffer.mtype = 6;
1199 memset(msg_buffer.mtext, 0, MUS_MSG_MTEXT_LENGTH);
1200 snprintf(msg_buffer.mtext, MUS_MSG_MTEXT_LENGTH-1, "O%s", mus_ipc_opt_tab[bi] );
1201 msg_buffer.mtext[MUS_MSG_MTEXT_LENGTH-1] = 0;
1202 #ifdef DEBUG_MUSSERV
1203 GenPrintf( EMSG_debug, "Send musserver option: %s\n", msg_buffer.mtext );
1204 #endif
1205 msg_buffer.mtext[MUS_MSG_MTEXT_LENGTH-1] = 0;
1206 msgsnd(msg_id, MSGBUF(msg_buffer), MUS_MSG_MTEXT_LENGTH, IPC_NOWAIT);
1207 }
1208
1209
1210
1211 static byte music_looping = 0;
1212 static int music_dies = -1;
1213
1214
1215
1216 void I_PauseSong(int handle)
1217 {
1218 if (nomusic)
1219 return;
1220
1221 #ifdef MUSSERV
1222 send_val_musserver( 'P', 'P', 1 );
1223 #endif
1224 handle = 0; // UNUSED
1225 }
1226
1227 void I_ResumeSong(int handle)
1228 {
1229 if (nomusic)
1230 return;
1231
1232 #ifdef MUSSERV
1233 send_val_musserver( 'P', 'R', 0 );
1234 #endif
1235 handle = 0; // UNUSED
1236 }
1237
1238 void I_StopSong(int handle)
1239 {
1240 if (nomusic)
1241 return;
1242
1243 #ifdef MUSSERV
1244 send_val_musserver( 'X', 'X', 0 );
1245 #endif
1246 handle = 0; // UNUSED.
1247 music_looping = 0;
1248 music_dies = 0;
1249 }
1250
1251 void I_UnRegisterSong(int handle)
1252 {
1253 handle = 0; // UNUSED.
1254 }
1255
1256
1257 #ifdef MUSSERV
1258 // Information for ports with music servers.
1259 // name : name of song
1260 // Return handle
1261 int I_PlayServerSong( char * name, lumpnum_t lumpnum, byte looping )
1262 {
1263 if (nomusic)
1264 {
1265 return 1;
1266 }
1267
1268 music_dies = gametic + (TICRATE * 30);
1269
1270 music_looping = looping;
1271
1272 if (msg_id != -1)
1273 {
1274 static byte sent_genmidi = 0;
1275 wadfile_t * wadp;
1276
1277 msg_buffer.mtype = 6;
1278 if( sent_genmidi == 0 )
1279 {
1280 sent_genmidi = 1;
1281 // Music server needs the GENMIDI lump, which may depend
1282 // upon the IWAD and PWAD order.
1283 lumpnum_t genmidi_lumpnum = W_GetNumForName( "GENMIDI" );
1284 wadp = lumpnum_to_wad( genmidi_lumpnum );
1285 if( wadp )
1286 {
1287 memset(msg_buffer.mtext, 0, MUS_MSG_MTEXT_LENGTH);
1288 snprintf(msg_buffer.mtext, MUS_MSG_MTEXT_LENGTH-1, "W%s", wadp->filename);
1289 msg_buffer.mtext[MUS_MSG_MTEXT_LENGTH-1] = 0;
1290 #ifdef DEBUG_MUSSERV
1291 GenPrintf( EMSG_debug, "Send musserver wad: %s\n", msg_buffer.mtext );
1292 #endif
1293 msgsnd(msg_id, MSGBUF(msg_buffer), MUS_MSG_MTEXT_LENGTH, IPC_NOWAIT);
1294 }
1295 // Sending genmidi lumpnum to musserver.
1296 send_val_musserver( 'G', ' ', LUMPNUM(genmidi_lumpnum) );
1297 }
1298 // Send song name to musserver
1299 memset(msg_buffer.mtext, 0, MUS_MSG_MTEXT_LENGTH);
1300 sprintf(msg_buffer.mtext, "D %s", name);
1301 #ifdef DEBUG_MUSSERV
1302 GenPrintf( EMSG_debug, "Send musserver song: %s\n", msg_buffer.mtext );
1303 #endif
1304 msgsnd(msg_id, MSGBUF(msg_buffer), 12, IPC_NOWAIT);
1305 // Song info
1306 wadp = lumpnum_to_wad( lumpnum );
1307 if( wadp )
1308 {
1309 // Send song wad information to server
1310 memset(msg_buffer.mtext, 0, MUS_MSG_MTEXT_LENGTH);
1311 snprintf(msg_buffer.mtext, MUS_MSG_MTEXT_LENGTH-1, "W%s", wadp->filename);
1312 msg_buffer.mtext[MUS_MSG_MTEXT_LENGTH-1] = 0;
1313 #ifdef DEBUG_MUSSERV
1314 GenPrintf( EMSG_debug, "Send musserver wad: %s\n", msg_buffer.mtext );
1315 #endif
1316 msgsnd(msg_id, MSGBUF(msg_buffer), MUS_MSG_MTEXT_LENGTH, IPC_NOWAIT);
1317 }
1318 // Sending song lumpnum to musserver.
1319 send_val_musserver( 'S', (looping?'C':' '), LUMPNUM(lumpnum) );
1320 }
1321 return 1;
1322 }
1323
1324
1325 #else
1326 // not MUSSERV
1327
1328 // Interface
1329 int I_RegisterSong( void* data, int len )
1330 {
1331 if (nomusic)
1332 {
1333 return 1;
1334 }
1335
1336 data = NULL;
1337 return 1;
1338 }
1339
1340 // Interface
1341 void I_PlaySong(int handle, int looping)
1342 {
1343 music_dies = gametic + (TICRATE * 30);
1344
1345 if (nomusic)
1346 return;
1347
1348 music_looping = looping;
1349 handle = 0;
1350 }
1351 #endif
1352
1353
1354 #if 0
1355 // Disabled call, no interface.
1356 // Is the song playing?
1357 int I_QrySongPlaying(int handle)
1358 {
1359 handle = 0; // UNUSED
1360 return music_looping || (music_dies > gametic);
1361 }
1362 #endif
1363
1364
1365 //--- Sound system Interface
1366 // Interface, Start sound system.
1367 void I_StartupSound()
1368 {
1369 if( dedicated )
1370 return;
1371
1372 if(! nosoundfx)
1373 LX_InitSound();
1374 if(! nomusic )
1375 LX_InitMusic();
1376 }
1377
1378 // Interface, Shutdown sound system.
1379 void I_ShutdownSound(void)
1380 {
1381 LX_ShutdownSound();
1382 LX_ShutdownMusic();
1383 }
1384
1385
1386 #ifdef SNDINTR
1387 //
1388 // Experimental stuff.
1389 // A Linux timer interrupt, for asynchronous
1390 // sound output.
1391 // I ripped this out of the Timer class in
1392 // our Difference Engine, including a few
1393 // SUN remains...
1394 //
1395 #ifdef sun
1396 typedef sigset_t tSigSet;
1397 #else
1398 typedef int tSigSet;
1399 #endif
1400
1401 // We might use SIGVTALRM and ITIMER_VIRTUAL, if the process
1402 // time independend timer happens to get lost due to heavy load.
1403 // SIGALRM and ITIMER_REAL doesn't really work well.
1404 // There are issues with profiling as well.
1405
1406 //static int /*__itimer_which*/ itimer = ITIMER_REAL;
1407 static int /*__itimer_which*/ itimer = ITIMER_VIRTUAL;
1408
1409 //static int sig = SIGALRM;
1410 static int sig = SIGVTALRM;
1411
1412 // Interrupt handler.
1413 static void I_HandleSoundTimer(int ignore)
1414 {
1415 // Debug.
1416 //GenPrintf(EMSG_debug, "%c", '+' ); fflush( stderr );
1417
1418 // Feed sound device if necesary.
1419 if (mix_cnt)
1420 {
1421 // See I_SubmitSound().
1422 // Write it to DSP device.
1423 if (!audio_8bit_flag)
1424 write(audio_fd, mixbuffer, SAMPLECOUNT * BUFMUL);
1425 else
1426 write(audio_fd, mixbuffer, SAMPLECOUNT);
1427
1428 // Reset flag counter.
1429 mix_cnt = 0;
1430 }
1431 else
1432 return;
1433
1434 // UNUSED, but required.
1435 ignore = 0;
1436 return;
1437 }
1438
1439 // Get the interrupt. Set duration in millisecs.
1440 static int I_SoundSetTimer(int duration_of_tick)
1441 {
1442 // Needed for gametick clockwork.
1443 struct itimerval value;
1444 struct itimerval ovalue;
1445 struct sigaction act;
1446 struct sigaction oact;
1447
1448 int res;
1449
1450 // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it.
1451 // signal( _sig, handle_SIG_TICK );
1452
1453 // Now we have to change this attribute for repeated calls.
1454 act.sa_handler = I_HandleSoundTimer;
1455 #ifndef sun
1456 //ac t.sa_mask = _sig;
1457 #endif
1458 act.sa_flags = SA_RESTART;
1459
1460 sigaction(sig, &act, &oact);
1461
1462 value.it_interval.tv_sec = 0;
1463 value.it_interval.tv_usec = duration_of_tick;
1464 value.it_value.tv_sec = 0;
1465 value.it_value.tv_usec = duration_of_tick;
1466
1467 // Error is -1.
1468 res = setitimer(itimer, &value, &ovalue);
1469
1470 // Debug.
1471 if (res == -1)
1472 GenPrintf(EMSG_debug, "I_SoundSetTimer: interrupt n.a.\n");
1473
1474 return res;
1475 }
1476
1477 // Remove the interrupt. Set duration to zero.
1478 static void I_SoundDelTimer()
1479 {
1480 // Debug.
1481 if (I_SoundSetTimer(0) == -1)
1482 GenPrintf(EMSG_debug, "I_SoundDelTimer: failed to remove interrupt. Doh!\n");
1483 }
1484 #endif
1485
1486 #ifdef FMOD_SONG
1487 //Hurdler: TODO
1488 void I_StartFMODSong()
1489 {
1490 CONS_Printf("I_StartFMODSong: Not yet supported under Linux.\n");
1491 }
1492
1493 void I_StopFMODSong()
1494 {
1495 CONS_Printf("I_StopFMODSong: Not yet supported under Linux.\n");
1496 }
1497 void I_SetFMODVolume(int volume)
1498 {
1499 CONS_Printf("I_SetFMODVolume: Not yet supported under Linux.\n");
1500 }
1501 #endif
1502