snd_dma.c (24635B)
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 */ 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 /* 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 /* 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]; 594 char sexedFilename[MAX_QPATH]; 595 char maleFilename[MAX_QPATH]; 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 617 Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1); 618 sfx = S_FindName (sexedFilename, false); 619 620 if (!sfx) 621 { 622 // no, so see if it exists 623 FS_FOpenFile (&sexedFilename[1], &f); 624 if (f) 625 { 626 // yes, close the file and register it 627 FS_FCloseFile (f); 628 sfx = S_RegisterSound (sexedFilename); 629 } 630 else 631 { 632 // no, revert to the male sound in the pak0.pak 633 Com_sprintf (maleFilename, sizeof(maleFilename), "player/%s/%s", "male", base+1); 634 sfx = S_AliasName (sexedFilename, maleFilename); 635 } 636 } 637 638 return sfx; 639 } 640 641 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++; 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; 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++; 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; 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++; 963 s_rawsamples[dst].left = 964 LittleShort(((short *)data)[src]) << 8; 965 s_rawsamples[dst].right = 966 LittleShort(((short *)data)[src]) << 8; 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++; 978 s_rawsamples[dst].left = 979 ((char *)data)[src*2] << 16; 980 s_rawsamples[dst].right = 981 ((char *)data)[src*2+1] << 16; 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++; 993 s_rawsamples[dst].left = 994 (((byte *)data)[src]-128) << 16; 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