Crossfire Client, Branch
R11627
|
00001 /* 00002 * static char *rcsid_sdl_c = 00003 * "$Id: porting.c 8077 2008-01-03 12:07:59Z ryo_saeba $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00010 Copyright (C) 1992 Frank Tore Johansen 00011 00012 This program is free software; you can redistribute it and/or modify 00013 it under the terms of the GNU General Public License as published by 00014 the Free Software Foundation; either version 2 of the License, or 00015 (at your option) any later version. 00016 00017 This program is distributed in the hope that it will be useful, 00018 but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 GNU General Public License for more details. 00021 00022 You should have received a copy of the GNU General Public License 00023 along with this program; if not, write to the Free Software 00024 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00025 00026 The author can be reached via e-mail to crossfire-devel@real-time.com 00027 */ 00028 00029 #include <config.h> 00030 #include <ctype.h> 00031 #include <time.h> 00032 00033 #ifdef WIN32 00034 #include <sys/stat.h> 00035 #include <stdio.h> 00036 #include <mmsystem.h> 00037 #include "client.h" 00038 #include "soundsdef.h" 00039 00040 #ifdef HAVE_SDL 00041 #include <math.h> 00042 #include "sdl_mixer.h" 00043 #pragma comment( lib, "sdl.lib" ) 00044 #pragma comment( lib, "sdl_mixer.lib" ) 00045 #endif /* HAVE_SDL */ 00046 00047 #define MAX_SOUNDS 1024 00048 #define SOUND_NORMAL 0 00049 #define SOUND_SPELL 1 00050 00051 typedef struct Sound_Info { 00052 char *filename; 00053 char *symbolic; 00054 unsigned char volume; 00055 int size; 00056 #ifdef HAVE_SDL 00057 Mix_Chunk *data; 00058 #else 00059 char* data; 00060 #endif 00061 } Sound_Info; 00062 00063 Sound_Info normal_sounds[MAX_SOUNDS], spell_sounds[MAX_SOUNDS], 00064 default_normal, default_spell; 00065 00066 00067 #define SOUND_DECREASE 0.1 00068 00069 /* Parse a line from the sound config file. 00070 */ 00071 static void parse_sound_line(char *line, int lineno) 00072 { 00073 static int readtype=0, lastnum=0; 00074 int newnum, len; 00075 char *cp,*volume,*symbolic,*cp1,filename[512]; 00076 00077 if (line[0]=='#' || line[0]=='\n') return; 00078 00079 if ( !strcmp(line,"Standard Sounds:\n")) { 00080 lastnum = 0; 00081 readtype = 1; 00082 return; 00083 } 00084 if ( !strcmp(line,"Spell Sounds:\n")) { 00085 lastnum = 0; 00086 readtype = 2; 00087 return; 00088 } 00089 if ( !readtype ) { 00090 fprintf(stderr,"Got input without finding section header yet:\n%d:%s\n", 00091 lineno, line); 00092 return; 00093 } 00094 00095 if (line[strlen(line)-1]=='\n') { 00096 line[strlen(line)-1]='\0'; 00097 } 00098 00099 len = strcspn(line," \t"); 00100 line[len]='\0'; 00101 cp = line+len+1; 00102 00103 /* Skip all whitespace for the next field */ 00104 while(*cp != '\0' && (*cp==' ' || *cp=='\t')) { 00105 cp++; 00106 } 00107 00108 volume=cp; 00109 00110 /* No symbolic name or number - that is ok */ 00111 cp1=cp; 00112 if (!(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) { 00113 newnum=lastnum+1; 00114 symbolic=NULL; 00115 } else { 00116 /* We think we have a symbolic name */ 00117 /* Don't need to nulterm the volume, since we atoi it anyways */ 00118 while(*cp != '\0' && (*cp==' ' || *cp=='\t')) { 00119 cp++; 00120 } 00121 symbolic = cp; 00122 /* Some symbolic names are double quote protected. If, do some 00123 * special processing. We strip off the quotes. 00124 */ 00125 if ( *symbolic=='"') { 00126 symbolic++; 00127 for (cp=symbolic; *cp != '\0' && *cp !='"'; cp++ ); 00128 *cp = '\0'; 00129 cp++; 00130 } 00131 /* Let's try to find the sound number now */ 00132 cp1 = cp; 00133 if ( !(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) { 00134 newnum=lastnum+1; 00135 } else { 00136 *cp++='\0'; 00137 while(*cp!='\0' && (*cp==' ' || *cp=='\t')) { 00138 cp++; 00139 } 00140 if ( isdigit(*cp)) { 00141 newnum=atoi(cp); 00142 } else { 00143 newnum=lastnum+1; 00144 } 00145 } 00146 } 00147 if ( newnum < 0 || newnum >MAX_SOUNDS ) { 00148 fprintf(stderr,"Invalid sound number %d, line %d, buf %s\n", 00149 newnum, lineno, line ); 00150 return; 00151 } 00152 00153 strcpy(filename, line); 00154 00155 if ( symbolic && !strcmp(symbolic,"DEFAULT")) { 00156 if (readtype==1) { 00157 default_normal.filename=strdup(filename); 00158 default_normal.volume = atoi(volume); 00159 } else if (readtype==2) { 00160 default_spell.filename = strdup(filename); 00161 default_spell.volume = atoi(volume); 00162 } 00163 return; 00164 } else { 00165 if ( readtype==1 ) { 00166 normal_sounds[newnum].filename = strdup(filename); 00167 normal_sounds[newnum].volume = atoi(volume); 00168 if ( symbolic ) { 00169 normal_sounds[newnum].symbolic = strdup(symbolic); 00170 } else { 00171 normal_sounds[newnum].symbolic = NULL; 00172 } 00173 } else if (readtype==2) { 00174 spell_sounds[newnum].filename = strdup(filename); 00175 spell_sounds[newnum].volume = atoi(volume); 00176 if ( symbolic ) { 00177 spell_sounds[newnum].symbolic = strdup(symbolic); 00178 } else { 00179 spell_sounds[newnum].symbolic = NULL; 00180 } 00181 } 00182 lastnum = newnum; 00183 } 00184 } 00185 00186 void load_sounds_file( ) 00187 { 00188 int i; 00189 FILE *fp; 00190 char path[256], buf[512]; 00191 00192 for ( i=0;i<MAX_SOUNDS; i++ ) { 00193 normal_sounds[i].filename = NULL; 00194 spell_sounds[i].filename = NULL; 00195 normal_sounds[i].size = -1; 00196 spell_sounds[i].size = -1; 00197 } 00198 default_normal.filename = NULL; 00199 default_spell.filename = NULL; 00200 00201 sprintf(path,"%s/sounds", getenv("HOME")); 00202 i=0; 00203 if ( !(fp=fopen(path,"r"))) { 00204 fprintf(stderr,"Unable to open %s - will use built in defaults\n", path); 00205 for (; i<sizeof(def_sounds)/sizeof(char*); i++ ) { 00206 strcpy(buf,def_sounds[i]); 00207 parse_sound_line(buf,i); 00208 } 00209 } else { 00210 while(fgets(buf,511,fp)!=NULL) { 00211 buf[511] = '\0'; 00212 parse_sound_line(buf,++i); 00213 } 00214 fclose( fp ); 00215 } 00216 /* Note in both cases below, we leave the symbolic name untouched */ 00217 for ( i=0; i<MAX_SOUNDS; i++ ) { 00218 if ( !normal_sounds[i].filename ) { 00219 normal_sounds[i].filename = strdup( default_normal.filename ); 00220 normal_sounds[i].volume = default_normal.volume; 00221 } 00222 if ( !spell_sounds[i].filename ) { 00223 spell_sounds[i].filename= strdup( default_spell.filename ); 00224 spell_sounds[i].volume = default_spell.volume; 00225 } 00226 normal_sounds[i].data = NULL; 00227 spell_sounds[i].volume = 0; 00228 } 00229 } 00230 00231 #ifdef HAVE_SDL /* HAVE_SDL */ 00232 00233 #include <SDL.h> 00234 #include <SDL_Mixer.h> 00235 00236 /* mixer variables */ 00237 char *buffers = NULL; 00238 int *sounds_in_buffer=NULL; 00239 int current_buffer=0; /* Next buffer we will write out */ 00240 int first_free_buffer=0; /* So we know when to stop playing sounds */ 00241 00242 /* sound device parameters */ 00243 int stereo=0,bit8=0,sample_size=0,frequency=0,sign=0,zerolevel=0; 00244 00245 struct sound_settings{ 00246 int stereo,bit8,sign,frequency,buffers,buflen,simultaneously; 00247 } settings={0,1,0,11025,100,1024,4}; 00248 00249 00250 /* Background music */ 00251 Mix_Music *music = NULL; 00252 00253 00254 /* Initialize SDL sound. 00255 */ 00256 int init_sounds() 00257 { 00258 #ifdef DEBUG 00259 fprintf( stderr,"Settings: bits: %i, ",settings.bit8?8:16); 00260 fprintf( stderr,"%s, ",settings.sign?"signed":"unsigned"); 00261 fprintf( stderr,"%s, ",settings.stereo?"stereo":"mono"); 00262 fprintf( stderr,"frequency: %i\n ",settings.frequency); 00263 #endif 00264 00265 /* If SDL audio wasn't init'ed, init it. */ 00266 if( SDL_WasInit(SDL_INIT_AUDIO) == 0) { 00267 int audio_rate = 22050; 00268 uint16 audio_format = AUDIO_S16; 00269 int audio_channels = 2; 00270 int audio_buffers = 4096; 00271 00272 if( SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) 00273 { 00274 fprintf( stderr, "Could not initialize SDL audio: %s\n", SDL_GetError()); 00275 return -1; 00276 } 00277 00278 /* init SDL_mixer */ 00279 if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers)) { 00280 fprintf(stderr,"SDL_MIXER: Unable to open audio: %s\n", SDL_GetError()); 00281 return -1; 00282 } else { 00283 int numtimesopened; 00284 char format_str[8]; 00285 numtimesopened = Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); 00286 00287 sprintf(format_str,"unknown"); 00288 switch(audio_format) { 00289 case AUDIO_U8: sprintf(format_str,"U8"); break; 00290 case AUDIO_S8: sprintf(format_str,"S8"); break; 00291 case AUDIO_U16LSB: sprintf(format_str,"U16LSB"); break; 00292 case AUDIO_S16LSB: sprintf(format_str,"S16LSB"); break; 00293 case AUDIO_U16MSB: sprintf(format_str,"U16MSB"); break; 00294 case AUDIO_S16MSB: sprintf(format_str,"S16MSB"); break; 00295 } 00296 fprintf(stderr,"SDL_MIXER: Using SDL Mixer for audio [ %d kHz | %d channels | Audio Format %s ].\n", 00297 audio_rate, audio_channels, format_str ); 00298 /* 00299 * start playing the background music 00300 * Possibly have different background music for each map? 00301 */ 00302 Mix_HaltChannel(-1); 00303 Mix_HaltMusic(); 00304 00305 if ( music == NULL ) { 00306 music = Mix_LoadMUS("sfx/backg1.wav"); 00307 if ( music ) { 00308 Mix_PlayMusic(music,-1); 00309 } 00310 } else { 00311 Mix_PlayMusic(music,-1); 00312 } 00313 } 00314 } 00315 00316 00317 buffers = (char *)malloc(settings.buffers * settings.buflen ); 00318 if ( !buffers ) { 00319 return -1; 00320 } 00321 sounds_in_buffer = (int*)calloc(settings.buffers,sizeof(int)); 00322 if ( !sounds_in_buffer ) { 00323 return -1; 00324 } 00325 00326 if ( sign ) { 00327 zerolevel = 0; 00328 } else { 00329 zerolevel = bit8?0x80:0x8000; 00330 } 00331 00332 memset(buffers,zerolevel,settings.buflen * settings.buffers); 00333 00334 00335 #ifdef DEBUG 00336 fprintf( stderr,"bits: %i, ",bit8?8:16); 00337 fprintf( stderr,"%s, ",sign?"signed":"unsigned"); 00338 fprintf( stderr,"%s, ",stereo?"stereo":"mono"); 00339 fprintf( stderr,"freq: %i, ",frequency); 00340 fprintf( stderr,"smpl_size: %i, ",sample_size); 00341 fprintf( stderr,"0level: %i\n",zerolevel); 00342 #endif 00343 00344 load_sounds_file( ); 00345 PlaySound(NULL,NULL,SND_ASYNC); 00346 00347 return 0; 00348 } 00349 00350 /* Plays sound 'soundnum', soundtype is 0 for normal sounds, 1 for 00351 * spell sounds. This might get extended in the futur. x,y are offset 00352 * (assumed from player) to play sound. This information is used to 00353 * determine value and left vs right speaker balance. 00354 * This doesn't really play a sound, rather it just adds it to 00355 * the buffer to be played later on. 00356 */ 00357 00358 static void play_sound(int soundnum, int soundtype, sint8 x, sint8 y ) 00359 { 00360 Sound_Info *si; 00361 double dist; 00362 int index; 00363 00364 if (!use_config[CONFIG_SOUND]) return; 00365 00366 if ( soundnum>=MAX_SOUNDS || soundnum<0 ) { 00367 fprintf(stderr,"Invalid sound number: %d\n", soundnum ); 00368 return; 00369 } 00370 if (soundtype == SOUND_NORMAL ) { 00371 si = &normal_sounds[soundnum]; 00372 } else if ( soundtype == SOUND_SPELL ) { 00373 si = &spell_sounds[soundnum]; 00374 } else { 00375 fprintf(stderr,"Unknown soundtype: %d\n", soundtype); 00376 return; 00377 } 00378 00379 if (!si->data) { 00380 si->data = Mix_LoadWAV(si->filename); 00381 if ( !si->data ) { 00382 fprintf(stderr, "SDL_MIXER: Couldn't load %s: %s\n", si->filename, SDL_GetError()); 00383 } 00384 } 00385 if (si->data) { 00386 int playchannel; 00387 int angle; 00388 00389 playchannel = 0; 00390 si->data->volume = si->volume; 00391 for ( index=0; index<MIX_CHANNELS; index++ ) { 00392 if ( !Mix_Playing(index) ) { 00393 playchannel = index; 00394 break; 00395 } 00396 } 00397 dist = sqrt(x*x+y*y); 00398 if ( x == 0 ) 00399 { 00400 angle = ( y < 0 ) ? 0 : 180; 00401 } 00402 else 00403 { 00404 angle = ( asin( ( double )x / ( double )dist ) ) * 180. / 3.14159; 00405 if ( y < 0 ) 00406 angle = - angle; 00407 } 00408 00409 if ( Mix_Playing(playchannel) ) { 00410 Mix_HaltChannel(playchannel); 00411 } 00412 00413 /*Mix_SetDistance(playchannel,dist);*/ 00414 Mix_SetPosition( playchannel, angle, dist ); 00415 00416 Mix_PlayChannel(playchannel,si->data,0); 00417 00418 return; 00419 } 00420 00421 /* 00422 * Load the sound if it is not loaded yet 00423 * 00424 */ 00425 /* if ( !si->data ) { 00426 FILE *f; 00427 struct stat sbuf; 00428 fprintf(stderr,"Loading file: %s\n",si->filename ); 00429 if (stat(si->filename,&sbuf)) { 00430 perror(si->filename); 00431 return; 00432 } 00433 si->size=sbuf.st_size; 00434 if ( si->size<=0) { 00435 return; 00436 } 00437 if ( si->size * sample_size > settings.buflen*(settings.buffers-1)) { 00438 fprintf(stderr,"Sound %s too long (%i > %i)\n",si->filename,si->size, 00439 settings.buflen*(settings.buffers-1)/sample_size); 00440 return; 00441 } 00442 si->data=(unsigned char*)malloc(si->size); 00443 f=fopen(si->filename,"r"); 00444 if ( !f ) { 00445 perror(si->filename); 00446 return; 00447 } 00448 fread(si->data,1,si->size,f); 00449 fclose(f); 00450 } 00451 #ifdef DEBUG 00452 fprintf(stderr,"Playing sound %i (%s), volume %i, x,y=%d,%d\n",soundnum,si->symbolic,si->volume,x,y); 00453 #endif 00454 00455 PlaySound(NULL,NULL,SND_ASYNC); 00456 00457 PlaySound(si->data,NULL,SND_ASYNC | SND_MEMORY ); 00458 00459 return; 00460 */ 00461 } 00462 00463 void SoundCmd(unsigned char *data, int len) 00464 { 00465 int num, type; 00466 sint8 x, y; 00467 00468 if (len!=5) { 00469 fprintf(stderr,"Got invalid length on sound command: %d\n", len); 00470 return; 00471 } 00472 x = data[0]; 00473 y = data[1]; 00474 num = GetShort_String(data+2); 00475 type = data[4]; 00476 00477 #ifdef DEBUG 00478 fprintf(stderr,"Playing sound %d (type %d), offset %d, %x\n", 00479 num, type, x ,y); 00480 #endif 00481 00482 play_sound(num, type, x, y); 00483 } 00484 00485 #else /* HAVE_SDL */ 00486 /* No SDL, let's use dumb PlaySound (better than nothing). 00487 */ 00488 00489 int init_sounds() 00490 { 00491 LOG(LOG_INFO,"init_sounds","using regular Windows PlaySound"); 00492 PlaySound(NULL,NULL,SND_ASYNC); 00493 load_sounds_file( ); 00494 return 0; 00495 } 00496 00497 void SoundCmd(unsigned char *data, int len) 00498 { 00499 int num, type; 00500 Sound_Info* si; 00501 00502 if (len!=5) { 00503 LOG(LOG_WARNING,"SoundCmd(win)","Got invalid length on sound command: %d\n", len); 00504 return; 00505 } 00506 num = GetShort_String(data+2); 00507 type = data[4]; 00508 00509 if (type == SOUND_NORMAL ) { 00510 si = &normal_sounds[ num ]; 00511 } else if ( type == SOUND_SPELL ) { 00512 si = &spell_sounds[ num ]; 00513 } else { 00514 LOG(LOG_WARNING,"SoundCmd(win)","invalid sound type %d",type); 00515 return; 00516 } 00517 00518 if ( !si->filename ) 00519 /* Already tried to load sound, failed, let's stop here. */ 00520 return; 00521 00522 if ( !si->data ) 00523 { 00524 /* Let's try to load the sound */ 00525 FILE* fsound; 00526 struct stat sbuf; 00527 00528 if ( ( stat( si->filename, &sbuf ) == -1 ) || ( ( fsound = fopen( si->filename, "rb" ) ) == NULL ) ) 00529 { 00530 // Failed to load it, clear name & such so we don't try again. 00531 LOG( LOG_WARNING, "SoundCmd(win)", "Can't open sound %s", si->filename ); 00532 perror( si->filename ); 00533 free( si->filename ); 00534 si->filename = NULL; 00535 return; 00536 } 00537 00538 si->size=sbuf.st_size; 00539 si->data = malloc( si->size ); 00540 fread( si->data, si->size, 1, fsound ); 00541 fclose( fsound ); 00542 } 00543 00544 PlaySound( si->data, NULL, SND_ASYNC | SND_MEMORY | SND_NOWAIT); 00545 } 00546 00547 #endif /* HAVE_SDL */ 00548 00549 00550 /* The only gettimeofday calls appears to be ones added for purposes of 00551 * timing the map redraws, so for practical purposes, it should just 00552 * always return 0 with no real harm. 00553 */ 00554 #include <winsock.h> 00555 void gettimeofday(struct timeval *tv, void* unused) 00556 { 00557 memset(tv, 0, sizeof(struct timeval)); 00558 } 00559 00560 00561 /* This is functionally equivalent to Sleep(x) under win32. 00562 void Sleep(long SleepMilliseconds) 00563 { 00564 static struct timeval t; 00565 t.tv_sec = SleepMilliseconds/1000; 00566 t.tv_usec = (SleepMilliseconds %1000000) *1000; 00567 00568 select(0, NULL, NULL, NULL, &t); 00569 } 00570 */ 00571 00572 int strncasecmp(const char *s1, const char *s2, int n) 00573 { 00574 register char c1, c2; 00575 00576 while (*s1 && *s2 && n) { 00577 c1 = tolower(*s1); 00578 c2 = tolower(*s2); 00579 if (c1 != c2) 00580 return (c1 - c2); 00581 s1++; 00582 s2++; 00583 n--; 00584 } 00585 if (!n) 00586 return(0); 00587 return (int) (*s1 - *s2); 00588 } 00589 00590 int strcasecmp(const char *s1, const char*s2) 00591 { 00592 register char c1, c2; 00593 00594 while (*s1 && *s2) { 00595 c1 = tolower(*s1); 00596 c2 = tolower(*s2); 00597 if (c1 != c2) 00598 return (c1 - c2); 00599 s1++; 00600 s2++; 00601 } 00602 if (*s1=='\0' && *s2=='\0') 00603 return 0; 00604 return (int) (*s1 - *s2); 00605 } 00606 #endif /* WIN32 */