Crossfire Client, Branches  R11627
porting.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_sdl_c =
3  * "$Id: porting.c 8077 2008-01-03 12:07:59Z ryo_saeba $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2001 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The author can be reached via e-mail to crossfire-devel@real-time.com
27 */
28 
29 #include <config.h>
30 #include <ctype.h>
31 #include <time.h>
32 
33 #ifdef WIN32
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <mmsystem.h>
37 #include "client.h"
38 #include "soundsdef.h"
39 
40 #ifdef HAVE_SDL
41 #include <math.h>
42 #include "sdl_mixer.h"
43 #pragma comment( lib, "sdl.lib" )
44 #pragma comment( lib, "sdl_mixer.lib" )
45 #endif /* HAVE_SDL */
46 
47 #define MAX_SOUNDS 1024
48 #define SOUND_NORMAL 0
49 #define SOUND_SPELL 1
50 
51 typedef struct Sound_Info {
52  char *filename;
53  char *symbolic;
54  unsigned char volume;
55  int size;
56 #ifdef HAVE_SDL
57  Mix_Chunk *data;
58 #else
59  char* data;
60 #endif
61 } Sound_Info;
62 
65 
66 
67 #define SOUND_DECREASE 0.1
68 
69 /* Parse a line from the sound config file.
70  */
71 static void parse_sound_line(char *line, int lineno)
72 {
73  static int readtype=0, lastnum=0;
74  int newnum, len;
75  char *cp,*volume,*symbolic,*cp1,filename[512];
76 
77  if (line[0]=='#' || line[0]=='\n') return;
78 
79  if ( !strcmp(line,"Standard Sounds:\n")) {
80  lastnum = 0;
81  readtype = 1;
82  return;
83  }
84  if ( !strcmp(line,"Spell Sounds:\n")) {
85  lastnum = 0;
86  readtype = 2;
87  return;
88  }
89  if ( !readtype ) {
90  fprintf(stderr,"Got input without finding section header yet:\n%d:%s\n",
91  lineno, line);
92  return;
93  }
94 
95  if (line[strlen(line)-1]=='\n') {
96  line[strlen(line)-1]='\0';
97  }
98 
99  len = strcspn(line," \t");
100  line[len]='\0';
101  cp = line+len+1;
102 
103  /* Skip all whitespace for the next field */
104  while(*cp != '\0' && (*cp==' ' || *cp=='\t')) {
105  cp++;
106  }
107 
108  volume=cp;
109 
110  /* No symbolic name or number - that is ok */
111  cp1=cp;
112  if (!(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) {
113  newnum=lastnum+1;
114  symbolic=NULL;
115  } else {
116  /* We think we have a symbolic name */
117  /* Don't need to nulterm the volume, since we atoi it anyways */
118  while(*cp != '\0' && (*cp==' ' || *cp=='\t')) {
119  cp++;
120  }
121  symbolic = cp;
122  /* Some symbolic names are double quote protected. If, do some
123  * special processing. We strip off the quotes.
124  */
125  if ( *symbolic=='"') {
126  symbolic++;
127  for (cp=symbolic; *cp != '\0' && *cp !='"'; cp++ );
128  *cp = '\0';
129  cp++;
130  }
131  /* Let's try to find the sound number now */
132  cp1 = cp;
133  if ( !(cp=strchr(cp1,' ')) && !(cp=strchr(cp1,'\t'))) {
134  newnum=lastnum+1;
135  } else {
136  *cp++='\0';
137  while(*cp!='\0' && (*cp==' ' || *cp=='\t')) {
138  cp++;
139  }
140  if ( isdigit(*cp)) {
141  newnum=atoi(cp);
142  } else {
143  newnum=lastnum+1;
144  }
145  }
146  }
147  if ( newnum < 0 || newnum >MAX_SOUNDS ) {
148  fprintf(stderr,"Invalid sound number %d, line %d, buf %s\n",
149  newnum, lineno, line );
150  return;
151  }
152 
153  strcpy(filename, line);
154 
155  if ( symbolic && !strcmp(symbolic,"DEFAULT")) {
156  if (readtype==1) {
157  default_normal.filename=strdup(filename);
158  default_normal.volume = atoi(volume);
159  } else if (readtype==2) {
160  default_spell.filename = strdup(filename);
161  default_spell.volume = atoi(volume);
162  }
163  return;
164  } else {
165  if ( readtype==1 ) {
166  normal_sounds[newnum].filename = strdup(filename);
167  normal_sounds[newnum].volume = atoi(volume);
168  if ( symbolic ) {
169  normal_sounds[newnum].symbolic = strdup(symbolic);
170  } else {
171  normal_sounds[newnum].symbolic = NULL;
172  }
173  } else if (readtype==2) {
174  spell_sounds[newnum].filename = strdup(filename);
175  spell_sounds[newnum].volume = atoi(volume);
176  if ( symbolic ) {
177  spell_sounds[newnum].symbolic = strdup(symbolic);
178  } else {
179  spell_sounds[newnum].symbolic = NULL;
180  }
181  }
182  lastnum = newnum;
183  }
184 }
185 
186 void load_sounds_file( )
187  {
188  int i;
189  FILE *fp;
190  char path[256], buf[512];
191 
192  for ( i=0;i<MAX_SOUNDS; i++ ) {
193  normal_sounds[i].filename = NULL;
194  spell_sounds[i].filename = NULL;
195  normal_sounds[i].size = -1;
196  spell_sounds[i].size = -1;
197  }
198  default_normal.filename = NULL;
199  default_spell.filename = NULL;
200 
201  sprintf(path,"%s/sounds", getenv("HOME"));
202  i=0;
203  if ( !(fp=fopen(path,"r"))) {
204  fprintf(stderr,"Unable to open %s - will use built in defaults\n", path);
205  for (; i<sizeof(def_sounds)/sizeof(char*); i++ ) {
206  strcpy(buf,def_sounds[i]);
207  parse_sound_line(buf,i);
208  }
209  } else {
210  while(fgets(buf,511,fp)!=NULL) {
211  buf[511] = '\0';
212  parse_sound_line(buf,++i);
213  }
214  fclose( fp );
215  }
216  /* Note in both cases below, we leave the symbolic name untouched */
217  for ( i=0; i<MAX_SOUNDS; i++ ) {
218  if ( !normal_sounds[i].filename ) {
219  normal_sounds[i].filename = strdup( default_normal.filename );
220  normal_sounds[i].volume = default_normal.volume;
221  }
222  if ( !spell_sounds[i].filename ) {
223  spell_sounds[i].filename= strdup( default_spell.filename );
224  spell_sounds[i].volume = default_spell.volume;
225  }
226  normal_sounds[i].data = NULL;
227  spell_sounds[i].volume = 0;
228  }
229  }
230 
231 #ifdef HAVE_SDL /* HAVE_SDL */
232 
233 #include <SDL.h>
234 #include <SDL_Mixer.h>
235 
236 /* mixer variables */
237 char *buffers = NULL;
238 int *sounds_in_buffer=NULL;
239 int current_buffer=0; /* Next buffer we will write out */
240 int first_free_buffer=0; /* So we know when to stop playing sounds */
241 
242 /* sound device parameters */
244 
245 struct sound_settings{
247 } settings={0,1,0,11025,100,1024,4};
248 
249 
250 /* Background music */
251 Mix_Music *music = NULL;
252 
253 
254 /* Initialize SDL sound.
255  */
256 int init_sounds()
257 {
258 #ifdef DEBUG
259  fprintf( stderr,"Settings: bits: %i, ",settings.bit8?8:16);
260  fprintf( stderr,"%s, ",settings.sign?"signed":"unsigned");
261  fprintf( stderr,"%s, ",settings.stereo?"stereo":"mono");
262  fprintf( stderr,"frequency: %i\n ",settings.frequency);
263 #endif
264 
265  /* If SDL audio wasn't init'ed, init it. */
266  if( SDL_WasInit(SDL_INIT_AUDIO) == 0) {
267  int audio_rate = 22050;
268  uint16 audio_format = AUDIO_S16;
269  int audio_channels = 2;
270  int audio_buffers = 4096;
271 
272  if( SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
273  {
274  fprintf( stderr, "Could not initialize SDL audio: %s\n", SDL_GetError());
275  return -1;
276  }
277 
278  /* init SDL_mixer */
279  if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers)) {
280  fprintf(stderr,"SDL_MIXER: Unable to open audio: %s\n", SDL_GetError());
281  return -1;
282  } else {
283  int numtimesopened;
284  char format_str[8];
285  numtimesopened = Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
286 
287  sprintf(format_str,"unknown");
288  switch(audio_format) {
289  case AUDIO_U8: sprintf(format_str,"U8"); break;
290  case AUDIO_S8: sprintf(format_str,"S8"); break;
291  case AUDIO_U16LSB: sprintf(format_str,"U16LSB"); break;
292  case AUDIO_S16LSB: sprintf(format_str,"S16LSB"); break;
293  case AUDIO_U16MSB: sprintf(format_str,"U16MSB"); break;
294  case AUDIO_S16MSB: sprintf(format_str,"S16MSB"); break;
295  }
296  fprintf(stderr,"SDL_MIXER: Using SDL Mixer for audio [ %d kHz | %d channels | Audio Format %s ].\n",
297  audio_rate, audio_channels, format_str );
298  /*
299  * start playing the background music
300  * Possibly have different background music for each map?
301  */
302  Mix_HaltChannel(-1);
303  Mix_HaltMusic();
304 
305  if ( music == NULL ) {
306  music = Mix_LoadMUS("sfx/backg1.wav");
307  if ( music ) {
308  Mix_PlayMusic(music,-1);
309  }
310  } else {
311  Mix_PlayMusic(music,-1);
312  }
313  }
314  }
315 
316 
317  buffers = (char *)malloc(settings.buffers * settings.buflen );
318  if ( !buffers ) {
319  return -1;
320  }
321  sounds_in_buffer = (int*)calloc(settings.buffers,sizeof(int));
322  if ( !sounds_in_buffer ) {
323  return -1;
324  }
325 
326  if ( sign ) {
327  zerolevel = 0;
328  } else {
329  zerolevel = bit8?0x80:0x8000;
330  }
331 
332  memset(buffers,zerolevel,settings.buflen * settings.buffers);
333 
334 
335 #ifdef DEBUG
336  fprintf( stderr,"bits: %i, ",bit8?8:16);
337  fprintf( stderr,"%s, ",sign?"signed":"unsigned");
338  fprintf( stderr,"%s, ",stereo?"stereo":"mono");
339  fprintf( stderr,"freq: %i, ",frequency);
340  fprintf( stderr,"smpl_size: %i, ",sample_size);
341  fprintf( stderr,"0level: %i\n",zerolevel);
342 #endif
343 
344  load_sounds_file( );
345  PlaySound(NULL,NULL,SND_ASYNC);
346 
347  return 0;
348 }
349 
350 /* Plays sound 'soundnum', soundtype is 0 for normal sounds, 1 for
351  * spell sounds. This might get extended in the futur. x,y are offset
352  * (assumed from player) to play sound. This information is used to
353  * determine value and left vs right speaker balance.
354  * This doesn't really play a sound, rather it just adds it to
355  * the buffer to be played later on.
356  */
357 
358 static void play_sound(int soundnum, int soundtype, sint8 x, sint8 y )
359 {
360  Sound_Info *si;
361  double dist;
362  int index;
363 
364  if (!use_config[CONFIG_SOUND]) return;
365 
366  if ( soundnum>=MAX_SOUNDS || soundnum<0 ) {
367  fprintf(stderr,"Invalid sound number: %d\n", soundnum );
368  return;
369  }
370  if (soundtype == SOUND_NORMAL ) {
371  si = &normal_sounds[soundnum];
372  } else if ( soundtype == SOUND_SPELL ) {
373  si = &spell_sounds[soundnum];
374  } else {
375  fprintf(stderr,"Unknown soundtype: %d\n", soundtype);
376  return;
377  }
378 
379  if (!si->data) {
380  si->data = Mix_LoadWAV(si->filename);
381  if ( !si->data ) {
382  fprintf(stderr, "SDL_MIXER: Couldn't load %s: %s\n", si->filename, SDL_GetError());
383  }
384  }
385  if (si->data) {
386  int playchannel;
387  int angle;
388 
389  playchannel = 0;
390  si->data->volume = si->volume;
391  for ( index=0; index<MIX_CHANNELS; index++ ) {
392  if ( !Mix_Playing(index) ) {
393  playchannel = index;
394  break;
395  }
396  }
397  dist = sqrt(x*x+y*y);
398  if ( x == 0 )
399  {
400  angle = ( y < 0 ) ? 0 : 180;
401  }
402  else
403  {
404  angle = ( asin( ( double )x / ( double )dist ) ) * 180. / 3.14159;
405  if ( y < 0 )
406  angle = - angle;
407  }
408 
409  if ( Mix_Playing(playchannel) ) {
410  Mix_HaltChannel(playchannel);
411  }
412 
413  /*Mix_SetDistance(playchannel,dist);*/
414  Mix_SetPosition( playchannel, angle, dist );
415 
416  Mix_PlayChannel(playchannel,si->data,0);
417 
418  return;
419  }
420 
421  /*
422  * Load the sound if it is not loaded yet
423  *
424  */
425 /* if ( !si->data ) {
426  FILE *f;
427  struct stat sbuf;
428  fprintf(stderr,"Loading file: %s\n",si->filename );
429  if (stat(si->filename,&sbuf)) {
430  perror(si->filename);
431  return;
432  }
433  si->size=sbuf.st_size;
434  if ( si->size<=0) {
435  return;
436  }
437  if ( si->size * sample_size > settings.buflen*(settings.buffers-1)) {
438  fprintf(stderr,"Sound %s too long (%i > %i)\n",si->filename,si->size,
439  settings.buflen*(settings.buffers-1)/sample_size);
440  return;
441  }
442  si->data=(unsigned char*)malloc(si->size);
443  f=fopen(si->filename,"r");
444  if ( !f ) {
445  perror(si->filename);
446  return;
447  }
448  fread(si->data,1,si->size,f);
449  fclose(f);
450  }
451 #ifdef DEBUG
452  fprintf(stderr,"Playing sound %i (%s), volume %i, x,y=%d,%d\n",soundnum,si->symbolic,si->volume,x,y);
453 #endif
454 
455  PlaySound(NULL,NULL,SND_ASYNC);
456 
457  PlaySound(si->data,NULL,SND_ASYNC | SND_MEMORY );
458 
459  return;
460  */
461 }
462 
463 void SoundCmd(unsigned char *data, int len)
464 {
465  int num, type;
466  sint8 x, y;
467 
468  if (len!=5) {
469  fprintf(stderr,"Got invalid length on sound command: %d\n", len);
470  return;
471  }
472  x = data[0];
473  y = data[1];
474  num = GetShort_String(data+2);
475  type = data[4];
476 
477 #ifdef DEBUG
478  fprintf(stderr,"Playing sound %d (type %d), offset %d, %x\n",
479  num, type, x ,y);
480 #endif
481 
482  play_sound(num, type, x, y);
483 }
484 
485 #else /* HAVE_SDL */
486 /* No SDL, let's use dumb PlaySound (better than nothing).
487  */
488 
489 int init_sounds()
490 {
491  LOG(LOG_INFO,"init_sounds","using regular Windows PlaySound");
492  PlaySound(NULL,NULL,SND_ASYNC);
493  load_sounds_file( );
494  return 0;
495 }
496 
497 void SoundCmd(unsigned char *data, int len)
498 {
499  int num, type;
500  Sound_Info* si;
501 
502  if (len!=5) {
503  LOG(LOG_WARNING,"SoundCmd(win)","Got invalid length on sound command: %d\n", len);
504  return;
505  }
506  num = GetShort_String(data+2);
507  type = data[4];
508 
509  if (type == SOUND_NORMAL ) {
510  si = &normal_sounds[ num ];
511  } else if ( type == SOUND_SPELL ) {
512  si = &spell_sounds[ num ];
513  } else {
514  LOG(LOG_WARNING,"SoundCmd(win)","invalid sound type %d",type);
515  return;
516  }
517 
518  if ( !si->filename )
519  /* Already tried to load sound, failed, let's stop here. */
520  return;
521 
522  if ( !si->data )
523  {
524  /* Let's try to load the sound */
525  FILE* fsound;
526  struct stat sbuf;
527 
528  if ( ( stat( si->filename, &sbuf ) == -1 ) || ( ( fsound = fopen( si->filename, "rb" ) ) == NULL ) )
529  {
530  // Failed to load it, clear name & such so we don't try again.
531  LOG( LOG_WARNING, "SoundCmd(win)", "Can't open sound %s", si->filename );
532  perror( si->filename );
533  free( si->filename );
534  si->filename = NULL;
535  return;
536  }
537 
538  si->size=sbuf.st_size;
539  si->data = malloc( si->size );
540  fread( si->data, si->size, 1, fsound );
541  fclose( fsound );
542  }
543 
544  PlaySound( si->data, NULL, SND_ASYNC | SND_MEMORY | SND_NOWAIT);
545 }
546 
547 #endif /* HAVE_SDL */
548 
549 
550 /* The only gettimeofday calls appears to be ones added for purposes of
551  * timing the map redraws, so for practical purposes, it should just
552  * always return 0 with no real harm.
553  */
554 #include <winsock.h>
555 void gettimeofday(struct timeval *tv, void* unused)
556 {
557  memset(tv, 0, sizeof(struct timeval));
558 }
559 
560 
561 /* This is functionally equivalent to Sleep(x) under win32.
562 void Sleep(long SleepMilliseconds)
563 {
564  static struct timeval t;
565  t.tv_sec = SleepMilliseconds/1000;
566  t.tv_usec = (SleepMilliseconds %1000000) *1000;
567 
568  select(0, NULL, NULL, NULL, &t);
569 }
570 */
571 
572 int strncasecmp(const char *s1, const char *s2, int n)
573 {
574  register char c1, c2;
575 
576  while (*s1 && *s2 && n) {
577  c1 = tolower(*s1);
578  c2 = tolower(*s2);
579  if (c1 != c2)
580  return (c1 - c2);
581  s1++;
582  s2++;
583  n--;
584  }
585  if (!n)
586  return(0);
587  return (int) (*s1 - *s2);
588 }
589 
590 int strcasecmp(const char *s1, const char*s2)
591 {
592  register char c1, c2;
593 
594  while (*s1 && *s2) {
595  c1 = tolower(*s1);
596  c2 = tolower(*s2);
597  if (c1 != c2)
598  return (c1 - c2);
599  s1++;
600  s2++;
601  }
602  if (*s1=='\0' && *s2=='\0')
603  return 0;
604  return (int) (*s1 - *s2);
605 }
606 #endif /* WIN32 */
#define MAX_SOUNDS
Definition: cfsndserv.c:104
unsigned char volume
Definition: cfsndserv.c:122
Sound_Info spell_sounds[MAX_SOUNDS]
Definition: cfsndserv.c:127
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:162
int buffers
Definition: alsa9.c:104
int current_buffer
Definition: alsa9.c:95
int stereo
Definition: alsa9.c:101
static void play_sound(int soundnum, int soundtype, int x, int y)
Definition: sound.c:112
char * filename
Definition: cfsndserv.c:120
int init_sounds(void)
Definition: sound.c:60
Sound_Info normal_sounds[MAX_SOUNDS]
Definition: cfsndserv.c:127
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
static void parse_sound_line(char *line, int lineno)
Definition: cfsndserv.c:167
int stereo
Definition: alsa9.c:104
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
#define SOUND_NORMAL
Definition: newclient.h:267
Sound_Info default_spell
Definition: cfsndserv.c:127
int bit8
Definition: cfsndserv.c:141
char * symbolic
Definition: cfsndserv.c:121
struct Sound_Info Sound_Info
unsigned short uint16
Definition: client-types.h:79
int frequency
Definition: alsa9.c:104
#define SOUND_SPELL
Definition: newclient.h:268
int first_free_buffer
Definition: alsa9.c:96
int frequency
Definition: alsa9.c:101
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
int * sounds_in_buffer
Definition: alsa9.c:94
signed char sint8
Definition: client-types.h:82
Sound_Info default_normal
Definition: cfsndserv.c:127
struct sound_settings settings
int buflen
Definition: alsa9.c:104
void SoundCmd(unsigned char *data, int len)
Definition: sound.c:130
int zerolevel
Definition: alsa9.c:101
int sign
Definition: alsa9.c:101
#define tolower(C)
Definition: p_cmd.c:799
#define CONFIG_SOUND
Definition: client.h:164
int sample_size
Definition: alsa9.c:101