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
28 * System interface for sound.
30 *-----------------------------------------------------------------------------
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.
56 #define MIXBUFFERSIZE (SAMPLECOUNT*BUFMUL)
59 #define SAMPLERATE SAMPR_11 // 44100 22050 11025
61 #define SAMPLERATE SAMPR_44 // 44100 22050 11025
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. */
74 // SFX id of the playing sound effect.
75 // Used to catch duplicates (like chainsaw).
77 // The channel step amount...
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.
91 // Hardware left and right channel volume lookup.
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);
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
)
116 unsigned char* paddedsfx
;
121 // Get the sound data from the WAD, allocate lump
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");
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.
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.
163 int addsfx( int sfxid
, int 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 */
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
;
194 static void updateSoundParams(int handle
, int volume
, int seperation
, int pitch
)
199 int step
= steptable
[pitch
];
201 if (handle
>=NUM_CHANNELS
)
202 I_Error("I_UpdateSoundParams: handle out of range");
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
210 channelinfo
[slot
].step
= step
+ (((channelinfo
[slot
].samplerate
<<16)/SAMPLERATE
)-65536);
212 channelinfo
[slot
].step
= ((channelinfo
[slot
].samplerate
<<16)/SAMPLERATE
);
214 // Separation, that is, orientation/stereo.
218 // Per left/right channel.
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
);
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
250 // See soundserver initdata().
254 // Init internal lookups (raw data, mixing buffer, channels).
255 // This function sets up internal lookups used during
256 // the mixing process.
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
++)
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
)
281 // Basically, this should propagate
282 // the menu/config file setting
283 // to the state variable used in
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
)
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,
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
)
325 // Returns a handle (not used).
326 handle
= addsfx(id
,channel
);
329 if (handle
>=NUM_CHANNELS
)
330 I_Error("I_StartSound: handle out of range");
332 updateSoundParams(handle
, vol
, sep
, pitch
);
337 void I_StopSound (int handle
)
340 if (handle
>=NUM_CHANNELS
)
341 I_Error("I_StopSound: handle out of range");
346 int I_SoundIsPlaying(int handle
)
349 if (handle
>=NUM_CHANNELS
)
350 I_Error("I_SoundIsPlaying: handle out of range");
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
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
;
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.
383 // Mixing channel index.
386 // Left and right channel
387 // are in global mixbuffer, alternating.
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.
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;
426 channelinfo
[chan
].stepremainder
&= 0xffff;
428 // Check whether we are done.
429 if (channelinfo
[chan
].data
>= channelinfo
[chan
].enddata
)
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.
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)
474 rb
->pcm_play_data(&get_more
, NULL
, 0);
477 void I_ShutdownSound(void)
480 rb
->pcm_set_frequency(HW_SAMPR_DEFAULT
); // 44100
487 // Initialize external data (all sounds) at start, keep static.
488 printf( "I_InitSound: ");
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
);
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.
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
++ )
517 // Finished initialization.
518 printf("I_InitSound: sound module ready\n");
523 // Still no music done.
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
)
537 handle
= looping
= 0;
538 musicdies
= gametic
+ TICRATE
*30;
541 void I_PauseSong (int handle
)
547 void I_ResumeSong (int handle
)
553 void I_StopSong(int handle
)
562 void I_UnRegisterSong(int handle
)
568 int I_RegisterSong(const void *data
)
576 // Is the song playing?
577 int I_QrySongPlaying(int handle
)
581 return looping
|| musicdies
> gametic
;
584 // Interrupt handler.
585 void I_HandleSoundTimer( int ignore
)
590 // Get the interrupt. Set duration in millisecs.
591 int I_SoundSetTimer( int duration_of_tick
)
593 (void)duration_of_tick
;
598 // Remove the interrupt. Set duration to zero.
599 void I_SoundDelTimer(void)