|
|
1.1.1.3 ! root 1: /* ! 2: Copyright (C) 1997-2001 Id Software, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or ! 5: modify it under the terms of the GNU General Public License ! 6: as published by the Free Software Foundation; either version 2 ! 7: of the License, or (at your option) any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ! 12: ! 13: See the GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ! 18: ! 19: */ 1.1 root 20: // snd_dma.c -- main control for any streaming sound output device 21: 22: #include "client.h" 23: #include "snd_loc.h" 24: 25: void S_Play(void); 26: void S_SoundList(void); 27: void S_Update_(); 28: void S_StopAllSounds(void); 29: 30: 31: // ======================================================================= 32: // Internal sound data & structures 33: // ======================================================================= 34: 35: // only begin attenuating sound volumes when outside the FULLVOLUME range 36: #define SOUND_FULLVOLUME 80 37: 38: #define SOUND_LOOPATTENUATE 0.003 39: 40: int s_registration_sequence; 41: 42: channel_t channels[MAX_CHANNELS]; 43: 44: qboolean snd_initialized = false; 45: int sound_started=0; 46: 47: dma_t dma; 48: 49: vec3_t listener_origin; 50: vec3_t listener_forward; 51: vec3_t listener_right; 52: vec3_t listener_up; 53: 54: qboolean s_registering; 55: 56: int soundtime; // sample PAIRS 57: int paintedtime; // sample PAIRS 58: 59: // during registration it is possible to have more sounds 60: // than could actually be referenced during gameplay, 61: // because we don't want to free anything until we are 62: // sure we won't need it. 63: #define MAX_SFX (MAX_SOUNDS*2) 64: sfx_t known_sfx[MAX_SFX]; 65: int num_sfx; 66: 67: #define MAX_PLAYSOUNDS 128 68: playsound_t s_playsounds[MAX_PLAYSOUNDS]; 69: playsound_t s_freeplays; 70: playsound_t s_pendingplays; 71: 72: int s_beginofs; 73: 74: cvar_t *s_volume; 75: cvar_t *s_testsound; 76: cvar_t *s_loadas8bit; 77: cvar_t *s_khz; 78: cvar_t *s_show; 79: cvar_t *s_mixahead; 80: cvar_t *s_primary; 81: 82: 83: int s_rawend; 84: portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; 85: 86: 87: // ==================================================================== 88: // User-setable variables 89: // ==================================================================== 90: 91: 92: void S_SoundInfo_f(void) 93: { 94: if (!sound_started) 95: { 96: Com_Printf ("sound system not started\n"); 97: return; 98: } 99: 100: Com_Printf("%5d stereo\n", dma.channels - 1); 101: Com_Printf("%5d samples\n", dma.samples); 102: Com_Printf("%5d samplepos\n", dma.samplepos); 103: Com_Printf("%5d samplebits\n", dma.samplebits); 104: Com_Printf("%5d submission_chunk\n", dma.submission_chunk); 105: Com_Printf("%5d speed\n", dma.speed); 106: Com_Printf("0x%x dma buffer\n", dma.buffer); 107: } 108: 109: 110: 111: /* 112: ================ 113: S_Init 114: ================ 115: */ 116: void S_Init (void) 117: { 118: cvar_t *cv; 119: 120: Com_Printf("\n------- sound initialization -------\n"); 121: 122: cv = Cvar_Get ("s_initsound", "1", 0); 123: if (!cv->value) 124: Com_Printf ("not initializing.\n"); 125: else 126: { 127: s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE); 128: s_khz = Cvar_Get ("s_khz", "11", CVAR_ARCHIVE); 129: s_loadas8bit = Cvar_Get ("s_loadas8bit", "1", CVAR_ARCHIVE); 130: s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE); 131: s_show = Cvar_Get ("s_show", "0", 0); 132: s_testsound = Cvar_Get ("s_testsound", "0", 0); 133: s_primary = Cvar_Get ("s_primary", "0", CVAR_ARCHIVE); // win32 specific 134: 135: Cmd_AddCommand("play", S_Play); 136: Cmd_AddCommand("stopsound", S_StopAllSounds); 137: Cmd_AddCommand("soundlist", S_SoundList); 138: Cmd_AddCommand("soundinfo", S_SoundInfo_f); 139: 140: if (!SNDDMA_Init()) 141: return; 142: 143: S_InitScaletable (); 144: 145: sound_started = 1; 146: num_sfx = 0; 147: 148: soundtime = 0; 149: paintedtime = 0; 150: 151: Com_Printf ("sound sampling rate: %i\n", dma.speed); 152: 153: S_StopAllSounds (); 154: } 155: 156: Com_Printf("------------------------------------\n"); 157: } 158: 159: 160: // ======================================================================= 161: // Shutdown sound engine 162: // ======================================================================= 163: 164: void S_Shutdown(void) 165: { 166: int i; 167: sfx_t *sfx; 168: 169: if (!sound_started) 170: return; 171: 172: SNDDMA_Shutdown(); 173: 174: sound_started = 0; 175: 176: Cmd_RemoveCommand("play"); 177: Cmd_RemoveCommand("stopsound"); 178: Cmd_RemoveCommand("soundlist"); 179: Cmd_RemoveCommand("soundinfo"); 180: 181: // free all sounds 182: for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) 183: { 184: if (!sfx->name[0]) 185: continue; 186: if (sfx->cache) 187: Z_Free (sfx->cache); 188: memset (sfx, 0, sizeof(*sfx)); 189: } 190: 191: num_sfx = 0; 192: } 193: 194: 195: // ======================================================================= 196: // Load a sound 197: // ======================================================================= 198: 199: /* 200: ================== 201: S_FindName 202: 203: ================== 204: */ 205: sfx_t *S_FindName (char *name, qboolean create) 206: { 207: int i; 208: sfx_t *sfx; 209: 210: if (!name) 211: Com_Error (ERR_FATAL, "S_FindName: NULL\n"); 212: if (!name[0]) 213: Com_Error (ERR_FATAL, "S_FindName: empty name\n"); 214: 215: if (strlen(name) >= MAX_QPATH) 216: Com_Error (ERR_FATAL, "Sound name too long: %s", name); 217: 218: // see if already loaded 219: for (i=0 ; i < num_sfx ; i++) 220: if (!strcmp(known_sfx[i].name, name)) 221: { 222: return &known_sfx[i]; 223: } 224: 225: if (!create) 226: return NULL; 227: 228: // find a free sfx 229: for (i=0 ; i < num_sfx ; i++) 230: if (!known_sfx[i].name[0]) 231: // registration_sequence < s_registration_sequence) 232: break; 233: 234: if (i == num_sfx) 235: { 236: if (num_sfx == MAX_SFX) 237: Com_Error (ERR_FATAL, "S_FindName: out of sfx_t"); 238: num_sfx++; 239: } 240: 241: sfx = &known_sfx[i]; 242: memset (sfx, 0, sizeof(*sfx)); 243: strcpy (sfx->name, name); 244: sfx->registration_sequence = s_registration_sequence; 245: 246: return sfx; 247: } 248: 249: 250: /* 1.1.1.2 root 251: ================== 252: S_AliasName 253: 254: ================== 255: */ 256: sfx_t *S_AliasName (char *aliasname, char *truename) 257: { 258: sfx_t *sfx; 259: char *s; 260: int i; 261: 262: s = Z_Malloc (MAX_QPATH); 263: strcpy (s, truename); 264: 265: // find a free sfx 266: for (i=0 ; i < num_sfx ; i++) 267: if (!known_sfx[i].name[0]) 268: break; 269: 270: if (i == num_sfx) 271: { 272: if (num_sfx == MAX_SFX) 273: Com_Error (ERR_FATAL, "S_FindName: out of sfx_t"); 274: num_sfx++; 275: } 276: 277: sfx = &known_sfx[i]; 278: memset (sfx, 0, sizeof(*sfx)); 279: strcpy (sfx->name, aliasname); 280: sfx->registration_sequence = s_registration_sequence; 281: sfx->truename = s; 282: 283: return sfx; 284: } 285: 286: 287: /* 1.1 root 288: ===================== 289: S_BeginRegistration 290: 291: ===================== 292: */ 293: void S_BeginRegistration (void) 294: { 295: s_registration_sequence++; 296: s_registering = true; 297: } 298: 299: /* 300: ================== 301: S_RegisterSound 302: 303: ================== 304: */ 305: sfx_t *S_RegisterSound (char *name) 306: { 307: sfx_t *sfx; 308: 309: if (!sound_started) 310: return NULL; 311: 312: sfx = S_FindName (name, true); 313: sfx->registration_sequence = s_registration_sequence; 314: 315: if (!s_registering) 316: S_LoadSound (sfx); 317: 318: return sfx; 319: } 320: 321: 322: /* 323: ===================== 324: S_EndRegistration 325: 326: ===================== 327: */ 328: void S_EndRegistration (void) 329: { 330: int i; 331: sfx_t *sfx; 332: int size; 333: 334: // free any sounds not from this registration sequence 335: for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) 336: { 337: if (!sfx->name[0]) 338: continue; 339: if (sfx->registration_sequence != s_registration_sequence) 340: { // don't need this sound 341: if (sfx->cache) // it is possible to have a leftover 342: Z_Free (sfx->cache); // from a server that didn't finish loading 343: memset (sfx, 0, sizeof(*sfx)); 344: } 345: else 346: { // make sure it is paged in 347: if (sfx->cache) 348: { 349: size = sfx->cache->length*sfx->cache->width; 350: Com_PageInMemory ((byte *)sfx->cache, size); 351: } 352: } 353: 354: } 355: 356: // load everything in 357: for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) 358: { 359: if (!sfx->name[0]) 360: continue; 361: S_LoadSound (sfx); 362: } 363: 364: s_registering = false; 365: } 366: 367: 368: //============================================================================= 369: 370: /* 371: ================= 372: S_PickChannel 373: ================= 374: */ 375: channel_t *S_PickChannel(int entnum, int entchannel) 376: { 377: int ch_idx; 378: int first_to_die; 379: int life_left; 380: channel_t *ch; 381: 382: if (entchannel<0) 383: Com_Error (ERR_DROP, "S_PickChannel: entchannel<0"); 384: 385: // Check for replacement sound, or find the best one to replace 386: first_to_die = -1; 387: life_left = 0x7fffffff; 388: for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++) 389: { 390: if (entchannel != 0 // channel 0 never overrides 391: && channels[ch_idx].entnum == entnum 392: && channels[ch_idx].entchannel == entchannel) 393: { // always override sound from same entity 394: first_to_die = ch_idx; 395: break; 396: } 397: 398: // don't let monster sounds override player sounds 399: if (channels[ch_idx].entnum == cl.playernum+1 && entnum != cl.playernum+1 && channels[ch_idx].sfx) 400: continue; 401: 402: if (channels[ch_idx].end - paintedtime < life_left) 403: { 404: life_left = channels[ch_idx].end - paintedtime; 405: first_to_die = ch_idx; 406: } 407: } 408: 409: if (first_to_die == -1) 410: return NULL; 411: 412: ch = &channels[first_to_die]; 413: memset (ch, 0, sizeof(*ch)); 414: 415: return ch; 416: } 417: 418: /* 419: ================= 420: S_SpatializeOrigin 421: 422: Used for spatializing channels and autosounds 423: ================= 424: */ 425: void S_SpatializeOrigin (vec3_t origin, float master_vol, float dist_mult, int *left_vol, int *right_vol) 426: { 427: vec_t dot; 428: vec_t dist; 429: vec_t lscale, rscale, scale; 430: vec3_t source_vec; 431: 432: if (cls.state != ca_active) 433: { 434: *left_vol = *right_vol = 255; 435: return; 436: } 437: 438: // calculate stereo seperation and distance attenuation 439: VectorSubtract(origin, listener_origin, source_vec); 440: 441: dist = VectorNormalize(source_vec); 442: dist -= SOUND_FULLVOLUME; 443: if (dist < 0) 444: dist = 0; // close enough to be at full volume 445: dist *= dist_mult; // different attenuation levels 446: 447: dot = DotProduct(listener_right, source_vec); 448: 449: if (dma.channels == 1 || !dist_mult) 450: { // no attenuation = no spatialization 451: rscale = 1.0; 452: lscale = 1.0; 453: } 454: else 455: { 456: rscale = 0.5 * (1.0 + dot); 457: lscale = 0.5*(1.0 - dot); 458: } 459: 460: // add in distance effect 461: scale = (1.0 - dist) * rscale; 462: *right_vol = (int) (master_vol * scale); 463: if (*right_vol < 0) 464: *right_vol = 0; 465: 466: scale = (1.0 - dist) * lscale; 467: *left_vol = (int) (master_vol * scale); 468: if (*left_vol < 0) 469: *left_vol = 0; 470: } 471: 472: /* 473: ================= 474: S_Spatialize 475: ================= 476: */ 477: void S_Spatialize(channel_t *ch) 478: { 479: vec3_t origin; 480: 481: // anything coming from the view entity will always be full volume 482: if (ch->entnum == cl.playernum+1) 483: { 484: ch->leftvol = ch->master_vol; 485: ch->rightvol = ch->master_vol; 486: return; 487: } 488: 489: if (ch->fixed_origin) 490: { 491: VectorCopy (ch->origin, origin); 492: } 493: else 494: CL_GetEntitySoundOrigin (ch->entnum, origin); 495: 496: S_SpatializeOrigin (origin, ch->master_vol, ch->dist_mult, &ch->leftvol, &ch->rightvol); 497: } 498: 499: 500: /* 501: ================= 502: S_AllocPlaysound 503: ================= 504: */ 505: playsound_t *S_AllocPlaysound (void) 506: { 507: playsound_t *ps; 508: 509: ps = s_freeplays.next; 510: if (ps == &s_freeplays) 511: return NULL; // no free playsounds 512: 513: // unlink from freelist 514: ps->prev->next = ps->next; 515: ps->next->prev = ps->prev; 516: 517: return ps; 518: } 519: 520: 521: /* 522: ================= 523: S_FreePlaysound 524: ================= 525: */ 526: void S_FreePlaysound (playsound_t *ps) 527: { 528: // unlink from channel 529: ps->prev->next = ps->next; 530: ps->next->prev = ps->prev; 531: 532: // add to free list 533: ps->next = s_freeplays.next; 534: s_freeplays.next->prev = ps; 535: ps->prev = &s_freeplays; 536: s_freeplays.next = ps; 537: } 538: 539: 540: 541: /* 542: =============== 543: S_IssuePlaysound 544: 545: Take the next playsound and begin it on the channel 546: This is never called directly by S_Play*, but only 547: by the update loop. 548: =============== 549: */ 550: void S_IssuePlaysound (playsound_t *ps) 551: { 552: channel_t *ch; 553: sfxcache_t *sc; 554: 555: if (s_show->value) 556: Com_Printf ("Issue %i\n", ps->begin); 557: // pick a channel to play on 558: ch = S_PickChannel(ps->entnum, ps->entchannel); 559: if (!ch) 560: { 561: S_FreePlaysound (ps); 562: return; 563: } 564: 565: // spatialize 566: if (ps->attenuation == ATTN_STATIC) 567: ch->dist_mult = ps->attenuation * 0.001; 568: else 569: ch->dist_mult = ps->attenuation * 0.0005; 570: ch->master_vol = ps->volume; 571: ch->entnum = ps->entnum; 572: ch->entchannel = ps->entchannel; 573: ch->sfx = ps->sfx; 574: VectorCopy (ps->origin, ch->origin); 575: ch->fixed_origin = ps->fixed_origin; 576: 577: S_Spatialize(ch); 578: 579: ch->pos = 0; 580: sc = S_LoadSound (ch->sfx); 581: ch->end = paintedtime + sc->length; 582: 583: // free the playsound 584: S_FreePlaysound (ps); 585: } 586: 587: struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base) 588: { 589: int n; 590: char *p; 591: struct sfx_s *sfx; 592: FILE *f; 593: char model[MAX_QPATH]; 1.1.1.2 root 594: char sexedFilename[MAX_QPATH]; 595: char maleFilename[MAX_QPATH]; 1.1 root 596: 597: // determine what model the client is using 598: model[0] = 0; 599: n = CS_PLAYERSKINS + ent->number - 1; 600: if (cl.configstrings[n][0]) 601: { 602: p = strchr(cl.configstrings[n], '\\'); 603: if (p) 604: { 605: p += 1; 606: strcpy(model, p); 607: p = strchr(model, '/'); 608: if (p) 609: *p = 0; 610: } 611: } 612: // if we can't figure it out, they're male 613: if (!model[0]) 614: strcpy(model, "male"); 615: 616: // see if we already know of the model specific sound 1.1.1.2 root 617: Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1); 618: sfx = S_FindName (sexedFilename, false); 1.1 root 619: 620: if (!sfx) 621: { 622: // no, so see if it exists 1.1.1.2 root 623: FS_FOpenFile (&sexedFilename[1], &f); 1.1 root 624: if (f) 625: { 626: // yes, close the file and register it 627: FS_FCloseFile (f); 1.1.1.2 root 628: sfx = S_RegisterSound (sexedFilename); 1.1 root 629: } 630: else 631: { 632: // no, revert to the male sound in the pak0.pak 1.1.1.2 root 633: Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1); 634: sfx = S_AliasName (sexedFilename, maleFilename); 1.1 root 635: } 636: } 637: 638: return sfx; 639: } 640: 1.1.1.2 root 641: 1.1 root 642: // ======================================================================= 643: // Start a sound effect 644: // ======================================================================= 645: 646: /* 647: ==================== 648: S_StartSound 649: 650: Validates the parms and ques the sound up 651: if pos is NULL, the sound will be dynamically sourced from the entity 652: Entchannel 0 will never override a playing sound 653: ==================== 654: */ 655: void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float fvol, float attenuation, float timeofs) 656: { 657: sfxcache_t *sc; 658: int vol; 659: playsound_t *ps, *sort; 660: int start; 661: 662: if (!sound_started) 663: return; 664: 665: if (!sfx) 666: return; 667: 668: if (sfx->name[0] == '*') 669: sfx = S_RegisterSexedSound(&cl_entities[entnum].current, sfx->name); 670: 671: // make sure the sound is loaded 672: sc = S_LoadSound (sfx); 673: if (!sc) 674: return; // couldn't load the sound's data 675: 676: vol = fvol*255; 677: 678: // make the playsound_t 679: ps = S_AllocPlaysound (); 680: if (!ps) 681: return; 682: 683: if (origin) 684: { 685: VectorCopy (origin, ps->origin); 686: ps->fixed_origin = true; 687: } 688: else 689: ps->fixed_origin = false; 690: 691: ps->entnum = entnum; 692: ps->entchannel = entchannel; 693: ps->attenuation = attenuation; 694: ps->volume = vol; 695: ps->sfx = sfx; 696: 697: // drift s_beginofs 698: start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs; 699: if (start < paintedtime) 700: { 701: start = paintedtime; 702: s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed); 703: } 704: else if (start > paintedtime + 0.3 * dma.speed) 705: { 706: start = paintedtime + 0.1 * dma.speed; 707: s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed); 708: } 709: else 710: { 711: s_beginofs-=10; 712: } 713: 714: if (!timeofs) 715: ps->begin = paintedtime; 716: else 717: ps->begin = start + timeofs * dma.speed; 718: 719: // sort into the pending sound list 720: for (sort = s_pendingplays.next ; 721: sort != &s_pendingplays && sort->begin < ps->begin ; 722: sort = sort->next) 723: ; 724: 725: ps->next = sort; 726: ps->prev = sort->prev; 727: 728: ps->next->prev = ps; 729: ps->prev->next = ps; 730: } 731: 732: 733: /* 734: ================== 735: S_StartLocalSound 736: ================== 737: */ 738: void S_StartLocalSound (char *sound) 739: { 740: sfx_t *sfx; 741: 742: if (!sound_started) 743: return; 744: 745: sfx = S_RegisterSound (sound); 746: if (!sfx) 747: { 748: Com_Printf ("S_StartLocalSound: can't cache %s\n", sound); 749: return; 750: } 751: S_StartSound (NULL, cl.playernum+1, 0, sfx, 1, 1, 0); 752: } 753: 754: 755: /* 756: ================== 757: S_ClearBuffer 758: ================== 759: */ 760: void S_ClearBuffer (void) 761: { 762: int clear; 763: 764: if (!sound_started) 765: return; 766: 767: s_rawend = 0; 768: 769: if (dma.samplebits == 8) 770: clear = 0x80; 771: else 772: clear = 0; 773: 774: SNDDMA_BeginPainting (); 775: if (dma.buffer) 776: memset(dma.buffer, clear, dma.samples * dma.samplebits/8); 777: SNDDMA_Submit (); 778: } 779: 780: /* 781: ================== 782: S_StopAllSounds 783: ================== 784: */ 785: void S_StopAllSounds(void) 786: { 787: int i; 788: 789: if (!sound_started) 790: return; 791: 792: // clear all the playsounds 793: memset(s_playsounds, 0, sizeof(s_playsounds)); 794: s_freeplays.next = s_freeplays.prev = &s_freeplays; 795: s_pendingplays.next = s_pendingplays.prev = &s_pendingplays; 796: 797: for (i=0 ; i<MAX_PLAYSOUNDS ; i++) 798: { 799: s_playsounds[i].prev = &s_freeplays; 800: s_playsounds[i].next = s_freeplays.next; 801: s_playsounds[i].prev->next = &s_playsounds[i]; 802: s_playsounds[i].next->prev = &s_playsounds[i]; 803: } 804: 805: // clear all the channels 806: memset(channels, 0, sizeof(channels)); 807: 808: S_ClearBuffer (); 809: } 810: 811: /* 812: ================== 813: S_AddLoopSounds 814: 815: Entities with a ->sound field will generated looped sounds 816: that are automatically started, stopped, and merged together 817: as the entities are sent to the client 818: ================== 819: */ 820: void S_AddLoopSounds (void) 821: { 822: int i, j; 823: int sounds[MAX_EDICTS]; 824: int left, right, left_total, right_total; 825: channel_t *ch; 826: sfx_t *sfx; 827: sfxcache_t *sc; 828: int num; 829: entity_state_t *ent; 830: 831: if (cl_paused->value) 832: return; 833: 834: if (cls.state != ca_active) 835: return; 836: 837: if (!cl.sound_prepped) 838: return; 839: 840: for (i=0 ; i<cl.frame.num_entities ; i++) 841: { 842: num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); 843: ent = &cl_parse_entities[num]; 844: sounds[i] = ent->sound; 845: } 846: 847: for (i=0 ; i<cl.frame.num_entities ; i++) 848: { 849: if (!sounds[i]) 850: continue; 851: 852: sfx = cl.sound_precache[sounds[i]]; 853: if (!sfx) 854: continue; // bad sound effect 855: sc = sfx->cache; 856: if (!sc) 857: continue; 858: 859: num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); 860: ent = &cl_parse_entities[num]; 861: 862: // find the total contribution of all sounds of this type 863: S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE, 864: &left_total, &right_total); 865: for (j=i+1 ; j<cl.frame.num_entities ; j++) 866: { 867: if (sounds[j] != sounds[i]) 868: continue; 869: sounds[j] = 0; // don't check this again later 870: 871: num = (cl.frame.parse_entities + j)&(MAX_PARSE_ENTITIES-1); 872: ent = &cl_parse_entities[num]; 873: 874: S_SpatializeOrigin (ent->origin, 255.0, SOUND_LOOPATTENUATE, 875: &left, &right); 876: left_total += left; 877: right_total += right; 878: } 879: 880: if (left_total == 0 && right_total == 0) 881: continue; // not audible 882: 883: // allocate a channel 884: ch = S_PickChannel(0, 0); 885: if (!ch) 886: return; 887: 888: if (left_total > 255) 889: left_total = 255; 890: if (right_total > 255) 891: right_total = 255; 892: ch->leftvol = left_total; 893: ch->rightvol = right_total; 894: ch->autosound = true; // remove next frame 895: ch->sfx = sfx; 896: ch->pos = paintedtime % sc->length; 897: ch->end = paintedtime + sc->length - ch->pos; 898: } 899: } 900: 901: //============================================================================= 902: 903: /* 904: ============ 905: S_RawSamples 906: 907: Cinematic streaming and voice over network 908: ============ 909: */ 910: void S_RawSamples (int samples, int rate, int width, int channels, byte *data) 911: { 912: int i; 913: int src, dst; 914: float scale; 915: 916: if (!sound_started) 917: return; 918: 919: if (s_rawend < paintedtime) 920: s_rawend = paintedtime; 921: scale = (float)rate / dma.speed; 922: 923: //Com_Printf ("%i < %i < %i\n", soundtime, paintedtime, s_rawend); 924: if (channels == 2 && width == 2) 925: { 926: if (scale == 1.0) 927: { // optimized case 928: for (i=0 ; i<samples ; i++) 929: { 930: dst = s_rawend&(MAX_RAW_SAMPLES-1); 931: s_rawend++; 1.1.1.2 root 932: s_rawsamples[dst].left = 933: LittleShort(((short *)data)[i*2]) << 8; 934: s_rawsamples[dst].right = 935: LittleShort(((short *)data)[i*2+1]) << 8; 1.1 root 936: } 937: } 938: else 939: { 940: for (i=0 ; ; i++) 941: { 942: src = i*scale; 943: if (src >= samples) 944: break; 945: dst = s_rawend&(MAX_RAW_SAMPLES-1); 946: s_rawend++; 1.1.1.2 root 947: s_rawsamples[dst].left = 948: LittleShort(((short *)data)[src*2]) << 8; 949: s_rawsamples[dst].right = 950: LittleShort(((short *)data)[src*2+1]) << 8; 1.1 root 951: } 952: } 953: } 954: else if (channels == 1 && width == 2) 955: { 956: for (i=0 ; ; i++) 957: { 958: src = i*scale; 959: if (src >= samples) 960: break; 961: dst = s_rawend&(MAX_RAW_SAMPLES-1); 962: s_rawend++; 1.1.1.2 root 963: s_rawsamples[dst].left = 964: LittleShort(((short *)data)[src]) << 8; 965: s_rawsamples[dst].right = 966: LittleShort(((short *)data)[src]) << 8; 1.1 root 967: } 968: } 969: else if (channels == 2 && width == 1) 970: { 971: for (i=0 ; ; i++) 972: { 973: src = i*scale; 974: if (src >= samples) 975: break; 976: dst = s_rawend&(MAX_RAW_SAMPLES-1); 977: s_rawend++; 1.1.1.2 root 978: s_rawsamples[dst].left = 979: ((char *)data)[src*2] << 16; 980: s_rawsamples[dst].right = 981: ((char *)data)[src*2+1] << 16; 1.1 root 982: } 983: } 984: else if (channels == 1 && width == 1) 985: { 986: for (i=0 ; ; i++) 987: { 988: src = i*scale; 989: if (src >= samples) 990: break; 991: dst = s_rawend&(MAX_RAW_SAMPLES-1); 992: s_rawend++; 1.1.1.2 root 993: s_rawsamples[dst].left = 994: (((byte *)data)[src]-128) << 16; 1.1 root 995: s_rawsamples[dst].right = (((byte *)data)[src]-128) << 16; 996: } 997: } 998: } 999: 1000: //============================================================================= 1001: 1002: /* 1003: ============ 1004: S_Update 1005: 1006: Called once each time through the main loop 1007: ============ 1008: */ 1009: void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) 1010: { 1011: int i; 1012: int total; 1013: channel_t *ch; 1014: channel_t *combine; 1015: 1016: if (!sound_started) 1017: return; 1018: 1019: // if the laoding plaque is up, clear everything 1020: // out to make sure we aren't looping a dirty 1021: // dma buffer while loading 1022: if (cls.disable_screen) 1023: { 1024: S_ClearBuffer (); 1025: return; 1026: } 1027: 1028: // rebuild scale tables if volume is modified 1029: if (s_volume->modified) 1030: S_InitScaletable (); 1031: 1032: VectorCopy(origin, listener_origin); 1033: VectorCopy(forward, listener_forward); 1034: VectorCopy(right, listener_right); 1035: VectorCopy(up, listener_up); 1036: 1037: combine = NULL; 1038: 1039: // update spatialization for dynamic sounds 1040: ch = channels; 1041: for (i=0 ; i<MAX_CHANNELS; i++, ch++) 1042: { 1043: if (!ch->sfx) 1044: continue; 1045: if (ch->autosound) 1046: { // autosounds are regenerated fresh each frame 1047: memset (ch, 0, sizeof(*ch)); 1048: continue; 1049: } 1050: S_Spatialize(ch); // respatialize channel 1051: if (!ch->leftvol && !ch->rightvol) 1052: { 1053: memset (ch, 0, sizeof(*ch)); 1054: continue; 1055: } 1056: } 1057: 1058: // add loopsounds 1059: S_AddLoopSounds (); 1060: 1061: // 1062: // debugging output 1063: // 1064: if (s_show->value) 1065: { 1066: total = 0; 1067: ch = channels; 1068: for (i=0 ; i<MAX_CHANNELS; i++, ch++) 1069: if (ch->sfx && (ch->leftvol || ch->rightvol) ) 1070: { 1071: Com_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name); 1072: total++; 1073: } 1074: 1075: Com_Printf ("----(%i)---- painted: %i\n", total, paintedtime); 1076: } 1077: 1078: // mix some sound 1079: S_Update_(); 1080: } 1081: 1082: void GetSoundtime(void) 1083: { 1084: int samplepos; 1085: static int buffers; 1086: static int oldsamplepos; 1087: int fullsamples; 1088: 1089: fullsamples = dma.samples / dma.channels; 1090: 1091: // it is possible to miscount buffers if it has wrapped twice between 1092: // calls to S_Update. Oh well. 1093: samplepos = SNDDMA_GetDMAPos(); 1094: 1095: if (samplepos < oldsamplepos) 1096: { 1097: buffers++; // buffer wrapped 1098: 1099: if (paintedtime > 0x40000000) 1100: { // time to chop things off to avoid 32 bit limits 1101: buffers = 0; 1102: paintedtime = fullsamples; 1103: S_StopAllSounds (); 1104: } 1105: } 1106: oldsamplepos = samplepos; 1107: 1108: soundtime = buffers*fullsamples + samplepos/dma.channels; 1109: } 1110: 1111: 1112: void S_Update_(void) 1113: { 1114: unsigned endtime; 1115: int samps; 1116: 1117: if (!sound_started) 1118: return; 1119: 1120: SNDDMA_BeginPainting (); 1121: 1122: if (!dma.buffer) 1123: return; 1124: 1125: // Updates DMA time 1126: GetSoundtime(); 1127: 1128: // check to make sure that we haven't overshot 1129: if (paintedtime < soundtime) 1130: { 1131: Com_DPrintf ("S_Update_ : overflow\n"); 1132: paintedtime = soundtime; 1133: } 1134: 1135: // mix ahead of current position 1136: endtime = soundtime + s_mixahead->value * dma.speed; 1137: //endtime = (soundtime + 4096) & ~4095; 1138: 1139: // mix to an even submission block size 1140: endtime = (endtime + dma.submission_chunk-1) 1141: & ~(dma.submission_chunk-1); 1142: samps = dma.samples >> (dma.channels-1); 1143: if (endtime - soundtime > samps) 1144: endtime = soundtime + samps; 1145: 1146: S_PaintChannels (endtime); 1147: 1148: SNDDMA_Submit (); 1149: } 1150: 1151: /* 1152: =============================================================================== 1153: 1154: console functions 1155: 1156: =============================================================================== 1157: */ 1158: 1159: void S_Play(void) 1160: { 1161: int i; 1162: char name[256]; 1163: sfx_t *sfx; 1164: 1165: i = 1; 1166: while (i<Cmd_Argc()) 1167: { 1168: if (!strrchr(Cmd_Argv(i), '.')) 1169: { 1170: strcpy(name, Cmd_Argv(i)); 1171: strcat(name, ".wav"); 1172: } 1173: else 1174: strcpy(name, Cmd_Argv(i)); 1175: sfx = S_RegisterSound(name); 1176: S_StartSound(NULL, cl.playernum+1, 0, sfx, 1.0, 1.0, 0); 1177: i++; 1178: } 1179: } 1180: 1181: void S_SoundList(void) 1182: { 1183: int i; 1184: sfx_t *sfx; 1185: sfxcache_t *sc; 1186: int size, total; 1187: 1188: total = 0; 1189: for (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++) 1190: { 1191: if (!sfx->registration_sequence) 1192: continue; 1193: sc = sfx->cache; 1194: if (sc) 1195: { 1196: size = sc->length*sc->width*(sc->stereo+1); 1197: total += size; 1198: if (sc->loopstart >= 0) 1199: Com_Printf ("L"); 1200: else 1201: Com_Printf (" "); 1202: Com_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name); 1203: } 1204: else 1205: { 1206: if (sfx->name[0] == '*') 1207: Com_Printf(" placeholder : %s\n", sfx->name); 1208: else 1209: Com_Printf(" not loaded : %s\n", sfx->name); 1210: } 1211: } 1212: Com_Printf ("Total resident: %i\n", total); 1213: } 1214:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.