home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / xgalaga-2_0_tar.gz / xgalaga-2_0_tar / xgalaga-2.0 / xgal.sndsrv.linux.c < prev    next >
C/C++ Source or Header  |  1998-04-12  |  7KB  |  278 lines

  1. /*
  2.  * xgal.sndsrv.c - VoxWare(tm) Compatible Sound - Apr. 1995
  3.  *                 PC Speaker  Compatible Sound 
  4.  *                 This server is Linux Specific.
  5.  *
  6.  * Copyright 1994-1995 Sujal M. Patel (smpatel@wam.umd.edu)
  7.  * Conditions in "copyright.h"
  8.  */
  9.  
  10. /* $Id: xgal.sndsrv.linux.c,v 1.2 1998/04/12 08:10:49 mrogre Exp $ */
  11. #include <config.h>
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <unistd.h>
  16. #include <fcntl.h>
  17. #include <sys/ioctl.h>
  18. #include <linux/soundcard.h>
  19. /*#include "linux_pcsp.h"      /* /usr/include/linux/pcsp.h      */
  20. #include <sys/time.h>
  21. #include <signal.h>
  22. #include <string.h>
  23.  
  24. #ifndef PCSP_ONLY
  25. #define PCSP_ONLY 0
  26. #endif
  27.  
  28. char *FILENAME[] = {
  29.                      "/explode.raw",
  30.                      "/firetorp.raw",
  31.                      "/shield.raw",
  32.                      "/torphit.raw",
  33.                      "/explode_big.raw",
  34.              "/ddloo.raw",
  35.              "/warp.raw",
  36.              "/smart.raw",
  37.                    };
  38.  
  39. #define NUM_SOUNDS    (sizeof(FILENAME)/sizeof(char*))
  40.  
  41. signed char *sound_buffer[NUM_SOUNDS];
  42. int sound_size[NUM_SOUNDS];
  43. int fragsize;
  44.  
  45.  
  46. /* Terminate: Signal Handler */
  47. void quit ()
  48. {
  49.   exit (0);
  50. }
  51.  
  52.  
  53.  
  54. void init (int argc, char **argv)
  55. {
  56.   int i;
  57.   char s[1024];
  58.  
  59.   if (argc != 3)
  60.   {
  61.     printf ("This program is only executed by xgal\n");
  62.     exit (1);
  63.   }
  64.  
  65.   for (i=0; i < NUM_SOUNDS; i++)
  66.   {
  67.     s[0] = 0;
  68.     strcat (s, argv[1]);
  69.     if (s[(int)strlen(s) - 1] == '/') FILENAME[i]++;
  70.     strcat (s, FILENAME[i]);
  71.     FILENAME[i] = malloc ((int)strlen (s));
  72.     strcpy (FILENAME[i],s);
  73.     sound_buffer[i]=NULL;
  74.     sound_size[i]=0;
  75.   }
  76.  
  77.   signal(SIGTERM, quit);   /* Setup Terminate Signal Handler */
  78. }
  79.  
  80.  
  81. /*
  82.    Setup DSP: Opens /dev/dsp or /dev/pcdsp
  83.               Sets fragment size on VoxWare
  84.               Sets speed to 8000hz
  85.               Should set mono mode
  86.               Error checking                
  87. */
  88. int setup_dsp (char *dspdev,int *is_pcsp)
  89. {
  90.   int dsp, frag, value;
  91.   int mixer;
  92.  
  93.   dsp = open(dspdev, O_RDWR);
  94.   if (dsp < 0)
  95.   {
  96.     fprintf (stderr, "xgal.sndsrv: Couldn't open DSP %s\n",dspdev);
  97.     return -1;
  98.   }
  99.  
  100.   *is_pcsp = 0;
  101.   fragsize = 0;
  102.  
  103.   frag = 0x00020009;   /* try 512 bytes, for 1/16 second frag size */
  104.   ioctl(dsp, SNDCTL_DSP_SETFRAGMENT, &frag);
  105.   value = 8010;
  106.   if (ioctl(dsp, SNDCTL_DSP_SPEED, &value))
  107.   {
  108.       fprintf (stderr, "xgal.sndsrv: Couldn't set DSP rate!\n");
  109.   };
  110.   value = 0;
  111.   ioctl(dsp, SNDCTL_DSP_STEREO, &value);
  112.   ioctl(dsp, SNDCTL_DSP_GETBLKSIZE, &fragsize);
  113. /*  fprintf(stderr,"xgal.sndsrv: fragment set to %d\n",fragsize);*/
  114.  
  115.   if (!fragsize || PCSP_ONLY)
  116.   { 
  117.     /* Don't Assume just because you can't set the fragment, use proper IOCTL */
  118.     fprintf (stderr, "xgal.sndsrv: Couldn't set Fragment Size.\nAssuming PC Speaker!\n");
  119.     fragsize = 128;
  120.     *is_pcsp = 1;
  121.   } else {
  122.       mixer = open("/dev/mixer",O_RDWR | O_NONBLOCK);
  123.       if(mixer==-1)  {
  124.           fprintf(stderr,"xgal.sndsrv: Couldn't open mixer %s\n","/dev/mixer");
  125.           return(-1);
  126.       };
  127. #if 0
  128.       value=0x6464;
  129.       ioctl(mixer,SOUND_MIXER_WRITE_PCM,&value);
  130.       ioctl(mixer,SOUND_MIXER_WRITE_VOLUME,&value);  /*what does this do?*/
  131. #endif
  132.       close(mixer);
  133.  
  134.   }
  135.   
  136.   return dsp;
  137. }
  138.  
  139. /*
  140.    This just keeps the pipe from breaking...
  141.    Eventually I'll look at the xgal signal handlers and
  142.    just trap this.
  143. */
  144. int do_nothing(void)
  145. {
  146.     fprintf(stderr,"xgal.sndsrv: Sound not available\n");
  147.     while(1)  sleep (5);
  148. }
  149.  
  150. int read_sound(int k)
  151. {
  152.   int i,fd,size;
  153.  
  154.   /*fprintf(stderr,"loading sound %d, %s\n",k,FILENAME[k]);*/
  155.  
  156.   fd = open(FILENAME[k], O_RDONLY);
  157.   if(fd<=0) 
  158.   {
  159.     fprintf (stderr, "xgal.sndsrv: The sound %s could not be opened\n", FILENAME[k]);
  160.     sound_size[k]=-1;
  161.     return(0);
  162.   };
  163.   size=lseek(fd,0,SEEK_END);
  164.   sound_size[k]=(size/fragsize)+1;   /*size in fragments*/
  165.   sound_buffer[k]=malloc(sound_size[k]*fragsize);
  166.   if(sound_buffer[k]==NULL)
  167.   {
  168.     fprintf(stderr,"xgal.sndsrv: couldn't malloc memory for sound\n");
  169.     sound_size[k]=-1;
  170.     close(fd);
  171.     return(0);
  172.   };
  173.   lseek(fd,0,SEEK_SET);
  174.   read(fd,sound_buffer[k],size);
  175.   close(fd);
  176.   for(i=0;i<size;i++)  sound_buffer[k][i]^=0x80;
  177.   memset(sound_buffer[k]+size,0,sound_size[k]*fragsize-size);
  178.   
  179.   /*fprintf(stderr,"sound has been loaded, %d bytes\n",size);*/ /*DEBUG*/
  180.   return(1);
  181. }
  182.  
  183.  
  184. void do_everything (int dsp, int is_pcsp)
  185. {
  186.   char k;
  187.   int i, j ;
  188.   int terminate = -1;             /* Which Sound to Terminate                              */
  189.   int playing[16];                /* Sound numbers that we are playing                     */
  190.   int position[16];          /* Current position in each sound file */
  191.   int playnum = 0;                /* Number of sounds currently being played               */
  192.   unsigned char final[512];       /* Final Mixing Buffer                                   */
  193.   int premix[512];
  194.   char *sample;
  195.  
  196.   for(;;)  {
  197.     terminate = -1;
  198.     /* Try to open a new sound if we get an integer on the 'in' pipe */
  199.     i=read(STDIN_FILENO,&k,sizeof(k));
  200.     if(i==0)  {   /* EOF on pipe means parent has closed its end */
  201.         /*fprintf(stderr,"xgal.sndsrv: shutting down\n"); */
  202.         kill(getpid(), SIGTERM);
  203.     };
  204.     if(i!=-1)  {  /* there was something in the pipe */
  205.         /*fprintf(stderr,"Just read a %d from pipe\n",(int)k);*/ /*DEBUG*/
  206.         /* Negative means terminate the FIRST sound in the buffer */
  207.         if(k<0)  {
  208.             /*fprintf(stderr,"terminating sound\n");*/ /*DEBUG*/
  209.             terminate = 0;
  210.         } else {
  211.             if(sound_size[(int)k]==0) read_sound(k);
  212.             if(sound_size[(int)k]>0 && playnum<16)  {
  213.             position[playnum]=0;
  214.                 playing[playnum++]=k;
  215.                 /*fprintf(stderr,"sound %d added to play queue\n",playnum-1);*/ /*DEBUG*/
  216.             };
  217.         };
  218.     };
  219.  
  220.     /* terminate a sound if necessary */
  221.     for(i=0;i<playnum;i++)
  222.     {
  223.       if((position[i]==sound_size[playing[i]]) || (terminate==i))
  224.       {
  225.         /*fprintf(stderr,"finished playing sound %d\n",i);*/ /*DEBUG*/
  226.     /*fprintf(stderr,"is was at position %d\n",position[i]);*/ /*DEBUG*/
  227.         memmove(playing+i,playing+i+1,(playnum-i)*sizeof(int));
  228.         memmove(position+i,position+i+1,(playnum-i)*sizeof(int));
  229.         playnum--;i--;
  230.       };
  231.     };
  232.  
  233.     if(playnum)  {
  234.         /* Mix each sound into the final buffer */
  235.         memset(premix,0,sizeof(premix));
  236.         for(i=0;i<playnum;i++)  {
  237.             sample=sound_buffer[playing[i]]+position[i]*fragsize;
  238.             for(j=0;j<fragsize;j++)  {
  239.                 premix[j]+=*(sample+j);
  240.             };
  241.             position[i]++;
  242.         };
  243.         for(i=0;i<fragsize;i++)
  244.             final[i]=(premix[i]>255)?255:(premix[i]<-256?0:(premix[i]>>1)+128);
  245.     } else {
  246.         /* 
  247.            We have no sounds to play
  248.            Just fill the buffer with silence and maybe play it 
  249.         */
  250.         memset(final,128,sizeof(final));
  251.     };
  252.     write (dsp, final, fragsize);
  253.     /*
  254.        The sound server is in a tight loop, EXCEPT for this
  255.        write which blocks.  Any optimizations in the above
  256.        code would really be helpful.  Right now the server
  257.        takes up to 7% cpu on a 486DX/50.
  258.     */
  259.   }
  260. }
  261.  
  262.  
  263.  
  264. void main (argc, argv)
  265. int argc;
  266. char **argv;
  267. {
  268.   int dsp, is_pcsp;
  269.  
  270.   fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
  271.   init (argc, argv);
  272.   dsp = setup_dsp (argv[2],&is_pcsp);
  273.  
  274.   if (dsp<0) do_nothing();
  275.  
  276.   do_everything (dsp, is_pcsp);
  277. }
  278.