FS#8961 - Anti-Aliased Fonts.
[kugel-rb.git] / apps / plugins / doom / i_sound.c
blob35cecd8abb94c5e2a7a28f674e02d4214364612c
1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
5 * PrBoom a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * 02111-1307, USA.
27 * DESCRIPTION:
28 * System interface for sound.
30 *-----------------------------------------------------------------------------
33 #include "z_zone.h"
35 #include "i_system.h"
36 #include "i_sound.h"
37 #include "m_argv.h"
38 #include "m_misc.h"
39 #include "w_wad.h"
40 #include "m_swap.h"
41 #include "d_main.h"
42 #include "doomdef.h"
43 #include "rockmacros.h"
45 // The number of internal mixing channels,
46 // the samples calculated for each mixing step,
47 // the size of the 16bit, 2 hardware channel (stereo)
48 // mixing buffer, and the samplerate of the raw data.
50 // Needed for calling the actual sound output.
51 #define SAMPLECOUNT 128
53 #define NUM_CHANNELS 24
54 // It is 2 for 16bit, and 2 for two channels.
55 #define BUFMUL 2
56 #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL)
58 #ifdef HW_HAVE_11
59 #define SAMPLERATE SAMPR_11 // 44100 22050 11025
60 #else
61 #define SAMPLERATE SAMPR_44 // 44100 22050 11025
62 #endif
63 #define SAMPLESIZE 2 // 16bit
65 // The global mixing buffer.
66 // Basically, samples from all active internal channels
67 // are modifed and added, and stored in the buffer
68 // that is submitted to the audio device.
69 signed short *mixbuffer;
70 /* Don't place this in IRAM!
71 * Sound playback uses DMA, and not all IRAM is DMA capable on coldfire. */
73 typedef struct {
74 // SFX id of the playing sound effect.
75 // Used to catch duplicates (like chainsaw).
76 int id;
77 // The channel step amount...
78 unsigned int step;
79 // ... and a 0.16 bit remainder of last step.
80 unsigned int stepremainder;
81 unsigned int samplerate;
82 // The channel data pointers, start and end.
83 const unsigned char* data;
84 const unsigned char* enddata;
85 // Time/gametic that the channel started playing,
86 // used to determine oldest, which automatically
87 // has lowest priority.
88 // In case number of active sounds exceeds
89 // available channels.
90 int starttime;
91 // Hardware left and right channel volume lookup.
92 int *leftvol_lookup;
93 int *rightvol_lookup;
94 } channel_info_t;
96 channel_info_t channelinfo[NUM_CHANNELS] IBSS_ATTR;
98 int *vol_lookup; // Volume lookups.
100 int *steptable; // Pitch to stepping lookup. (Not setup properly right now)
102 static inline int32_t clip_sample16(int32_t sample)
104 if ((int16_t)sample != sample)
105 sample = 0x7fff ^ (sample >> 31);
106 return sample;
110 // This function loads the sound data from the WAD lump for single sound.
111 // It is used to cache all the sounddata at startup.
113 void* getsfx( const char* sfxname )
115 unsigned char* sfx;
116 unsigned char* paddedsfx;
117 int size;
118 char name[20];
119 int sfxlump;
121 // Get the sound data from the WAD, allocate lump
122 // in zone memory.
123 snprintf(name, sizeof(name), "ds%s", sfxname);
125 // Now, there is a severe problem with the sound handling, in it is not
126 // (yet/anymore) gamemode aware. That means, sounds from DOOM II will be
127 // requested even with DOOM shareware.
128 // The sound list is wired into sounds.c, which sets the external variable.
129 // I do not do runtime patches to that variable. Instead, we will use a
130 // default sound for replacement.
131 if ( W_CheckNumForName(name) == -1 )
132 sfxlump = W_GetNumForName("dspistol");
133 else
134 sfxlump = W_GetNumForName(name);
136 size = W_LumpLength( sfxlump );
138 sfx = (unsigned char*)W_CacheLumpNum( sfxlump);
140 paddedsfx = (unsigned char*)malloc( size ); // Allocate from memory.
141 memcpy(paddedsfx, sfx, size ); // Now copy and pad.
142 W_UnlockLumpNum(sfxlump); // Remove the cached lump.
144 return (void *) (paddedsfx); // Return allocated data.
147 /* cph
148 * stopchan
149 * Stops a sound
151 static void stopchan(int i)
153 channelinfo[i].data=NULL;
157 // This function adds a sound to the
158 // list of currently active sounds,
159 // which is maintained as a given number
160 // (eight, usually) of internal channels.
161 // Returns a handle.
163 int addsfx( int sfxid, int channel)
165 stopchan(channel);
167 // We will handle the new SFX.
168 // Set pointer to raw data.
170 int lump = S_sfx[sfxid].lumpnum;
171 size_t len = W_LumpLength(lump);
173 /* Find padded length */
174 len -= 8;
175 channelinfo[channel].data = S_sfx[sfxid].data;
177 /* Set pointer to end of raw data. */
178 channelinfo[channel].enddata = channelinfo[channel].data + len - 1;
179 channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2];
180 channelinfo[channel].data += 8; /* Skip header */
183 channelinfo[channel].stepremainder = 0;
184 // Should be gametic, I presume.
185 channelinfo[channel].starttime = gametic;
187 // Preserve sound SFX id,
188 // e.g. for avoiding duplicates of chainsaw.
189 channelinfo[channel].id = sfxid;
191 return channel;
194 static void updateSoundParams(int handle, int volume, int seperation, int pitch)
196 int rightvol;
197 int leftvol;
198 int slot = handle;
199 int step = steptable[pitch];
200 #ifdef RANGECHECK
201 if (handle>=NUM_CHANNELS)
202 I_Error("I_UpdateSoundParams: handle out of range");
203 #endif
204 // Set stepping
205 // MWM 2000-12-24: Calculates proportion of channel samplerate
206 // to global samplerate for mixing purposes.
207 // Patched to shift left *then* divide, to minimize roundoff errors
208 // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz
209 if (pitched_sounds)
210 channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/SAMPLERATE)-65536);
211 else
212 channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/SAMPLERATE);
214 // Separation, that is, orientation/stereo.
215 // range is: 1 - 256
216 seperation += 1;
218 // Per left/right channel.
219 // x^2 seperation,
220 // adjust volume properly.
221 leftvol = volume - ((volume*seperation*seperation) >> 16);
222 seperation = seperation - 257;
223 rightvol= volume - ((volume*seperation*seperation) >> 16);
225 // Sanity check, clamp volume.
226 if (rightvol < 0 || rightvol > 127)
227 I_Error("rightvol out of bounds");
229 if (leftvol < 0 || leftvol > 127)
230 I_Error("leftvol out of bounds");
232 // Get the proper lookup table piece
233 // for this volume level???
234 channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256];
235 channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256];
238 void I_UpdateSoundParams(int handle, int volume, int seperation, int pitch)
240 updateSoundParams(handle, volume, seperation, pitch);
244 // SFX API
245 // Note: this was called by S_Init.
246 // However, whatever they did in the
247 // old DPMS based DOS version, this
248 // were simply dummies in the Linux
249 // version.
250 // See soundserver initdata().
252 void I_SetChannels()
254 // Init internal lookups (raw data, mixing buffer, channels).
255 // This function sets up internal lookups used during
256 // the mixing process.
257 int i;
258 int j;
259 int* steptablemid = steptable + 128;
261 // Okay, reset internal mixing channels to zero.
262 for (i=0; i<NUM_CHANNELS; i++)
263 memset(&channelinfo[i],0,sizeof(channel_info_t));
265 // This table provides step widths for pitch parameters.
266 for (i=-128 ; i<128 ; i++)
267 steptablemid[i]=2;
268 // steptablemid[i] = (int)(pow(1.2, ((double)i/(64.0*SAMPLERATE/11025)))*65536.0);
270 // Generates volume lookup tables
271 // which also turn the unsigned samples
272 // into signed samples.
273 for (i=0 ; i<128 ; i++)
274 for (j=0 ; j<256 ; j++)
275 vol_lookup[i*256+j] = 3*(i*(j-128)*256)/191;
278 void I_SetSfxVolume(int volume)
280 // Identical to DOS.
281 // Basically, this should propagate
282 // the menu/config file setting
283 // to the state variable used in
284 // the mixing.
285 snd_SfxVolume = volume;
288 // MUSIC API - dummy. Some code from DOS version.
289 void I_SetMusicVolume(int volume)
291 // Internal state variable.
292 snd_MusicVolume = volume;
293 // Now set volume on output device.
294 // Whatever( snd_MusciVolume );
298 // Retrieve the raw data lump index
299 // for a given SFX name.
301 int I_GetSfxLumpNum(sfxinfo_t* sfx)
303 char namebuf[9];
304 snprintf(namebuf, sizeof(namebuf), "ds%s", sfx->name);
305 return W_GetNumForName(namebuf);
309 // Starting a sound means adding it
310 // to the current list of active sounds
311 // in the internal channels.
312 // As the SFX info struct contains
313 // e.g. a pointer to the raw data,
314 // it is ignored.
315 // As our sound handling does not handle
316 // priority, it is ignored.
317 // Pitching (that is, increased speed of playback)
318 // is set, but currently not used by mixing.
320 int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority)
322 (void)priority;
323 int handle;
325 // Returns a handle (not used).
326 handle = addsfx(id,channel);
328 #ifdef RANGECHECK
329 if (handle>=NUM_CHANNELS)
330 I_Error("I_StartSound: handle out of range");
331 #endif
332 updateSoundParams(handle, vol, sep, pitch);
334 return handle;
337 void I_StopSound (int handle)
339 #ifdef RANGECHECK
340 if (handle>=NUM_CHANNELS)
341 I_Error("I_StopSound: handle out of range");
342 #endif
343 stopchan(handle);
346 int I_SoundIsPlaying(int handle)
348 #ifdef RANGECHECK
349 if (handle>=NUM_CHANNELS)
350 I_Error("I_SoundIsPlaying: handle out of range");
351 #endif
352 return channelinfo[handle].data != NULL;
356 // This function loops all active (internal) sound
357 // channels, retrieves a given number of samples
358 // from the raw sound data, modifies it according
359 // to the current (internal) channel parameters,
360 // mixes the per channel samples into the given
361 // mixing buffer, and clamping it to the allowed
362 // range.
364 // This function currently supports only 16bit.
367 void I_UpdateSound( void )
369 // Mix current sound data.
370 // Data, from raw sound, for right and left.
371 register unsigned char sample;
372 register int dl;
373 register int dr;
375 // Pointers in global mixbuffer, left, right, end.
376 signed short* leftout;
377 signed short* rightout;
378 signed short* leftend;
380 // Step in mixbuffer, left and right, thus two.
381 const int step = 2;
383 // Mixing channel index.
384 int chan;
386 // Left and right channel
387 // are in global mixbuffer, alternating.
388 leftout = mixbuffer;
389 rightout = mixbuffer +1;
391 // Determine end, for left channel only
392 // (right channel is implicit).
393 leftend = mixbuffer + SAMPLECOUNT*step;
395 // Mix sounds into the mixing buffer.
396 // Loop over step*SAMPLECOUNT,
397 // that is 512 values for two channels.
398 while (leftout != leftend)
400 // Reset left/right value.
401 dl = 0;
402 dr = 0;
404 // Love thy L2 chache - made this a loop.
405 // Now more channels could be set at compile time
406 // as well. Thus loop those channels.
407 for ( chan = 0; chan < NUM_CHANNELS; chan++ )
409 // Check channel, if active.
410 if (channelinfo[chan].data)
412 // Get the raw data from the channel.
413 sample = (((unsigned int)channelinfo[chan].data[0] * (0x10000 - channelinfo[chan].stepremainder))
414 + ((unsigned int)channelinfo[chan].data[1] * (channelinfo[chan].stepremainder))) >> 16;
415 // Add left and right part
416 // for this channel (sound)
417 // to the current data.
418 // Adjust volume accordingly.
419 dl += channelinfo[chan].leftvol_lookup[sample];
420 dr += channelinfo[chan].rightvol_lookup[sample];
421 // Increment index ???
422 channelinfo[chan].stepremainder += channelinfo[chan].step;
423 // MSB is next sample???
424 channelinfo[chan].data += channelinfo[chan].stepremainder >> 16;
425 // Limit to LSB???
426 channelinfo[chan].stepremainder &= 0xffff;
428 // Check whether we are done.
429 if (channelinfo[chan].data >= channelinfo[chan].enddata)
430 stopchan(chan);
434 // Clamp to range. Left hardware channel.
435 // Has been char instead of short.
436 // if (dl > 127) *leftout = 127;
437 // else if (dl < -128) *leftout = -128;
438 // else *leftout = dl;
440 *leftout = clip_sample16(dl);
442 // Same for right hardware channel.
443 *rightout = clip_sample16(dr);
445 // Increment current pointers in mixbuffer.
446 leftout += step;
447 rightout += step;
452 // This would be used to write out the mixbuffer
453 // during each game loop update.
454 // Updates sound buffer and audio device at runtime.
455 // It is called during Timer interrupt with SNDINTR.
456 // Mixing now done synchronous, and
457 // only output be done asynchronous?
460 void get_more(unsigned char** start, size_t* size)
462 I_UpdateSound(); // Force sound update
464 *start = (unsigned char*)(mixbuffer);
465 *size = SAMPLECOUNT*2*sizeof(short);
469 void I_SubmitSound(void)
471 if (!enable_sound)
472 return;
474 rb->pcm_play_data(&get_more, NULL, 0);
477 void I_ShutdownSound(void)
479 rb->pcm_play_stop();
480 rb->pcm_set_frequency(HW_SAMPR_DEFAULT); // 44100
483 void I_InitSound()
485 int i;
487 // Initialize external data (all sounds) at start, keep static.
488 printf( "I_InitSound: ");
489 rb->pcm_play_stop();
491 #if INPUT_SRC_CAPS != 0
492 /* Select playback */
493 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
494 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
495 #endif
496 rb->pcm_set_frequency(SAMPLERATE);
498 vol_lookup=malloc(128*256*sizeof(int));
500 mixbuffer=malloc(MIXBUFFERSIZE*sizeof(short));
501 steptable=malloc(256*sizeof(int));
503 for (i=1 ; i<NUMSFX ; i++)
505 if (!S_sfx[i].link) // Alias? Example is the chaingun sound linked to pistol.
506 S_sfx[i].data = getsfx( S_sfx[i].name); // Load data from WAD file.
507 else
508 S_sfx[i].data = S_sfx[i].link->data; // Previously loaded already?
511 printf( " pre-cached all sound data\n");
513 // Now initialize mixbuffer with zero.
514 for ( i = 0; i< MIXBUFFERSIZE; i++ )
515 mixbuffer[i] = 0;
517 // Finished initialization.
518 printf("I_InitSound: sound module ready\n");
522 // MUSIC API.
523 // Still no music done.
524 // Remains. Dummies.
526 void I_InitMusic(void) {
528 void I_ShutdownMusic(void) {
531 static int looping=0;
532 static int musicdies=-1;
534 void I_PlaySong(int handle, int looping)
536 // UNUSED.
537 handle = looping = 0;
538 musicdies = gametic + TICRATE*30;
541 void I_PauseSong (int handle)
543 // UNUSED.
544 handle = 0;
547 void I_ResumeSong (int handle)
549 // UNUSED.
550 handle = 0;
553 void I_StopSong(int handle)
555 // UNUSED.
556 handle = 0;
558 looping = 0;
559 musicdies = 0;
562 void I_UnRegisterSong(int handle)
564 // UNUSED.
565 handle = 0;
568 int I_RegisterSong(const void *data)
570 // UNUSED.
571 data = NULL;
573 return 1;
576 // Is the song playing?
577 int I_QrySongPlaying(int handle)
579 // UNUSED.
580 handle = 0;
581 return looping || musicdies > gametic;
584 // Interrupt handler.
585 void I_HandleSoundTimer( int ignore )
587 (void)ignore;
590 // Get the interrupt. Set duration in millisecs.
591 int I_SoundSetTimer( int duration_of_tick )
593 (void)duration_of_tick;
594 // Error is -1.
595 return 0;
598 // Remove the interrupt. Set duration to zero.
599 void I_SoundDelTimer(void)