|
|
1.1 root 1: // Emacs style mode select -*- C++ -*-
2: //-----------------------------------------------------------------------------
3: //
4: // $Id:$
5: //
6: // Copyright (C) 1993-1996 by id Software, Inc.
7: //
8: // This program is free software; you can redistribute it and/or
9: // modify it under the terms of the GNU General Public License
10: // as published by the Free Software Foundation; either version 2
11: // of the License, or (at your option) any later version.
12: //
13: // This program is distributed in the hope that it will be useful,
14: // but WITHOUT ANY WARRANTY; without even the implied warranty of
15: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: // GNU General Public License for more details.
17: //
18: // $Log:$
19: //
20: // DESCRIPTION:
21: // System interface for sound.
22: //
23: //-----------------------------------------------------------------------------
24:
25: static const char
26: rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $";
27:
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <stdarg.h>
31:
32: #include <math.h>
33:
34: #include <sys/time.h>
35: #include <sys/types.h>
36:
37: #ifndef LINUX
38: #include <sys/filio.h>
39: #endif
40:
41: #include <fcntl.h>
42: #include <unistd.h>
43: #include <sys/ioctl.h>
44:
45: // Linux voxware output.
46: #include <linux/soundcard.h>
47:
48: // Timer stuff. Experimental.
49: #include <time.h>
50: #include <signal.h>
51:
52: #include "z_zone.h"
53:
54: #include "i_system.h"
55: #include "i_sound.h"
56: #include "m_argv.h"
57: #include "m_misc.h"
58: #include "w_wad.h"
59:
60: #include "doomdef.h"
61:
62: // UNIX hack, to be removed.
63: #ifdef SNDSERV
64: // Separate sound server process.
65: FILE* sndserver=0;
66: char* sndserver_filename = "./sndserver ";
67: #elif SNDINTR
68:
69: // Update all 30 millisecs, approx. 30fps synchronized.
70: // Linux resolution is allegedly 10 millisecs,
71: // scale is microseconds.
72: #define SOUND_INTERVAL 500
73:
74: // Get the interrupt. Set duration in millisecs.
75: int I_SoundSetTimer( int duration_of_tick );
76: void I_SoundDelTimer( void );
77: #else
78: // None?
79: #endif
80:
81:
82: // A quick hack to establish a protocol between
83: // synchronous mix buffer updates and asynchronous
84: // audio writes. Probably redundant with gametic.
85: static int flag = 0;
86:
87: // The number of internal mixing channels,
88: // the samples calculated for each mixing step,
89: // the size of the 16bit, 2 hardware channel (stereo)
90: // mixing buffer, and the samplerate of the raw data.
91:
92:
93: // Needed for calling the actual sound output.
94: #define SAMPLECOUNT 512
95: #define NUM_CHANNELS 8
96: // It is 2 for 16bit, and 2 for two channels.
97: #define BUFMUL 4
98: #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL)
99:
100: #define SAMPLERATE 11025 // Hz
101: #define SAMPLESIZE 2 // 16bit
102:
103: // The actual lengths of all sound effects.
104: int lengths[NUMSFX];
105:
106: // The actual output device.
107: int audio_fd;
108:
109: // The global mixing buffer.
110: // Basically, samples from all active internal channels
111: // are modifed and added, and stored in the buffer
112: // that is submitted to the audio device.
113: signed short mixbuffer[MIXBUFFERSIZE];
114:
115:
116: // The channel step amount...
117: unsigned int channelstep[NUM_CHANNELS];
118: // ... and a 0.16 bit remainder of last step.
119: unsigned int channelstepremainder[NUM_CHANNELS];
120:
121:
122: // The channel data pointers, start and end.
123: unsigned char* channels[NUM_CHANNELS];
124: unsigned char* channelsend[NUM_CHANNELS];
125:
126:
127: // Time/gametic that the channel started playing,
128: // used to determine oldest, which automatically
129: // has lowest priority.
130: // In case number of active sounds exceeds
131: // available channels.
132: int channelstart[NUM_CHANNELS];
133:
134: // The sound in channel handles,
135: // determined on registration,
136: // might be used to unregister/stop/modify,
137: // currently unused.
138: int channelhandles[NUM_CHANNELS];
139:
140: // SFX id of the playing sound effect.
141: // Used to catch duplicates (like chainsaw).
142: int channelids[NUM_CHANNELS];
143:
144: // Pitch to stepping lookup, unused.
145: int steptable[256];
146:
147: // Volume lookups.
148: int vol_lookup[128*256];
149:
150: // Hardware left and right channel volume lookup.
151: int* channelleftvol_lookup[NUM_CHANNELS];
152: int* channelrightvol_lookup[NUM_CHANNELS];
153:
154:
155:
156:
157: //
158: // Safe ioctl, convenience.
159: //
160: void
161: myioctl
162: ( int fd,
163: int command,
164: int* arg )
165: {
166: int rc;
167: extern int errno;
168:
169: rc = ioctl(fd, command, arg);
170: if (rc < 0)
171: {
172: fprintf(stderr, "ioctl(dsp,%d,arg) failed\n", command);
173: fprintf(stderr, "errno=%d\n", errno);
174: exit(-1);
175: }
176: }
177:
178:
179:
180:
181:
182: //
183: // This function loads the sound data from the WAD lump,
184: // for single sound.
185: //
186: void*
187: getsfx
188: ( char* sfxname,
189: int* len )
190: {
191: unsigned char* sfx;
192: unsigned char* paddedsfx;
193: int i;
194: int size;
195: int paddedsize;
196: char name[20];
197: int sfxlump;
198:
199:
200: // Get the sound data from the WAD, allocate lump
201: // in zone memory.
202: sprintf(name, "ds%s", sfxname);
203:
204: // Now, there is a severe problem with the
205: // sound handling, in it is not (yet/anymore)
206: // gamemode aware. That means, sounds from
207: // DOOM II will be requested even with DOOM
208: // shareware.
209: // The sound list is wired into sounds.c,
210: // which sets the external variable.
211: // I do not do runtime patches to that
212: // variable. Instead, we will use a
213: // default sound for replacement.
214: if ( W_CheckNumForName(name) == -1 )
215: sfxlump = W_GetNumForName("dspistol");
216: else
217: sfxlump = W_GetNumForName(name);
218:
219: size = W_LumpLength( sfxlump );
220:
221: // Debug.
222: // fprintf( stderr, "." );
223: //fprintf( stderr, " -loading %s (lump %d, %d bytes)\n",
224: // sfxname, sfxlump, size );
225: //fflush( stderr );
226:
227: sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC );
228:
229: // Pads the sound effect out to the mixing buffer size.
230: // The original realloc would interfere with zone memory.
231: paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
232:
233: // Allocate from zone memory.
234: paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 );
235: // ddt: (unsigned char *) realloc(sfx, paddedsize+8);
236: // This should interfere with zone memory handling,
237: // which does not kick in in the soundserver.
238:
239: // Now copy and pad.
240: memcpy( paddedsfx, sfx, size );
241: for (i=size ; i<paddedsize+8 ; i++)
242: paddedsfx[i] = 128;
243:
244: // Remove the cached lump.
245: Z_Free( sfx );
246:
247: // Preserve padded length.
248: *len = paddedsize;
249:
250: // Return allocated padded data.
251: return (void *) (paddedsfx + 8);
252: }
253:
254:
255:
256:
257:
258: //
259: // This function adds a sound to the
260: // list of currently active sounds,
261: // which is maintained as a given number
262: // (eight, usually) of internal channels.
263: // Returns a handle.
264: //
265: int
266: addsfx
267: ( int sfxid,
268: int volume,
269: int step,
270: int seperation )
271: {
272: static unsigned short handlenums = 0;
273:
274: int i;
275: int rc = -1;
276:
277: int oldest = gametic;
278: int oldestnum = 0;
279: int slot;
280:
281: int rightvol;
282: int leftvol;
283:
284: // Chainsaw troubles.
285: // Play these sound effects only one at a time.
286: if ( sfxid == sfx_sawup
287: || sfxid == sfx_sawidl
288: || sfxid == sfx_sawful
289: || sfxid == sfx_sawhit
290: || sfxid == sfx_stnmov
291: || sfxid == sfx_pistol )
292: {
293: // Loop all channels, check.
294: for (i=0 ; i<NUM_CHANNELS ; i++)
295: {
296: // Active, and using the same SFX?
297: if ( (channels[i])
298: && (channelids[i] == sfxid) )
299: {
300: // Reset.
301: channels[i] = 0;
302: // We are sure that iff,
303: // there will only be one.
304: break;
305: }
306: }
307: }
308:
309: // Loop all channels to find oldest SFX.
310: for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++)
311: {
312: if (channelstart[i] < oldest)
313: {
314: oldestnum = i;
315: oldest = channelstart[i];
316: }
317: }
318:
319: // Tales from the cryptic.
320: // If we found a channel, fine.
321: // If not, we simply overwrite the first one, 0.
322: // Probably only happens at startup.
323: if (i == NUM_CHANNELS)
324: slot = oldestnum;
325: else
326: slot = i;
327:
328: // Okay, in the less recent channel,
329: // we will handle the new SFX.
330: // Set pointer to raw data.
331: channels[slot] = (unsigned char *) S_sfx[sfxid].data;
332: // Set pointer to end of raw data.
333: channelsend[slot] = channels[slot] + lengths[sfxid];
334:
335: // Reset current handle number, limited to 0..100.
336: if (!handlenums)
337: handlenums = 100;
338:
339: // Assign current handle number.
340: // Preserved so sounds could be stopped (unused).
341: channelhandles[slot] = rc = handlenums++;
342:
343: // Set stepping???
344: // Kinda getting the impression this is never used.
345: channelstep[slot] = step;
346: // ???
347: channelstepremainder[slot] = 0;
348: // Should be gametic, I presume.
349: channelstart[slot] = gametic;
350:
351: // Separation, that is, orientation/stereo.
352: // range is: 1 - 256
353: seperation += 1;
354:
355: // Per left/right channel.
356: // x^2 seperation,
357: // adjust volume properly.
358: leftvol =
359: volume - ((volume*seperation*seperation) >> 16); ///(256*256);
360: seperation = seperation - 257;
361: rightvol =
362: volume - ((volume*seperation*seperation) >> 16);
363:
364: // Sanity check, clamp volume.
365: if (rightvol < 0 || rightvol > 127)
366: I_Error("rightvol out of bounds");
367:
368: if (leftvol < 0 || leftvol > 127)
369: I_Error("leftvol out of bounds");
370:
371: // Get the proper lookup table piece
372: // for this volume level???
373: channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
374: channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
375:
376: // Preserve sound SFX id,
377: // e.g. for avoiding duplicates of chainsaw.
378: channelids[slot] = sfxid;
379:
380: // You tell me.
381: return rc;
382: }
383:
384:
385:
386:
387:
388: //
389: // SFX API
390: // Note: this was called by S_Init.
391: // However, whatever they did in the
392: // old DPMS based DOS version, this
393: // were simply dummies in the Linux
394: // version.
395: // See soundserver initdata().
396: //
397: void I_SetChannels()
398: {
399: // Init internal lookups (raw data, mixing buffer, channels).
400: // This function sets up internal lookups used during
401: // the mixing process.
402: int i;
403: int j;
404:
405: int* steptablemid = steptable + 128;
406:
407: // Okay, reset internal mixing channels to zero.
408: /*for (i=0; i<NUM_CHANNELS; i++)
409: {
410: channels[i] = 0;
411: }*/
412:
413: // This table provides step widths for pitch parameters.
414: // I fail to see that this is currently used.
415: for (i=-128 ; i<128 ; i++)
416: steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
417:
418:
419: // Generates volume lookup tables
420: // which also turn the unsigned samples
421: // into signed samples.
422: for (i=0 ; i<128 ; i++)
423: for (j=0 ; j<256 ; j++)
424: vol_lookup[i*256+j] = (i*(j-128)*256)/127;
425: }
426:
427:
428: void I_SetSfxVolume(int volume)
429: {
430: // Identical to DOS.
431: // Basically, this should propagate
432: // the menu/config file setting
433: // to the state variable used in
434: // the mixing.
435: snd_SfxVolume = volume;
436: }
437:
438: // MUSIC API - dummy. Some code from DOS version.
439: void I_SetMusicVolume(int volume)
440: {
441: // Internal state variable.
442: snd_MusicVolume = volume;
443: // Now set volume on output device.
444: // Whatever( snd_MusciVolume );
445: }
446:
447:
448: //
449: // Retrieve the raw data lump index
450: // for a given SFX name.
451: //
452: int I_GetSfxLumpNum(sfxinfo_t* sfx)
453: {
454: char namebuf[9];
455: sprintf(namebuf, "ds%s", sfx->name);
456: return W_GetNumForName(namebuf);
457: }
458:
459: //
460: // Starting a sound means adding it
461: // to the current list of active sounds
462: // in the internal channels.
463: // As the SFX info struct contains
464: // e.g. a pointer to the raw data,
465: // it is ignored.
466: // As our sound handling does not handle
467: // priority, it is ignored.
468: // Pitching (that is, increased speed of playback)
469: // is set, but currently not used by mixing.
470: //
471: int
472: I_StartSound
473: ( int id,
474: int vol,
475: int sep,
476: int pitch,
477: int priority )
478: {
479:
480: // UNUSED
481: priority = 0;
482:
483: #ifdef SNDSERV
484: if (sndserver)
485: {
486: fprintf(sndserver, "p%2.2x%2.2x%2.2x%2.2x\n", id, pitch, vol, sep);
487: fflush(sndserver);
488: }
489: // warning: control reaches end of non-void function.
490: return id;
491: #else
492: // Debug.
493: //fprintf( stderr, "starting sound %d", id );
494:
495: // Returns a handle (not used).
496: id = addsfx( id, vol, steptable[pitch], sep );
497:
498: // fprintf( stderr, "/handle is %d\n", id );
499:
500: return id;
501: #endif
502: }
503:
504:
505:
506: void I_StopSound (int handle)
507: {
508: // You need the handle returned by StartSound.
509: // Would be looping all channels,
510: // tracking down the handle,
511: // an setting the channel to zero.
512:
513: // UNUSED.
514: handle = 0;
515: }
516:
517:
518: int I_SoundIsPlaying(int handle)
519: {
520: // Ouch.
521: return gametic < handle;
522: }
523:
524:
525:
526:
527: //
528: // This function loops all active (internal) sound
529: // channels, retrieves a given number of samples
530: // from the raw sound data, modifies it according
531: // to the current (internal) channel parameters,
532: // mixes the per channel samples into the global
533: // mixbuffer, clamping it to the allowed range,
534: // and sets up everything for transferring the
535: // contents of the mixbuffer to the (two)
536: // hardware channels (left and right, that is).
537: //
538: // This function currently supports only 16bit.
539: //
540: void I_UpdateSound( void )
541: {
542: #ifdef SNDINTR
543: // Debug. Count buffer misses with interrupt.
544: static int misses = 0;
545: #endif
546:
547:
548: // Mix current sound data.
549: // Data, from raw sound, for right and left.
550: register unsigned int sample;
551: register int dl;
552: register int dr;
553:
554: // Pointers in global mixbuffer, left, right, end.
555: signed short* leftout;
556: signed short* rightout;
557: signed short* leftend;
558: // Step in mixbuffer, left and right, thus two.
559: int step;
560:
561: // Mixing channel index.
562: int chan;
563:
564: // Left and right channel
565: // are in global mixbuffer, alternating.
566: leftout = mixbuffer;
567: rightout = mixbuffer+1;
568: step = 2;
569:
570: // Determine end, for left channel only
571: // (right channel is implicit).
572: leftend = mixbuffer + SAMPLECOUNT*step;
573:
574: // Mix sounds into the mixing buffer.
575: // Loop over step*SAMPLECOUNT,
576: // that is 512 values for two channels.
577: while (leftout != leftend)
578: {
579: // Reset left/right value.
580: dl = 0;
581: dr = 0;
582:
583: // Love thy L2 chache - made this a loop.
584: // Now more channels could be set at compile time
585: // as well. Thus loop those channels.
586: for ( chan = 0; chan < NUM_CHANNELS; chan++ )
587: {
588: // Check channel, if active.
589: if (channels[ chan ])
590: {
591: // Get the raw data from the channel.
592: sample = *channels[ chan ];
593: // Add left and right part
594: // for this channel (sound)
595: // to the current data.
596: // Adjust volume accordingly.
597: dl += channelleftvol_lookup[ chan ][sample];
598: dr += channelrightvol_lookup[ chan ][sample];
599: // Increment index ???
600: channelstepremainder[ chan ] += channelstep[ chan ];
601: // MSB is next sample???
602: channels[ chan ] += channelstepremainder[ chan ] >> 16;
603: // Limit to LSB???
604: channelstepremainder[ chan ] &= 65536-1;
605:
606: // Check whether we are done.
607: if (channels[ chan ] >= channelsend[ chan ])
608: channels[ chan ] = 0;
609: }
610: }
611:
612: // Clamp to range. Left hardware channel.
613: // Has been char instead of short.
614: // if (dl > 127) *leftout = 127;
615: // else if (dl < -128) *leftout = -128;
616: // else *leftout = dl;
617:
618: if (dl > 0x7fff)
619: *leftout = 0x7fff;
620: else if (dl < -0x8000)
621: *leftout = -0x8000;
622: else
623: *leftout = dl;
624:
625: // Same for right hardware channel.
626: if (dr > 0x7fff)
627: *rightout = 0x7fff;
628: else if (dr < -0x8000)
629: *rightout = -0x8000;
630: else
631: *rightout = dr;
632:
633: // Increment current pointers in mixbuffer.
634: leftout += step;
635: rightout += step;
636: }
637:
638: #ifdef SNDINTR
639: // Debug check.
640: if ( flag )
641: {
642: misses += flag;
643: flag = 0;
644: }
645:
646: if ( misses > 10 )
647: {
648: fprintf( stderr, "I_SoundUpdate: missed 10 buffer writes\n");
649: misses = 0;
650: }
651:
652: // Increment flag for update.
653: flag++;
654: #endif
655: }
656:
657:
658: //
659: // This would be used to write out the mixbuffer
660: // during each game loop update.
661: // Updates sound buffer and audio device at runtime.
662: // It is called during Timer interrupt with SNDINTR.
663: // Mixing now done synchronous, and
664: // only output be done asynchronous?
665: //
666: void
667: I_SubmitSound(void)
668: {
669: // Write it to DSP device.
670: write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
671: }
672:
673:
674:
675: void
676: I_UpdateSoundParams
677: ( int handle,
678: int vol,
679: int sep,
680: int pitch)
681: {
682: // I fail too see that this is used.
683: // Would be using the handle to identify
684: // on which channel the sound might be active,
685: // and resetting the channel parameters.
686:
687: // UNUSED.
688: handle = vol = sep = pitch = 0;
689: }
690:
691:
692:
693:
694: void I_ShutdownSound(void)
695: {
696: #ifdef SNDSERV
697: if (sndserver)
698: {
699: // Send a "quit" command.
700: fprintf(sndserver, "q\n");
701: fflush(sndserver);
702: }
703: #else
704: // Wait till all pending sounds are finished.
705: int done = 0;
706: int i;
707:
708:
709: // FIXME (below).
710: fprintf( stderr, "I_ShutdownSound: NOT finishing pending sounds\n");
711: fflush( stderr );
712:
713: while ( !done )
714: {
715: for( i=0 ; i<8 && !channels[i] ; i++);
716:
717: // FIXME. No proper channel output.
718: //if (i==8)
719: done=1;
720: }
721: #ifdef SNDINTR
722: I_SoundDelTimer();
723: #endif
724:
725: // Cleaning up -releasing the DSP device.
726: close ( audio_fd );
727: #endif
728:
729: // Done.
730: return;
731: }
732:
733:
734:
735:
736:
737:
738: void
739: I_InitSound()
740: {
741: #ifdef SNDSERV
742: char buffer[256];
743:
744: if (getenv("DOOMWADDIR"))
745: sprintf(buffer, "%s/%s",
746: getenv("DOOMWADDIR"),
747: sndserver_filename);
748: else
749: sprintf(buffer, "%s", sndserver_filename);
750:
751: // start sound process
752: if ( !access(buffer, X_OK) )
753: {
754: strcat(buffer, " -quiet");
755: sndserver = popen(buffer, "w");
756: }
757: else
758: fprintf(stderr, "Could not start sound server [%s]\n", buffer);
759: #else
760:
761: int i;
762:
763: #ifdef SNDINTR
764: fprintf( stderr, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL );
765: I_SoundSetTimer( SOUND_INTERVAL );
766: #endif
767:
768: // Secure and configure sound device first.
769: fprintf( stderr, "I_InitSound: ");
770:
771: audio_fd = open("/dev/dsp", O_WRONLY);
772: if (audio_fd<0)
773: fprintf(stderr, "Could not open /dev/dsp\n");
774:
775:
776: i = 11 | (2<<16);
777: myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);
778: myioctl(audio_fd, SNDCTL_DSP_RESET, 0);
779:
780: i=SAMPLERATE;
781:
782: myioctl(audio_fd, SNDCTL_DSP_SPEED, &i);
783:
784: i=1;
785: myioctl(audio_fd, SNDCTL_DSP_STEREO, &i);
786:
787: myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i);
788:
789: if (i&=AFMT_S16_LE)
790: myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i);
791: else
792: fprintf(stderr, "Could not play signed 16 data\n");
793:
794: fprintf(stderr, " configured audio device\n" );
795:
796:
797: // Initialize external data (all sounds) at start, keep static.
798: fprintf( stderr, "I_InitSound: ");
799:
800: for (i=1 ; i<NUMSFX ; i++)
801: {
802: // Alias? Example is the chaingun sound linked to pistol.
803: if (!S_sfx[i].link)
804: {
805: // Load data from WAD file.
806: S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
807: }
808: else
809: {
810: // Previously loaded already?
811: S_sfx[i].data = S_sfx[i].link->data;
812: lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
813: }
814: }
815:
816: fprintf( stderr, " pre-cached all sound data\n");
817:
818: // Now initialize mixbuffer with zero.
819: for ( i = 0; i< MIXBUFFERSIZE; i++ )
820: mixbuffer[i] = 0;
821:
822: // Finished initialization.
823: fprintf(stderr, "I_InitSound: sound module ready\n");
824:
825: #endif
826: }
827:
828:
829:
830:
831: //
832: // MUSIC API.
833: // Still no music done.
834: // Remains. Dummies.
835: //
836: void I_InitMusic(void) { }
837: void I_ShutdownMusic(void) { }
838:
839: static int looping=0;
840: static int musicdies=-1;
841:
842: void I_PlaySong(int handle, int looping)
843: {
844: // UNUSED.
845: handle = looping = 0;
846: musicdies = gametic + TICRATE*30;
847: }
848:
849: void I_PauseSong (int handle)
850: {
851: // UNUSED.
852: handle = 0;
853: }
854:
855: void I_ResumeSong (int handle)
856: {
857: // UNUSED.
858: handle = 0;
859: }
860:
861: void I_StopSong(int handle)
862: {
863: // UNUSED.
864: handle = 0;
865:
866: looping = 0;
867: musicdies = 0;
868: }
869:
870: void I_UnRegisterSong(int handle)
871: {
872: // UNUSED.
873: handle = 0;
874: }
875:
876: int I_RegisterSong(void* data)
877: {
878: // UNUSED.
879: data = NULL;
880:
881: return 1;
882: }
883:
884: // Is the song playing?
885: int I_QrySongPlaying(int handle)
886: {
887: // UNUSED.
888: handle = 0;
889: return looping || musicdies > gametic;
890: }
891:
892:
893:
894: //
895: // Experimental stuff.
896: // A Linux timer interrupt, for asynchronous
897: // sound output.
898: // I ripped this out of the Timer class in
899: // our Difference Engine, including a few
900: // SUN remains...
901: //
902: #ifdef sun
903: typedef sigset_t tSigSet;
904: #else
905: typedef int tSigSet;
906: #endif
907:
908:
909: // We might use SIGVTALRM and ITIMER_VIRTUAL, if the process
910: // time independend timer happens to get lost due to heavy load.
911: // SIGALRM and ITIMER_REAL doesn't really work well.
912: // There are issues with profiling as well.
913: static int /*__itimer_which*/ itimer = ITIMER_REAL;
914:
915: static int sig = SIGALRM;
916:
917: // Interrupt handler.
918: void I_HandleSoundTimer( int ignore )
919: {
920: // Debug.
921: //fprintf( stderr, "%c", '+' ); fflush( stderr );
922:
923: // Feed sound device if necesary.
924: if ( flag )
925: {
926: // See I_SubmitSound().
927: // Write it to DSP device.
928: write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
929:
930: // Reset flag counter.
931: flag = 0;
932: }
933: else
934: return;
935:
936: // UNUSED, but required.
937: ignore = 0;
938: return;
939: }
940:
941: // Get the interrupt. Set duration in millisecs.
942: int I_SoundSetTimer( int duration_of_tick )
943: {
944: // Needed for gametick clockwork.
945: struct itimerval value;
946: struct itimerval ovalue;
947: struct sigaction act;
948: struct sigaction oact;
949:
950: int res;
951:
952: // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it.
953: // signal( _sig, handle_SIG_TICK );
954:
955: // Now we have to change this attribute for repeated calls.
956: act.sa_handler = I_HandleSoundTimer;
957: #ifndef sun
958: //ac t.sa_mask = _sig;
959: #endif
960: act.sa_flags = SA_RESTART;
961:
962: sigaction( sig, &act, &oact );
963:
964: value.it_interval.tv_sec = 0;
965: value.it_interval.tv_usec = duration_of_tick;
966: value.it_value.tv_sec = 0;
967: value.it_value.tv_usec = duration_of_tick;
968:
969: // Error is -1.
970: res = setitimer( itimer, &value, &ovalue );
971:
972: // Debug.
973: if ( res == -1 )
974: fprintf( stderr, "I_SoundSetTimer: interrupt n.a.\n");
975:
976: return res;
977: }
978:
979:
980: // Remove the interrupt. Set duration to zero.
981: void I_SoundDelTimer()
982: {
983: // Debug.
984: if ( I_SoundSetTimer( 0 ) == -1)
985: fprintf( stderr, "I_SoundDelTimer: failed to remove interrupt. Doh!\n");
986: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.