1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // System interface for sound.
25 //-----------------------------------------------------------------------------
37 #include <sys/types.h>
40 #include <sys/filio.h>
45 #include <sys/ioctl.h>
47 // Linux voxware output.
48 #include <linux/soundcard.h>
50 // Timer stuff. Experimental.
64 // UNIX hack, to be removed.
66 // Separate sound server process.
68 char* sndserver_filename
= "./sndserver ";
71 // Update all 30 millisecs, approx. 30fps synchronized.
72 // Linux resolution is allegedly 10 millisecs,
73 // scale is microseconds.
74 #define SOUND_INTERVAL 500
76 // Get the interrupt. Set duration in millisecs.
77 int I_SoundSetTimer( int duration_of_tick
);
78 void I_SoundDelTimer( void );
84 // A quick hack to establish a protocol between
85 // synchronous mix buffer updates and asynchronous
86 // audio writes. Probably redundant with gametic.
89 // The number of internal mixing channels,
90 // the samples calculated for each mixing step,
91 // the size of the 16bit, 2 hardware channel (stereo)
92 // mixing buffer, and the samplerate of the raw data.
95 // Needed for calling the actual sound output.
96 #define SAMPLECOUNT 512
97 #define NUM_CHANNELS 8
98 // It is 2 for 16bit, and 2 for two channels.
100 #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL)
102 #define SAMPLERATE 11025 // Hz
103 #define SAMPLESIZE 2 // 16bit
105 // The actual lengths of all sound effects.
108 // The actual output device.
111 // The global mixing buffer.
112 // Basically, samples from all active internal channels
113 // are modifed and added, and stored in the buffer
114 // that is submitted to the audio device.
115 signed short mixbuffer
[MIXBUFFERSIZE
];
118 // The channel step amount...
119 unsigned int channelstep
[NUM_CHANNELS
];
120 // ... and a 0.16 bit remainder of last step.
121 unsigned int channelstepremainder
[NUM_CHANNELS
];
124 // The channel data pointers, start and end.
125 unsigned char* channels
[NUM_CHANNELS
];
126 unsigned char* channelsend
[NUM_CHANNELS
];
129 // Time/gametic that the channel started playing,
130 // used to determine oldest, which automatically
131 // has lowest priority.
132 // In case number of active sounds exceeds
133 // available channels.
134 int channelstart
[NUM_CHANNELS
];
136 // The sound in channel handles,
137 // determined on registration,
138 // might be used to unregister/stop/modify,
140 int channelhandles
[NUM_CHANNELS
];
142 // SFX id of the playing sound effect.
143 // Used to catch duplicates (like chainsaw).
144 int channelids
[NUM_CHANNELS
];
146 // Pitch to stepping lookup, unused.
150 int vol_lookup
[128*256];
152 // Hardware left and right channel volume lookup.
153 int* channelleftvol_lookup
[NUM_CHANNELS
];
154 int* channelrightvol_lookup
[NUM_CHANNELS
];
160 // Safe ioctl, convenience.
171 rc
= ioctl(fd
, command
, arg
);
174 fprintf(stderr
, "ioctl(dsp,%d,arg) failed\n", command
);
175 fprintf(stderr
, "errno=%d\n", errno
);
185 // This function loads the sound data from the WAD lump,
194 unsigned char* paddedsfx
;
202 // Get the sound data from the WAD, allocate lump
204 sprintf(name
, "ds%s", sfxname
);
206 // Now, there is a severe problem with the
207 // sound handling, in it is not (yet/anymore)
208 // gamemode aware. That means, sounds from
209 // DOOM II will be requested even with DOOM
211 // The sound list is wired into sounds.c,
212 // which sets the external variable.
213 // I do not do runtime patches to that
214 // variable. Instead, we will use a
215 // default sound for replacement.
216 if ( W_CheckNumForName(name
) == -1 )
217 sfxlump
= W_GetNumForName("dspistol");
219 sfxlump
= W_GetNumForName(name
);
221 size
= W_LumpLength( sfxlump
);
224 // fprintf( stderr, "." );
225 //fprintf( stderr, " -loading %s (lump %d, %d bytes)\n",
226 // sfxname, sfxlump, size );
229 sfx
= (unsigned char*)W_CacheLumpNum( sfxlump
, PU_STATIC
);
231 // Pads the sound effect out to the mixing buffer size.
232 // The original realloc would interfere with zone memory.
233 paddedsize
= ((size
-8 + (SAMPLECOUNT
-1)) / SAMPLECOUNT
) * SAMPLECOUNT
;
235 // Allocate from zone memory.
236 paddedsfx
= (unsigned char*)Z_Malloc( paddedsize
+8, PU_STATIC
, 0 );
237 // ddt: (unsigned char *) realloc(sfx, paddedsize+8);
238 // This should interfere with zone memory handling,
239 // which does not kick in in the soundserver.
242 memcpy( paddedsfx
, sfx
, size
);
243 for (i
=size
; i
<paddedsize
+8 ; i
++)
246 // Remove the cached lump.
249 // Preserve padded length.
252 // Return allocated padded data.
253 return (void *) (paddedsfx
+ 8);
261 // This function adds a sound to the
262 // list of currently active sounds,
263 // which is maintained as a given number
264 // (eight, usually) of internal channels.
274 static unsigned short handlenums
= 0;
279 int oldest
= gametic
;
286 // Chainsaw troubles.
287 // Play these sound effects only one at a time.
288 if ( sfxid
== sfx_sawup
289 || sfxid
== sfx_sawidl
290 || sfxid
== sfx_sawful
291 || sfxid
== sfx_sawhit
292 || sfxid
== sfx_stnmov
293 || sfxid
== sfx_pistol
)
295 // Loop all channels, check.
296 for (i
=0 ; i
<NUM_CHANNELS
; i
++)
298 // Active, and using the same SFX?
300 && (channelids
[i
] == sfxid
) )
304 // We are sure that iff,
305 // there will only be one.
311 // Loop all channels to find oldest SFX.
312 for (i
=0; (i
<NUM_CHANNELS
) && (channels
[i
]); i
++)
314 if (channelstart
[i
] < oldest
)
317 oldest
= channelstart
[i
];
321 // Tales from the cryptic.
322 // If we found a channel, fine.
323 // If not, we simply overwrite the first one, 0.
324 // Probably only happens at startup.
325 if (i
== NUM_CHANNELS
)
330 // Okay, in the less recent channel,
331 // we will handle the new SFX.
332 // Set pointer to raw data.
333 channels
[slot
] = (unsigned char *) S_sfx
[sfxid
].data
;
334 // Set pointer to end of raw data.
335 channelsend
[slot
] = channels
[slot
] + lengths
[sfxid
];
337 // Reset current handle number, limited to 0..100.
341 // Assign current handle number.
342 // Preserved so sounds could be stopped (unused).
343 channelhandles
[slot
] = rc
= handlenums
++;
346 // Kinda getting the impression this is never used.
347 channelstep
[slot
] = step
;
349 channelstepremainder
[slot
] = 0;
350 // Should be gametic, I presume.
351 channelstart
[slot
] = gametic
;
353 // Separation, that is, orientation/stereo.
357 // Per left/right channel.
359 // adjust volume properly.
361 volume
- ((volume
*seperation
*seperation
) >> 16); ///(256*256);
362 seperation
= seperation
- 257;
364 volume
- ((volume
*seperation
*seperation
) >> 16);
366 // Sanity check, clamp volume.
367 if (rightvol
< 0 || rightvol
> 127)
368 I_Error("rightvol out of bounds");
370 if (leftvol
< 0 || leftvol
> 127)
371 I_Error("leftvol out of bounds");
373 // Get the proper lookup table piece
374 // for this volume level???
375 channelleftvol_lookup
[slot
] = &vol_lookup
[leftvol
*256];
376 channelrightvol_lookup
[slot
] = &vol_lookup
[rightvol
*256];
378 // Preserve sound SFX id,
379 // e.g. for avoiding duplicates of chainsaw.
380 channelids
[slot
] = sfxid
;
392 // Note: this was called by S_Init.
393 // However, whatever they did in the
394 // old DPMS based DOS version, this
395 // were simply dummies in the Linux
397 // See soundserver initdata().
401 // Init internal lookups (raw data, mixing buffer, channels).
402 // This function sets up internal lookups used during
403 // the mixing process.
407 int* steptablemid
= steptable
+ 128;
409 // Okay, reset internal mixing channels to zero.
410 /*for (i=0; i<NUM_CHANNELS; i++)
415 // This table provides step widths for pitch parameters.
416 // I fail to see that this is currently used.
417 for (i
=-128 ; i
<128 ; i
++)
418 steptablemid
[i
] = (int)(pow(2.0, (i
/64.0))*65536.0);
421 // Generates volume lookup tables
422 // which also turn the unsigned samples
423 // into signed samples.
424 for (i
=0 ; i
<128 ; i
++)
425 for (j
=0 ; j
<256 ; j
++)
426 vol_lookup
[i
*256+j
] = (i
*(j
-128)*256)/127;
430 void I_SetSfxVolume(int volume
)
433 // Basically, this should propagate
434 // the menu/config file setting
435 // to the state variable used in
437 snd_SfxVolume
= volume
;
440 // MUSIC API - dummy. Some code from DOS version.
441 void I_SetMusicVolume(int volume
)
443 // Internal state variable.
444 snd_MusicVolume
= volume
;
445 // Now set volume on output device.
446 // Whatever( snd_MusciVolume );
451 // Retrieve the raw data lump index
452 // for a given SFX name.
454 int I_GetSfxLumpNum(sfxinfo_t
* sfx
)
457 sprintf(namebuf
, "ds%s", sfx
->name
);
458 return W_GetNumForName(namebuf
);
462 // Starting a sound means adding it
463 // to the current list of active sounds
464 // in the internal channels.
465 // As the SFX info struct contains
466 // e.g. a pointer to the raw data,
468 // As our sound handling does not handle
469 // priority, it is ignored.
470 // Pitching (that is, increased speed of playback)
471 // is set, but currently not used by mixing.
488 fprintf(sndserver
, "p%2.2x%2.2x%2.2x%2.2x\n", id
, pitch
, vol
, sep
);
491 // warning: control reaches end of non-void function.
495 //fprintf( stderr, "starting sound %d", id );
497 // Returns a handle (not used).
498 id
= addsfx( id
, vol
, steptable
[pitch
], sep
);
500 // fprintf( stderr, "/handle is %d\n", id );
508 void I_StopSound (int handle
)
510 // You need the handle returned by StartSound.
511 // Would be looping all channels,
512 // tracking down the handle,
513 // an setting the channel to zero.
520 int I_SoundIsPlaying(int handle
)
523 return gametic
< handle
;
530 // This function loops all active (internal) sound
531 // channels, retrieves a given number of samples
532 // from the raw sound data, modifies it according
533 // to the current (internal) channel parameters,
534 // mixes the per channel samples into the global
535 // mixbuffer, clamping it to the allowed range,
536 // and sets up everything for transferring the
537 // contents of the mixbuffer to the (two)
538 // hardware channels (left and right, that is).
540 // This function currently supports only 16bit.
542 void I_UpdateSound( void )
545 // Debug. Count buffer misses with interrupt.
546 static int misses
= 0;
550 // Mix current sound data.
551 // Data, from raw sound, for right and left.
552 register unsigned int sample
;
556 // Pointers in global mixbuffer, left, right, end.
557 signed short* leftout
;
558 signed short* rightout
;
559 signed short* leftend
;
560 // Step in mixbuffer, left and right, thus two.
563 // Mixing channel index.
566 // Left and right channel
567 // are in global mixbuffer, alternating.
569 rightout
= mixbuffer
+1;
572 // Determine end, for left channel only
573 // (right channel is implicit).
574 leftend
= mixbuffer
+ SAMPLECOUNT
*step
;
576 // Mix sounds into the mixing buffer.
577 // Loop over step*SAMPLECOUNT,
578 // that is 512 values for two channels.
579 while (leftout
!= leftend
)
581 // Reset left/right value.
585 // Love thy L2 chache - made this a loop.
586 // Now more channels could be set at compile time
587 // as well. Thus loop those channels.
588 for ( chan
= 0; chan
< NUM_CHANNELS
; chan
++ )
590 // Check channel, if active.
591 if (channels
[ chan
])
593 // Get the raw data from the channel.
594 sample
= *channels
[ chan
];
595 // Add left and right part
596 // for this channel (sound)
597 // to the current data.
598 // Adjust volume accordingly.
599 dl
+= channelleftvol_lookup
[ chan
][sample
];
600 dr
+= channelrightvol_lookup
[ chan
][sample
];
601 // Increment index ???
602 channelstepremainder
[ chan
] += channelstep
[ chan
];
603 // MSB is next sample???
604 channels
[ chan
] += channelstepremainder
[ chan
] >> 16;
606 channelstepremainder
[ chan
] &= 65536-1;
608 // Check whether we are done.
609 if (channels
[ chan
] >= channelsend
[ chan
])
610 channels
[ chan
] = 0;
614 // Clamp to range. Left hardware channel.
615 // Has been char instead of short.
616 // if (dl > 127) *leftout = 127;
617 // else if (dl < -128) *leftout = -128;
618 // else *leftout = dl;
622 else if (dl
< -0x8000)
627 // Same for right hardware channel.
630 else if (dr
< -0x8000)
635 // Increment current pointers in mixbuffer.
650 fprintf( stderr
, "I_SoundUpdate: missed 10 buffer writes\n");
654 // Increment flag for update.
661 // This would be used to write out the mixbuffer
662 // during each game loop update.
663 // Updates sound buffer and audio device at runtime.
664 // It is called during Timer interrupt with SNDINTR.
665 // Mixing now done synchronous, and
666 // only output be done asynchronous?
671 // Write it to DSP device.
672 write(audio_fd
, mixbuffer
, SAMPLECOUNT
*BUFMUL
);
684 // I fail too see that this is used.
685 // Would be using the handle to identify
686 // on which channel the sound might be active,
687 // and resetting the channel parameters.
690 handle
= vol
= sep
= pitch
= 0;
696 void I_ShutdownSound(void)
701 // Send a "quit" command.
702 fprintf(sndserver
, "q\n");
706 // Wait till all pending sounds are finished.
712 fprintf( stderr
, "I_ShutdownSound: NOT finishing pending sounds\n");
717 for( i
=0 ; i
<8 && !channels
[i
] ; i
++);
719 // FIXME. No proper channel output.
727 // Cleaning up -releasing the DSP device.
746 if (getenv("DOOMWADDIR"))
747 sprintf(buffer
, "%s/%s",
748 getenv("DOOMWADDIR"),
751 sprintf(buffer
, "%s", sndserver_filename
);
753 // start sound process
754 if ( !access(buffer
, X_OK
) )
756 strcat(buffer
, " -quiet");
757 sndserver
= popen(buffer
, "w");
760 fprintf(stderr
, "Could not start sound server [%s]\n", buffer
);
766 fprintf( stderr
, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL
);
767 I_SoundSetTimer( SOUND_INTERVAL
);
770 // Secure and configure sound device first.
771 fprintf( stderr
, "I_InitSound: ");
773 audio_fd
= open("/dev/dsp", O_WRONLY
);
775 fprintf(stderr
, "Could not open /dev/dsp\n");
779 myioctl(audio_fd
, SNDCTL_DSP_SETFRAGMENT
, &i
);
780 myioctl(audio_fd
, SNDCTL_DSP_RESET
, 0);
784 myioctl(audio_fd
, SNDCTL_DSP_SPEED
, &i
);
787 myioctl(audio_fd
, SNDCTL_DSP_STEREO
, &i
);
789 myioctl(audio_fd
, SNDCTL_DSP_GETFMTS
, &i
);
792 myioctl(audio_fd
, SNDCTL_DSP_SETFMT
, &i
);
794 fprintf(stderr
, "Could not play signed 16 data\n");
796 fprintf(stderr
, " configured audio device\n" );
799 // Initialize external data (all sounds) at start, keep static.
800 fprintf( stderr
, "I_InitSound: ");
802 for (i
=1 ; i
<NUMSFX
; i
++)
804 // Alias? Example is the chaingun sound linked to pistol.
807 // Load data from WAD file.
808 S_sfx
[i
].data
= getsfx( S_sfx
[i
].name
, &lengths
[i
] );
812 // Previously loaded already?
813 S_sfx
[i
].data
= S_sfx
[i
].link
->data
;
814 lengths
[i
] = lengths
[(S_sfx
[i
].link
- S_sfx
)/sizeof(sfxinfo_t
)];
818 fprintf( stderr
, " pre-cached all sound data\n");
820 // Now initialize mixbuffer with zero.
821 for ( i
= 0; i
< MIXBUFFERSIZE
; i
++ )
824 // Finished initialization.
825 fprintf(stderr
, "I_InitSound: sound module ready\n");
835 // Still no music done.
838 void I_InitMusic(void) { }
839 void I_ShutdownMusic(void) { }
841 static int looping
=0;
842 static int musicdies
=-1;
844 void I_PlaySong(int handle
, int looping
)
847 handle
= looping
= 0;
848 musicdies
= gametic
+ TICRATE
*30;
851 void I_PauseSong (int handle
)
857 void I_ResumeSong (int handle
)
863 void I_StopSong(int handle
)
872 void I_UnRegisterSong(int handle
)
878 int I_RegisterSong(void* data
)
886 // Is the song playing?
887 int I_QrySongPlaying(int handle
)
891 return looping
|| musicdies
> gametic
;
897 // Experimental stuff.
898 // A Linux timer interrupt, for asynchronous
900 // I ripped this out of the Timer class in
901 // our Difference Engine, including a few
905 typedef sigset_t tSigSet
;
911 // We might use SIGVTALRM and ITIMER_VIRTUAL, if the process
912 // time independend timer happens to get lost due to heavy load.
913 // SIGALRM and ITIMER_REAL doesn't really work well.
914 // There are issues with profiling as well.
915 static int /*__itimer_which*/ itimer
= ITIMER_REAL
;
917 static int sig
= SIGALRM
;
919 // Interrupt handler.
920 void I_HandleSoundTimer( int ignore
)
923 //fprintf( stderr, "%c", '+' ); fflush( stderr );
925 // Feed sound device if necesary.
928 // See I_SubmitSound().
929 // Write it to DSP device.
930 write(audio_fd
, mixbuffer
, SAMPLECOUNT
*BUFMUL
);
932 // Reset flag counter.
938 // UNUSED, but required.
943 // Get the interrupt. Set duration in millisecs.
944 int I_SoundSetTimer( int duration_of_tick
)
946 // Needed for gametick clockwork.
947 struct itimerval value
;
948 struct itimerval ovalue
;
949 struct sigaction act
;
950 struct sigaction oact
;
954 // This sets to SA_ONESHOT and SA_NOMASK, thus we can not use it.
955 // signal( _sig, handle_SIG_TICK );
957 // Now we have to change this attribute for repeated calls.
958 act
.sa_handler
= I_HandleSoundTimer
;
960 //ac t.sa_mask = _sig;
962 act
.sa_flags
= SA_RESTART
;
964 sigaction( sig
, &act
, &oact
);
966 value
.it_interval
.tv_sec
= 0;
967 value
.it_interval
.tv_usec
= duration_of_tick
;
968 value
.it_value
.tv_sec
= 0;
969 value
.it_value
.tv_usec
= duration_of_tick
;
972 res
= setitimer( itimer
, &value
, &ovalue
);
976 fprintf( stderr
, "I_SoundSetTimer: interrupt n.a.\n");
982 // Remove the interrupt. Set duration to zero.
983 void I_SoundDelTimer()
986 if ( I_SoundSetTimer( 0 ) == -1)
987 fprintf( stderr
, "I_SoundDelTimer: failed to remove interrupt. Doh!\n");