Subversion Repositories Kolibri OS

Rev

Rev 298 | Go to most recent revision | Details | Compare with Previous | 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:
20
//	System interface for sound.
21
//
22
//-----------------------------------------------------------------------------
23
 
24
static const char
25
rcsid[] = "$Id: i_unix.c,v 1.5 1997/02/03 22:45:10 b1 Exp $";
26
 
27
#include 
28
#include 
29
#include 
30
 
31
#include 
32
 
33
#include 
34
 
35
#include 
36
 
37
// Timer stuff. Experimental.
38
#include 
39
#include 
40
 
41
#include "z_zone.h"
42
 
43
#include "i_system.h"
44
#include "i_sound.h"
45
#include "m_argv.h"
46
#include "m_misc.h"
47
#include "w_wad.h"
48
 
49
#include "doomdef.h"
50
 
51
// The number of internal mixing channels,
52
//  the samples calculated for each mixing step,
53
//  the size of the 16bit, 2 hardware channel (stereo)
54
//  mixing buffer, and the samplerate of the raw data.
55
 
56
 
57
// Needed for calling the actual sound output.
58
#define SAMPLECOUNT		512
59
#define NUM_CHANNELS	16
60
// It is 2 for 16bit, and 2 for two channels.
61
#define BUFMUL                  4
62
#define MIXBUFFERSIZE		(SAMPLECOUNT*BUFMUL)
63
 
64
#define SAMPLERATE		11025	// Hz
65
#define SAMPLESIZE		2   	// 16bit
66
 
67
// The actual lengths of all sound effects.
68
int 		lengths[NUMSFX];
69
 
70
// The actual output device.
71
int	audio_fd;
72
 
73
// The global mixing buffer.
74
// Basically, samples from all active internal channels
75
//  are modifed and added, and stored in the buffer
76
//  that is submitted to the audio device.
77
signed short	mixbuffer[MIXBUFFERSIZE];
78
 
79
 
80
// The channel step amount...
81
unsigned int	channelstep[NUM_CHANNELS];
82
// ... and a 0.16 bit remainder of last step.
83
unsigned int	channelstepremainder[NUM_CHANNELS];
84
 
85
 
86
// The channel data pointers, start and end.
87
unsigned char*	channels[NUM_CHANNELS];
88
unsigned char*	channelsend[NUM_CHANNELS];
89
 
90
 
91
// Time/gametic that the channel started playing,
92
//  used to determine oldest, which automatically
93
//  has lowest priority.
94
// In case number of active sounds exceeds
95
//  available channels.
96
int		channelstart[NUM_CHANNELS];
97
 
98
// The sound in channel handles,
99
//  determined on registration,
100
//  might be used to unregister/stop/modify,
101
//  currently unused.
102
int 		channelhandles[NUM_CHANNELS];
103
 
104
// SFX id of the playing sound effect.
105
// Used to catch duplicates (like chainsaw).
106
int		channelids[NUM_CHANNELS];
107
 
108
// Pitch to stepping lookup, unused.
109
int		steptable[256];
110
 
111
// Volume lookups.
112
int		vol_lookup[128*256];
113
 
114
// Hardware left and right channel volume lookup.
115
int*		channelleftvol_lookup[NUM_CHANNELS];
116
int*		channelrightvol_lookup[NUM_CHANNELS];
117
 
118
 
