Crossfire Client, Branches  R11627
cfsndserv.c
Go to the documentation of this file.
1 static char *rcsid_cfsndserv_c =
2  "$Id: cfsndserv.c 8649 2008-03-29 10:58:58Z ryo_saeba $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
7  Copyright (C) 2003 Tim Hentenaar
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23  The author can be reached via e-mail to crossfire-devel@real-time.com
24 */
25 
26 /* Comment from the original author is below. In addition to OSS
27  * and ALSA, sun sound is also supported.
28  */
29 
30 /*
31  * (c) 1998 Jacek Konieczny <jajcus@zeus.polsl.gliwice.pl>
32  *
33  * This file contains the server for sound support for the client.
34  * It supports both ALSA_SOUND and OSS_SOUND. Any other sound system support
35  * can be easily added - only new init_audio and audio_play
36  * need be written.
37  *
38  * If you have any problems please e-mail me.
39  */
40 
41 
42 /*#define ALSA_SOUND*/
43 /*#define OSS_SOUND*/
44 /*#define SGI_SOUND*/
45 /*#define SUN_SOUND*/
46 
47 /*#define SOUND_DEBUG*/
48 
49 #include <config.h>
50 
51 #include <stdio.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <time.h>
55 
56 #ifdef HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif
59 
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 
64 #include <math.h>
65 
66 #ifdef HAVE_SYS_IOCTL_H
67 #include <sys/ioctl.h>
68 #endif
69 
70 #ifdef HAVE_SYS_SELECT_H
71 #include <sys/select.h>
72 #endif
73 
74 #ifdef HAVE_STRING_H
75 #include <string.h>
76 #endif
77 
78 #include <stdlib.h>
79 #include <ctype.h>
80 #include <errno.h>
81 
82 #include "newclient.h"
83 #include "soundsdef.h"
84 
85 
86 #if defined(ALSA_SOUND)
87 # include <sys/asoundlib.h>
88 # define AUDIODEV "/dev/dsp"
89  snd_pcm_t *handle=NULL;
90 #elif defined(OSS_SOUND)
91 # include <sys/soundcard.h>
92 # define AUDIODEV "/dev/dsp"
93 #elif defined(SGI_SOUND)
94 # include <audio.h>
95 # define AUDIODEV "/foo/bar"
96 #elif defined(SUN_SOUND)
97 # include <sys/audioio.h>
98 # define AUDIODEV "/dev/audio"
99 #else
100 #error Not known sound system defined
101 #endif
102 
103 #define CONFIG_FILE "/.crossfire/sndconfig"
104 #define MAX_SOUNDS 1024
105 
106 /*
107  * A replacement of strdup(), since it's not defined at some
108  * unix variants.
109  */
110 
111 char *strdup_local(char *str) {
112  char *c=(char *)malloc(sizeof(char)*strlen(str)+1);
113  strcpy(c,str);
114  return c;
115 }
116 
117 
118 
119 typedef struct Sound_Info {
120  char *filename;
121  char *symbolic;
122  unsigned char volume;
123  int size;
124  unsigned char *data;
125 } Sound_Info;
126 
129 
130 #define SOUND_DECREASE 0.1
131 
132 /* mixer variables */
133 char *buffers=NULL;
135 int current_buffer=0; /* Next buffer we will write out */
136 int first_free_buffer=0; /* So we know when to stop playing sounds */
137 
138 int soundfd=0;
139 
140 /* sound device parameters */
142 
143 #ifdef SUN_SOUND
144 struct sound_settings{
146  const char *audiodev;
147 } settings={0,1,1,11025,100,4096,4,AUDIODEV};
148 
149 #else
150 
151 struct sound_settings{
153  const char *audiodev;
154 } settings={0,1,0,11025,100,1024,4,AUDIODEV};
155 
156 #endif
157 
158 /* parses a line from the sound file. This is a little uglier because
159  * we store some static values in the function so we know what we are doing -
160  * however, it is somewhat necessary so that we can use this same function
161  * to parse both files and the compiled in data.
162  *
163  * Note that this function will modify the data in line. lineno is just
164  * for error tracking purposes.
165  */
166 
167 static void parse_sound_line(char *line, int lineno) {
168  static int readtype=0, lastnum=0;
169  int newnum, len;
170  char *cp,*volume,*symbolic,*cp1,filename[512];
171 
172  if (line[0]=='#' || line[0]=='\n') return;
173 
174  if (!strcmp(line,"Standard Sounds:\n")) {
175  lastnum=0;
176  readtype=1;
177  return;
178  }
179  if (!strcmp(line,"Spell Sounds:\n")) {
180  lastnum=0;
181  readtype=2;
182  return;
183  }
184  if (!readtype) {
185 #ifdef SOUND_DEBUG
186  fprintf(stderr,"Got input without finding section header yet:\n%d:%s\n",
187  lineno, line);
188 #endif
189  return;
190  }
191 
192  if (line[strlen(line)-1]=='\n') line[strlen(line)-1]='\0';
193 
194  len=strcspn(line, " \t");
195  line[len]='\0';
196  cp = line+len+1;
197 
198 
199  /* Skip all whitespace for the next field */
200  while (*cp!='\0' && (*cp==' ' || *cp=='\t'))
201  cp++;
202 
203  volume=cp;
204 
205  /* No symbolic name or number - that is ok */
206  cp1=cp;
207  if (!(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) {
208  newnum=lastnum+1;
209  symbolic=NULL;
210  } else { /* We think we have a symbolic name */
211  /* Don't need to nulterm the volume, since we atoi it anyways */
212  while (*cp!='\0' && (*cp==' ' || *cp=='\t'))
213  cp++;
214 
215  symbolic=cp;
216  /* Some symbolc names are double quote protected. If, do some
217  * special processing. We strip off the quotes.
218  */
219  if (*symbolic=='"') {
220  symbolic++;
221  for (cp=symbolic; *cp!='\0' && *cp!='"'; cp++) ;
222  *cp='\0';
223  cp++;
224  }
225  /* Lets try to find the sound number now */
226  cp1 = cp;
227  if (!(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t')))
228  newnum=lastnum+1;
229  else {
230  *cp++='\0';
231  while (*cp!='\0' && (*cp==' ' || *cp=='\t'))
232  cp++;
233  if (isdigit(*cp))
234  newnum=atoi(cp);
235  else newnum=lastnum+1;
236  }
237  }
238  if (newnum < 0 || newnum>MAX_SOUNDS) {
239  fprintf(stderr,"Invalid sound number %d, line %d, buf %s\n",
240  newnum, lineno, line);
241  return;
242  }
243 
244  /* Compatibility processing for older files - if the file ends in
245  * .au, convert to .raw. A bit of a hack, but probably better than
246  * trying to play an au file.
247  */
248  strcpy(filename, line);
249  cp = filename + strlen(filename)-3;
250  if (!strcmp(cp, ".au"))
251  strcpy(cp, ".raw");
252 
253  if (symbolic && !strcmp(symbolic,"DEFAULT")) {
254  if (readtype==1) {
255  default_normal.filename=strdup_local(filename);
256  default_normal.volume=atoi(volume);
257  } else if (readtype==2) {
258  default_spell.filename=strdup_local(filename);
259  default_spell.volume=atoi(volume);
260  }
261  return;
262  }
263  else {
264  if (readtype==1) {
265  normal_sounds[newnum].filename = strdup_local(filename);
266  normal_sounds[newnum].volume = atoi(volume);
267  if (symbolic) normal_sounds[newnum].symbolic=strdup_local(symbolic);
268  else normal_sounds[newnum].symbolic=NULL;
269  } else if (readtype==2) {
270  spell_sounds[newnum].filename = strdup_local(filename);
271  spell_sounds[newnum].volume = atoi(volume);
272  if (symbolic) spell_sounds[newnum].symbolic=strdup_local(symbolic);
273  else spell_sounds[newnum].symbolic=NULL;
274  }
275  lastnum=newnum;
276  }
277 }
278 
279 #if defined(ALSA_SOUND)
280 int init_audio(){
281 
282  int card=0,device=0,err;
283  snd_pcm_channel_params_t params;
284 
285  printf("cfsndserv compiled for ALSA sound system\n");
286  fflush(stdout);
287 
288  if ( (err = snd_pcm_open( &handle, card, device, SND_PCM_OPEN_PLAYBACK )) <0 ) {
289  fprintf( stderr, "open failed: %s\n", snd_strerror( err ) );
290  return -1;
291  }
292 
293  params.channel = SND_PCM_CHANNEL_PLAYBACK;
294  params.mode = SND_PCM_MODE_BLOCK;
295 
296  if (settings.bit8)
297  params.format.format = settings.sign?SND_PCM_SFMT_S8:SND_PCM_SFMT_U8;
298  else
299  params.format.format = settings.sign?SND_PCM_SFMT_S16_LE:SND_PCM_SFMT_U16_LE;
300 
301  params.format.rate = settings.frequency;
302  params.format.voices = settings.stereo?2:1;
303  params.buf.block.frag_size = settings.buflen/2;
304  params.buf.block.frags_max = 2;
305  params.buf.block.frags_min = 1;
306 
307  if ( (err = snd_pcm_channel_params( handle, &params )) < 0 ) {
308  fprintf( stderr, "format setup failed: %s\nTrying defaults\n"
309  , snd_strerror( err ) );
310  params.format.format = SND_PCM_SFMT_U8;
311  params.format.rate = 11025;
312  params.format.voices = 1;
313  if ( (err = snd_pcm_channel_params( handle, &params )) < 0 ) {
314  fprintf( stderr, "format setup failed: %s\n", snd_strerror( err ) );
315  snd_pcm_close( handle );
316  return -1;
317  }
318  }
319  switch(params.format.format){
320  case SND_PCM_SFMT_S8:
321  bit8=1;
322  sign=1;
323  break;
324  case SND_PCM_SFMT_U8:
325  bit8=1;
326  sign=0;
327  break;
328  case SND_PCM_SFMT_S16_LE:
329  bit8=0;
330  sign=1;
331  break;
332  case SND_PCM_SFMT_U16_LE:
333  bit8=0;
334  sign=0;
335  break;
336  default:
337  fprintf(stderr,"Coulnd't set proper format\n");
338  return -1;
339  }
340 
341  sample_size=params.format.voices*(bit8?1:2);
342  stereo=(params.format.voices==1)?0:1;
343  frequency=params.format.rate;
344 
345  soundfd=snd_pcm_file_descriptor(handle,SND_PCM_CHANNEL_PLAYBACK);
346  snd_pcm_nonblock_mode( handle, 1 );
347 
348  return 0;
349 }
350 
351 int audio_play(int buffer,int off){
352 
353  return snd_pcm_write(handle,buffers+settings.buflen*buffer+off,settings.buflen-off);
354 }
355 
356 #elif defined(OSS_SOUND)
357 
358 int init_audio(void){
359 
360  const char *audiodev;
361  int value,format,tmp;
362 
363  printf("cfsndserv compiled for OSS sound system\n");
364  fflush(stdout);
365 
366  /* Open the audio device */
367  if ( (audiodev=getenv("AUDIODEV")) == NULL ) {
368  audiodev = settings.audiodev;
369  }
370  soundfd = open(audiodev, (O_WRONLY|O_NONBLOCK), 0);
371  if ( soundfd < 0 ) {
372  fprintf(stderr,"Couldn't open %s: %s\n", audiodev, strerror(errno)); return(-1);
373  }
374 
375  /* Set the audio buffering parameters */
376  value=0;
377  for(tmp=settings.buflen/2;tmp;tmp>>=1) value++;
378 
379  value |= 0x00020000;
380  if ( ioctl(soundfd, SNDCTL_DSP_SETFRAGMENT, &value) < 0 ) {
381  fprintf(stderr,"Couldn't set audio fragment spec\n");
382  return(-1);
383  }
384  if (settings.bit8)
385  format=settings.sign?AFMT_S8:AFMT_U8;
386  else
387  format=settings.sign?AFMT_S16_LE:AFMT_U16_LE;
388 
389  value=format;
390  if ( (ioctl(soundfd, SNDCTL_DSP_SETFMT,&value) < 0) ||
391  (value != format) ) {
392  fprintf(stderr,"Couldn't set audio format\n");
393  }
394 
395  switch(value){
396  case AFMT_S16_LE:
397  bit8=0;
398  sign=1;
399  break;
400  case AFMT_U16_LE:
401  bit8=0;
402  sign=0;
403  break;
404  case AFMT_S8:
405  bit8=1;
406  sign=1;
407  break;
408  case AFMT_U8:
409  bit8=1;
410  sign=0;
411  break;
412  default:
413  return -1;
414  }
415 
417  ioctl(soundfd, SNDCTL_DSP_STEREO, &stereo);
418 
420  if ( ioctl(soundfd, SNDCTL_DSP_SPEED, &frequency) < 0 ) {
421  fprintf(stderr,"Couldn't set audio frequency\n");
422  return(-1);
423  }
424  sample_size=(bit8?1:2)*(stereo?2:1);
425  return 0;
426 }
427 
428 int audio_play(int buffer,int off){
429  int wrote;
430 #ifdef SOUND_DEBUG
431  printf("audio play - writing starting at %d, %d bytes",
432  settings.buflen*buffer+off,settings.buflen-off);
433  fflush(stdout);
434 #endif
435  wrote=write(soundfd,buffers+settings.buflen*buffer+off,settings.buflen-off);
436 #ifdef SOUND_DEBUG
437  printf("...wrote %d bytes\n", wrote);
438  fflush(stdout);
439 #endif
440  return wrote;
441 }
442 /* End of OSS sound */
443 
444 #elif defined(SGI_SOUND)
445 
446 ALconfig soundconfig;
447 ALport soundport;
448 
449 int init_audio()
450 {
451  long params[2];
452 
453  printf("cfsndserv compiled for SGI sound system\n");
454  fflush(stdout);
455 
456  /* Allocate ALconfig structure. */
457 
458  if ((soundconfig=ALnewconfig())==0)
459  {
460  fprintf(stderr,"Could not allocate ALconfig structure.\n");
461  return -1;
462  }
463 
464  /* Set number of channels */
465 
466  if (ALsetchannels(soundconfig,(stereo=settings.stereo)?2:1)==-1)
467  {
468  fprintf(stderr,"Could not set number of channels.\n");
469  return -1;
470  }
471 
472  /* Set sample format */
473 
474  if (ALsetsampfmt(soundconfig,AL_SAMPFMT_TWOSCOMP)==-1)
475  {
476  fprintf(stderr,"Could not set audio sample format.\n");
477  return -1;
478  }
479  sign=1;
480 
481  /* Set sample width */
482 
483  if (ALsetwidth(soundconfig,(bit8=settings.bit8)?AL_SAMPLE_8:AL_SAMPLE_16)==-1)
484  {
485  fprintf(stderr,"Could not set audio sample width.\n");
486  return -1;
487  }
488  sample_size=(stereo?2:1)*(bit8?1:2);
489 
490  /* Set frequency */
491 
492  params[0]=AL_OUTPUT_RATE;
493  params[1]=frequency=settings.frequency;
494  if (ALsetparams(AL_DEFAULT_DEVICE,params,2)==-1)
495  {
496  fprintf(stderr,"Could not set output rate of default device.\n");
497  return -1;
498  }
499 
500  /* Open audio port */
501 
502  if ((soundport=ALopenport("cfsndserv port","w",soundconfig))==NULL)
503  {
504  fprintf(stderr,"Could not open audio port.\n");
505  return -1;
506  }
507  soundfd=ALgetfd(soundport);
508  return 0;
509 }
510 
511 int audio_play(int buffer,int off)
512 {
513  ALwritesamps(soundport,buffers+settings.buflen*buffer+off,(settings.buflen-off)/sample_size);
514  return settings.buflen-off;
515 }
516 
517 #elif defined(SUN_SOUND)
518 
519 int init_audio(){
520 
521  const char *audiodev;
522  int value,format,tmp;
523  audio_info_t audio_info;
524  audio_device_t audio_device;
525 
526  printf("cfsndserv compiled for SUN sound system\n");
527  fflush(stdout);
528 
529  /* Open the audio device */
530  if ( (audiodev=getenv("AUDIODEV")) == NULL ) {
531  audiodev = settings.audiodev;
532  }
533  soundfd = open(audiodev, (O_WRONLY|O_NONBLOCK), 0);
534  if ( soundfd < 0 ) {
535  fprintf(stderr,"Couldn't open %s: %s\n", audiodev, strerror(errno)); return(-1);
536  }
537 
538  if (ioctl(soundfd, AUDIO_GETDEV, &audio_device) < 0) {
539  fprintf(stderr,"Couldn't get audio device ioctl\n");
540  return(-1);
541  }
542  if ( ioctl(soundfd, AUDIO_GETINFO, &audio_info) < 0 ) {
543  fprintf(stderr,"Couldn't get audio information ioctl\n");
544  return(-1);
545  }
546  /* The capabilities on different sun hardware vary wildly.
547  * We attempt to get a working setup no matter what hardware we are
548  * running on.
549  */
550 
551  /* This is sparc 10, sparc 20 class systems */
552  if (!strcmp(audio_device.name, "SUNW,dbri")) {
553  /* To use linear encoding, we must use 16 bit and some fixed
554  * frequencies. 11025 matches what the rest of the systems use
555  */
556  audio_info.play.precision = 16;
557  audio_info.play.encoding=AUDIO_ENCODING_LINEAR;
558  audio_info.play.sample_rate=11025;
559  }
560  /* This is used on many of the ultra machines */
561  else if (!strcmp(audio_device.name, "SUNW,CS4231")) {
562  /* To use linear encoding, we must use 16 bit and some fixed
563  * frequencies. 11025 matches what the rest of the systems use
564  */
565  audio_info.play.precision = 16;
566  audio_info.play.encoding=AUDIO_ENCODING_LINEAR;
567  audio_info.play.sample_rate=11025;
568  }
569 
570  audio_info.play.channels = settings.stereo?2:1;
572 
573  bit8=(audio_info.play.precision==8)?1:0;
575  sample_size=(bit8?1:2)*(stereo?2:1);
576  fprintf(stderr,"SUN_SOUND: bit8=%d, stereo=%d, freq=%d, sample_size=%d\n",
578 
579  if ( ioctl(soundfd, AUDIO_SETINFO, &audio_info) < 0 ) {
580  perror("Couldn't set audio information ioctl");
581  return(-1);
582  }
583  return 0;
584 }
585 
586 int audio_play(int buffer,int off){
587  int wrote;
588 #ifdef SOUND_DEBUG
589  printf("audio play - writing starting at %d, %d bytes",
590  settings.buflen*buffer+off,settings.buflen-off);
591  fflush(stdout);
592 #endif
593  wrote=write(soundfd,buffers+settings.buflen*buffer+off,settings.buflen-off);
594 #ifdef SOUND_DEBUG
595  printf("...wrote %d bytes\n", wrote);
596  fflush(stdout);
597 #endif
598  return wrote;
599 }
600 /* End of Sun sound */
601 
602 #endif
603 
604 
605 
606 /* init_sounds open the audio device, and reads any configuration files
607  * that need to be. It returns 0 on success. On failure, the calling
608  * function will likely disable sound support/requests from the server.
609  */
610 
611 int init_sounds(void)
612 {
613  int i;
614  FILE *fp;
615  char path[256], buf[512];
616 
617 #ifdef SOUND_DEBUG
618  fprintf( stderr,"Settings: bits: %i, ",settings.bit8?8:16);
619  fprintf( stderr,"%s, ",settings.sign?"signed":"unsigned");
620  fprintf( stderr,"%s, ",settings.stereo?"stereo":"mono");
621  fprintf( stderr,"frequency: %i, ",settings.frequency);
622  fprintf( stderr,"device: %s\n",settings.audiodev);
623 #endif
624 
625  buffers = (char *)malloc( settings.buffers * settings.buflen );
626  if ( !buffers ) return -1;
627  sounds_in_buffer = (int *)calloc( settings.buffers,sizeof(int) );
628  if ( !sounds_in_buffer ) return -1;
629 
630  if (init_audio()) return -1;
631 
632  if (sign) zerolevel=0;
633  else zerolevel=bit8?0x80:0x8000;
634 
636 
637 #ifdef SOUND_DEBUG
638  fprintf( stderr,"bits: %i, ",bit8?8:16);
639  fprintf( stderr,"%s, ",sign?"signed":"unsigned");
640  fprintf( stderr,"%s, ",stereo?"stereo":"mono");
641  fprintf( stderr,"freq: %i, ",frequency);
642  fprintf( stderr,"smpl_size: %i, ",sample_size);
643  fprintf( stderr,"0level: %i\n",zerolevel);
644 #endif
645 
646  for (i=0; i<MAX_SOUNDS; i++) {
647  normal_sounds[i].filename=NULL;
648  spell_sounds[i].filename=NULL;
649  normal_sounds[i].size=-1;
650  spell_sounds[i].size=-1;
651  }
652  default_normal.filename=NULL;
653  default_spell.filename=NULL;
654 
655  sprintf(path,"%s/.crossfire/sounds", getenv("HOME"));
656  i=0;
657  if (!(fp=fopen(path,"r"))) {
658  fprintf(stderr,"Unable to open %s - will use built in defaults\n", path);
659  for (; i<sizeof(def_sounds)/sizeof(char*); i++) {
660  strcpy(buf, def_sounds[i]);
661  parse_sound_line(buf,i);
662  }
663  } else while (fgets(buf, 511, fp)!=NULL) {
664  buf[511]='\0';
665  parse_sound_line(buf, ++i);
666  }
667  /* Note in both cases below, we leave the symbolic name untouched. */
668  for (i=0; i<MAX_SOUNDS; i++) {
669  if (!normal_sounds[i].filename) {
670  normal_sounds[i].filename=default_normal.filename;
671  normal_sounds[i].volume=default_normal.volume;
672  }
673  if (!spell_sounds[i].filename) {
674  spell_sounds[i].filename=default_spell.filename;
675  spell_sounds[i].volume=default_spell.volume;
676  }
677  normal_sounds[i].data=NULL;
678  spell_sounds[i].data=NULL;
679  }
680  return 0;
681 }
682 
683 /* Plays sound 'soundnum'. soundtype is 0 for normal sounds, 1 for
684  * spell_sounds. This might get extended in the future. x,y are offset
685  * (assumed from player) to play sound. This information is used to
686  * determine value and left vs right speaker balance.
687  * This doesn't really play a sound, rather it just addes it to
688  * the buffer to be played later on.
689  */
690 
691 static void play_sound(int soundnum, int soundtype, int x, int y)
692 {
693  Sound_Info *si;
694  int buf,off;
695  int i;
696  unsigned left_ratio,right_ratio;
697  double dist;
698 
699  buf=current_buffer;
700  if (buf>=settings.buffers) buf=1;
701 
702  if (buf == 0) buf++;
703 
704  /* check if the buffer isn't full */
705 #ifdef SOUND_DEBUG
706  fprintf(stderr,"Sounds in buffer %i: %i\n",buf,sounds_in_buffer[buf]);
707 #endif
708  if (sounds_in_buffer[buf]>settings.simultaneously) return;
709 
710  if (soundnum>=MAX_SOUNDS || soundnum<0) {
711  fprintf(stderr,"Invalid sound number: %d\n", soundnum);
712  return;
713  }
714  if (soundfd==-1) {
715  fprintf(stderr,"Sound device is not open\n");
716  return;
717  }
718 
719  if (soundtype < SOUND_NORMAL || soundtype == 0) soundtype = SOUND_NORMAL;
720 
721  if (soundtype==SOUND_NORMAL) {
722  si = &normal_sounds[soundnum];
723  }
724  else if (soundtype==SOUND_SPELL) {
725  si = &spell_sounds[soundnum];
726  }
727  else {
728  fprintf(stderr,"Unknown soundtype: %d\n", soundtype);
729  return;
730  }
731 
732  if (!si->filename) {
733  fprintf(stderr,"Sound %d (type %d) is not defined\n", soundnum, soundtype);
734  return;
735  }
736 
737  /*
738  * Load the sound if it is not loaded yet.
739  *
740  */
741  if (!si->data){
742  FILE *f;
743  struct stat sbuf;
744 #ifdef SOUND_DEBUG
745  fprintf(stderr,"Loading file: %s\n",si->filename);
746 #endif
747  if (stat(si->filename,&sbuf)){
748  perror(si->filename);
749  return;
750  }
751  si->size=sbuf.st_size;
752  if (si->size <=0 ) return;
754  fprintf(stderr,"Sound %s too long (%i > %i)\n",si->filename,si->size,
756  return;
757  }
758  si->data=(unsigned char *)malloc(si->size);
759  f=fopen(si->filename,"r");
760  if (!f){
761  perror(si->filename);
762  return;
763  }
764  fread(si->data,1,si->size,f);
765  fclose(f);
766  }
767 
768 #ifdef SOUND_DEBUG
769  fprintf(stderr,"Playing sound %i (%s), volume %i, x,y=%d,%d\n",soundnum,si->symbolic,si->volume,x,y);
770 #endif
771  /* calculate volume multiplers */
772  dist=sqrt(x*x+y*y);
773  right_ratio=left_ratio=((1<<16)*si->volume)/(100*settings.simultaneously*(1+SOUND_DECREASE*dist));
774  if (stereo){
775  double diff;
776  if (dist)
777  diff=(1.0-fabs((double)x/dist));
778  else
779  diff=1;
780 #ifdef SOUND_DEBUG
781  printf("diff: %f\n",diff);
782  fflush(stdout);
783 #endif
784  if (x<0) right_ratio*=diff;
785  else left_ratio*=diff;
786  }
787 
788 #ifdef SOUND_DEBUG
789  fprintf(stderr,"Ratio: %i, %i\n",left_ratio,right_ratio);
790 #endif
791 
792  /* insert the sound to the buffers */
793  sounds_in_buffer[buf]++;
794  off=0;
795  for(i=0;i<si->size;i++){
796  int dat=si->data[i]-0x80;
797 
798  if (bit8){
799  if (!stereo){
800  buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16;
801  }
802  else{
803  buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16;
804  buffers[buf*settings.buflen+off+1]+=(dat*right_ratio)>>16;
805  }
806  }
807  else{ /* 16 bit output */
808  if (!stereo){
809 #ifdef WORDS_BIGENDIAN
810  buffers[buf*settings.buflen+off+1]+=((dat*left_ratio)>>8)&0xff;
811  buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16;
812  }
813  else{
814  buffers[buf*settings.buflen+off+1]+=((dat*left_ratio)>>8)&0xff;
815  buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16;
816  buffers[buf*settings.buflen+off+3]+=((dat*right_ratio)>>8)&0xff;
817  buffers[buf*settings.buflen+off+2]+=(dat*right_ratio)>>16;
818  }
819 #else
820  buffers[buf*settings.buflen+off]+=((dat*left_ratio)>>8)&0xff;
821  buffers[buf*settings.buflen+off+1]+=(dat*left_ratio)>>16;
822  }
823  else{
824  buffers[buf*settings.buflen+off]+=((dat*left_ratio)>>8)&0xff;
825  buffers[buf*settings.buflen+off+1]+=(dat*left_ratio)>>16;
826  buffers[buf*settings.buflen+off+2]+=((dat*right_ratio)>>8)&0xff;
827  buffers[buf*settings.buflen+off+3]+=(dat*right_ratio)>>16;
828  }
829 #endif
830  }
831 
832  off+=sample_size;
833 
834  if (off>=settings.buflen){
835  off=0;
836  buf++;
837  if (buf>=settings.buffers) {
838  buf=0;
839  }
840  }
841  }
842 #ifdef SOUND_DEBUG
843  fprintf(stderr,"Added %d bytes, last buffer=%d, lastpos=%d\n",
844  si->size, buf, off);
845 #endif
846  /* This write did not wrap the buffers */
847  if (buf+1 > current_buffer) {
848  if ((buf+1 > first_free_buffer) && (first_free_buffer >= current_buffer))
849  first_free_buffer = buf+1;
850  } else { /* Buffers did wrap */
851  if (((buf+1 > first_free_buffer) && (first_free_buffer < current_buffer)) ||
853  first_free_buffer = buf+1;
854  }
856 
857 }
858 
859 int SoundCmd(unsigned char *data, int len)
860 {
861  int x, y, num, type;
862  int i;
863 
864  i=sscanf((char *)data,"%x %x %x %x",&num,&type,&x,&y);
865  if (i!=4){
866  fprintf(stderr,"Wrong input!\n");
867  return -1;
868  }
869 #ifdef SOUND_DEBUG
870  fprintf(stderr,"Playing sound %d (type %d), offset %d, %d\n",
871  num, type, x ,y);
872 #endif
873  play_sound(num, type, x, y);
874  return 0;
875 }
876 
877 int write_settings(void) {
878 FILE *f;
879 char *home;
880 char *path;
881 
882  if ( (home=getenv("HOME")) == NULL ) return -1;
883  path=(char *)malloc(strlen(home)+strlen(CONFIG_FILE)+1);
884  if (!path) return -1;
885  strcpy(path,home);
886  strcat(path,CONFIG_FILE);
887  f=fopen(path,"w");
888  if (!f) return -1;
889  fprintf(f,"# Crossfire sound server settings\n");
890  fprintf(f,"# Please note, that not everything will work\n\n");
891  fprintf(f,"stereo: %i\n",settings.stereo);
892  fprintf(f,"bits: %i\n",settings.bit8?8:16);
893  fprintf(f,"signed: %i\n",settings.sign);
894  fprintf(f,"frequency: %i\n",settings.frequency);
895  fprintf(f,"buffers: %i\n",settings.buffers);
896  fprintf(f,"buflen: %i\n",settings.buflen);
897  fprintf(f,"simultaneously: %i\n",settings.simultaneously);
898 /* fprintf(f,"device: %s\n",settings.audiodev);*/
899  fclose(f);
900  return 0;
901 }
902 
903 int read_settings(void) {
904  FILE *f;
905  char *home;
906  char *path;
907  char linebuf[1024];
908  if ( (home=getenv("HOME")) == NULL ) return 0;
909 
910  path=(char *)malloc(strlen(home)+strlen(CONFIG_FILE)+1);
911  if (!path) return 0;
912 
913  strcpy(path,home);
914  strcat(path,CONFIG_FILE);
915 
916  f=fopen(path,"r");
917  if (!f) return -1;
918 
919  while(fgets(linebuf,1023,f)!=NULL) {
920  linebuf[1023]=0;
921  /* Strip off the newline */
922  linebuf[strlen(linebuf)-1]=0;
923 
924  if (strncmp(linebuf,"stereo:",strlen("stereo:"))==0)
925  settings.stereo=atoi(linebuf+strlen("stereo:"))?1:0;
926  else if (strncmp(linebuf,"bits:",strlen("bits:"))==0)
927  settings.bit8=(atoi(linebuf+strlen("bits:"))==8)?1:0;
928  else if (strncmp(linebuf,"signed:",strlen("signed:"))==0)
929  settings.sign=atoi(linebuf+strlen("signed:"))?1:0;
930  else if (strncmp(linebuf,"buffers:",strlen("buffers:"))==0)
931  settings.buffers=atoi(linebuf+strlen("buffers:"));
932  else if (strncmp(linebuf,"buflen:",strlen("buflen:"))==0)
933  settings.buflen=atoi(linebuf+strlen("buflen:"));
934  else if (strncmp(linebuf,"frequency:",strlen("frequency:"))==0)
935  settings.frequency=atoi(linebuf+strlen("frequency:"));
936  else if (strncmp(linebuf,"simultaneously:",strlen("simultaneously:"))==0)
937  settings.simultaneously=atoi(linebuf+strlen("simultaneously:"));
938 #if 0
939  else if (strncmp(linebuf,"device: ",strlen("device: "))==0)
940  settings.audiodev=strdup_local(linebuf+strlen("device: "));
941 #endif
942  }
943  fclose(f);
944  return 0;
945 }
946 
947 int main(int argc, char *argv[])
948 {
949  int infd;
950  char inbuf[1024];
951  int inbuf_pos=0,sndbuf_pos=0;
952  fd_set inset,outset;
953 
954  printf ("%s\n",rcsid_cfsndserv_c);
955  fflush(stdout);
956  if (read_settings()) write_settings();
957  if (init_sounds()) return 1;
958  /* we don't use the file descriptor method */
959  if (!soundfd) return 1;
960  infd=fileno(stdin);
961  FD_ZERO(&inset);
962  FD_ZERO(&outset);
963  FD_SET(soundfd,&outset);
964  FD_SET(infd,&inset);
965  while(1){
966 #if defined(SGI_SOUND)
967  /*
968  The buffer of an audio port can hold 100000 samples. If we allow sounds to
969  be written to the port whenever there is enough room in the buffer, all
970  sounds will be played sequentially, which is wrong. We can set the
971  fillpoint to a high value to prevent this.
972  */
973  ALsetfillpoint(soundport,100000);
974 #endif
975 
976 
977  select(FD_SETSIZE,&inset,&outset,NULL,NULL);
978 
979  if (FD_ISSET(soundfd,&outset)){
980  /* no sounds to play */
981  if (current_buffer==first_free_buffer) FD_CLR(soundfd,&outset);
982  else{
983  int wrote;
985  if (wrote<settings.buflen-sndbuf_pos) sndbuf_pos+=wrote;
986  else{
987  /* clean the buffer */
990  sndbuf_pos=0;
991  current_buffer++;
993  }
994  }
995  } else {
996  /* We need to reset this if it is not set - otherwise, we will never
997  * finish playing the sounds
998  */
999  FD_SET(soundfd,&outset);
1000  }
1001 
1002  if (FD_ISSET(infd,&inset)){
1003  int err=read(infd,inbuf+inbuf_pos,1);
1004  if (err<1 && errno!=EINTR){
1005  if (err<0) perror("read");
1006  break;
1007  }
1008  if (inbuf[inbuf_pos]=='\n'){
1009  inbuf[inbuf_pos++]=0;
1010  if (!SoundCmd((unsigned char*)inbuf,inbuf_pos)) FD_SET(soundfd,&outset);
1011  inbuf_pos=0;
1012  }
1013  else{
1014  inbuf_pos++;
1015  if (inbuf_pos>=1024){
1016  fprintf(stderr,"Input buffer overflow!\n");
1017  inbuf_pos=0;
1018  }
1019  }
1020  }
1021  FD_SET(infd,&inset);
1022  }
1023 
1024  return 0;
1025 }
int * sounds_in_buffer
Definition: cfsndserv.c:134
#define MAX_SOUNDS
Definition: cfsndserv.c:104
unsigned char volume
Definition: cfsndserv.c:122
int audio_play(int buffer, int off)
Definition: alsa9.c:260
int zerolevel
Definition: cfsndserv.c:141
int write_settings(void)
Definition: cfsndserv.c:877
int init_audio(void)
Definition: alsa9.c:117
int frequency
Definition: cfsndserv.c:141
Sound_Info spell_sounds[MAX_SOUNDS]
Definition: cfsndserv.c:127
int soundfd
Definition: cfsndserv.c:138
const char * audiodev
Definition: alsa9.c:105
int sign
Definition: cfsndserv.c:141
snd_pcm_hw_params_t * params
Definition: alsa9.c:111
int stereo
Definition: cfsndserv.c:141
int buffers
Definition: alsa9.c:104
int sample_size
Definition: cfsndserv.c:141
char * strdup_local(char *str)
Definition: cfsndserv.c:111
char * filename
Definition: cfsndserv.c:120
int err
Definition: alsa9.c:113
Sound_Info normal_sounds[MAX_SOUNDS]
Definition: cfsndserv.c:127
static void parse_sound_line(char *line, int lineno)
Definition: cfsndserv.c:167
int stereo
Definition: alsa9.c:104
int main(int argc, char *argv[])
Definition: cfsndserv.c:947
#define SOUND_NORMAL
Definition: newclient.h:267
int SoundCmd(unsigned char *data, int len)
Definition: cfsndserv.c:859
int read_settings(void)
Definition: cfsndserv.c:903
Sound_Info default_spell
Definition: cfsndserv.c:127
struct sound_settings settings
int bit8
Definition: cfsndserv.c:141
int sndbuf_pos
Definition: alsa9.c:83
int init_sounds(void)
Definition: cfsndserv.c:611
char * symbolic
Definition: cfsndserv.c:121
struct Sound_Info Sound_Info
#define AUDIODEV
Definition: alsa9.c:81
int frequency
Definition: alsa9.c:104
snd_pcm_t * handle
Definition: alsa9.c:82
#define SOUND_SPELL
Definition: newclient.h:268
#define CONFIG_FILE
Definition: cfsndserv.c:103
const char *const def_sounds[]
Definition: soundsdef.h:1
int simultaneously
Definition: alsa9.c:104
unsigned char * data
Definition: cfsndserv.c:124
char * buffers
Definition: cfsndserv.c:133
Sound_Info default_normal
Definition: cfsndserv.c:127
#define SOUND_DECREASE
Definition: cfsndserv.c:130
int buflen
Definition: alsa9.c:104
int first_free_buffer
Definition: cfsndserv.c:136
static void play_sound(int soundnum, int soundtype, int x, int y)
Definition: cfsndserv.c:691
static char * rcsid_cfsndserv_c
Definition: cfsndserv.c:1
int current_buffer
Definition: cfsndserv.c:135