|
Crossfire Client, Trunk
R18666
|
00001 const char * rcsid_sound_src_common_c = 00002 "$Id: common.c 13995 2010-10-14 04:01:47Z kbulgrien $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire-devel@real-time.com 00023 */ 00024 00029 #include "config.h" 00030 00031 #include <stdio.h> 00032 #include <stdlib.h> 00033 00034 #ifdef HAVE_STRING_H 00035 #include <string.h> 00036 #endif 00037 00038 #include <ctype.h> 00039 00040 #include "client-types.h" 00041 #include "newclient.h" 00042 #include "client.h" 00043 00044 #include "def_sounds.h" 00045 #include "common.h" 00046 00047 Sound_Info normal_sounds[MAX_SOUNDS]; 00048 Sound_Info spell_sounds[MAX_SOUNDS]; 00049 Sound_Info default_normal; 00050 Sound_Info default_spell; 00051 00052 char *client_sounds_path = NULL; /* Client sound file folder */ 00053 char *user_sounds_path = NULL; /* User sound file folder */ 00054 char *user_sounds_file = NULL; /* User sound mappings */ 00055 char *user_config_file = NULL; /* User sndconfig file. */ 00056 00057 char *buffers = NULL; 00058 00059 /* 00060 * Sound device parameters. See also sound_settings. 00061 */ 00062 int stereo = 0; 00063 int bit8 = 0; 00064 int sample_size = 0; 00065 int frequency = 0; 00066 int sign = 0; 00067 int zerolevel = 0; 00068 00098 static void parse_sound_line(char *line, int lineno) { 00099 static int readtype=0; 00104 static int lastnum=0; 00107 int newnum, len; 00108 char *cp, *volume, *symbolic, *cp1, filename[512]; 00109 00110 if (line[0] == '#' || line[0] == '\n') 00111 return; 00112 00113 if (!strcmp(line, "Standard Sounds:\n")) { 00114 lastnum = 0; 00115 readtype = 1; 00116 return; 00117 } 00118 00119 if (!strcmp(line, "Spell Sounds:\n")) { 00120 lastnum = 0; 00121 readtype = 2; 00122 return; 00123 } 00124 if (!readtype) { 00125 #ifdef SOUND_DEBUG 00126 fprintf(stderr, 00127 "parse_sound_line: Ignored file header:\n%d:%s\n", lineno, line); 00128 #endif 00129 return; 00130 } 00131 /* 00132 * Change the LF delimiter at the end of the line to a null terminator. 00133 */ 00134 if (line[strlen(line)-1] == '\n') 00135 line[strlen(line)-1] = '\0'; 00136 /* 00137 * Convert the first whitespace found to a null terminator. 00138 */ 00139 len = strcspn(line, " \t"); 00140 line[len] = '\0'; 00141 cp = line + len + 1; 00142 /* 00143 * Skip all the following whitespace to locate the next field, and save a 00144 * pointer to the volume data. 00145 */ 00146 while (*cp != '\0' && (*cp == ' ' || *cp == '\t')) 00147 cp++; 00148 volume = cp; 00149 /* 00150 * There is no need to null terminate the volume since it is processed 00151 * with atoi. 00152 * 00153 * Next, check to see if the unprocessed portion of the line has any 00154 * whitespace following the default volume. 00155 */ 00156 cp1 = cp; 00157 if (!(cp = strchr(cp1, ' ')) && !(cp = strchr(cp1, '\t'))) { 00158 /* 00159 * If not, there cannot be a sound number, and any data left is an 00160 * unused symbolic name, so the sound number is auto-assigned. 00161 */ 00162 newnum = lastnum + 1; 00163 symbolic = NULL; 00164 } else { 00165 /* 00166 * Since there is more whitespace, there might be a symbolic name and 00167 * sound number. Ignore any additional whitespace following the 00168 * volume, and treat the next character as the beginning of a symbolic 00169 * name. 00170 */ 00171 while (*cp != '\0' && (*cp == ' ' || *cp == '\t')) 00172 cp++; 00173 symbolic = cp; 00174 /* 00175 * Some symbolic names are double-quoted to allow them to contain 00176 * whitespace. If a quote starts the name, advance the name pointer 00177 * to effectively strip the quote, and convert the final quote to a 00178 * null terminator. 00179 */ 00180 if (*symbolic == '"') { 00181 symbolic++; 00182 for (cp = symbolic; *cp != '\0' && *cp != '"'; cp++); 00183 *cp = '\0'; 00184 cp++; 00185 } 00186 /* 00187 * cp is either the beginning of an unquoted symbolic name or is 00188 * pointing to the whitespace between a quoted symbolic name and the 00189 * sound number. 00190 */ 00191 cp1 = cp; 00192 if (!(cp = strchr(cp1, ' ')) && !(cp = strchr(cp1, '\t'))) { 00193 /* 00194 * There is no more whitespace on the line. If the name was 00195 * quoted, there should have been whitespace following that cp was 00196 * pointing to, so there cannot be a sound number present. On the 00197 * other hand, if the name was not quoted, cp would point at the 00198 * symbolic name and whitespace should follow if a sound number is 00199 * present. Either way, the sound number must be auto-assigned. 00200 */ 00201 newnum = lastnum + 1; 00202 } else { 00203 /* 00204 * If there was whitespace left, cp points to it now, whether or 00205 * not the symbolic name was quoted. A sound number should follow 00206 * the whitespace. First, try to null terminate the prior data, 00207 * then skip all subsequent whitespace, and point at what should 00208 * be the sound number. If numeric data is found, read the sound 00209 * number, otherwise auto-assign the sound number. This is a bit 00210 * dodgy as invalid data is silently ignored. 00211 */ 00212 *cp++ = '\0'; 00213 while (*cp != '\0' && (*cp == ' ' || *cp == '\t')) 00214 cp++; 00215 if (isdigit(*cp)) 00216 newnum = atoi(cp); 00217 else 00218 newnum = lastnum + 1; 00219 } 00220 } 00221 if (newnum < 0 || newnum > MAX_SOUNDS) { 00222 fprintf(stderr, 00223 "Invalid sound number %d, line %d, buf %s\n", 00224 newnum, lineno, line); 00225 return; 00226 } 00227 /* 00228 * Compatibility processing for older files and/or the SDL_mixer setup. 00229 * If the filename ends in .au, convert the ending to a more appropriate 00230 * one as .au files are not distributed by the project. 00231 * 00232 * Use .raw instead of .au for most sound setups, as this is what has been 00233 * supported by the clients for a long time. 00234 * 00235 * As SDL_mixer does not support .raw, change the extension to .ogg for 00236 * systems other than Windows, or .wav for Windows. Technically, it would 00237 * be okay to use either .wav or .ogg whatever the platform, so it is a 00238 * FIXME in that it would probably be best for the file extension to be a 00239 * configurable option. 00240 * 00241 * Overriding the content of the sound file is a bit of a kludge, but 00242 * allows legacy .crossfire/sound files to work with the current client. 00243 * The dodgy part is that if someone looks in the file, it will not 00244 * necessarily indicate the actual file being played. 00245 */ 00246 strcpy(filename, line); 00247 cp = filename + strlen(filename) - 3; 00248 if (!strcmp(cp, ".au")) 00249 strcpy(cp, ".raw"); 00250 #ifdef SDL_SOUND 00251 cp = filename + strlen(filename) - 4; 00252 if (!strcmp(cp, ".raw")) 00253 #ifndef WIN32 00254 strcpy(cp, ".ogg"); 00255 #else 00256 strcpy(cp, ".wav"); 00257 #endif 00258 #endif 00259 /* 00260 * One symbolic name is used: DEFAULT. If it is found, the sound file 00261 * becomes the default sound for any undefined sound number, so set the 00262 * appropriate default, and ignore any sound number that may follow. 00263 */ 00264 if (symbolic && !strcmp(symbolic, "DEFAULT")) { 00265 if (readtype == 1) { 00266 /* 00267 * Standard Sounds 00268 */ 00269 default_normal.filename = strdup_local(filename); 00270 default_normal.volume = atoi(volume); 00271 } else if (readtype == 2) { 00272 /* 00273 * Spell Sounds 00274 */ 00275 default_spell.filename = strdup_local(filename); 00276 default_spell.volume = atoi(volume); 00277 } 00278 return; 00279 } 00280 /* 00281 * The only way for processing to reach this point is if valid sound data 00282 * was found in a section. Process it according to the section it is in. 00283 */ 00284 if (readtype == 1) { 00285 /* 00286 * Standard Sounds 00287 */ 00288 normal_sounds[newnum].filename = strdup_local(filename); 00289 normal_sounds[newnum].volume = atoi(volume); 00290 if (symbolic) 00291 normal_sounds[newnum].symbolic = strdup_local(symbolic); 00292 else 00293 normal_sounds[newnum].symbolic = NULL; 00294 } else if (readtype == 2) { 00295 /* 00296 * Spell Sounds 00297 */ 00298 spell_sounds[newnum].filename = strdup_local(filename); 00299 spell_sounds[newnum].volume = atoi(volume); 00300 if (symbolic) 00301 spell_sounds[newnum].symbolic = strdup_local(symbolic); 00302 else 00303 spell_sounds[newnum].symbolic = NULL; 00304 } 00305 /* 00306 * Retain the assigned sound number for possible use in subsquent data 00307 * lines. 00308 */ 00309 lastnum = newnum; 00310 } 00311 00329 int init_sounds(void) { 00330 FILE *fp; 00331 char path[MAXSOCKBUF]; 00332 char buf[512]; 00333 int i; 00334 00335 #ifdef SOUND_DEBUG 00336 fprintf( stderr, "Settings: bits: %i, ", settings.bit8 ? 8 : 16); 00337 fprintf( stderr, "%s, ",settings.sign ? "signed" : "unsigned"); 00338 fprintf( stderr, "%s, ",settings.stereo ? "stereo" : "mono"); 00339 fprintf( stderr, "frequency: %i, ", settings.frequency); 00340 fprintf( stderr, "device: %s\n", settings.audiodev); 00341 #endif 00342 00343 /* 00344 * Force the last char of the buffer to null in case strn* cuts off the 00345 * terminating null while copying file information. 00346 */ 00347 path[sizeof(path) - 1] = '\0'; 00348 /* 00349 * Initialize paths to various sound system resources. Bail if any of 00350 * the buffer allocations fail. 00351 */ 00352 strncpy(path, getenv("HOME"), sizeof(path) - 1); 00353 strncat(path, USER_CONFIG_FILE, sizeof(path) - 1); 00354 CONVERT_FILESPEC_TO_OS_FORMAT(path); 00355 user_config_file = (char *) malloc(strlen(path)); 00356 if (user_config_file) 00357 strcpy(user_config_file, path); 00358 else 00359 return -1; 00360 00361 strncpy(path, getenv("HOME"), sizeof(path) - 1); 00362 strncat(path, USER_SOUNDS_FILE, sizeof(path) - 1); 00363 CONVERT_FILESPEC_TO_OS_FORMAT(path); 00364 user_sounds_file = (char *) malloc(strlen(path)); 00365 if (user_sounds_file) 00366 strcpy(user_sounds_file, path); 00367 else 00368 return -1; 00369 00370 strncpy(path, getenv("HOME"), sizeof(path) - 1); 00371 strncat(path, USER_SOUNDS_PATH, sizeof(path) - 1); 00372 CONVERT_FILESPEC_TO_OS_FORMAT(path); 00373 user_sounds_path = (char *) malloc(strlen(path)); 00374 if (user_sounds_path) 00375 strcpy(user_sounds_path, path); 00376 else 00377 return -1; 00378 00379 strncpy(path, CLIENT_SOUNDS_PATH, sizeof(path) - 1); 00380 CONVERT_FILESPEC_TO_OS_FORMAT(path); 00381 client_sounds_path = (char *) malloc(strlen(path)); 00382 if (client_sounds_path) 00383 strcpy(client_sounds_path, path); 00384 else 00385 return -1; 00386 00387 buffers = (char *) malloc(settings.buffers * settings.buflen); 00388 if (!buffers) 00389 return -1; 00390 00391 sounds_in_buffer = (int *) calloc(settings.buffers, sizeof(int)); 00392 if (!sounds_in_buffer) 00393 return -1; 00394 00395 if (init_audio()) 00396 return -1; 00397 00398 if (sign) 00399 zerolevel = 0; 00400 else 00401 zerolevel = bit8 ? 0x80 : 0x00; 00402 00403 memset(buffers, zerolevel, settings.buflen * settings.buffers); 00404 00405 #ifdef SOUND_DEBUG 00406 fprintf( stderr, "bits: %i, ", bit8 ? 8 : 16); 00407 fprintf( stderr, "%s, ", sign ? "signed" : "unsigned"); 00408 fprintf( stderr, "%s, ", stereo ? "stereo" : "mono"); 00409 fprintf( stderr, "freq: %i, ", frequency); 00410 fprintf( stderr, "smpl_size: %i, ", sample_size); 00411 fprintf( stderr, "0level: %i\n", zerolevel); 00412 #endif 00413 00414 for (i = 0; i < MAX_SOUNDS; i++) { 00415 normal_sounds[i].filename = NULL; 00416 spell_sounds[i].filename = NULL; 00417 normal_sounds[i].size = -1; 00418 spell_sounds[i].size = -1; 00419 } 00420 default_normal.filename = NULL; 00421 default_spell.filename = NULL; 00422 00423 i = 0; 00424 if (!(fp = fopen(user_sounds_file, "r"))) { 00425 fprintf(stderr, 00426 "Unable to open %s - using built-in defaults\n", 00427 user_sounds_file); 00428 for (; i < sizeof(def_sounds) / sizeof(char*); i++) { 00429 strcpy(buf, def_sounds[i]); 00430 parse_sound_line(buf, i); 00431 } 00432 } else while (fgets(buf, 511, fp) != NULL) { 00433 buf[511] = '\0'; 00434 parse_sound_line(buf, ++i); 00435 } 00436 /* Note in both cases below, we leave the symbolic name untouched. */ 00437 for (i = 0; i < MAX_SOUNDS; i++) { 00438 if (!normal_sounds[i].filename) { 00439 normal_sounds[i].filename = default_normal.filename; 00440 normal_sounds[i].volume = default_normal.volume; 00441 } 00442 if (!spell_sounds[i].filename) { 00443 spell_sounds[i].filename = default_spell.filename; 00444 spell_sounds[i].volume = default_spell.volume; 00445 } 00446 normal_sounds[i].data = NULL; 00447 spell_sounds[i].data = NULL; 00448 } 00449 return 0; 00450 } 00451 00461 int sound_to_soundnum(const char *name, uint8 type) { 00462 00463 fprintf(stderr, "name=%s type=%d\n", name, type); 00468 return 1; 00469 } 00470 00480 int type_to_soundtype(uint8 type) { 00481 00482 #ifdef SOUND_DEBUG 00483 fprintf(stderr, 00484 "Converted type %d to legacy type %d.\n", type, (type == 2) ? 2 : 1); 00485 #endif 00486 00489 return (type == 2) ? 2 : 1; 00490 } 00491 00519 int StdinCmd(char *data, int len) { 00520 char* dptr; /* Pointer used when parsing data */ 00521 char* fptr; 00522 char* sound = NULL; /* Points to a sound or music name */ 00523 char* source = NULL; 00524 char soundfile[MAXSOCKBUF]; 00525 int sourcelen; 00526 int soundlen; 00527 int spacelen; 00528 int type = 0; 00529 int dir = 0; 00530 int vol = 0; 00531 int x = 0; 00532 int y = 0; 00533 int i = 0; 00534 00535 fptr = soundfile; 00536 dptr = strtok(data, "\""); 00537 /* 00538 * Is data a blank line (ending with LF) or is it a quoted, empty string? 00539 */ 00540 if (dptr == NULL) { 00541 fprintf(stderr, "Sound/music command does not contain any data.\n"); 00542 return -1; 00543 } 00544 /* 00545 * If the first character is not a quote character, a sound command is 00546 * expected. 00547 */ 00548 if (data[0] != '\"') { 00549 /* 00550 * There are 5 numeric values expected and required. Technically, if 00551 * cfsndserv was new, and the client old, 4 might be present, but the 00552 * player does not attempt to support old clients. 00553 */ 00554 i = sscanf(dptr, "%d %d %d %d %d", &x, &y, &dir, &vol, &type); 00555 00556 if ((i != 5) 00557 || (dir < 0) 00558 || (dir > 8) 00559 || (vol < 0) 00560 || (vol > 100) 00561 || (type < 1)) { 00562 /* 00563 * There is not much point in trying to work with data that does 00564 * not fit some basic rules known at the time of development. 00565 */ 00566 fprintf(stderr, "Unrecognized sound command data format.\n"); 00567 #ifdef SOUND_DEBUG 00568 fprintf(stderr, 00569 "(%d valid items read) x=%d y=%d dir=%d vol=%d type=%d\n", 00570 i, x, y, dir, vol, type); 00571 #endif 00572 return -1; 00573 } 00574 } 00575 /* 00576 * Below this point, when type == 0, a music command is expected, and when 00577 * type != 0, a sound command is required. 00578 */ 00579 if (type) { 00580 /* 00581 * dptr points to the numerics already read, so advance to the string 00582 * following the first quote delimiter. A sound source name is 00583 * expected. 00584 */ 00585 dptr = strtok(NULL, "\""); 00586 if (dptr == NULL) { 00587 fprintf(stderr, "Sound command is missing sound/source names.\n"); 00588 return -1; 00589 } 00590 source = dptr; 00591 sourcelen = strlen(dptr); 00592 /* 00593 * Verify there is whitespace between source and sound names. 00594 */ 00595 dptr = strtok(NULL, "\""); 00596 if (dptr == NULL) { 00597 fprintf(stderr, "Sound command is missing the sound name.\n"); 00598 return -1; 00599 } 00600 spacelen = strlen(dptr); 00601 for (i = 0; i < spacelen; i++) { 00602 if (dptr[i] != ' ' && dptr[i] != '\t') { 00603 fprintf(stderr, "Invalid characters after source name.\n"); 00604 return -1; 00605 } 00606 } 00607 /* 00608 * Advance the data pointer to the following sound name. 00609 */ 00610 dptr = strtok(NULL, "\""); 00611 if (dptr == NULL) { 00612 fprintf(stderr, "Sound command is missing the sound name.\n"); 00613 return -1; 00614 } 00615 } 00616 /* 00617 * Record the sound or music name here (type determines which it is). 00618 */ 00619 sound = dptr; 00620 soundlen = strlen(dptr); 00621 /* 00622 * If there was a trailing quote after the sound or music name, there will 00623 * be a null there now, and sound[soundlen] should point to the character 00624 * just before another null at data[len-1] (that terminates the command). 00625 */ 00626 i = sound - data + soundlen + 1 + 1; 00627 if (i - 1 == len) { 00628 fprintf(stderr, "Sound or music name does not end with a quote.\n"); 00629 return -1; 00630 } 00631 if (i > len) { 00632 fprintf(stderr, 00633 "Invalid data after sound/music name (a quoted string needed)\n"); 00634 return -1; 00635 } 00636 00637 if (type) { 00638 /* 00639 * Play sound effect here. 00640 */ 00641 #ifdef SOUND_DEBUG 00642 fprintf(stderr, "Playing sound " 00643 "%d,%d dir=%d vol=%d type=%d source=\"%s\" sound=\"%s\"\n", 00644 x, y, dir, vol, type, source, sound); 00645 #endif 00646 play_sound(sound_to_soundnum(sound, type), 00647 type_to_soundtype(type), x, y); 00648 return 0; 00649 } else { 00650 /* 00651 * Play music here. 00652 */ 00653 #ifdef SOUND_DEBUG 00654 fprintf(stderr, 00655 "Playing music \"%s\"\n", sound); 00656 #endif 00657 play_music(sound); 00658 } 00659 00660 return 0; 00661 } 00662 00668 int write_settings(void) { 00669 FILE *f; 00670 00671 f = fopen(user_config_file, "w"); 00672 if (!f) 00673 return -1; 00674 00675 fprintf(f, "# Crossfire sound server settings\n"); 00676 fprintf(f, "# Please note, that not everything will work\n\n"); 00677 fprintf(f, "stereo: %i\n", settings.stereo); 00678 fprintf(f, "bits: %i\n", settings.bit8?8:16); 00679 fprintf(f, "signed: %i\n", settings.sign); 00680 fprintf(f, "frequency: %i\n", settings.frequency); 00681 fprintf(f, "buffers: %i\n", settings.buffers); 00682 fprintf(f, "buflen: %i\n", settings.buflen); 00683 fprintf(f, "simultaneously: %i\n", settings.simultaneously); 00684 /* fprintf(f,"device: %s\n",settings.audiodev); */ 00685 fclose(f); 00686 return 0; 00687 } 00688 00694 int read_settings(void) { 00695 char linebuf[1024]; 00696 FILE *f; 00697 00698 if (user_config_file == NULL) 00699 return 0; 00700 00701 f = fopen(user_config_file, "r"); 00702 if (!f) 00703 return -1; 00704 00705 while(fgets(linebuf, 1023, f) != NULL) { 00706 linebuf[1023] = 0; 00707 /* Strip off the newline */ 00708 linebuf[strlen(linebuf) - 1] = 0; 00709 00710 if (strncmp(linebuf, "stereo:", strlen("stereo:")) == 0) 00711 settings.stereo = atoi(linebuf + strlen("stereo:")) ? 1 : 0; 00712 else if (strncmp(linebuf, "bits:", strlen("bits:")) == 0) 00713 settings.bit8 = (atoi(linebuf + strlen("bits:"))==8) ? 1 : 0; 00714 else if (strncmp(linebuf, "signed:", strlen("signed:")) == 0) 00715 settings.sign = atoi(linebuf + strlen("signed:")) ? 1 : 0; 00716 else if (strncmp(linebuf, "buffers:", strlen("buffers:")) == 0) 00717 settings.buffers = atoi(linebuf + strlen("buffers:")); 00718 else if (strncmp(linebuf, "buflen:", strlen("buflen:")) == 0) 00719 settings.buflen = atoi(linebuf + strlen("buflen:")); 00720 else if (strncmp(linebuf, "frequency:", strlen("frequency:")) == 0) 00721 settings.frequency = atoi(linebuf + strlen("frequency:")); 00722 else if (strncmp(linebuf, "simultaneously:", strlen("simultaneously:")) == 0) 00723 settings.simultaneously = atoi(linebuf + strlen("simultaneously:")); 00724 #if 0 00725 else if (strncmp(linebuf,"device: ",strlen("device: "))==0) 00726 settings.audiodev=strdup_local(linebuf+strlen("device: ")); 00727 #endif 00728 } 00729 fclose(f); 00730 return 0; 00731 } 00732
1.7.6.1