Crossfire Client, Branch
R11627
|
00001 static char *rcsid_cfsndserv_c = 00002 "$Id: cfsndserv.c 8649 2008-03-29 10:58:58Z ryo_saeba $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00007 Copyright (C) 2003 Tim Hentenaar 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00022 00023 The author can be reached via e-mail to crossfire-devel@real-time.com 00024 */ 00025 00026 /* Comment from the original author is below. In addition to OSS 00027 * and ALSA, sun sound is also supported. 00028 */ 00029 00030 /* 00031 * (c) 1998 Jacek Konieczny <jajcus@zeus.polsl.gliwice.pl> 00032 * 00033 * This file contains the server for sound support for the client. 00034 * It supports both ALSA_SOUND and OSS_SOUND. Any other sound system support 00035 * can be easily added - only new init_audio and audio_play 00036 * need be written. 00037 * 00038 * If you have any problems please e-mail me. 00039 */ 00040 00041 00042 /*#define ALSA_SOUND*/ 00043 /*#define OSS_SOUND*/ 00044 /*#define SGI_SOUND*/ 00045 /*#define SUN_SOUND*/ 00046 00047 /*#define SOUND_DEBUG*/ 00048 00049 #include <config.h> 00050 00051 #include <stdio.h> 00052 #include <sys/types.h> 00053 #include <sys/stat.h> 00054 #include <time.h> 00055 00056 #ifdef HAVE_FCNTL_H 00057 #include <fcntl.h> 00058 #endif 00059 00060 #ifdef HAVE_UNISTD_H 00061 #include <unistd.h> 00062 #endif 00063 00064 #include <math.h> 00065 00066 #ifdef HAVE_SYS_IOCTL_H 00067 #include <sys/ioctl.h> 00068 #endif 00069 00070 #ifdef HAVE_SYS_SELECT_H 00071 #include <sys/select.h> 00072 #endif 00073 00074 #ifdef HAVE_STRING_H 00075 #include <string.h> 00076 #endif 00077 00078 #include <stdlib.h> 00079 #include <ctype.h> 00080 #include <errno.h> 00081 00082 #include "newclient.h" 00083 #include "soundsdef.h" 00084 00085 00086 #if defined(ALSA_SOUND) 00087 # include <sys/asoundlib.h> 00088 # define AUDIODEV "/dev/dsp" 00089 snd_pcm_t *handle=NULL; 00090 #elif defined(OSS_SOUND) 00091 # include <sys/soundcard.h> 00092 # define AUDIODEV "/dev/dsp" 00093 #elif defined(SGI_SOUND) 00094 # include <audio.h> 00095 # define AUDIODEV "/foo/bar" 00096 #elif defined(SUN_SOUND) 00097 # include <sys/audioio.h> 00098 # define AUDIODEV "/dev/audio" 00099 #else 00100 #error Not known sound system defined 00101 #endif 00102 00103 #define CONFIG_FILE "/.crossfire/sndconfig" 00104 #define MAX_SOUNDS 1024 00105 00106 /* 00107 * A replacement of strdup(), since it's not defined at some 00108 * unix variants. 00109 */ 00110 00111 char *strdup_local(char *str) { 00112 char *c=(char *)malloc(sizeof(char)*strlen(str)+1); 00113 strcpy(c,str); 00114 return c; 00115 } 00116 00117 00118 00119 typedef struct Sound_Info { 00120 char *filename; 00121 char *symbolic; 00122 unsigned char volume; 00123 int size; 00124 unsigned char *data; 00125 } Sound_Info; 00126 00127 Sound_Info normal_sounds[MAX_SOUNDS], spell_sounds[MAX_SOUNDS], 00128 default_normal, default_spell; 00129 00130 #define SOUND_DECREASE 0.1 00131 00132 /* mixer variables */ 00133 char *buffers=NULL; 00134 int *sounds_in_buffer=NULL; 00135 int current_buffer=0; /* Next buffer we will write out */ 00136 int first_free_buffer=0; /* So we know when to stop playing sounds */ 00137 00138 int soundfd=0; 00139 00140 /* sound device parameters */ 00141 int stereo=0,bit8=0,sample_size=0,frequency=0,sign=0,zerolevel=0; 00142 00143 #ifdef SUN_SOUND 00144 struct sound_settings{ 00145 int stereo, bit8, sign, frequency, buffers, buflen,simultaneously; 00146 const char *audiodev; 00147 } settings={0,1,1,11025,100,4096,4,AUDIODEV}; 00148 00149 #else 00150 00151 struct sound_settings{ 00152 int stereo, bit8, sign, frequency, buffers, buflen,simultaneously; 00153 const char *audiodev; 00154 } settings={0,1,0,11025,100,1024,4,AUDIODEV}; 00155 00156 #endif 00157 00158 /* parses a line from the sound file. This is a little uglier because 00159 * we store some static values in the function so we know what we are doing - 00160 * however, it is somewhat necessary so that we can use this same function 00161 * to parse both files and the compiled in data. 00162 * 00163 * Note that this function will modify the data in line. lineno is just 00164 * for error tracking purposes. 00165 */ 00166 00167 static void parse_sound_line(char *line, int lineno) { 00168 static int readtype=0, lastnum=0; 00169 int newnum, len; 00170 char *cp,*volume,*symbolic,*cp1,filename[512]; 00171 00172 if (line[0]=='#' || line[0]=='\n') return; 00173 00174 if (!strcmp(line,"Standard Sounds:\n")) { 00175 lastnum=0; 00176 readtype=1; 00177 return; 00178 } 00179 if (!strcmp(line,"Spell Sounds:\n")) { 00180 lastnum=0; 00181 readtype=2; 00182 return; 00183 } 00184 if (!readtype) { 00185 #ifdef SOUND_DEBUG 00186 fprintf(stderr,"Got input without finding section header yet:\n%d:%s\n", 00187 lineno, line); 00188 #endif 00189 return; 00190 } 00191 00192 if (line[strlen(line)-1]=='\n') line[strlen(line)-1]='\0'; 00193 00194 len=strcspn(line, " \t"); 00195 line[len]='\0'; 00196 cp = line+len+1; 00197 00198 00199 /* Skip all whitespace for the next field */ 00200 while (*cp!='\0' && (*cp==' ' || *cp=='\t')) 00201 cp++; 00202 00203 volume=cp; 00204 00205 /* No symbolic name or number - that is ok */ 00206 cp1=cp; 00207 if (!(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) { 00208 newnum=lastnum+1; 00209 symbolic=NULL; 00210 } else { /* We think we have a symbolic name */ 00211 /* Don't need to nulterm the volume, since we atoi it anyways */ 00212 while (*cp!='\0' && (*cp==' ' || *cp=='\t')) 00213 cp++; 00214 00215 symbolic=cp; 00216 /* Some symbolc names are double quote protected. If, do some 00217 * special processing. We strip off the quotes. 00218 */ 00219 if (*symbolic=='"') { 00220 symbolic++; 00221 for (cp=symbolic; *cp!='\0' && *cp!='"'; cp++) ; 00222 *cp='\0'; 00223 cp++; 00224 } 00225 /* Lets try to find the sound number now */ 00226 cp1 = cp; 00227 if (!(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) 00228 newnum=lastnum+1; 00229 else { 00230 *cp++='\0'; 00231 while (*cp!='\0' && (*cp==' ' || *cp=='\t')) 00232 cp++; 00233 if (isdigit(*cp)) 00234 newnum=atoi(cp); 00235 else newnum=lastnum+1; 00236 } 00237 } 00238 if (newnum < 0 || newnum>MAX_SOUNDS) { 00239 fprintf(stderr,"Invalid sound number %d, line %d, buf %s\n", 00240 newnum, lineno, line); 00241 return; 00242 } 00243 00244 /* Compatibility processing for older files - if the file ends in 00245 * .au, convert to .raw. A bit of a hack, but probably better than 00246 * trying to play an au file. 00247 */ 00248 strcpy(filename, line); 00249 cp = filename + strlen(filename)-3; 00250 if (!strcmp(cp, ".au")) 00251 strcpy(cp, ".raw"); 00252 00253 if (symbolic && !strcmp(symbolic,"DEFAULT")) { 00254 if (readtype==1) { 00255 default_normal.filename=strdup_local(filename); 00256 default_normal.volume=atoi(volume); 00257 } else if (readtype==2) { 00258 default_spell.filename=strdup_local(filename); 00259 default_spell.volume=atoi(volume); 00260 } 00261 return; 00262 } 00263 else { 00264 if (readtype==1) { 00265 normal_sounds[newnum].filename = strdup_local(filename); 00266 normal_sounds[newnum].volume = atoi(volume); 00267 if (symbolic) normal_sounds[newnum].symbolic=strdup_local(symbolic); 00268 else normal_sounds[newnum].symbolic=NULL; 00269 } else if (readtype==2) { 00270 spell_sounds[newnum].filename = strdup_local(filename); 00271 spell_sounds[newnum].volume = atoi(volume); 00272 if (symbolic) spell_sounds[newnum].symbolic=strdup_local(symbolic); 00273 else spell_sounds[newnum].symbolic=NULL; 00274 } 00275 lastnum=newnum; 00276 } 00277 } 00278 00279 #if defined(ALSA_SOUND) 00280 int init_audio(){ 00281 00282 int card=0,device=0,err; 00283 snd_pcm_channel_params_t params; 00284 00285 printf("cfsndserv compiled for ALSA sound system\n"); 00286 fflush(stdout); 00287 00288 if ( (err = snd_pcm_open( &handle, card, device, SND_PCM_OPEN_PLAYBACK )) <0 ) { 00289 fprintf( stderr, "open failed: %s\n", snd_strerror( err ) ); 00290 return -1; 00291 } 00292 00293 params.channel = SND_PCM_CHANNEL_PLAYBACK; 00294 params.mode = SND_PCM_MODE_BLOCK; 00295 00296 if (settings.bit8) 00297 params.format.format = settings.sign?SND_PCM_SFMT_S8:SND_PCM_SFMT_U8; 00298 else 00299 params.format.format = settings.sign?SND_PCM_SFMT_S16_LE:SND_PCM_SFMT_U16_LE; 00300 00301 params.format.rate = settings.frequency; 00302 params.format.voices = settings.stereo?2:1; 00303 params.buf.block.frag_size = settings.buflen/2; 00304 params.buf.block.frags_max = 2; 00305 params.buf.block.frags_min = 1; 00306 00307 if ( (err = snd_pcm_channel_params( handle, ¶ms )) < 0 ) { 00308 fprintf( stderr, "format setup failed: %s\nTrying defaults\n" 00309 , snd_strerror( err ) ); 00310 params.format.format = SND_PCM_SFMT_U8; 00311 params.format.rate = 11025; 00312 params.format.voices = 1; 00313 if ( (err = snd_pcm_channel_params( handle, ¶ms )) < 0 ) { 00314 fprintf( stderr, "format setup failed: %s\n", snd_strerror( err ) ); 00315 snd_pcm_close( handle ); 00316 return -1; 00317 } 00318 } 00319 switch(params.format.format){ 00320 case SND_PCM_SFMT_S8: 00321 bit8=1; 00322 sign=1; 00323 break; 00324 case SND_PCM_SFMT_U8: 00325 bit8=1; 00326 sign=0; 00327 break; 00328 case SND_PCM_SFMT_S16_LE: 00329 bit8=0; 00330 sign=1; 00331 break; 00332 case SND_PCM_SFMT_U16_LE: 00333 bit8=0; 00334 sign=0; 00335 break; 00336 default: 00337 fprintf(stderr,"Coulnd't set proper format\n"); 00338 return -1; 00339 } 00340 00341 sample_size=params.format.voices*(bit8?1:2); 00342 stereo=(params.format.voices==1)?0:1; 00343 frequency=params.format.rate; 00344 00345 soundfd=snd_pcm_file_descriptor(handle,SND_PCM_CHANNEL_PLAYBACK); 00346 snd_pcm_nonblock_mode( handle, 1 ); 00347 00348 return 0; 00349 } 00350 00351 int audio_play(int buffer,int off){ 00352 00353 return snd_pcm_write(handle,buffers+settings.buflen*buffer+off,settings.buflen-off); 00354 } 00355 00356 #elif defined(OSS_SOUND) 00357 00358 int init_audio(void){ 00359 00360 const char *audiodev; 00361 int value,format,tmp; 00362 00363 printf("cfsndserv compiled for OSS sound system\n"); 00364 fflush(stdout); 00365 00366 /* Open the audio device */ 00367 if ( (audiodev=getenv("AUDIODEV")) == NULL ) { 00368 audiodev = settings.audiodev; 00369 } 00370 soundfd = open(audiodev, (O_WRONLY|O_NONBLOCK), 0); 00371 if ( soundfd < 0 ) { 00372 fprintf(stderr,"Couldn't open %s: %s\n", audiodev, strerror(errno)); return(-1); 00373 } 00374 00375 /* Set the audio buffering parameters */ 00376 value=0; 00377 for(tmp=settings.buflen/2;tmp;tmp>>=1) value++; 00378 00379 value |= 0x00020000; 00380 if ( ioctl(soundfd, SNDCTL_DSP_SETFRAGMENT, &value) < 0 ) { 00381 fprintf(stderr,"Couldn't set audio fragment spec\n"); 00382 return(-1); 00383 } 00384 if (settings.bit8) 00385 format=settings.sign?AFMT_S8:AFMT_U8; 00386 else 00387 format=settings.sign?AFMT_S16_LE:AFMT_U16_LE; 00388 00389 value=format; 00390 if ( (ioctl(soundfd, SNDCTL_DSP_SETFMT,&value) < 0) || 00391 (value != format) ) { 00392 fprintf(stderr,"Couldn't set audio format\n"); 00393 } 00394 00395 switch(value){ 00396 case AFMT_S16_LE: 00397 bit8=0; 00398 sign=1; 00399 break; 00400 case AFMT_U16_LE: 00401 bit8=0; 00402 sign=0; 00403 break; 00404 case AFMT_S8: 00405 bit8=1; 00406 sign=1; 00407 break; 00408 case AFMT_U8: 00409 bit8=1; 00410 sign=0; 00411 break; 00412 default: 00413 return -1; 00414 } 00415 00416 stereo = settings.stereo; 00417 ioctl(soundfd, SNDCTL_DSP_STEREO, &stereo); 00418 00419 frequency = settings.frequency; 00420 if ( ioctl(soundfd, SNDCTL_DSP_SPEED, &frequency) < 0 ) { 00421 fprintf(stderr,"Couldn't set audio frequency\n"); 00422 return(-1); 00423 } 00424 sample_size=(bit8?1:2)*(stereo?2:1); 00425 return 0; 00426 } 00427 00428 int audio_play(int buffer,int off){ 00429 int wrote; 00430 #ifdef SOUND_DEBUG 00431 printf("audio play - writing starting at %d, %d bytes", 00432 settings.buflen*buffer+off,settings.buflen-off); 00433 fflush(stdout); 00434 #endif 00435 wrote=write(soundfd,buffers+settings.buflen*buffer+off,settings.buflen-off); 00436 #ifdef SOUND_DEBUG 00437 printf("...wrote %d bytes\n", wrote); 00438 fflush(stdout); 00439 #endif 00440 return wrote; 00441 } 00442 /* End of OSS sound */ 00443 00444 #elif defined(SGI_SOUND) 00445 00446 ALconfig soundconfig; 00447 ALport soundport; 00448 00449 int init_audio() 00450 { 00451 long params[2]; 00452 00453 printf("cfsndserv compiled for SGI sound system\n"); 00454 fflush(stdout); 00455 00456 /* Allocate ALconfig structure. */ 00457 00458 if ((soundconfig=ALnewconfig())==0) 00459 { 00460 fprintf(stderr,"Could not allocate ALconfig structure.\n"); 00461 return -1; 00462 } 00463 00464 /* Set number of channels */ 00465 00466 if (ALsetchannels(soundconfig,(stereo=settings.stereo)?2:1)==-1) 00467 { 00468 fprintf(stderr,"Could not set number of channels.\n"); 00469 return -1; 00470 } 00471 00472 /* Set sample format */ 00473 00474 if (ALsetsampfmt(soundconfig,AL_SAMPFMT_TWOSCOMP)==-1) 00475 { 00476 fprintf(stderr,"Could not set audio sample format.\n"); 00477 return -1; 00478 } 00479 sign=1; 00480 00481 /* Set sample width */ 00482 00483 if (ALsetwidth(soundconfig,(bit8=settings.bit8)?AL_SAMPLE_8:AL_SAMPLE_16)==-1) 00484 { 00485 fprintf(stderr,"Could not set audio sample width.\n"); 00486 return -1; 00487 } 00488 sample_size=(stereo?2:1)*(bit8?1:2); 00489 00490 /* Set frequency */ 00491 00492 params[0]=AL_OUTPUT_RATE; 00493 params[1]=frequency=settings.frequency; 00494 if (ALsetparams(AL_DEFAULT_DEVICE,params,2)==-1) 00495 { 00496 fprintf(stderr,"Could not set output rate of default device.\n"); 00497 return -1; 00498 } 00499 00500 /* Open audio port */ 00501 00502 if ((soundport=ALopenport("cfsndserv port","w",soundconfig))==NULL) 00503 { 00504 fprintf(stderr,"Could not open audio port.\n"); 00505 return -1; 00506 } 00507 soundfd=ALgetfd(soundport); 00508 return 0; 00509 } 00510 00511 int audio_play(int buffer,int off) 00512 { 00513 ALwritesamps(soundport,buffers+settings.buflen*buffer+off,(settings.buflen-off)/sample_size); 00514 return settings.buflen-off; 00515 } 00516 00517 #elif defined(SUN_SOUND) 00518 00519 int init_audio(){ 00520 00521 const char *audiodev; 00522 int value,format,tmp; 00523 audio_info_t audio_info; 00524 audio_device_t audio_device; 00525 00526 printf("cfsndserv compiled for SUN sound system\n"); 00527 fflush(stdout); 00528 00529 /* Open the audio device */ 00530 if ( (audiodev=getenv("AUDIODEV")) == NULL ) { 00531 audiodev = settings.audiodev; 00532 } 00533 soundfd = open(audiodev, (O_WRONLY|O_NONBLOCK), 0); 00534 if ( soundfd < 0 ) { 00535 fprintf(stderr,"Couldn't open %s: %s\n", audiodev, strerror(errno)); return(-1); 00536 } 00537 00538 if (ioctl(soundfd, AUDIO_GETDEV, &audio_device) < 0) { 00539 fprintf(stderr,"Couldn't get audio device ioctl\n"); 00540 return(-1); 00541 } 00542 if ( ioctl(soundfd, AUDIO_GETINFO, &audio_info) < 0 ) { 00543 fprintf(stderr,"Couldn't get audio information ioctl\n"); 00544 return(-1); 00545 } 00546 /* The capabilities on different sun hardware vary wildly. 00547 * We attempt to get a working setup no matter what hardware we are 00548 * running on. 00549 */ 00550 00551 /* This is sparc 10, sparc 20 class systems */ 00552 if (!strcmp(audio_device.name, "SUNW,dbri")) { 00553 /* To use linear encoding, we must use 16 bit and some fixed 00554 * frequencies. 11025 matches what the rest of the systems use 00555 */ 00556 audio_info.play.precision = 16; 00557 audio_info.play.encoding=AUDIO_ENCODING_LINEAR; 00558 audio_info.play.sample_rate=11025; 00559 } 00560 /* This is used on many of the ultra machines */ 00561 else if (!strcmp(audio_device.name, "SUNW,CS4231")) { 00562 /* To use linear encoding, we must use 16 bit and some fixed 00563 * frequencies. 11025 matches what the rest of the systems use 00564 */ 00565 audio_info.play.precision = 16; 00566 audio_info.play.encoding=AUDIO_ENCODING_LINEAR; 00567 audio_info.play.sample_rate=11025; 00568 } 00569 00570 audio_info.play.channels = settings.stereo?2:1; 00571 stereo= settings.stereo; 00572 00573 bit8=(audio_info.play.precision==8)?1:0; 00574 frequency=settings.frequency; 00575 sample_size=(bit8?1:2)*(stereo?2:1); 00576 fprintf(stderr,"SUN_SOUND: bit8=%d, stereo=%d, freq=%d, sample_size=%d\n", 00577 bit8, stereo, frequency, sample_size); 00578 00579 if ( ioctl(soundfd, AUDIO_SETINFO, &audio_info) < 0 ) { 00580 perror("Couldn't set audio information ioctl"); 00581 return(-1); 00582 } 00583 return 0; 00584 } 00585 00586 int audio_play(int buffer,int off){ 00587 int wrote; 00588 #ifdef SOUND_DEBUG 00589 printf("audio play - writing starting at %d, %d bytes", 00590 settings.buflen*buffer+off,settings.buflen-off); 00591 fflush(stdout); 00592 #endif 00593 wrote=write(soundfd,buffers+settings.buflen*buffer+off,settings.buflen-off); 00594 #ifdef SOUND_DEBUG 00595 printf("...wrote %d bytes\n", wrote); 00596 fflush(stdout); 00597 #endif 00598 return wrote; 00599 } 00600 /* End of Sun sound */ 00601 00602 #endif 00603 00604 00605 00606 /* init_sounds open the audio device, and reads any configuration files 00607 * that need to be. It returns 0 on success. On failure, the calling 00608 * function will likely disable sound support/requests from the server. 00609 */ 00610 00611 int init_sounds(void) 00612 { 00613 int i; 00614 FILE *fp; 00615 char path[256], buf[512]; 00616 00617 #ifdef SOUND_DEBUG 00618 fprintf( stderr,"Settings: bits: %i, ",settings.bit8?8:16); 00619 fprintf( stderr,"%s, ",settings.sign?"signed":"unsigned"); 00620 fprintf( stderr,"%s, ",settings.stereo?"stereo":"mono"); 00621 fprintf( stderr,"frequency: %i, ",settings.frequency); 00622 fprintf( stderr,"device: %s\n",settings.audiodev); 00623 #endif 00624 00625 buffers = (char *)malloc( settings.buffers * settings.buflen ); 00626 if ( !buffers ) return -1; 00627 sounds_in_buffer = (int *)calloc( settings.buffers,sizeof(int) ); 00628 if ( !sounds_in_buffer ) return -1; 00629 00630 if (init_audio()) return -1; 00631 00632 if (sign) zerolevel=0; 00633 else zerolevel=bit8?0x80:0x8000; 00634 00635 memset(buffers,zerolevel,settings.buflen*settings.buffers); 00636 00637 #ifdef SOUND_DEBUG 00638 fprintf( stderr,"bits: %i, ",bit8?8:16); 00639 fprintf( stderr,"%s, ",sign?"signed":"unsigned"); 00640 fprintf( stderr,"%s, ",stereo?"stereo":"mono"); 00641 fprintf( stderr,"freq: %i, ",frequency); 00642 fprintf( stderr,"smpl_size: %i, ",sample_size); 00643 fprintf( stderr,"0level: %i\n",zerolevel); 00644 #endif 00645 00646 for (i=0; i<MAX_SOUNDS; i++) { 00647 normal_sounds[i].filename=NULL; 00648 spell_sounds[i].filename=NULL; 00649 normal_sounds[i].size=-1; 00650 spell_sounds[i].size=-1; 00651 } 00652 default_normal.filename=NULL; 00653 default_spell.filename=NULL; 00654 00655 sprintf(path,"%s/.crossfire/sounds", getenv("HOME")); 00656 i=0; 00657 if (!(fp=fopen(path,"r"))) { 00658 fprintf(stderr,"Unable to open %s - will use built in defaults\n", path); 00659 for (; i<sizeof(def_sounds)/sizeof(char*); i++) { 00660 strcpy(buf, def_sounds[i]); 00661 parse_sound_line(buf,i); 00662 } 00663 } else while (fgets(buf, 511, fp)!=NULL) { 00664 buf[511]='\0'; 00665 parse_sound_line(buf, ++i); 00666 } 00667 /* Note in both cases below, we leave the symbolic name untouched. */ 00668 for (i=0; i<MAX_SOUNDS; i++) { 00669 if (!normal_sounds[i].filename) { 00670 normal_sounds[i].filename=default_normal.filename; 00671 normal_sounds[i].volume=default_normal.volume; 00672 } 00673 if (!spell_sounds[i].filename) { 00674 spell_sounds[i].filename=default_spell.filename; 00675 spell_sounds[i].volume=default_spell.volume; 00676 } 00677 normal_sounds[i].data=NULL; 00678 spell_sounds[i].data=NULL; 00679 } 00680 return 0; 00681 } 00682 00683 /* Plays sound 'soundnum'. soundtype is 0 for normal sounds, 1 for 00684 * spell_sounds. This might get extended in the future. x,y are offset 00685 * (assumed from player) to play sound. This information is used to 00686 * determine value and left vs right speaker balance. 00687 * This doesn't really play a sound, rather it just addes it to 00688 * the buffer to be played later on. 00689 */ 00690 00691 static void play_sound(int soundnum, int soundtype, int x, int y) 00692 { 00693 Sound_Info *si; 00694 int buf,off; 00695 int i; 00696 unsigned left_ratio,right_ratio; 00697 double dist; 00698 00699 buf=current_buffer; 00700 if (buf>=settings.buffers) buf=1; 00701 00702 if (buf == 0) buf++; 00703 00704 /* check if the buffer isn't full */ 00705 #ifdef SOUND_DEBUG 00706 fprintf(stderr,"Sounds in buffer %i: %i\n",buf,sounds_in_buffer[buf]); 00707 #endif 00708 if (sounds_in_buffer[buf]>settings.simultaneously) return; 00709 00710 if (soundnum>=MAX_SOUNDS || soundnum<0) { 00711 fprintf(stderr,"Invalid sound number: %d\n", soundnum); 00712 return; 00713 } 00714 if (soundfd==-1) { 00715 fprintf(stderr,"Sound device is not open\n"); 00716 return; 00717 } 00718 00719 if (soundtype < SOUND_NORMAL || soundtype == 0) soundtype = SOUND_NORMAL; 00720 00721 if (soundtype==SOUND_NORMAL) { 00722 si = &normal_sounds[soundnum]; 00723 } 00724 else if (soundtype==SOUND_SPELL) { 00725 si = &spell_sounds[soundnum]; 00726 } 00727 else { 00728 fprintf(stderr,"Unknown soundtype: %d\n", soundtype); 00729 return; 00730 } 00731 00732 if (!si->filename) { 00733 fprintf(stderr,"Sound %d (type %d) is not defined\n", soundnum, soundtype); 00734 return; 00735 } 00736 00737 /* 00738 * Load the sound if it is not loaded yet. 00739 * 00740 */ 00741 if (!si->data){ 00742 FILE *f; 00743 struct stat sbuf; 00744 #ifdef SOUND_DEBUG 00745 fprintf(stderr,"Loading file: %s\n",si->filename); 00746 #endif 00747 if (stat(si->filename,&sbuf)){ 00748 perror(si->filename); 00749 return; 00750 } 00751 si->size=sbuf.st_size; 00752 if (si->size <=0 ) return; 00753 if (si->size*sample_size > settings.buflen*(settings.buffers-1) ){ 00754 fprintf(stderr,"Sound %s too long (%i > %i)\n",si->filename,si->size, 00755 settings.buflen*(settings.buffers-1)/sample_size); 00756 return; 00757 } 00758 si->data=(unsigned char *)malloc(si->size); 00759 f=fopen(si->filename,"r"); 00760 if (!f){ 00761 perror(si->filename); 00762 return; 00763 } 00764 fread(si->data,1,si->size,f); 00765 fclose(f); 00766 } 00767 00768 #ifdef SOUND_DEBUG 00769 fprintf(stderr,"Playing sound %i (%s), volume %i, x,y=%d,%d\n",soundnum,si->symbolic,si->volume,x,y); 00770 #endif 00771 /* calculate volume multiplers */ 00772 dist=sqrt(x*x+y*y); 00773 right_ratio=left_ratio=((1<<16)*si->volume)/(100*settings.simultaneously*(1+SOUND_DECREASE*dist)); 00774 if (stereo){ 00775 double diff; 00776 if (dist) 00777 diff=(1.0-fabs((double)x/dist)); 00778 else 00779 diff=1; 00780 #ifdef SOUND_DEBUG 00781 printf("diff: %f\n",diff); 00782 fflush(stdout); 00783 #endif 00784 if (x<0) right_ratio*=diff; 00785 else left_ratio*=diff; 00786 } 00787 00788 #ifdef SOUND_DEBUG 00789 fprintf(stderr,"Ratio: %i, %i\n",left_ratio,right_ratio); 00790 #endif 00791 00792 /* insert the sound to the buffers */ 00793 sounds_in_buffer[buf]++; 00794 off=0; 00795 for(i=0;i<si->size;i++){ 00796 int dat=si->data[i]-0x80; 00797 00798 if (bit8){ 00799 if (!stereo){ 00800 buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16; 00801 } 00802 else{ 00803 buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16; 00804 buffers[buf*settings.buflen+off+1]+=(dat*right_ratio)>>16; 00805 } 00806 } 00807 else{ /* 16 bit output */ 00808 if (!stereo){ 00809 #ifdef WORDS_BIGENDIAN 00810 buffers[buf*settings.buflen+off+1]+=((dat*left_ratio)>>8)&0xff; 00811 buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16; 00812 } 00813 else{ 00814 buffers[buf*settings.buflen+off+1]+=((dat*left_ratio)>>8)&0xff; 00815 buffers[buf*settings.buflen+off]+=(dat*left_ratio)>>16; 00816 buffers[buf*settings.buflen+off+3]+=((dat*right_ratio)>>8)&0xff; 00817 buffers[buf*settings.buflen+off+2]+=(dat*right_ratio)>>16; 00818 } 00819 #else 00820 buffers[buf*settings.buflen+off]+=((dat*left_ratio)>>8)&0xff; 00821 buffers[buf*settings.buflen+off+1]+=(dat*left_ratio)>>16; 00822 } 00823 else{ 00824 buffers[buf*settings.buflen+off]+=((dat*left_ratio)>>8)&0xff; 00825 buffers[buf*settings.buflen+off+1]+=(dat*left_ratio)>>16; 00826 buffers[buf*settings.buflen+off+2]+=((dat*right_ratio)>>8)&0xff; 00827 buffers[buf*settings.buflen+off+3]+=(dat*right_ratio)>>16; 00828 } 00829 #endif 00830 } 00831 00832 off+=sample_size; 00833 00834 if (off>=settings.buflen){ 00835 off=0; 00836 buf++; 00837 if (buf>=settings.buffers) { 00838 buf=0; 00839 } 00840 } 00841 } 00842 #ifdef SOUND_DEBUG 00843 fprintf(stderr,"Added %d bytes, last buffer=%d, lastpos=%d\n", 00844 si->size, buf, off); 00845 #endif 00846 /* This write did not wrap the buffers */ 00847 if (buf+1 > current_buffer) { 00848 if ((buf+1 > first_free_buffer) && (first_free_buffer >= current_buffer)) 00849 first_free_buffer = buf+1; 00850 } else { /* Buffers did wrap */ 00851 if (((buf+1 > first_free_buffer) && (first_free_buffer < current_buffer)) || 00852 (first_free_buffer >= current_buffer)) 00853 first_free_buffer = buf+1; 00854 } 00855 if (first_free_buffer >= settings.buffers) first_free_buffer=0; 00856 00857 } 00858 00859 int SoundCmd(unsigned char *data, int len) 00860 { 00861 int x, y, num, type; 00862 int i; 00863 00864 i=sscanf((char *)data,"%x %x %x %x",&num,&type,&x,&y); 00865 if (i!=4){ 00866 fprintf(stderr,"Wrong input!\n"); 00867 return -1; 00868 } 00869 #ifdef SOUND_DEBUG 00870 fprintf(stderr,"Playing sound %d (type %d), offset %d, %d\n", 00871 num, type, x ,y); 00872 #endif 00873 play_sound(num, type, x, y); 00874 return 0; 00875 } 00876 00877 int write_settings(void) { 00878 FILE *f; 00879 char *home; 00880 char *path; 00881 00882 if ( (home=getenv("HOME")) == NULL ) return -1; 00883 path=(char *)malloc(strlen(home)+strlen(CONFIG_FILE)+1); 00884 if (!path) return -1; 00885 strcpy(path,home); 00886 strcat(path,CONFIG_FILE); 00887 f=fopen(path,"w"); 00888 if (!f) return -1; 00889 fprintf(f,"# Crossfire sound server settings\n"); 00890 fprintf(f,"# Please note, that not everything will work\n\n"); 00891 fprintf(f,"stereo: %i\n",settings.stereo); 00892 fprintf(f,"bits: %i\n",settings.bit8?8:16); 00893 fprintf(f,"signed: %i\n",settings.sign); 00894 fprintf(f,"frequency: %i\n",settings.frequency); 00895 fprintf(f,"buffers: %i\n",settings.buffers); 00896 fprintf(f,"buflen: %i\n",settings.buflen); 00897 fprintf(f,"simultaneously: %i\n",settings.simultaneously); 00898 /* fprintf(f,"device: %s\n",settings.audiodev);*/ 00899 fclose(f); 00900 return 0; 00901 } 00902 00903 int read_settings(void) { 00904 FILE *f; 00905 char *home; 00906 char *path; 00907 char linebuf[1024]; 00908 if ( (home=getenv("HOME")) == NULL ) return 0; 00909 00910 path=(char *)malloc(strlen(home)+strlen(CONFIG_FILE)+1); 00911 if (!path) return 0; 00912 00913 strcpy(path,home); 00914 strcat(path,CONFIG_FILE); 00915 00916 f=fopen(path,"r"); 00917 if (!f) return -1; 00918 00919 while(fgets(linebuf,1023,f)!=NULL) { 00920 linebuf[1023]=0; 00921 /* Strip off the newline */ 00922 linebuf[strlen(linebuf)-1]=0; 00923 00924 if (strncmp(linebuf,"stereo:",strlen("stereo:"))==0) 00925 settings.stereo=atoi(linebuf+strlen("stereo:"))?1:0; 00926 else if (strncmp(linebuf,"bits:",strlen("bits:"))==0) 00927 settings.bit8=(atoi(linebuf+strlen("bits:"))==8)?1:0; 00928 else if (strncmp(linebuf,"signed:",strlen("signed:"))==0) 00929 settings.sign=atoi(linebuf+strlen("signed:"))?1:0; 00930 else if (strncmp(linebuf,"buffers:",strlen("buffers:"))==0) 00931 settings.buffers=atoi(linebuf+strlen("buffers:")); 00932 else if (strncmp(linebuf,"buflen:",strlen("buflen:"))==0) 00933 settings.buflen=atoi(linebuf+strlen("buflen:")); 00934 else if (strncmp(linebuf,"frequency:",strlen("frequency:"))==0) 00935 settings.frequency=atoi(linebuf+strlen("frequency:")); 00936 else if (strncmp(linebuf,"simultaneously:",strlen("simultaneously:"))==0) 00937 settings.simultaneously=atoi(linebuf+strlen("simultaneously:")); 00938 #if 0 00939 else if (strncmp(linebuf,"device: ",strlen("device: "))==0) 00940 settings.audiodev=strdup_local(linebuf+strlen("device: ")); 00941 #endif 00942 } 00943 fclose(f); 00944 return 0; 00945 } 00946 00947 int main(int argc, char *argv[]) 00948 { 00949 int infd; 00950 char inbuf[1024]; 00951 int inbuf_pos=0,sndbuf_pos=0; 00952 fd_set inset,outset; 00953 00954 printf ("%s\n",rcsid_cfsndserv_c); 00955 fflush(stdout); 00956 if (read_settings()) write_settings(); 00957 if (init_sounds()) return 1; 00958 /* we don't use the file descriptor method */ 00959 if (!soundfd) return 1; 00960 infd=fileno(stdin); 00961 FD_ZERO(&inset); 00962 FD_ZERO(&outset); 00963 FD_SET(soundfd,&outset); 00964 FD_SET(infd,&inset); 00965 while(1){ 00966 #if defined(SGI_SOUND) 00967 /* 00968 The buffer of an audio port can hold 100000 samples. If we allow sounds to 00969 be written to the port whenever there is enough room in the buffer, all 00970 sounds will be played sequentially, which is wrong. We can set the 00971 fillpoint to a high value to prevent this. 00972 */ 00973 ALsetfillpoint(soundport,100000); 00974 #endif 00975 00976 00977 select(FD_SETSIZE,&inset,&outset,NULL,NULL); 00978 00979 if (FD_ISSET(soundfd,&outset)){ 00980 /* no sounds to play */ 00981 if (current_buffer==first_free_buffer) FD_CLR(soundfd,&outset); 00982 else{ 00983 int wrote; 00984 wrote=audio_play(current_buffer,sndbuf_pos); 00985 if (wrote<settings.buflen-sndbuf_pos) sndbuf_pos+=wrote; 00986 else{ 00987 /* clean the buffer */ 00988 memset(buffers+settings.buflen*current_buffer,zerolevel,settings.buflen); 00989 sounds_in_buffer[current_buffer]=0; 00990 sndbuf_pos=0; 00991 current_buffer++; 00992 if (current_buffer>=settings.buffers) current_buffer=0; 00993 } 00994 } 00995 } else { 00996 /* We need to reset this if it is not set - otherwise, we will never 00997 * finish playing the sounds 00998 */ 00999 FD_SET(soundfd,&outset); 01000 } 01001 01002 if (FD_ISSET(infd,&inset)){ 01003 int err=read(infd,inbuf+inbuf_pos,1); 01004 if (err<1 && errno!=EINTR){ 01005 if (err<0) perror("read"); 01006 break; 01007 } 01008 if (inbuf[inbuf_pos]=='\n'){ 01009 inbuf[inbuf_pos++]=0; 01010 if (!SoundCmd((unsigned char*)inbuf,inbuf_pos)) FD_SET(soundfd,&outset); 01011 inbuf_pos=0; 01012 } 01013 else{ 01014 inbuf_pos++; 01015 if (inbuf_pos>=1024){ 01016 fprintf(stderr,"Input buffer overflow!\n"); 01017 inbuf_pos=0; 01018 } 01019 } 01020 } 01021 FD_SET(infd,&inset); 01022 } 01023 01024 return 0; 01025 }