5 #include "w_wad.h" // W_GetNumForName()
8 /* The number of internal mixing channels,
9 ** the samples calculated for each mixing step,
10 ** the size of the 16bit, 2 hardware channel (stereo)
11 ** mixing buffer, and the samplerate of the raw data.
14 /* Needed for calling the actual sound output. */
15 #define SAMPLECOUNT (512<<2)
16 #define NUM_CHANNELS 8
18 /* The actual lengths of all sound effects. */
21 /* The actual output device. */
24 /* The global mixing buffer.
25 ** Basically, samples from all active internal channels
26 ** are modified and added, and stored in the buffer
27 ** that is submitted to the audio device.
29 signed short mixbuffer[SAMPLECOUNT*2];
31 /* The channel step amount... */
32 uint channelstep[NUM_CHANNELS];
33 /* ... and a 0.16 bit remainder of last step. */
34 uint channelstepremainder[NUM_CHANNELS];
36 /* The channel data pointers, start and end. */
37 uchar* channels[NUM_CHANNELS];
38 uchar* channelsend[NUM_CHANNELS];
40 /* Time/gametic that the channel started playing,
41 ** used to determine oldest, which automatically
42 ** has lowest priority.
43 ** In case number of active sounds exceeds
44 ** available channels.
46 int channelstart[NUM_CHANNELS];
48 /* The sound in channel handles,
49 ** determined on registration,
50 ** might be used to unregister/stop/modify,
53 int channelhandles[NUM_CHANNELS];
55 /* SFX id of the playing sound effect.
56 ** Used to catch duplicates (like chainsaw).
58 int channelids[NUM_CHANNELS];
60 /* Pitch to stepping lookup, unused. */
64 int vol_lookup[128*256];
66 /* Hardware left and right channel volume lookup. */
67 int* channelleftvol_lookup[NUM_CHANNELS];
68 int* channelrightvol_lookup[NUM_CHANNELS];
70 static void* getsfx(char *sfxname, int *len)
80 /* Get the sound data from the WAD, allocate lump
82 sprintf(name, "ds%s", sfxname);
84 /* Now, there is a severe problem with the
85 ** sound handling, in it is not (yet/anymore)
86 ** gamemode aware. That means, sounds from
87 ** DOOM II will be requested even with DOOM
89 ** The sound list is wired into sounds.c,
90 ** which sets the external variable.
91 ** I do not do runtime patches to that
92 ** variable. Instead, we will use a
93 ** default sound for replacement.
95 if ( W_CheckNumForName(name) == -1 )
96 sfxlump = W_GetNumForName("dspistol");
98 sfxlump = W_GetNumForName(name);
100 size = W_LumpLength( sfxlump );
102 sfx = (uchar *)W_CacheLumpNum(sfxlump, PU_STATIC);
104 /* Pads the sound effect out to the mixing buffer size.
105 ** The original realloc would interfere with zone memory.
107 paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
109 /* Allocate from zone memory. */
110 paddedsfx = (uchar *)Z_Malloc(paddedsize+8, PU_STATIC, 0);
112 /* Now copy and pad. */
113 memcpy(paddedsfx, sfx, size);
114 for (i=size ; i<paddedsize+8 ; i++)
117 /* Remove the cached lump. */
120 /* Preserve padded length. */
123 /* Return allocated padded data. */
124 return (void *)(paddedsfx + 8);
127 void I_InitSound(void)
131 audio_fd = open("/dev/audio", OWRITE);
133 printf("WARN Failed to open /dev/audio, sound disabled\n");
135 /* Initialize external data (all sounds) at start, keep static. */
136 for (i=1 ; i<NUMSFX ; i++)
138 /* Alias? Example is the chaingun sound linked to pistol. */
141 /* Load data from WAD file. */
142 S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
146 /* Previously loaded already? */
147 S_sfx[i].data = S_sfx[i].link->data;
148 lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
152 /* Now initialize mixbuffer with zero. */
153 memset(mixbuffer, 0, sizeof mixbuffer);
156 /* This function loops all active (internal) sound
157 ** channels, retrieves a given number of samples
158 ** from the raw sound data, modifies it according
159 ** to the current (internal) channel parameters,
160 ** mixes the per-channel samples into the global
161 ** mixbuffer, clamping it to the allowed range,
162 ** and sets up everything for transferring the
163 ** contents of the mixbuffer to the (two)
164 ** hardware channels (left and right, that is).
166 ** This function currently supports only 16bit.
168 void I_UpdateSound(void)
170 /* Mix current sound data.
171 ** Data, from raw sound, for right and left.
173 register uint sample;
177 /* Pointers in global mixbuffer, left, right, end. */
178 signed short *leftout;
179 signed short *rightout;
180 signed short *leftend;
181 /* Step in mixbuffer, left and right, thus two. */
184 /* Mixing channel index. */
187 /* Left and right channel
188 ** are in global mixbuffer, alternating. */
190 rightout = mixbuffer+1;
193 /* Determine end, for left channel only
194 ** (right channel is implicit). */
195 leftend = mixbuffer + SAMPLECOUNT*step;
197 /* Mix sounds into the mixing buffer.
198 ** Loop over step*SAMPLECOUNT
199 ** that is 512 values for two channels.
201 while (leftout != leftend)
203 /* Reset left/right value. */
207 /* Love thy L2 cache - made this a loop.
208 ** Now more channels could be set at compile time
209 ** as well. Thus loop those channels.
211 for(chan=0; chan < NUM_CHANNELS; chan++)
213 /* Check channel, if active. */
216 /* Get the raw data from the channel. */
217 sample = *channels[ chan ];
218 /* Add left and right part
219 ** for this channel (sound)
220 ** to the current data.
221 ** Adjust volume accordingly.
223 dl += channelleftvol_lookup[ chan ][sample];
224 dr += channelrightvol_lookup[ chan ][sample];
225 /* Increment index ??? */
226 channelstepremainder[ chan ] += channelstep[ chan ];
227 /* MSB is next sample??? */
228 channels[ chan ] += channelstepremainder[ chan ] >> 16;
229 /* Limit to LSB??? */
230 channelstepremainder[ chan ] &= 65536-1;
232 /* Check whether we are done. */
233 if (channels[ chan ] >= channelsend[ chan ])
234 channels[ chan ] = 0;
238 /* Clamp to range. */
241 else if (dl < -0x8000)
245 else if (dr < -0x8000)
251 /* Increment current pointers in mixbuffer. */
272 void I_SubmitSound(void)
275 write(audio_fd, mixbuffer, sizeof mixbuffer);
278 void I_ShutdownSound(void)
286 void I_SetChannels(void)
288 /* Init internal lookups (raw data, mixing buffer, channels).
289 ** This function sets up internal lookups used during
290 ** the mixing process.
295 int *steptablemid = steptable + 128;
297 /* This table provides step widths for pitch parameters.
298 ** I fail to see that this is currently used. */
299 for (i=-128 ; i<128 ; i++)
300 steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
302 /* Generates volume lookup tables
303 ** which also turn the unsigned samples
304 ** into signed samples.
306 for (i=0 ; i<128 ; i++)
307 for (j=0 ; j<256 ; j++)
308 vol_lookup[i*256+j] = (i*(j-128)*256)/127;
311 int I_GetSfxLumpNum(sfxinfo_t *sfxinfo)
314 sprintf(namebuf, "ds%s", sfxinfo->name);
315 return W_GetNumForName(namebuf);
318 /* This function adds a sound to the
319 ** list of currently active sounds,
320 ** which is maintained as a given number
321 ** (eight, usually) of internal channels.
325 addsfx(int id, int vol, int step, int sep)
327 static unsigned short handlenums = 0;
330 int oldest = gametic;
336 /* Chainsaw troubles.
337 ** Play these sound effects only one at a time. */
338 if ( id == sfx_sawup ||
345 /* Loop all channels, check. */
346 for (i=0 ; i < NUM_CHANNELS ; i++)
348 /* Active and using the same SFX? */
349 if( (channels[i]) && (channelids[i] == id) )
353 /* We are sure that iff,
354 ** there will only be one. */
360 /* Loop all channels to find oldest SFX. */
361 for (i=0 ; (i<NUM_CHANNELS) && (channels[i]) ; i++)
363 if(channelstart[i] < oldest)
366 oldest = channelstart[i];
370 /* Tales from the cryptic.
371 ** If we found a channel, fine.
372 ** If not, we simply overwrite the first one, 0.
373 ** Probably only happens at startup.
375 if (i == NUM_CHANNELS)
380 /* Okay, in the less recent channel,
381 ** we will handle the new SFX.
382 ** Set pointer to raw data.
384 channels[slot] = (uchar*) S_sfx[id].data;
385 /* Set pointer to end of raw data. */
386 channelsend[slot] = channels[slot] + lengths[id];
388 /* Reset current handle number, limited to 0..100. */
392 /* Assign current handle number.
393 ** Preserved so sounds could be stopped (unused).
395 channelhandles[slot] = rc = handlenums++;
398 ** Kinda getting the impression this is never used.
400 channelstep[slot] = step;
402 channelstepremainder[slot] = 0;
403 /* Should be gametic, I presume. */
404 channelstart[slot] = gametic;
406 /* Separation, that is, orientation/stereo.
407 ** range is : 1 - 256
411 /* Per left/right channel.
413 ** adjust volume properly.
415 leftvol = vol - ((vol*sep*sep) >> 16); // /(256*256);
417 rightvol = vol - ((vol*sep*sep) >> 16);
419 /* Sanity check, clamp volume. */
420 if (rightvol < 0 || rightvol > 127)
421 I_Error("rightvol out of bounds");
422 if (leftvol < 0 || leftvol > 127)
423 I_Error("leftvol out of bounds");
425 /* Get the proper lookup table piece
426 ** for this volume level???
428 channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
429 channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
431 /* Preserve sound SFX id,
432 ** e.g. for avoiding duplicates of chainsaw.
433 channelids[slot] = id;
439 int I_StartSound(int id, int vol, int sep, int pitch, int priority)
442 id = addsfx(id, vol, steptable[pitch], sep);
446 void I_StopSound(int handle)
449 // printf("PORTME i_sound.c I_StopSound\n");
452 int I_SoundIsPlaying(int handle)
455 return gametic < handle;
458 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
460 /* I fail to see that this is used.
461 ** Would be using the handle to identify
462 ** on which channel the sound might be active,
463 ** and resetting the channel parameters.
465 USED(handle, vol, sep, pitch);
468 void I_InitMusic(void)
470 // printf("PORTME i_sound.c I_InitMusic\n");
473 void I_ShutdownMusic(void)
475 // printf("PORTME i_sound.c I_ShutdownMusic\n");
478 void I_SetMusicVolume(int volume)
481 // printf("PORTME i_sound.c I_SetMusicVolume\n");
484 void I_PauseSong(int handle)
487 // printf("PORTME i_sound.c I_PauseSong\n");
490 void I_ResumeSong(int handle)
493 // printf("PORTME i_sound.c I_ResumeSong\n");
496 int I_RegisterSong(void *data)
499 // printf("PORTME i_sound.c I_RegisterSong\n");
503 void I_PlaySong(int handle, int looping)
505 USED(handle, looping);
506 // printf("PORTME i_sound.c I_PlaySong\n");
509 void I_StopSong(int handle)
512 // printf("PORTME i_sound.c I_StopSong\n");
515 void I_UnRegisterSong(int handle)
518 // printf("PORTME i_sound.c I_UnregisterSong\n");