diff options
Diffstat (limited to 'src/KINDLE/i_sound.c')
-rw-r--r-- | src/KINDLE/i_sound.c | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/src/KINDLE/i_sound.c b/src/KINDLE/i_sound.c new file mode 100644 index 0000000..d020313 --- /dev/null +++ b/src/KINDLE/i_sound.c | |||
@@ -0,0 +1,534 @@ | |||
1 | /* Emacs style mode select -*- C++ -*- | ||
2 | *----------------------------------------------------------------------------- | ||
3 | * | ||
4 | * | ||
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 | ||
11 | * Copyright 2005, 2006 by | ||
12 | * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
27 | * 02111-1307, USA. | ||
28 | * | ||
29 | * DESCRIPTION: | ||
30 | * System interface for sound. | ||
31 | * | ||
32 | *----------------------------------------------------------------------------- | ||
33 | */ | ||
34 | |||
35 | #ifdef HAVE_CONFIG_H | ||
36 | #include "config.h" | ||
37 | #endif | ||
38 | #ifdef HAVE_LIBSDL_MIXER | ||
39 | #define HAVE_MIXER | ||
40 | #endif | ||
41 | #include <math.h> | ||
42 | #ifdef HAVE_UNISTD_H | ||
43 | #include <unistd.h> | ||
44 | #endif | ||
45 | |||
46 | #ifdef HAVE_MIXER | ||
47 | #include "SDL_mixer.h" | ||
48 | #endif | ||
49 | |||
50 | #include "z_zone.h" | ||
51 | |||
52 | #include "m_swap.h" | ||
53 | #include "i_sound.h" | ||
54 | #include "m_argv.h" | ||
55 | #include "m_misc.h" | ||
56 | #include "w_wad.h" | ||
57 | #include "lprintf.h" | ||
58 | #include "s_sound.h" | ||
59 | |||
60 | #include "doomdef.h" | ||
61 | #include "doomstat.h" | ||
62 | #include "doomtype.h" | ||
63 | |||
64 | #include "d_main.h" | ||
65 | |||
66 | // The number of internal mixing channels, | ||
67 | // the samples calculated for each mixing step, | ||
68 | // the size of the 16bit, 2 hardware channel (stereo) | ||
69 | // mixing buffer, and the samplerate of the raw data. | ||
70 | |||
71 | // Variables used by Boom from Allegro | ||
72 | // created here to avoid changes to core Boom files | ||
73 | int snd_card = 1; | ||
74 | int mus_card = 1; | ||
75 | int detect_voices = 0; // God knows | ||
76 | |||
77 | static boolean sound_inited = false; | ||
78 | static boolean first_sound_init = true; | ||
79 | |||
80 | // Needed for calling the actual sound output. | ||
81 | static int SAMPLECOUNT= 512; | ||
82 | #define MAX_CHANNELS 32 | ||
83 | |||
84 | // MWM 2000-01-08: Sample rate in samples/second | ||
85 | int snd_samplerate=11025; | ||
86 | |||
87 | // The actual output device. | ||
88 | int audio_fd; | ||
89 | |||
90 | typedef struct { | ||
91 | // SFX id of the playing sound effect. | ||
92 | // Used to catch duplicates (like chainsaw). | ||
93 | int id; | ||
94 | // The channel step amount... | ||
95 | unsigned int step; | ||
96 | // ... and a 0.16 bit remainder of last step. | ||
97 | unsigned int stepremainder; | ||
98 | unsigned int samplerate; | ||
99 | // The channel data pointers, start and end. | ||
100 | const unsigned char* data; | ||
101 | const unsigned char* enddata; | ||
102 | // Time/gametic that the channel started playing, | ||
103 | // used to determine oldest, which automatically | ||
104 | // has lowest priority. | ||
105 | // In case number of active sounds exceeds | ||
106 | // available channels. | ||
107 | int starttime; | ||
108 | // Hardware left and right channel volume lookup. | ||
109 | int *leftvol_lookup; | ||
110 | int *rightvol_lookup; | ||
111 | } channel_info_t; | ||
112 | |||
113 | channel_info_t channelinfo[MAX_CHANNELS]; | ||
114 | |||
115 | // Pitch to stepping lookup, unused. | ||
116 | int steptable[256]; | ||
117 | |||
118 | // Volume lookups. | ||
119 | int vol_lookup[128*256]; | ||
120 | |||
121 | /* cph | ||
122 | * stopchan | ||
123 | * Stops a sound, unlocks the data | ||
124 | */ | ||
125 | |||
126 | static void stopchan(int i) | ||
127 | { | ||
128 | if (channelinfo[i].data) /* cph - prevent excess unlocks */ | ||
129 | { | ||
130 | channelinfo[i].data=NULL; | ||
131 | W_UnlockLumpNum(S_sfx[channelinfo[i].id].lumpnum); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | // | ||
136 | // This function adds a sound to the | ||
137 | // list of currently active sounds, | ||
138 | // which is maintained as a given number | ||
139 | // (eight, usually) of internal channels. | ||
140 | // Returns a handle. | ||
141 | // | ||
142 | static int addsfx(int sfxid, int channel, const unsigned char* data, size_t len) | ||
143 | { | ||
144 | stopchan(channel); | ||
145 | |||
146 | channelinfo[channel].data = data; | ||
147 | /* Set pointer to end of raw data. */ | ||
148 | channelinfo[channel].enddata = channelinfo[channel].data + len - 1; | ||
149 | channelinfo[channel].samplerate = (channelinfo[channel].data[3]<<8)+channelinfo[channel].data[2]; | ||
150 | channelinfo[channel].data += 8; /* Skip header */ | ||
151 | |||
152 | channelinfo[channel].stepremainder = 0; | ||
153 | // Should be gametic, I presume. | ||
154 | channelinfo[channel].starttime = gametic; | ||
155 | |||
156 | // Preserve sound SFX id, | ||
157 | // e.g. for avoiding duplicates of chainsaw. | ||
158 | channelinfo[channel].id = sfxid; | ||
159 | |||
160 | return channel; | ||
161 | } | ||
162 | |||
163 | static void updateSoundParams(int handle, int volume, int seperation, int pitch) | ||
164 | { | ||
165 | int slot = handle; | ||
166 | int rightvol; | ||
167 | int leftvol; | ||
168 | int step = steptable[pitch]; | ||
169 | |||
170 | #ifdef RANGECHECK | ||
171 | if ((handle < 0) || (handle >= MAX_CHANNELS)) | ||
172 | I_Error("I_UpdateSoundParams: handle out of range"); | ||
173 | #endif | ||
174 | // Set stepping | ||
175 | // MWM 2000-12-24: Calculates proportion of channel samplerate | ||
176 | // to global samplerate for mixing purposes. | ||
177 | // Patched to shift left *then* divide, to minimize roundoff errors | ||
178 | // as well as to use SAMPLERATE as defined above, not to assume 11025 Hz | ||
179 | if (pitched_sounds) | ||
180 | channelinfo[slot].step = step + (((channelinfo[slot].samplerate<<16)/snd_samplerate)-65536); | ||
181 | else | ||
182 | channelinfo[slot].step = ((channelinfo[slot].samplerate<<16)/snd_samplerate); | ||
183 | |||
184 | // Separation, that is, orientation/stereo. | ||
185 | // range is: 1 - 256 | ||
186 | seperation += 1; | ||
187 | |||
188 | // Per left/right channel. | ||
189 | // x^2 seperation, | ||
190 | // adjust volume properly. | ||
191 | leftvol = volume - ((volume*seperation*seperation) >> 16); | ||
192 | seperation = seperation - 257; | ||
193 | rightvol= volume - ((volume*seperation*seperation) >> 16); | ||
194 | |||
195 | // Sanity check, clamp volume. | ||
196 | if (rightvol < 0 || rightvol > 127) | ||
197 | I_Error("rightvol out of bounds"); | ||
198 | |||
199 | if (leftvol < 0 || leftvol > 127) | ||
200 | I_Error("leftvol out of bounds"); | ||
201 | |||
202 | // Get the proper lookup table piece | ||
203 | // for this volume level??? | ||
204 | channelinfo[slot].leftvol_lookup = &vol_lookup[leftvol*256]; | ||
205 | channelinfo[slot].rightvol_lookup = &vol_lookup[rightvol*256]; | ||
206 | } | ||
207 | |||
208 | void I_UpdateSoundParams(int handle, int volume, int seperation, int pitch) | ||
209 | { | ||
210 | |||
211 | } | ||
212 | |||
213 | // | ||
214 | // SFX API | ||
215 | // Note: this was called by S_Init. | ||
216 | // However, whatever they did in the | ||
217 | // old DPMS based DOS version, this | ||
218 | // were simply dummies in the Linux | ||
219 | // version. | ||
220 | // See soundserver initdata(). | ||
221 | // | ||
222 | void I_SetChannels(void) | ||
223 | { | ||
224 | // Init internal lookups (raw data, mixing buffer, channels). | ||
225 | // This function sets up internal lookups used during | ||
226 | // the mixing process. | ||
227 | int i; | ||
228 | int j; | ||
229 | |||
230 | int* steptablemid = steptable + 128; | ||
231 | |||
232 | // Okay, reset internal mixing channels to zero. | ||
233 | for (i=0; i<MAX_CHANNELS; i++) | ||
234 | { | ||
235 | memset(&channelinfo[i],0,sizeof(channel_info_t)); | ||
236 | } | ||
237 | |||
238 | // This table provides step widths for pitch parameters. | ||
239 | // I fail to see that this is currently used. | ||
240 | for (i=-128 ; i<128 ; i++) | ||
241 | steptablemid[i] = (int)(pow(1.2, ((double)i/(64.0*snd_samplerate/11025)))*65536.0); | ||
242 | |||
243 | |||
244 | // Generates volume lookup tables | ||
245 | // which also turn the unsigned samples | ||
246 | // into signed samples. | ||
247 | for (i=0 ; i<128 ; i++) | ||
248 | for (j=0 ; j<256 ; j++) | ||
249 | { | ||
250 | // proff - made this a little bit softer, because with | ||
251 | // full volume the sound clipped badly | ||
252 | vol_lookup[i*256+j] = (i*(j-128)*256)/191; | ||
253 | //vol_lookup[i*256+j] = (i*(j-128)*256)/127; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | // | ||
258 | // Retrieve the raw data lump index | ||
259 | // for a given SFX name. | ||
260 | // | ||
261 | int I_GetSfxLumpNum(sfxinfo_t* sfx) | ||
262 | { | ||
263 | char namebuf[9]; | ||
264 | sprintf(namebuf, "ds%s", sfx->name); | ||
265 | return W_GetNumForName(namebuf); | ||
266 | } | ||
267 | |||
268 | // | ||
269 | // Starting a sound means adding it | ||
270 | // to the current list of active sounds | ||
271 | // in the internal channels. | ||
272 | // As the SFX info struct contains | ||
273 | // e.g. a pointer to the raw data, | ||
274 | // it is ignored. | ||
275 | // As our sound handling does not handle | ||
276 | // priority, it is ignored. | ||
277 | // Pitching (that is, increased speed of playback) | ||
278 | // is set, but currently not used by mixing. | ||
279 | // | ||
280 | int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority) | ||
281 | { | ||
282 | return -1; | ||
283 | } | ||
284 | |||
285 | |||
286 | |||
287 | void I_StopSound (int handle) | ||
288 | { | ||
289 | #ifdef RANGECHECK | ||
290 | if ((handle < 0) || (handle >= MAX_CHANNELS)) | ||
291 | I_Error("I_StopSound: handle out of range"); | ||
292 | #endif | ||
293 | } | ||
294 | |||
295 | |||
296 | boolean I_SoundIsPlaying(int handle) | ||
297 | { | ||
298 | #ifdef RANGECHECK | ||
299 | if ((handle < 0) || (handle >= MAX_CHANNELS)) | ||
300 | I_Error("I_SoundIsPlaying: handle out of range"); | ||
301 | #endif | ||
302 | return channelinfo[handle].data != NULL; | ||
303 | } | ||
304 | |||
305 | |||
306 | boolean I_AnySoundStillPlaying(void) | ||
307 | { | ||
308 | boolean result = false; | ||
309 | int i; | ||
310 | |||
311 | for (i=0; i<MAX_CHANNELS; i++) | ||
312 | result |= channelinfo[i].data != NULL; | ||
313 | |||
314 | return result; | ||
315 | } | ||
316 | |||
317 | |||
318 | // | ||
319 | // This function loops all active (internal) sound | ||
320 | // channels, retrieves a given number of samples | ||
321 | // from the raw sound data, modifies it according | ||
322 | // to the current (internal) channel parameters, | ||
323 | // mixes the per channel samples into the given | ||
324 | // mixing buffer, and clamping it to the allowed | ||
325 | // range. | ||
326 | // | ||
327 | // This function currently supports only 16bit. | ||
328 | // | ||
329 | |||
330 | static void I_UpdateSound(void *unused, int *stream, int len) | ||
331 | { | ||
332 | |||
333 | } | ||
334 | |||
335 | void I_ShutdownSound(void) | ||
336 | { | ||
337 | if (sound_inited) { | ||
338 | |||
339 | } | ||
340 | } | ||
341 | |||
342 | //static SDL_AudioSpec audio; | ||
343 | |||
344 | void I_InitSound(void) | ||
345 | { | ||
346 | |||
347 | } | ||
348 | |||
349 | |||
350 | |||
351 | |||
352 | // | ||
353 | // MUSIC API. | ||
354 | // | ||
355 | |||
356 | #ifndef HAVE_OWN_MUSIC | ||
357 | |||
358 | #ifdef HAVE_MIXER | ||
359 | #include "SDL_mixer.h" | ||
360 | #include "mmus2mid.h" | ||
361 | |||
362 | static Mix_Music *music[2] = { NULL, NULL }; | ||
363 | |||
364 | char* music_tmp = NULL; /* cph - name of music temporary file */ | ||
365 | |||
366 | #endif | ||
367 | |||
368 | void I_ShutdownMusic(void) | ||
369 | { | ||
370 | #ifdef HAVE_MIXER | ||
371 | if (music_tmp) { | ||
372 | unlink(music_tmp); | ||
373 | lprintf(LO_DEBUG, "I_ShutdownMusic: removing %s\n", music_tmp); | ||
374 | free(music_tmp); | ||
375 | music_tmp = NULL; | ||
376 | } | ||
377 | #endif | ||
378 | } | ||
379 | |||
380 | void I_InitMusic(void) | ||
381 | { | ||
382 | #ifdef HAVE_MIXER | ||
383 | if (!music_tmp) { | ||
384 | #ifndef _WIN32 | ||
385 | music_tmp = strdup("/tmp/prboom-music-XXXXXX"); | ||
386 | { | ||
387 | int fd = mkstemp(music_tmp); | ||
388 | if (fd<0) { | ||
389 | lprintf(LO_ERROR, "I_InitMusic: failed to create music temp file %s", music_tmp); | ||
390 | free(music_tmp); return; | ||
391 | } else | ||
392 | close(fd); | ||
393 | } | ||
394 | #else /* !_WIN32 */ | ||
395 | music_tmp = strdup("doom.tmp"); | ||
396 | #endif | ||
397 | atexit(I_ShutdownMusic); | ||
398 | } | ||
399 | #endif | ||
400 | } | ||
401 | |||
402 | void I_PlaySong(int handle, int looping) | ||
403 | { | ||
404 | #ifdef HAVE_MIXER | ||
405 | if ( music[handle] ) { | ||
406 | Mix_FadeInMusic(music[handle], looping ? -1 : 0, 500); | ||
407 | } | ||
408 | #endif | ||
409 | } | ||
410 | |||
411 | extern int mus_pause_opt; // From m_misc.c | ||
412 | |||
413 | void I_PauseSong (int handle) | ||
414 | { | ||
415 | #ifdef HAVE_MIXER | ||
416 | switch(mus_pause_opt) { | ||
417 | case 0: | ||
418 | I_StopSong(handle); | ||
419 | break; | ||
420 | case 1: | ||
421 | Mix_PauseMusic(); | ||
422 | break; | ||
423 | } | ||
424 | #endif | ||
425 | // Default - let music continue | ||
426 | } | ||
427 | |||
428 | void I_ResumeSong (int handle) | ||
429 | { | ||
430 | #ifdef HAVE_MIXER | ||
431 | switch(mus_pause_opt) { | ||
432 | case 0: | ||
433 | I_PlaySong(handle,1); | ||
434 | break; | ||
435 | case 1: | ||
436 | Mix_ResumeMusic(); | ||
437 | break; | ||
438 | } | ||
439 | #endif | ||
440 | /* Otherwise, music wasn't stopped */ | ||
441 | } | ||
442 | |||
443 | void I_StopSong(int handle) | ||
444 | { | ||
445 | #ifdef HAVE_MIXER | ||
446 | Mix_FadeOutMusic(500); | ||
447 | #endif | ||
448 | } | ||
449 | |||
450 | void I_UnRegisterSong(int handle) | ||
451 | { | ||
452 | #ifdef HAVE_MIXER | ||
453 | if ( music[handle] ) { | ||
454 | Mix_FreeMusic(music[handle]); | ||
455 | music[handle] = NULL; | ||
456 | } | ||
457 | #endif | ||
458 | } | ||
459 | |||
460 | int I_RegisterSong(const void *data, size_t len) | ||
461 | { | ||
462 | #ifdef HAVE_MIXER | ||
463 | MIDI *mididata; | ||
464 | FILE *midfile; | ||
465 | |||
466 | if ( len < 32 ) | ||
467 | return 0; // the data should at least as big as the MUS header | ||
468 | if ( music_tmp == NULL ) | ||
469 | return 0; | ||
470 | midfile = fopen(music_tmp, "wb"); | ||
471 | if ( midfile == NULL ) { | ||
472 | lprintf(LO_ERROR,"Couldn't write MIDI to %s\n", music_tmp); | ||
473 | return 0; | ||
474 | } | ||
475 | /* Convert MUS chunk to MIDI? */ | ||
476 | if ( memcmp(data, "MUS", 3) == 0 ) | ||
477 | { | ||
478 | UBYTE *mid; | ||
479 | int midlen; | ||
480 | |||
481 | mididata = malloc(sizeof(MIDI)); | ||
482 | mmus2mid(data, mididata, 89, 0); | ||
483 | MIDIToMidi(mididata,&mid,&midlen); | ||
484 | M_WriteFile(music_tmp,mid,midlen); | ||
485 | free(mid); | ||
486 | free_mididata(mididata); | ||
487 | free(mididata); | ||
488 | } else { | ||
489 | fwrite(data, len, 1, midfile); | ||
490 | } | ||
491 | fclose(midfile); | ||
492 | |||
493 | music[0] = Mix_LoadMUS(music_tmp); | ||
494 | if ( music[0] == NULL ) { | ||
495 | lprintf(LO_ERROR,"Couldn't load MIDI from %s: %s\n", music_tmp, Mix_GetError()); | ||
496 | } | ||
497 | #endif | ||
498 | return (0); | ||
499 | } | ||
500 | |||
501 | // cournia - try to load a music file into SDL_Mixer | ||
502 | // returns true if could not load the file | ||
503 | int I_RegisterMusic( const char* filename, musicinfo_t *song ) | ||
504 | { | ||
505 | #ifdef HAVE_MIXER | ||
506 | if (!filename) return 1; | ||
507 | if (!song) return 1; | ||
508 | music[0] = Mix_LoadMUS(filename); | ||
509 | if (music[0] == NULL) | ||
510 | { | ||
511 | lprintf(LO_WARN,"Couldn't load music from %s: %s\nAttempting to load default MIDI music.\n", filename, Mix_GetError()); | ||
512 | return 1; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | song->data = 0; | ||
517 | song->handle = 0; | ||
518 | song->lumpnum = 0; | ||
519 | return 0; | ||
520 | } | ||
521 | #else | ||
522 | return 1; | ||
523 | #endif | ||
524 | } | ||
525 | |||
526 | void I_SetMusicVolume(int volume) | ||
527 | { | ||
528 | #ifdef HAVE_MIXER | ||
529 | Mix_VolumeMusic(volume*8); | ||
530 | #endif | ||
531 | } | ||
532 | |||
533 | #endif /* HAVE_OWN_MUSIC */ | ||
534 | |||