doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

i_sound.c (11575B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <stdarg.h>
      4 
      5 #include <math.h>
      6 #include <errno.h>
      7 
      8 #include <sys/time.h>
      9 #include <sys/types.h>
     10 
     11 #include <fcntl.h>
     12 #include <unistd.h>
     13 #include <sys/ioctl.h>
     14 
     15 
     16 #include <linux/soundcard.h>
     17 
     18 
     19 #include <time.h>
     20 #include <signal.h>
     21 
     22 #include "z_zone.h"
     23 
     24 #include "i_system.h"
     25 #include "i_sound.h"
     26 #include "m_argv.h"
     27 #include "m_misc.h"
     28 #include "w_wad.h"
     29 
     30 #include "doomdef.h"
     31 
     32 
     33 #ifdef SNDSERV
     34 
     35 FILE*	sndserver=0;
     36 char*	sndserver_filename = "./sndserver ";
     37 #elif SNDINTR
     38 
     39 
     40 
     41 
     42 #define SOUND_INTERVAL     500
     43 
     44 
     45 int I_SoundSetTimer( int duration_of_tick );
     46 void I_SoundDelTimer( void );
     47 #else
     48 
     49 #endif
     50 
     51 
     52 
     53 
     54 
     55 static int flag = 0;
     56 
     57 
     58 
     59 
     60 
     61 
     62 
     63 
     64 #define SAMPLECOUNT		512
     65 #define NUM_CHANNELS		8
     66 
     67 #define BUFMUL                  4
     68 #define MIXBUFFERSIZE		(SAMPLECOUNT*BUFMUL)
     69 
     70 #define SAMPLERATE		11025	
     71 #define SAMPLESIZE		2   	
     72 
     73 
     74 int 		lengths[NUMSFX];
     75 
     76 
     77 int	audio_fd;
     78 
     79 
     80 
     81 
     82 
     83 signed short	mixbuffer[MIXBUFFERSIZE];
     84 
     85 
     86 
     87 unsigned int	channelstep[NUM_CHANNELS];
     88 
     89 unsigned int	channelstepremainder[NUM_CHANNELS];
     90 
     91 
     92 
     93 unsigned char*	channels[NUM_CHANNELS];
     94 unsigned char*	channelsend[NUM_CHANNELS];
     95 
     96 
     97 
     98 
     99 
    100 
    101 
    102 int		channelstart[NUM_CHANNELS];
    103 
    104 
    105 
    106 
    107 
    108 int 		channelhandles[NUM_CHANNELS];
    109 
    110 
    111 
    112 int		channelids[NUM_CHANNELS];			
    113 
    114 
    115 int		steptable[256];
    116 
    117 
    118 int		vol_lookup[128*256];
    119 
    120 
    121 int*		channelleftvol_lookup[NUM_CHANNELS];
    122 int*		channelrightvol_lookup[NUM_CHANNELS];
    123 
    124 
    125 
    126 
    127 
    128 
    129 
    130 void
    131 myioctl
    132 ( int	fd,
    133   int	command,
    134   int*	arg )
    135 {   
    136     int		rc;
    137     
    138     rc = ioctl(fd, command, arg);  
    139     if (rc < 0)
    140     {
    141 	fprintf(stderr, "ioctl(dsp,%d,arg) failed\n", command);
    142 	fprintf(stderr, "errno=%d\n", errno);
    143 	exit(-1);
    144     }
    145 }
    146 
    147 
    148 
    149 
    150 
    151 
    152 
    153 
    154 
    155 void*
    156 getsfx
    157 ( char*         sfxname,
    158   int*          len )
    159 {
    160     unsigned char*      sfx;
    161     unsigned char*      paddedsfx;
    162     int                 i;
    163     int                 size;
    164     int                 paddedsize;
    165     char                name[20];
    166     int                 sfxlump;
    167 
    168     
    169     
    170     
    171     sprintf(name, "DS%s", sfxname);
    172 
    173     
    174     
    175     
    176     
    177     
    178     
    179     
    180     
    181     
    182     
    183     if ( W_CheckNumForName(name) == -1 )
    184       sfxlump = W_GetNumForName("DSPISTOL");
    185     else
    186       sfxlump = W_GetNumForName(name);
    187     
    188     size = W_LumpLength( sfxlump );
    189 
    190     
    191     
    192     
    193     
    194     
    195     
    196     sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_STATIC );
    197 
    198     
    199     
    200     paddedsize = ((size-8 + (SAMPLECOUNT-1)) / SAMPLECOUNT) * SAMPLECOUNT;
    201 
    202     
    203     paddedsfx = (unsigned char*)Z_Malloc( paddedsize+8, PU_STATIC, 0 );
    204     
    205     
    206     
    207 
    208     
    209     memcpy(  paddedsfx, sfx, size );
    210     for (i=size ; i<paddedsize+8 ; i++)
    211         paddedsfx[i] = 128;
    212 
    213     
    214     Z_Free( sfx );
    215     
    216     
    217     *len = paddedsize;
    218 
    219     
    220     return (void *) (paddedsfx + 8);
    221 }
    222 
    223 
    224 
    225 
    226 
    227 
    228 
    229 
    230 
    231 
    232 
    233 
    234 int
    235 addsfx
    236 ( int		sfxid,
    237   int		volume,
    238   int		step,
    239   int		seperation )
    240 {
    241     static unsigned short	handlenums = 0;
    242  
    243     int		i;
    244     int		rc = -1;
    245     
    246     int		oldest = gametic;
    247     int		oldestnum = 0;
    248     int		slot;
    249 
    250     int		rightvol;
    251     int		leftvol;
    252 
    253     
    254     
    255     if ( sfxid == sfx_sawup
    256 	 || sfxid == sfx_sawidl
    257 	 || sfxid == sfx_sawful
    258 	 || sfxid == sfx_sawhit
    259 	 || sfxid == sfx_stnmov
    260 	 || sfxid == sfx_pistol	 )
    261     {
    262 	
    263 	for (i=0 ; i<NUM_CHANNELS ; i++)
    264 	{
    265 	    
    266 	    if ( (channels[i])
    267 		 && (channelids[i] == sfxid) )
    268 	    {
    269 		
    270 		channels[i] = 0;
    271 		
    272 		
    273 		break;
    274 	    }
    275 	}
    276     }
    277 
    278     
    279     for (i=0; (i<NUM_CHANNELS) && (channels[i]); i++)
    280     {
    281 	if (channelstart[i] < oldest)
    282 	{
    283 	    oldestnum = i;
    284 	    oldest = channelstart[i];
    285 	}
    286     }
    287 
    288     
    289     
    290     
    291     
    292     if (i == NUM_CHANNELS)
    293 	slot = oldestnum;
    294     else
    295 	slot = i;
    296 
    297     
    298     
    299     
    300     channels[slot] = (unsigned char *) S_sfx[sfxid].data;
    301     
    302     channelsend[slot] = channels[slot] + lengths[sfxid];
    303 
    304     
    305     if (!handlenums)
    306 	handlenums = 100;
    307 
    308     
    309     
    310     channelhandles[slot] = rc = handlenums++;
    311 
    312     
    313     
    314     channelstep[slot] = step;
    315     
    316     channelstepremainder[slot] = 0;
    317     
    318     channelstart[slot] = gametic;
    319 
    320     
    321     
    322     seperation += 1;
    323 
    324     
    325     
    326     
    327     leftvol =
    328 	volume - ((volume*seperation*seperation) >> 16); 
    329     seperation = seperation - 257;
    330     rightvol =
    331 	volume - ((volume*seperation*seperation) >> 16);	
    332 
    333     
    334     if (rightvol < 0 || rightvol > 127)
    335 	I_Error("rightvol out of bounds");
    336     
    337     if (leftvol < 0 || leftvol > 127)
    338 	I_Error("leftvol out of bounds");
    339     
    340     
    341     
    342     channelleftvol_lookup[slot] = &vol_lookup[leftvol*256];
    343     channelrightvol_lookup[slot] = &vol_lookup[rightvol*256];
    344 
    345     
    346     
    347     channelids[slot] = sfxid;
    348 
    349     
    350     return rc;
    351 }
    352 
    353 
    354 
    355 
    356 
    357 
    358 
    359 
    360 
    361 
    362 
    363 
    364 
    365 
    366 void I_SetChannels()
    367 {
    368   
    369   
    370   
    371   int		i;
    372   int		j;
    373     
    374   int*	steptablemid = steptable + 128;
    375   
    376   
    377   /*for (i=0; i<NUM_CHANNELS; i++)
    378   {
    379     channels[i] = 0;
    380   }*/
    381 
    382   
    383   
    384   for (i=-128 ; i<128 ; i++)
    385     steptablemid[i] = (int)(pow(2.0, (i/64.0))*65536.0);
    386   
    387   
    388   
    389   
    390   
    391   for (i=0 ; i<128 ; i++)
    392     for (j=0 ; j<256 ; j++)
    393       vol_lookup[i*256+j] = (i*(j-128)*256)/127;
    394 }	
    395 
    396  
    397 void I_SetSfxVolume(int volume)
    398 {
    399   
    400   
    401   
    402   
    403   
    404   snd_SfxVolume = volume;
    405 }
    406 
    407 
    408 void I_SetMusicVolume(int volume)
    409 {
    410   
    411   snd_MusicVolume = volume;
    412   
    413   
    414 }
    415 
    416 
    417 
    418 
    419 
    420 
    421 int I_GetSfxLumpNum(sfxinfo_t* sfx)
    422 {
    423     char namebuf[9];
    424     sprintf(namebuf, "DS%s", sfx->name);
    425     return W_GetNumForName(namebuf);
    426 }
    427 
    428 
    429 
    430 
    431 
    432 
    433 
    434 
    435 
    436 
    437 
    438 
    439 
    440 int
    441 I_StartSound
    442 ( int		id,
    443   int		vol,
    444   int		sep,
    445   int		pitch,
    446   int		priority )
    447 {
    448 
    449   
    450   priority = 0;
    451   
    452 #ifdef SNDSERV 
    453     if (sndserver)
    454     {
    455 	fprintf(sndserver, "p%2.2x%2.2x%2.2x%2.2x\n", id, pitch, vol, sep);
    456 	fflush(sndserver);
    457     }
    458     
    459     return id;
    460 #else
    461     
    462     
    463     
    464     
    465     id = addsfx( id, vol, steptable[pitch], sep );
    466 
    467     
    468     
    469     return id;
    470 #endif
    471 }
    472 
    473 
    474 
    475 void I_StopSound (int handle)
    476 {
    477   
    478   
    479   
    480   
    481   
    482   
    483   handle = 0;
    484 }
    485 
    486 
    487 int I_SoundIsPlaying(int handle)
    488 {
    489     
    490     return gametic < handle;
    491 }
    492 
    493 
    494 
    495 
    496 
    497 
    498 
    499 
    500 
    501 
    502 
    503 
    504 
    505 
    506 
    507 
    508 
    509 void I_UpdateSound( void )
    510 {
    511 #ifdef SNDINTR
    512   static int misses = 0;
    513 #endif
    514 
    515   
    516   
    517   
    518   register unsigned int	sample;
    519   register int		dl;
    520   register int		dr;
    521   
    522   
    523   signed short*		leftout;
    524   signed short*		rightout;
    525   signed short*		leftend;
    526   
    527   int				step;
    528 
    529   
    530   int				chan;
    531     
    532     
    533     
    534     leftout = mixbuffer;
    535     rightout = mixbuffer+1;
    536     step = 2;
    537 
    538     
    539     
    540     leftend = mixbuffer + SAMPLECOUNT*step;
    541 
    542     
    543     
    544     
    545     while (leftout != leftend)
    546     {
    547 	
    548 	dl = 0;
    549 	dr = 0;
    550 
    551 	
    552 	
    553 	
    554 	for ( chan = 0; chan < NUM_CHANNELS; chan++ )
    555 	{
    556 	    
    557 	    if (channels[ chan ])
    558 	    {
    559 		
    560 		sample = *channels[ chan ];
    561 		
    562 		
    563 		
    564 		
    565 		dl += channelleftvol_lookup[ chan ][sample];
    566 		dr += channelrightvol_lookup[ chan ][sample];
    567 		
    568 		channelstepremainder[ chan ] += channelstep[ chan ];
    569 		
    570 		channels[ chan ] += channelstepremainder[ chan ] >> 16;
    571 		
    572 		channelstepremainder[ chan ] &= 65536-1;
    573 
    574 		
    575 		if (channels[ chan ] >= channelsend[ chan ])
    576 		    channels[ chan ] = 0;
    577 	    }
    578 	}
    579 	
    580 	
    581 	
    582 	
    583 	
    584 	
    585 
    586 	if (dl > 0x7fff)
    587 	    *leftout = 0x7fff;
    588 	else if (dl < -0x8000)
    589 	    *leftout = -0x8000;
    590 	else
    591 	    *leftout = dl;
    592 
    593 	
    594 	if (dr > 0x7fff)
    595 	    *rightout = 0x7fff;
    596 	else if (dr < -0x8000)
    597 	    *rightout = -0x8000;
    598 	else
    599 	    *rightout = dr;
    600 
    601 	
    602 	leftout += step;
    603 	rightout += step;
    604     }
    605 
    606 #ifdef SNDINTR
    607     
    608     if ( flag )
    609     {
    610       misses += flag;
    611       flag = 0;
    612     }
    613     
    614     if ( misses > 10 )
    615     {
    616       fprintf( stderr, "I_SoundUpdate: missed 10 buffer writes\n");
    617       misses = 0;
    618     }
    619     
    620     
    621     flag++;
    622 #endif
    623 }
    624 
    625 
    626 
    627 
    628 
    629 
    630 
    631 
    632 
    633 
    634 void
    635 I_SubmitSound(void)
    636 {
    637   
    638   write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
    639 }
    640 
    641 
    642 
    643 void
    644 I_UpdateSoundParams
    645 ( int	handle,
    646   int	vol,
    647   int	sep,
    648   int	pitch)
    649 {
    650   
    651   
    652   
    653   
    654 
    655   
    656   handle = vol = sep = pitch = 0;
    657 }
    658 
    659 
    660 
    661 
    662 void I_ShutdownSound(void)
    663 {    
    664 #ifdef SNDSERV
    665   if (sndserver)
    666   {
    667     
    668     fprintf(sndserver, "q\n");
    669     fflush(sndserver);
    670   }
    671 #else
    672   
    673   int done = 0;
    674   int i;
    675   
    676 
    677   
    678   fprintf( stderr, "I_ShutdownSound: NOT finishing pending sounds\n");
    679   fflush( stderr );
    680   
    681   while ( !done )
    682   {
    683     for( i=0 ; i<8 && !channels[i] ; i++);
    684     
    685     
    686     
    687     done=1;
    688   }
    689 #ifdef SNDINTR
    690   I_SoundDelTimer();
    691 #endif
    692   
    693   
    694   close ( audio_fd );
    695 #endif
    696 
    697   
    698   return;
    699 }
    700 
    701 
    702 
    703 
    704 
    705 
    706 void
    707 I_InitSound()
    708 { 
    709 #ifdef SNDSERV
    710   char buffer[256];
    711   
    712   if (getenv("DOOMWADDIR"))
    713     sprintf(buffer, "%s/%s",
    714 	    getenv("DOOMWADDIR"),
    715 	    sndserver_filename);
    716   else
    717     sprintf(buffer, "%s", sndserver_filename);
    718   
    719   
    720   if ( !access(buffer, X_OK) )
    721   {
    722     strcat(buffer, " -quiet");
    723     sndserver = popen(buffer, "w");
    724   }
    725   else
    726     fprintf(stderr, "Could not start sound server [%s]\n", buffer);
    727 #else
    728     
    729   int i;
    730   
    731 #ifdef SNDINTR
    732   fprintf( stderr, "I_SoundSetTimer: %d microsecs\n", SOUND_INTERVAL );
    733   I_SoundSetTimer( SOUND_INTERVAL );
    734 #endif
    735     
    736   
    737   fprintf( stderr, "I_InitSound: ");
    738   
    739   audio_fd = open("/dev/dsp", O_WRONLY);
    740   if (audio_fd<0)
    741     fprintf(stderr, "Could not open /dev/dsp\n");
    742   
    743                      
    744   i = 11 | (2<<16);                                           
    745   myioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &i);
    746   myioctl(audio_fd, SNDCTL_DSP_RESET, 0);
    747   
    748   i=SAMPLERATE;
    749   
    750   myioctl(audio_fd, SNDCTL_DSP_SPEED, &i);
    751   
    752   i=1;
    753   myioctl(audio_fd, SNDCTL_DSP_STEREO, &i);
    754   
    755   myioctl(audio_fd, SNDCTL_DSP_GETFMTS, &i);
    756   
    757   if (i&=AFMT_S16_LE)    
    758     myioctl(audio_fd, SNDCTL_DSP_SETFMT, &i);
    759   else
    760     fprintf(stderr, "Could not play signed 16 data\n");
    761 
    762   fprintf(stderr, " configured audio device\n" );
    763 
    764     
    765   
    766   fprintf( stderr, "I_InitSound: ");
    767   
    768   for (i=1 ; i<NUMSFX ; i++)
    769   { 
    770     
    771     if (!S_sfx[i].link)
    772     {
    773       
    774       S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
    775     }	
    776     else
    777     {
    778       
    779       S_sfx[i].data = S_sfx[i].link->data;
    780       lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
    781     }
    782   }
    783 
    784   fprintf( stderr, " pre-cached all sound data\n");
    785   
    786   
    787   for ( i = 0; i< MIXBUFFERSIZE; i++ )
    788     mixbuffer[i] = 0;
    789   
    790   
    791   fprintf(stderr, "I_InitSound: sound module ready\n");
    792     
    793 #endif
    794 }
    795 
    796 
    797 
    798 
    799 
    800 
    801 
    802 
    803 
    804 void I_InitMusic(void)		{ }
    805 void I_ShutdownMusic(void)	{ }
    806 
    807 static int	looping=0;
    808 static int	musicdies=-1;
    809 
    810 void I_PlaySong(int handle, int looping)
    811 {
    812   
    813   handle = looping = 0;
    814   musicdies = gametic + TICRATE*30;
    815 }
    816 
    817 void I_PauseSong (int handle)
    818 {
    819   
    820   handle = 0;
    821 }
    822 
    823 void I_ResumeSong (int handle)
    824 {
    825   
    826   handle = 0;
    827 }
    828 
    829 void I_StopSong(int handle)
    830 {
    831   
    832   handle = 0;
    833   
    834   looping = 0;
    835   musicdies = 0;
    836 }
    837 
    838 void I_UnRegisterSong(int handle)
    839 {
    840   
    841   handle = 0;
    842 }
    843 
    844 int I_RegisterSong(void* data)
    845 {
    846   
    847   data = NULL;
    848   
    849   return 1;
    850 }
    851 
    852 
    853 int I_QrySongPlaying(int handle)
    854 {
    855   
    856   handle = 0;
    857   return looping || musicdies > gametic;
    858 }
    859 
    860 
    861 
    862 
    863 
    864 
    865 
    866 
    867 
    868 
    869 
    870 #ifdef sun
    871     typedef     sigset_t        tSigSet;
    872 #else    
    873     typedef     int             tSigSet;
    874 #endif
    875 
    876 
    877 
    878 
    879 
    880 
    881 static int /*__itimer_which*/  itimer = ITIMER_REAL;
    882 
    883 static int sig = SIGALRM;
    884 
    885 
    886 void I_HandleSoundTimer( int ignore )
    887 {
    888   
    889   
    890   
    891   
    892   if ( flag )
    893   {
    894     
    895     
    896     write(audio_fd, mixbuffer, SAMPLECOUNT*BUFMUL);
    897 
    898     
    899     flag = 0;
    900   }
    901   else
    902     return;
    903   
    904   
    905   ignore = 0;
    906   return;
    907 }
    908 
    909 
    910 int I_SoundSetTimer( int duration_of_tick )
    911 {
    912   
    913   struct itimerval    value;
    914   struct itimerval    ovalue;
    915   struct sigaction    act;
    916   struct sigaction    oact;
    917 
    918   int res;
    919   
    920   
    921   
    922   
    923   
    924   act.sa_handler = I_HandleSoundTimer;
    925 #ifndef sun    
    926   
    927 #endif
    928   act.sa_flags = SA_RESTART;
    929   
    930   sigaction( sig, &act, &oact );
    931 
    932   value.it_interval.tv_sec    = 0;
    933   value.it_interval.tv_usec   = duration_of_tick;
    934   value.it_value.tv_sec       = 0;
    935   value.it_value.tv_usec      = duration_of_tick;
    936 
    937   
    938   res = setitimer( itimer, &value, &ovalue );
    939 
    940   
    941   if ( res == -1 )
    942     fprintf( stderr, "I_SoundSetTimer: interrupt n.a.\n");
    943   
    944   return res;
    945 }
    946 
    947 
    948 
    949 void I_SoundDelTimer()
    950 {
    951   
    952   if ( I_SoundSetTimer( 0 ) == -1)
    953     fprintf( stderr, "I_SoundDelTimer: failed to remove interrupt. Doh!\n");
    954 }