119
//
120
// This function loads the sound data from the WAD lump,
121
//  for single sound.
122
//
123
void* getsfx (char* sfxname, int* len)
124
{
125
  unsigned char*      sfx;
126
  unsigned char*      paddedsfx;
127
  int                 i;
128
  int                 size;
129
  int                 paddedsize;
130
  char                name[20];
131
  int                 sfxlump;
132
 
133
 
134
    // Get the sound data from the WAD, allocate lump
135
    //  in zone memory.
136
    sprintf(name, "ds%s", sfxname);
137
 
138
    // Now, there is a severe problem with the
139
    //  sound handling, in it is not (yet/anymore)
140
    //  gamemode aware. That means, sounds from
141
    //  DOOM II will be requested even with DOOM
142
    //  shareware.
143
    // The sound list is wired into sounds.c,
144
    //  which sets the external variable.
145
    // I do not do runtime patches to that
146
    //  variable. Instead, we will use a
147
    //  default sound for replacement.
148
    if ( W_CheckNumForName(name) == -1 )
149
      sfxlump = W_GetNumForName("dspistol");
150
    else
151
      sfxlump = W_GetNumForName(name);
152
 
153
    size = W_LumpLength( sfxlump );
154
 
155
    // Debug.
156
    // fprintf( stderr, "." );
157
    //fprintf( stderr, " -loading  %s (lump %d, %d bytes)\n",
158
    //	     sfxname, sfxlump, size );
159
    //fflush( stderr );
160
 
161
    sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC );
162
 
163
    // Pads the sound effect out to the mixing buffer size.
164
    // The original realloc would interfere with zone memory.
165
    paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
166
 
167
    // Allocate from zone memory.
168
    paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 );
169
    // ddt: (unsigned char *) realloc(sfx, paddedsize+8);
170
    // This should interfere with zone memory handling,
171
    //  which does not kick in in the soundserver.
172
 
173
    // Now copy and pad.
174
    memcpy(  paddedsfx, sfx, size );
175
    for (i=size ; i
176
        paddedsfx[i] = 128;
177
 
178
    // Remove the cached lump.
179
    Z_Free( sfx );
180
 
181
    // Preserve padded length.
182
    *len = paddedsize;
183
 
184
    // Return allocated padded data.
185
    return (void *) (paddedsfx + 8);
186
}
187
 
188
//
189
// This function adds a sound to the
190
//  list of currently active sounds,
191
//  which is maintained as a given number
192
//  (eight, usually) of internal channels.
193
// Returns a handle.
194
//
195
 
196
static unsigned short	handlenums = 0;
197
 
