Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
298 serge 1
// Emacs style mode select   -*- C++ -*-
2
//-----------------------------------------------------------------------------
3
//
4
// $Id:$
5
//
6
// Copyright (C) 1993-1996 by id Software, Inc.
7
//
8
// This source is available for distribution and/or modification
9
// only under the terms of the DOOM Source Code License as
10
// published by id Software. All rights reserved.
11
//
12
// The source is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15
// for more details.
16
//
17
// $Log:$
18
//
19
// DESCRIPTION:  none
20
//
21
//-----------------------------------------------------------------------------
22
 
23
 
24
static const char
25
rcsid[] = "$Id: s_sound.c,v 1.6 1997/02/03 22:45:12 b1 Exp $";
26
 
27
 
28
#include 
29
#include 
30
 
31
#include "i_system.h"
32
#include "i_sound.h"
33
#include "sounds.h"
34
#include "s_sound.h"
35
 
36
#include "z_zone.h"
37
#include "m_random.h"
38
#include "w_wad.h"
39
 
40
#include "doomdef.h"
41
#include "p_local.h"
42
//#include "m_music.h"
43
 
44
#include "doomstat.h"
45
 
46
//#include "qmus2mid.h"
47
 
48
void WriteDebug(char *);
49
 
50
// Purpose?
51
const char snd_prefixen[]
52
= { 'P', 'P', 'A', 'S', 'S', 'S', 'M', 'M', 'M', 'S', 'S', 'S' };
53
 
54
#define S_MAX_VOLUME		127
55
 
56
// when to clip out sounds
57
// Does not fit the large outdoor areas.
58
#define S_CLIPPING_DIST		(1200*0x10000)
59
 
60
// Distance tp origin when sounds should be maxed out.
61
// This should relate to movement clipping resolution
62
// (see BLOCKMAP handling).
63
// Originally: (200*0x10000).
64
#define S_CLOSE_DIST		(160*0x10000)
65
 
66
 
67
#define S_ATTENUATOR		((S_CLIPPING_DIST-S_CLOSE_DIST)>>FRACBITS)
68
 
69
// Adjustable by menu.
70
#define NORM_VOLUME    		snd_MaxVolume
71
 
72
#define NORM_PITCH     		128
73
#define NORM_PRIORITY		64
74
#define NORM_SEP		128
75
 
76
#define S_PITCH_PERTURB		1
77
#define S_STEREO_SWING		(96*0x10000)
78
 
79
// percent attenuation from front to back
80
#define S_IFRACVOL		30
81
 
82
#define NA			0
83
//#define S_NUMCHANNELS		2
84
#define NUM_CHANNELS	16
85
 
86
// Current music/sfx card - index useless
87
//  w/o a reference LUT in a sound module.
88
extern int snd_MusicDevice;
89
extern int snd_SfxDevice;
90
// Config file? Same disclaimer as above.
91
extern int snd_DesiredMusicDevice;
92
extern int snd_DesiredSfxDevice;
93
 
94
 
95
typedef struct
96
{
97
    // sound information (if null, channel avail.)
98
    sfxinfo_t*	sfxinfo;
99
 
100
    // origin of sound
101
    void*	origin;
102
 
103
    // handle of the sound being played
104
    int		handle;
105
 
106
} channel_t;
107
 
108
 
109
// the set of channels available
110
static channel_t*	channels;
111
 
112
// These are not used, but should be (menu).
113
// Maximum volume of a sound effect.
114
// Internal default is max out of 0-15.
115
int 		snd_SfxVolume = 80;
116
 
117
// Maximum volume of music. Useless so far.
118
int 		snd_MusicVolume = 80;
119
 
120
 
121
 
122
// whether songs are mus_paused
123
static boolean		mus_paused;
124
 
125
// music currently being played
126
static musicinfo_t*	mus_playing=0;
127
 
128
// following is set
129
//  by the defaults code in M_misc:
130
// number of channels available
131
int			numChannels;
132
 
133
static int		nextcleanup;
134
 
135
 
136
 
137
//
138
// Internals.
139
//
140
int
141
S_getChannel
142
( void*		origin,
143
  sfxinfo_t*	sfxinfo,
144
  int       sfxid );
