5 #include "w_wad.h" // W_GetNumForName()
9 /* The number of internal mixing channels,
10 ** the samples calculated for each mixing step,
11 ** the size of the 16bit, 2 hardware channel (stereo)
12 ** mixing buffer, and the samplerate of the raw data.
15 /* Needed for calling the actual sound output. */
18 #define SAMPLECOUNT (AUDFREQ/TICRATE)
19 #define NUM_CHANNELS 8
21 /* The actual lengths of all sound effects. */
24 /* The actual output device. */
25 static int audio_fd = -1;
27 /* The global mixing buffer.
28 ** Basically, samples from all active internal channels
29 ** are modified and added, and stored in the buffer
30 ** that is submitted to the audio device.
32 uchar mixbuf[SAMPLECOUNT*4];
34 /* The channel step amount... */
35 uint channelstep[NUM_CHANNELS];
36 /* ... and a 0.16 bit remainder of last step. */
37 uint channelstepremainder[NUM_CHANNELS];
39 /* The channel data pointers, start and end. */
40 uchar* channels[NUM_CHANNELS];
41 uchar* channelsend[NUM_CHANNELS];
43 /* Time/gametic that the channel started playing,
44 ** used to determine oldest, which automatically
45 ** has lowest priority.
46 ** In case number of active sounds exceeds
47 ** available channels.
49 int channelstart[NUM_CHANNELS];
51 /* The sound in channel handles,
52 ** determined on registration,
53 ** might be used to unregister/stop/modify,
56 int channelhandles[NUM_CHANNELS];
58 /* SFX id of the playing sound effect.
59 ** Used to catch duplicates (like chainsaw).
61 int channelids[NUM_CHANNELS];
63 /* Pitch to stepping lookup, unused. */
67 int vol_lookup[128*256];
69 /* Hardware left and right channel volume lookup. */
70 int* channelleftvol_lookup[NUM_CHANNELS];
71 int* channelrightvol_lookup[NUM_CHANNELS];
73 extern boolean mus_paused;
75 static int mpfd[2] = {-1, -1};
77 static void* getsfx(char *sfxname, int *len)
87 /* Get the sound data from the WAD, allocate lump
89 sprintf(name, "ds%s", sfxname);
91 /* Now, there is a severe problem with the
92 ** sound handling, in it is not (yet/anymore)
93 ** gamemode aware. That means, sounds from
94 ** DOOM II will be requested even with DOOM
96 ** The sound list is wired into sounds.c,
97 ** which sets the external variable.
98 ** I do not do runtime patches to that
99 ** variable. Instead, we will use a
100 ** default sound for replacement.
102 if ( W_CheckNumForName(name) == -1 )
103 sfxlump = W_GetNumForName("dspistol");
105 sfxlump = W_GetNumForName(name);
107 size = W_LumpLength( sfxlump );
109 sfx = (uchar *)W_CacheLumpNum(sfxlump, PU_STATIC);
111 /* Pads the sound effect out to the mixing buffer size.
112 ** The original realloc would interfere with zone memory.
114 paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
116 /* Allocate from zone memory. */
117 paddedsfx = (uchar *)Z_Malloc(paddedsize+8, PU_STATIC, 0);
119 /* Now copy and pad. */
120 memcpy(paddedsfx, sfx, size);
121 for (i=size ; i<paddedsize+8 ; i++)
124 /* Remove the cached lump. */
127 /* Preserve padded length. */
130 /* Return allocated padded data. */
131 return (void *)(paddedsfx + 8);
134 void I_InitSound(void)
138 audio_fd = open("/dev/audio", OWRITE);
140 fprint(2, "I_InitSound: disabling sound: %r\n");
144 /* Initialize external data (all sounds) at start, keep static. */
145 for (i=1 ; i<NUMSFX ; i++)
149 /* Load data from WAD file. */
150 S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
153 /* Alias? Example is the chaingun sound linked to pistol. */
154 for (i=1 ; i<NUMSFX ; i++)
158 /* Previously loaded already? */
159 S_sfx[i].data = S_sfx[i].link->data;
160 lengths[i] = lengths[S_sfx[i].link - S_sfx];
165 /* This function loops all active (internal) sound
166 ** channels, retrieves a given number of samples
167 ** from the raw sound data, modifies it according
168 ** to the current (internal) channel parameters,
169 ** mixes the per-channel samples into the global
170 ** mixbuffer, clamping it to the allowed range,
171 ** and sets up everything for transferring the
172 ** contents of the mixbuffer to the (two)
173 ** hardware channels (left and right, that is).
175 ** This function currently supports only 16bit.
177 void I_UpdateSound(void)
184 memset(mixbuf, 0, sizeof mixbuf);
185 if(mpfd[0]>=0 && !mus_paused && readn(mpfd[0], mixbuf, sizeof mixbuf) < 0){
186 fprint(2, "I_UpdateSound: disabling music: %r\n");
190 while(p < mixbuf + sizeof mixbuf){
193 for(i=0; i<NUM_CHANNELS; i++){
194 if(channels[i] == nil)
197 l += channelleftvol_lookup[i][v];
198 r += channelrightvol_lookup[i][v];
199 channelstepremainder[i] += channelstep[i];
200 channels[i] += channelstepremainder[i] >> 16;
201 channelstepremainder[i] &= 0xffff;
202 if(channels[i] >= channelsend[i])
205 for(i=0; i<AUDFREQ/SFXFREQ; i++, p+=4){
206 v = (short)(p[1] << 8 | p[0]);
207 v = v * snd_MusicVolume / 15;
216 v = (short)(p[3] << 8 | p[2]);
217 v = v * snd_MusicVolume / 15;
227 if(snd_SfxVolume|snd_MusicVolume)
228 write(audio_fd, mixbuf, sizeof mixbuf);
231 void I_ShutdownSound(void)
239 void I_SetChannels(void)
241 /* Init internal lookups (raw data, mixing buffer, channels).
242 ** This function sets up internal lookups used during
243 ** the mixing process.
248 int *steptablemid = steptable + 128;
250 /* This table provides step widths for pitch parameters.
251 ** I fail to see that this is currently used. */
252 for (i=-128 ; i<128 ; i++)
253 steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
255 /* Generates volume lookup tables
256 ** which also turn the unsigned samples
257 ** into signed samples.
259 for (i=0 ; i<128 ; i++)
260 for (j=0 ; j<256 ; j++)
261 vol_lookup[i*256+j] = (i*(j-128)*256)/127;
264 int I_GetSfxLumpNum(sfxinfo_t *sfxinfo)
267 sprintf(namebuf, "ds%s", sfxinfo->name);
268 return W_GetNumForName(namebuf);
271 /* This function adds a sound to the
272 ** list of currently active sounds,
273 ** which is maintained as a given number
274 ** (eight, usually) of internal channels.
278 addsfx(int id, int vol, int step, int sep)
280 static unsigned short handlenums = 0;
283 int oldest = gametic;
289 /* Chainsaw troubles.
290 ** Play these sound effects only one at a time. */
291 if ( id == sfx_sawup ||
298 /* Loop all channels, check. */
299 for (i=0 ; i < NUM_CHANNELS ; i++)
301 /* Active and using the same SFX? */
302 if( (channels[i]) && (channelids[i] == id) )
306 /* We are sure that iff,
307 ** there will only be one. */
313 /* Loop all channels to find oldest SFX. */
314 for (i=0 ; (i<NUM_CHANNELS) && (channels[i]) ; i++)
316 if(channelstart[i] < oldest)
319 oldest = channelstart[i];
323 /* Tales from the cryptic.
324 ** If we found a channel, fine.
325 ** If not, we simply overwrite the first one, 0.
326 ** Probably only happens at startup.
328 if (i == NUM_CHANNELS)
333 /* Okay, in the less recent channel,
334 ** we will handle the new SFX.
335 ** Set pointer to raw data.
337 channels[slot] = (uchar*) S_sfx[id].data;
338 /* Set pointer to end of raw data. */
339 channelsend[slot] = channels[slot] + lengths[id];
341 /* Reset current handle number, limited to 0..100. */
345 /* Assign current handle number.
346 ** Preserved so sounds could be stopped (unused).
348 channelhandles[slot] = rc = handlenums++;
351 ** Kinda getting the impression this is never used.
353 channelstep[slot] = step;
355 channelstepremainder[slot] = 0;
356 /* Should be gametic, I presume. */
357 channelstart[slot] = gametic;
359 /* Separation, that is, orientation/stereo.
360 ** range is : 1 - 256
364 /* Per left/right channel.
366 ** adjust volume properly.
368 leftvol = vol - ((vol*sep*sep) >> 16); // /(256*256);
370 rightvol = vol - ((vol*sep*sep) >> 16);
372 /* Sanity check, clamp volume. */
373 if (rightvol < 0 || rightvol > 127)
374 I_Error("rightvol out of bounds");
375 if (leftvol < 0 || leftvol > 127)
376 I_Error("leftvol out of bounds");
378 /* Get the proper lookup table piece
379 ** for this volume level???
381 channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
382 channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
384 /* Preserve sound SFX id,
385 ** e.g. for avoiding duplicates of chainsaw.
387 channelids[slot] = id;
393 int I_StartSound(int id, int vol, int sep, int pitch, int)
397 id = addsfx(id, vol, steptable[pitch], sep);
401 void I_StopSound(int handle)
404 // printf("PORTME i_sound.c I_StopSound\n");
407 int I_SoundIsPlaying(int handle)
410 return gametic < handle;
413 void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
415 /* I fail to see that this is used.
416 ** Would be using the handle to identify
417 ** on which channel the sound might be active,
418 ** and resetting the channel parameters.
420 USED(handle, vol, sep, pitch);
423 void I_InitMusic(void)
427 void I_ShutdownMusic(void)
436 void I_SetMusicVolume(int)
440 void I_PauseSong(int)
444 void I_ResumeSong(int)
448 void I_PlaySong(musicinfo_t *m, int loop)
453 if(M_CheckParm("-nomusic") || audio_fd < 0)
458 switch(rfork(RFPROC|RFFDG|RFNAMEG)){
460 fprint(2, "I_PlaySong: %r\n");
464 for(n=3; n<20; n++) close(n);
465 snprint(name, sizeof(name), "/mnt/wad/d_%s", m->name);
466 if(bind("/fd/1", "/dev/audio", MREPL) < 0)
467 sysfatal("bind: %r");
468 while(loop && fork() > 0){
469 if(waitpid() < 0 || write(1, "", 0) < 0)
472 execl("/bin/dmus", "dmus", name, m->name, nil);
473 execl("/bin/play", "play", name, nil);
474 sysfatal("execl: %r");