aboutsummaryrefslogtreecommitdiff
path: root/src/KINDLE/i_sound.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/KINDLE/i_sound.c')
-rw-r--r--src/KINDLE/i_sound.c534
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
73int snd_card = 1;
74int mus_card = 1;
75int detect_voices = 0; // God knows
76
77static boolean sound_inited = false;
78static boolean first_sound_init = true;
79
80// Needed for calling the actual sound output.
81static int SAMPLECOUNT= 512;
82#define MAX_CHANNELS 32
83
84// MWM 2000-01-08: Sample rate in samples/second
85int snd_samplerate=11025;
86
87// The actual output device.
88int audio_fd;
89
90typedef 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
113channel_info_t channelinfo[MAX_CHANNELS];
114
115// Pitch to stepping lookup, unused.
116int steptable[256];
117
118// Volume lookups.
119int vol_lookup[128*256];
120
121/* cph
122 * stopchan
123 * Stops a sound, unlocks the data
124 */
125
126static 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//
142static 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
163static 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
208void 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//
222void 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//
261int 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//
280int I_StartSound(int id, int channel, int vol, int sep, int pitch, int priority)
281{
282 return -1;
283}
284
285
286
287void 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
296boolean 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
306boolean 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
330static void I_UpdateSound(void *unused, int *stream, int len)
331{
332
333}
334
335void I_ShutdownSound(void)
336{
337 if (sound_inited) {
338
339 }
340}
341
342//static SDL_AudioSpec audio;
343
344void 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
362static Mix_Music *music[2] = { NULL, NULL };
363
364char* music_tmp = NULL; /* cph - name of music temporary file */
365
366#endif
367
368void 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
380void 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
402void 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
411extern int mus_pause_opt; // From m_misc.c
412
413void 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
428void 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
443void I_StopSong(int handle)
444{
445#ifdef HAVE_MIXER
446 Mix_FadeOutMusic(500);
447#endif
448}
449
450void 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
460int 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
503int 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
526void I_SetMusicVolume(int volume)
527{
528#ifdef HAVE_MIXER
529 Mix_VolumeMusic(volume*8);
530#endif
531}
532
533#endif /* HAVE_OWN_MUSIC */
534