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