198
int addsfx(int sfxid, int volume, int step, int seperation)
199
{
200
 
201
    int		i;
202
    int		rc = -1;
203
 
204
    int		oldest = gametic;
205
    int		oldestnum = 0;
206
    int		slot;
207
 
208
    int		rightvol;
209
    int		leftvol;
210
 
211
    // Chainsaw troubles.
212
    // Play these sound effects only one at a time.
213
    if ( sfxid == sfx_sawup
214
	 || sfxid == sfx_sawidl
215
	 || sfxid == sfx_sawful
216
	 || sfxid == sfx_sawhit
217
	 || sfxid == sfx_stnmov
218
	 || sfxid == sfx_pistol	 )
219
    {
220
	// Loop all channels, check.
221
	for (i=0 ; i
222
	{
223
	    // Active, and using the same SFX?
224
	    if ( (channels[i])
225
		 && (channelids[i] == sfxid) )
226
	    {
227
		// Reset.
228
		channels[i] = 0;
229
		// We are sure that iff,
230
		//  there will only be one.
231
		break;
232
	    }
233
	}
234
    }
235
 
236
    // Loop all channels to find oldest SFX.
237
    for (i=0; (i
238
    {
239
	if (channelstart[i] < oldest)
240
	{
241
	    oldestnum = i;
242
	    oldest = channelstart[i];
243
	}
244
    }
245
 
246
    // Tales from the cryptic.
247
    // If we found a channel, fine.
248
    // If not, we simply overwrite the first one, 0.
249
    // Probably only happens at startup.
250
    if (i == NUM_CHANNELS)
251
	slot = oldestnum;
252
    else
253
	slot = i;
254
 
255
    // Okay, in the less recent channel,
256
    //  we will handle the new SFX.
257
    // Set pointer to raw data.
258
    channels[slot] = (unsigned char *) S_sfx[sfxid].data;
259
    // Set pointer to end of raw data.
260
    channelsend[slot] = channels[slot] + lengths[sfxid];
261
 
262
    // Reset current handle number, limited to 0..100.
263
    if (!handlenums)
264
	handlenums = 100;
265
 
266
    // Assign current handle number.
267
    // Preserved so sounds could be stopped (unused).
268
    channelhandles[slot] = rc = handlenums++;
269
 
270
    channelstep[slot] = step;
271
 
272
    channelstepremainder[slot] = 0;
273
    // Should be gametic, I presume.
274
    channelstart[slot] = gametic;
275
 
276
    // Separation, that is, orientation/stereo.
277
    //  range is: 1 - 256
278
    seperation += 1;
279
 
280
    volume *=7;
281
    // Per left/right channel.
282
    //  x^2 seperation,
283
    //  adjust volume properly.
284
    leftvol =
285
	volume - ((volume*seperation*seperation) >> 16); ///(256*256);
286
    seperation = seperation - 257;
287
    rightvol =
288
	volume - ((volume*seperation*seperation) >> 16);
289
 
290
    // Sanity check, clamp volume.
291
    if (rightvol < 0 || rightvol > 127)
292
	I_Error("rightvol out of bounds");
293
 
294
    if (leftvol < 0 || leftvol > 127)
295
	I_Error("leftvol out of bounds");
296
 
297
    // Get the proper lookup table piece
298
    //  for this volume level???
299
    channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
300
    channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
301
 
302
    // Preserve sound SFX id,
303
    //  e.g. for avoiding duplicates of chainsaw.
304
    channelids[slot] = sfxid;
305
 
306
    // You tell me.
307
    return rc;
308
}
309
 
310
//
311
// SFX API
312
// Note: this was called by S_Init.
313
// However, whatever they did in the
314
// old DPMS based DOS version, this
315
// were simply dummies in the Linux
316
// version.
317
// See soundserver initdata().
318
//
319
void I_SetChannels()
320
{
321
  // Init internal lookups (raw data, mixing buffer, channels).
322
  // This function sets up internal lookups used during
323
  //  the mixing process.
324
  int		i;
325
  int		j;
326
 
327
  int*	steptablemid = steptable + 128;
328
 
329
  // Okay, reset internal mixing channels to zero.
330
  for (i=0; i
331
  {
332
    channels[i] = 0;
333
  }
334
 
335
  for (i=-128 ; i<128 ; i++)
336
    steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
337
 
338
  // Generates volume lookup tables
339
  //  which also turn the unsigned samples
340
  //  into signed samples.
341
  for (i=0 ; i<128 ; i++)
342
    for (j=0 ; j<256 ; j++)
343
      vol_lookup[i*256+j] = (i*(j-128)*256)/127;
344
}
345
 
346
 
347
void I_SetSfxVolume(int volume)
348
{
349
  // Identical to DOS.
350
  // Basically, this should propagate
351
  //  the menu/config file setting
352
  //  to the state variable used in
353
  //  the mixing.
354
  snd_SfxVolume = volume;
355
}
356
 
357
// MUSIC API - dummy. Some code from DOS version.
358
void I_SetMusicVolume(int volume)
359
{
360
  // Internal state variable.
361
  snd_MusicVolume = volume;
362
}
363
 
364
 
365
//
366
// Retrieve the raw data lump index
367
//  for a given SFX name.
368
//
369
int I_GetSfxLumpNum(sfxinfo_t* sfx)
370
{
371
    char namebuf[9];
372
    sprintf(namebuf, "ds%s", sfx->name);
373
    return W_GetNumForName(namebuf);
374
}
375
 
376
//
377
// Starting a sound means adding it
378
//  to the current list of active sounds
379
//  in the internal channels.
380
// As the SFX info struct contains
381
//  e.g. a pointer to the raw data,
382
//  it is ignored.
383
// As our sound handling does not handle
384
//  priority, it is ignored.
385
// Pitching (that is, increased speed of playback)
386
//
387
int I_StartSound(int id, int vol, int sep,
388
                 int pitch, int priority )
389
{
390
    // Returns a handle (not used).
391
    id = addsfx( id, vol, steptable[pitch], sep );
392
    return id;
393
}
394
 
395
void I_StopSound (int handle)
396
{
397
  // You need the handle returned by StartSound.
398
  // Would be looping all channels,
399
  //  tracking down the handle,
400
  //  an setting the channel to zero.
401
 
402
  // UNUSED.
403
  handle = 0;
404
}
405
 
406
 
407
int I_SoundIsPlaying(int handle)
408
{
409
    // Ouch.
410
    return gametic < handle;
411
}
412
 
413
//
414
// This function loops all active (internal) sound
415
//  channels, retrieves a given number of samples
416
//  from the raw sound data, modifies it according
417
//  to the current (internal) channel parameters,
418
//  mixes the per channel samples into the global
419
//  mixbuffer, clamping it to the allowed range,
420
//  and sets up everything for transferring the
421
//  contents of the mixbuffer to the (two)
422
//  hardware channels (left and right, that is).
423
//
424
// This function currently supports only 16bit.
425
//
426
void I_UpdateSound( void )
427
{
428
 
429
  // Mix current sound data.
430
  // Data, from raw sound, for right and left.
431
  register unsigned int	sample;
432
  register int		dl;
433
  register int		dr;
434
 
435
  // Pointers in global mixbuffer, left, right, end.
436
  signed short*		leftout;
437
  signed short*		rightout;
438
  signed short*		leftend;
439
  // Step in mixbuffer, left and right, thus two.
440
  int				step;
441
 
442
  // Mixing channel index.
443
  int				chan;
444
 
445
    // Left and right channel
446
    //  are in global mixbuffer, alternating.
447
    leftout = mixbuffer;
448
    rightout = mixbuffer+1;
449
    step = 2;
450
 
451
    // Determine end, for left channel only
452
    //  (right channel is implicit).
453
    leftend = mixbuffer + SAMPLECOUNT*step;
454
 
455
    // Mix sounds into the mixing buffer.
456
    // Loop over step*SAMPLECOUNT,
457
    //  that is 512 values for two channels.
458
    while (leftout != leftend)
459
    {
460
	// Reset left/right value.
461
	dl = 0;
462
	dr = 0;
463
 
464
	// Love thy L2 chache - made this a loop.
465
	// Now more channels could be set at compile time
466
	//  as well. Thus loop those  channels.
467
	for ( chan = 0; chan < NUM_CHANNELS; chan++ )
468
	{
469
	    // Check channel, if active.
470
	    if (channels[ chan ])
471
	    {
472
		// Get the raw data from the channel.
473
		sample = *channels[ chan ];
474
		// Add left and right part
475
		//  for this channel (sound)
476
		//  to the current data.
477
		// Adjust volume accordingly.
478
		dl += channelleftvol_lookup[ chan ][sample];
479
		dr += channelrightvol_lookup[ chan ][sample];
480
 
481
		channelstepremainder[ chan ] += channelstep[ chan ];
482
 
483
		channels[ chan ] += channelstepremainder[ chan ] >> 16;
484
 
485
		channelstepremainder[ chan ] &= 65536-1;
486
 
487
		// Check whether we are done.
488
		if (channels[ chan ] >= channelsend[ chan ])
489
		    channels[ chan ] = 0;
490
	    }
491
	}
492
 
493
	// Clamp to range. Left hardware channel.
494
	// Has been char instead of short.
495
	// if (dl > 127) *leftout = 127;
496
	// else if (dl < -128) *leftout = -128;
497
	// else *leftout = dl;
498
 
499
	if (dl > 0x7fff)
500
	    *leftout = 0x7fff;
501
	else if (dl < -0x8000)
502
	    *leftout = -0x8000;
503
	else
504
	    *leftout = dl;
505
 
506
	// Same for right hardware channel.
507
	if (dr > 0x7fff)
508
	    *rightout = 0x7fff;
509
	else if (dr < -0x8000)
510
	    *rightout = -0x8000;
511
	else
512
	    *rightout = dr;
513
 
514
	// Increment current pointers in mixbuffer.
515
	leftout += step;
516
	rightout += step;
517
    }
518
    I_SubmitSound(mixbuffer);
519
}
520
 
521
 
522
//
523
// This would be used to write out the mixbuffer
524
//  during each game loop update.
525
// Updates sound buffer and audio device at runtime.
526
// It is called during Timer interrupt with SNDINTR.
527
// Mixing now done synchronous, and
528
//  only output be done asynchronous?
529
//
530
//void I_SubmitSound(void)
531
//{
532
  // Write it to DSP device.
533
//  write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
534
//}
535
 
536
 
537
void I_UpdateSoundParams(int handle, int vol, int sep, int pitch)
538
{
539
  // I fail too see that this is used.
540
  // Would be using the handle to identify
541
  //  on which channel the sound might be active,
542
  //  and resetting the channel parameters.
543
 
544
  // UNUSED.
545
  handle = vol = sep = pitch = 0;
546
}
547
 
548
void I_ShutdownSound(void)
549
{
550
  // Wait till all pending sounds are finished.
551
  int done = 0;
552
  int i;
553
 
554
  // FIXME (below).
300 serge 555
  printf( "I_ShutdownSound: NOT finishing pending sounds\n");
298 serge 556
 
557
  while ( !done )
558
  {
559
    for( i=0 ; i<8 && !channels[i] ; i++);
560
 
561
    // FIXME. No proper channel output.
562
    //if (i==8)
563
    done=1;
564
  }
565
  return;
566
}
567
 
568
void I_InitSound()
569
{ int i;
570
 
300 serge 571
  printf("I_InitSound: ");
298 serge 572
 
573
  for (i=1 ; i
574
  {
575
    // Alias? Example is the chaingun sound linked to pistol.
576
    if (!S_sfx[i].link)
577
    {
578
      // Load data from WAD file.
579
      S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
580
    }
581
    else
582
    {
583
      // Previously loaded already?
584
      S_sfx[i].data = S_sfx[i].link->data;
585
      lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
586
    }
587
  }
588
 
300 serge 589
  printf( " pre-cached all sound data\n");
298 serge 590
 
591
  // Now initialize mixbuffer with zero.
592
  for ( i = 0; i< MIXBUFFERSIZE; i++ )
593
    mixbuffer[i] = 0;
594
 
595
  // Finished initialization.
300 serge 596
  printf("I_InitSound: sound module ready\n");
298 serge 597
 
598
}
599
 
600
 
601
//
602
// MUSIC API.
603
// Still no music done.
604
// Remains. Dummies.
605
//
606
void I_InitMusic(void)		{ }
607
void I_ShutdownMusic(void)	{ }
608
 
609
static int	looping=0;
610
static int	musicdies=-1;
611
 
612
void I_PlaySong(int handle, int looping)
613
{
614
  // UNUSED.
615
  handle = looping = 0;
616
  musicdies = gametic + TICRATE*30;
617
}
618
 
619
void I_PauseSong (int handle)
620
{
621
  // UNUSED.
622
  handle = 0;
623
}
624
 
625
void I_ResumeSong (int handle)
626
{
627
  // UNUSED.
628
  handle = 0;
629
}
630
 
631
void I_StopSong(int handle)
632
{
633
  // UNUSED.
634
  handle = 0;
635
 
636
  looping = 0;
637
  musicdies = 0;
638
}
639
 
640
void I_UnRegisterSong(int handle)
641
{
642
  // UNUSED.
643
  handle = 0;
644
}
645
 
646
int I_RegisterSong(void* data)
647
{
648
  // UNUSED.
649
  data = NULL;
650
 
651
  return 1;
652
}
653
 
654
// Is the song playing?
655
int I_QrySongPlaying(int handle)
656
{
657
  // UNUSED.
658
  handle = 0;
659
  return looping || musicdies > gametic;
660
}
661
 
662
 
663
// Interrupt handler.
664
void I_HandleSoundTimer( int ignore )
665
{
666
 
667
  // UNUSED, but required.
668
  ignore = 0;
669
  return;
670
}
671