145
 
146
 
147
int
148
S_AdjustSoundParams
149
( mobj_t*	listener,
150
  mobj_t*	source,
151
  int*		vol,
152
  int*		sep,
153
  int*		pitch );
154
 
155
void S_StopChannel(int cnum);
156
 
157
 
158
 
159
//
160
// Initializes sound stuff, including volume
161
// Sets channels, SFX and music volume,
162
//  allocates channel buffer, sets S_sfx lookup.
163
//
164
void S_Init
165
( int		sfxVolume,
166
  int		musicVolume )
167
{
168
  int		i;
169
 
170
  printf("S_Init: default sfx volume %d\n", sfxVolume);
171
 
172
  I_CreateSound();
173
  numChannels = NUM_CHANNELS;
174
 
175
  // Whatever these did with DMX, these are rather dummies now.
176
  I_SetChannels();
177
 
178
  S_SetSfxVolume(sfxVolume);
179
  // No music with Linux - another dummy.
180
  S_SetMusicVolume(musicVolume);
181
 
182
  // Allocating the internal channels for mixing
183
  // (the maximum numer of sounds rendered
184
  // simultaneously) within zone memory.
185
  channels =
186
    (channel_t *) Z_Malloc(numChannels*sizeof(channel_t), PU_STATIC, 0);
187
 
188
  // Free all channels for use
189
  for (i=0 ; i
190
    channels[i].sfxinfo = 0;
191
 
192
  // no sounds are playing, and they are not mus_paused
193
  mus_paused = 0;
194
 
195
  // Note that sounds have not been cached (yet).
196
  for (i=1 ; i
197
    S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
198
}
199
 
200
//
201
// Per level startup code.
202
// Kills playing sounds at start of level,
203
//  determines music if any, changes music.
204
//
205
void S_Start(void)
206
{
207
  int cnum;
208
  int mnum;
209
 
210
  // kill all playing sounds at start of level
211
  //  (trust me - a good idea)
212
  for (cnum=0 ; cnum
213
    if (channels[cnum].sfxinfo)
214
      S_StopChannel(cnum);
215
 
216
  // start new music for the level
217
  mus_paused = 0;
218
 
219
  if (gamemode == commercial)
220
	  mnum = mus_runnin + gamemap - 1;
221
  else
222
  {
223
	  int spmus[]=
224
	  {
225
		  // Song - Who? - Where?
226
		mus_e3m4,	// American	e4m1
227
		mus_e3m2,	// Romero	e4m2
228
		mus_e3m3,	// Shawn	e4m3
229
		mus_e1m5,	// American	e4m4
230
		mus_e2m7,	// Tim 	e4m5
231
		mus_e2m4,	// Romero	e4m6
232
		mus_e2m6,	// J.Anderson	e4m7 CHIRON.WAD
233
		mus_e2m5,	// Shawn	e4m8
234
		mus_e1m9	// Tim		e4m9
235
	  };
236
 
237
	  if (gameepisode < 4)
238
		  mnum = mus_e1m1 + (gameepisode-1)*9 + gamemap-1;
239
	  else
240
		  mnum = spmus[gamemap-1];
241
  }
242
 
243
  // HACK FOR COMMERCIAL
244
  //  if (commercial && mnum > mus_e3m9)
245
  //      mnum -= mus_e3m9;
246
 
247
  S_ChangeMusic(mnum, true);
248
 
249
  nextcleanup = 15;
250
}
251
 
252
void S_StartSoundAtVolume( void *origin_p, int sfx_id, int volume )
253
   {
254
    int        rc;
255
    int        sep;
256
    int        pitch;
257
    int        priority;
258
    sfxinfo_t *sfx;
259
    int        cnum;
260
    // int        chnum;  <-- 10.9.98 compiler warning
261
 
262
    mobj_t*	origin = (mobj_t *)origin_p;
263
 
264
    //WriteDebug("S_StartSoundAtVolume...\n");
265
 
266
    // Debug.
267
    /*fprintf( stderr,"S_StartSoundAtVolume: playing sound %d (%s)\n",sfx_id, S_sfx[sfx_id].name );*/
268
 
269
    // check for bogus sound #
270
    if (sfx_id < 1 || sfx_id > NUMSFX)
271
        I_Error("Bad sfx #: %d", sfx_id);
272
 
273
    sfx = &S_sfx[sfx_id];
274
 
275
    // Initialize sound parameters
276
    if (sfx->link)
277
       {
278
        pitch = sfx->pitch;
279
        priority = sfx->priority;
280
        volume += sfx->volume;
281
 
282
        if (volume < 1)
283
           {
284
            //WriteDebug("Volume off...\n");
285
            return;
286
           }
287
 
288
        if (volume > snd_SfxVolume)
289
            volume = snd_SfxVolume;
290
       }
291
    else
292
       {
293
        pitch = NORM_PITCH;
294
        priority = NORM_PRIORITY;
295
       }
296
 
297
 
298
    // Check to see if it is audible,
299
    //  and if not, modify the params
300
    if (origin && origin != players[consoleplayer].mo)
301
       {
302
        rc = S_AdjustSoundParams(players[consoleplayer].mo, origin, &volume, &sep, &pitch);
303
        if ( origin->x == players[consoleplayer].mo->x && origin->y == players[consoleplayer].mo->y)
304
           {
305
            sep = NORM_SEP;
306
           }
307
        if (!rc)
308
           {
309
            //WriteDebug("No rc from S_AdjustSoundParams...\n");
310
            return;
311
           }
312
       }
313
    else
314
       {
315
        sep = NORM_SEP;
316
       }
317
 
318
    // hacks to vary the sfx pitches
319
    if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit)
320
       {
321
        pitch += 8 - (M_Random()&15);
322
        if (pitch < 0)
323
            pitch = 0;
324
        else
325
        if (pitch>255)
326
            pitch = 255;
327
       }
328
    else
329
    if (sfx_id != sfx_itemup && sfx_id != sfx_tink)
330
       {
331
        pitch += 16 - (M_Random()&31);
332
        if (pitch<0)
333
            pitch = 0;
334
        else
335
        if (pitch > 255)
336
            pitch = 255;
337
       }
338
 
339
  // kill old sound
340
  S_StopSound(origin);
341
 
342
  // try to find a channel
343
  cnum = S_getChannel(origin, sfx, sfx_id);
344
 
345
  if (cnum<0)
346
     {
347
        //WriteDebug("cnum < 0 -- no channel...\n");
348
    return;
349
     }
350
 
351
  //
352
  // This is supposed to handle the loading/caching.
353
  // For some odd reason, the caching is done nearly
354
  //  each time the sound is needed?
355
  //
356
 
357
  // get lumpnum if necessary
358
  if (sfx->lumpnum < 0)
359
    sfx->lumpnum = I_GetSfxLumpNum(sfx);
360
 
361
  // cache data if necessary
362
  if (!sfx->data)
363
  {
364
    sfx->data = (void *) W_CacheLumpNum(sfx->lumpnum, PU_MUSIC);
365
 
366
  }
367
 
368
  // increase the usefulness
369
  if (sfx->usefulness++ < 0)
370
      sfx->usefulness = 1;
371
 
372
  // Assigns the handle to one of the channels in the
373
  //  mix/output buffer.
374
  //WriteDebug("I_StartSound...\n");
375
  channels[cnum].handle = I_StartSound(sfx_id,/*sfx->data,*/volume,sep,pitch,priority,origin);
376
  //cnum = I_StartSound(sfx_id,/*sfx->data,*/volume,sep,pitch,priority,origin);
377
  channels[cnum].handle = cnum;
378
  channels[cnum].sfxinfo = sfx;
379
  channels[cnum].origin = origin;
380
}
381
 
382
void S_StartSound( void *origin, int sfx_id )
383
   {
384
#ifdef SAWDEBUG
385
    // if (sfx_id == sfx_sawful)
386
    // sfx_id = sfx_itemup;
387
#endif
388
 
389
    S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
390
 
391
 
392
    // UNUSED. We had problems, had we not?
393
#ifdef SAWDEBUG
394
{
395
    int i;
396
    int n;
397
 
398
    static mobj_t*      last_saw_origins[10] = {1,1,1,1,1,1,1,1,1,1};
399
    static int		first_saw=0;
400
    static int		next_saw=0;
401
 
402
    if (sfx_id == sfx_sawidl
403
	|| sfx_id == sfx_sawful
404
	|| sfx_id == sfx_sawhit)
405
    {
406
	for (i=first_saw;i!=next_saw;i=(i+1)%10)
407
	    if (last_saw_origins[i] != origin)
408
		fprintf(stderr, "old origin 0x%lx != "
409
			"origin 0x%lx for sfx %d\n",
410
			last_saw_origins[i],
411
			origin,
412
			sfx_id);
413
 
414
	last_saw_origins[next_saw] = origin;
415
	next_saw = (next_saw + 1) % 10;
416
	if (next_saw == first_saw)
417
	    first_saw = (first_saw + 1) % 10;
418
 
419
	for (n=i=0; i
420
	{
421
	    if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
422
		|| channels[i].sfxinfo == &S_sfx[sfx_sawful]
423
		|| channels[i].sfxinfo == &S_sfx[sfx_sawhit]) n++;
424
	}
425
 
426
	if (n>1)
427
	{
428
	    for (i=0; i
429
	    {
430
		if (channels[i].sfxinfo == &S_sfx[sfx_sawidl]
431
		    || channels[i].sfxinfo == &S_sfx[sfx_sawful]
432
		    || channels[i].sfxinfo == &S_sfx[sfx_sawhit])
433
		{
434
		    fprintf(stderr,
435
			    "chn: sfxinfo=0x%lx, origin=0x%lx, "
436
			    "handle=%d\n",
437
			    channels[i].sfxinfo,
438
			    channels[i].origin,
439
			    channels[i].handle);
440
		}
441
	    }
442
	    fprintf(stderr, "\n");
443
	}
444
    }
445
}
446
#endif
447
 
448
}
449
 
450
 
451
 
452
 
453
void S_StopSound(void *origin)
454
{
455
 
456
    int cnum;
457
 
458
    for (cnum=0 ; cnum
459
    {
460
	if (channels[cnum].sfxinfo && channels[cnum].origin == origin)
461
	{
462
	    S_StopChannel(cnum);
463
	    break;
464
	}
465
    }
466
}
467
 
468
 
469
 
470
 
471
 
472
 
473
 
474
 
475
 
476
//
477
// Stop and resume music, during game PAUSE.
478
//
479
void S_PauseSound(void)
480
{
481
    if (mus_playing && !mus_paused)
482
    {
483
	I_PauseSong(mus_playing->handle);
484
	mus_paused = true;
485
    }
486
}
487
 
488
void S_ResumeSound(void)
489
{
490
    if (mus_playing && mus_paused)
491
    {
492
	I_ResumeSong(mus_playing->handle);
493
	mus_paused = false;
494
    }
495
}
496
 
497
 
498
//
499
// Updates music & sounds
500
//
501
void S_UpdateSounds(void* listener_p)
502
{
503
    int		audible;
504
    int		cnum;
505
    int		volume;
506
    int		sep;
507
    int		pitch;
508
    sfxinfo_t*	sfx;
509
    channel_t*	c;
510
 
511
    mobj_t*	listener = (mobj_t*)listener_p;
512
 
513
 
514
 
515
    // Clean up unused data.
516
    // This is currently not done for 16bit (sounds cached static).
517
    // DOS 8bit remains.
518
    /*if (gametic > nextcleanup)
519
    {
520
	for (i=1 ; i
521
	{
522
	    if (S_sfx[i].usefulness < 1
523
		&& S_sfx[i].usefulness > -1)
524
	    {
525
		if (--S_sfx[i].usefulness == -1)
526
		{
527
		    Z_ChangeTag(S_sfx[i].data, PU_CACHE);
528
		    S_sfx[i].data = 0;
529
		}
530
	    }
531
	}
532
	nextcleanup = gametic + 15;
533
    }*/
534
 
535
    for (cnum=0 ; cnum
536
    {
537
	c = &channels[cnum];
538
	sfx = c->sfxinfo;
539
 
540
	if (c->sfxinfo)
541
	{
542
	    if (I_SoundIsPlaying(c->handle))
543
	    {
544
		// initialize parameters
545
		volume = snd_SfxVolume;
546
		pitch = NORM_PITCH;
547
		sep = NORM_SEP;
548
 
549
		if (sfx->link)
550
		{
551
		    pitch = sfx->pitch;
552
		    volume += sfx->volume;
553
		    if (volume < 1)
554
		    {
555
			S_StopChannel(cnum);
556
			continue;
557
		    }
558
		    else if (volume > snd_SfxVolume)
559
		    {
560
			volume = snd_SfxVolume;
561
		    }
562
		}
563
 
564
		// check non-local sounds for distance clipping
565
		//  or modify their params
566
		if (c->origin && listener_p != c->origin)
567
		{
568
		    audible = S_AdjustSoundParams(listener,
569
						  c->origin,
570
						  &volume,
571
						  &sep,
572
						  &pitch);
573
 
574
		    if (!audible)
575
		    {
576
			S_StopChannel(cnum);
577
		    }
578
		    else
579
			I_UpdateSoundParams(c->handle, volume, sep, pitch);
580
		}
581
	    }
582
	    else
583
	    {
584
		// if channel is allocated but sound has stopped,
585
		//  free it
586
		S_StopChannel(cnum);
587
	    }
588
	}
589
    }
590
    // kill music if it is a single-play && finished
591
    // if (	mus_playing
592
    //      && !I_QrySongPlaying(mus_playing->handle)
593
    //      && !mus_paused )
594
    // S_StopMusic();
595
}
596
 
597
 
598
void S_SetMusicVolume(int volume)
599
{
600
    if (volume < 0 || volume > 127)
601
    {
602
	I_Error("Attempt to set music volume at %d",
603
		volume);
604
    }
605
 
606
    I_SetMusicVolume(127);
607
    I_SetMusicVolume(volume);
608
    snd_MusicVolume = volume;
609
}
610
 
611
 
612
 
613
void S_SetSfxVolume(int volume)
614
{
615
 
616
    if (volume < 0 || volume > 127)
617
	I_Error("Attempt to set sfx volume at %d", volume);
618
 
619
    snd_SfxVolume = volume;
620
 
621
}
622
 
623
//
624
// Starts some music with the music id found in sounds.h.
625
//
626
void S_StartMusic(int m_id)
627
{
628
//    S_ChangeMusic(m_id, false);
629
}
630
 
631
 
632
// clean-up&code for orig midi 10.9.98-dlw
633
void S_ChangeMusic(int musicnum, int looping)
634
{
635
 
636
    // I_PlaySong(music->handle, looping);
637
//	mus_playing = music;
638
}
639
 
640
 
641
void S_StopMusic(void)
642
{
643
    if (mus_playing)
644
    {
645
		if (mus_paused) I_ResumeSong(mus_playing->handle);
646
		I_StopSong(mus_playing->handle);
647
		I_UnRegisterSong(mus_playing->handle);
648
		Z_ChangeTag(mus_playing->data, PU_CACHE);
649
		mus_playing->data = 0;
650
		mus_playing = 0;
651
    }
652
}
653
 
654
void S_StopChannel(int cnum)
655
{
656
 
657
    int		i;
658
    channel_t*	c = &channels[cnum];
659
 
660
    if (c->sfxinfo)
661
    {
662
	// stop the sound playing
663
	if (I_SoundIsPlaying(c->handle))
664
	{
665
#ifdef SAWDEBUG
666
	    if (c->sfxinfo == &S_sfx[sfx_sawful])
667
		fprintf(stderr, "stopped\n");
668
#endif
669
	    I_StopSound(c->handle);
670
	}
671
 
672
	// check to see
673
	//  if other channels are playing the sound
674
	for (i=0 ; i
675
	{
676
	    if (cnum != i
677
		&& c->sfxinfo == channels[i].sfxinfo)
678
	    {
679
		break;
680
	    }
681
	}
682
 
683
	// degrade usefulness of sound data
684
	c->sfxinfo->usefulness--;
685
 
686
	c->sfxinfo = 0;
687
    }
688
}
689
 
690
 
691
//
692
// Changes volume, stereo-separation, and pitch variables
693
//  from the norm of a sound effect to be played.
694
// If the sound is not audible, returns a 0.
695
// Otherwise, modifies parameters and returns 1.
696
//
697
int
698
S_AdjustSoundParams (mobj_t* listener, mobj_t* source,
699
                     int* vol, int* sep, int* pitch)
700
{
701
    fixed_t	approx_dist;
702
    fixed_t	adx;
703
    fixed_t	ady;
704
    angle_t	angle;
705
 
706
    // calculate the distance to sound origin
707
    //  and clip it if necessary
708
    adx = abs(listener->x - source->x);
709
    ady = abs(listener->y - source->y);
710
 
711
    // From _GG1_ p.428. Appox. eucledian distance fast.
712
    approx_dist = adx + ady - ((adx < ady ? adx : ady)>>1);
713
 
714
    if (gamemap != 8
715
	&& approx_dist > S_CLIPPING_DIST)
716
    {
717
	return 0;
718
    }
719
 
720
    // angle of source to listener
721
    angle = R_PointToAngle2(listener->x,
722
			    listener->y,
723
			    source->x,
724
			    source->y);
725
 
726
    if (angle > listener->angle)
727
	angle = angle - listener->angle;
728
    else
729
	angle = angle + (0xffffffff - listener->angle);
730
 
731
    angle >>= ANGLETOFINESHIFT;
732
 
733
    // stereo separation
734
    *sep = 128 - (FixedMul(S_STEREO_SWING,finesine[angle])>>FRACBITS);
735
 
736
    // volume calculation
737
    if (approx_dist < S_CLOSE_DIST)
738
    {
739
	*vol = snd_SfxVolume;
740
    }
741
    else if (gamemap == 8)
742
    {
743
	if (approx_dist > S_CLIPPING_DIST)
744
	    approx_dist = S_CLIPPING_DIST;
745
 
746
	*vol = 15+ ((snd_SfxVolume-15)
747
		    *((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
748
	    / S_ATTENUATOR;
749
    }
750
    else
751
    {
752
	// distance effect
753
	*vol = (snd_SfxVolume
754
		* ((S_CLIPPING_DIST - approx_dist)>>FRACBITS))
755
	    / S_ATTENUATOR;
756
    }
757
 
758
    return (*vol > 0);
759
}
760
 
761
//
762
// S_getChannel :
763
//   If none available, return -1.  Otherwise channel #.
764
//
765
int S_getChannel( void *origin, sfxinfo_t *sfxinfo, int sfxid )
766
   {
767
    // channel number to use
768
    int		cnum;
769
 
770
    channel_t*	c;
771
 
772
    // Find an open channel
773
    //for (cnum = 0; cnum < numChannels; cnum++)
774
    for (cnum = 0; cnum < NUM_CHANNELS; cnum++)
775
       {
776
        if (!channels[cnum].sfxinfo)
777
            break;
778
        else
779
        if (origin && channels[cnum].origin == origin)
780
           {
781
            S_StopChannel(cnum);
782
            break;
783
           }
784
       }
785
 
786
    // None available
787
    if (cnum == NUM_CHANNELS)
788
       {
789
        // Look for lower priority
790
        for (cnum = NUMSFX; cnum < NUM_CHANNELS; cnum++)
791
             if (channels[cnum].sfxinfo->priority >= sfxinfo->priority)
792
                 break;
793
 
794
        if (cnum == numChannels)
795
           {
796
            // FUCK!  No lower priority.  Sorry, Charlie.
797
            return -1;
798
           }
799
        else
800
           {
801
            // Otherwise, kick out lower priority.
802
            S_StopChannel(cnum);
803
           }
804
       }
805
 
806
    c = &channels[cnum];
807
 
808
    // channel is decided to be cnum.
809
    c->sfxinfo = sfxinfo;
810
    c->origin = origin;
811
 
812
    return cnum;
813
   }
814
 
815
 
816