i_sound_win32.cpp (26837B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #include "Precompiled.h" 30 #include "globaldata.h" 31 32 // 33 // DESCRIPTION: 34 // System interface for sound. 35 // 36 //----------------------------------------------------------------------------- 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <stdarg.h> 41 #include <math.h> 42 #include <sys/types.h> 43 #include <fcntl.h> 44 // Timer stuff. Experimental. 45 #include <time.h> 46 #include <signal.h> 47 #include "z_zone.h" 48 #include "i_system.h" 49 #include "i_sound.h" 50 #include "m_argv.h" 51 #include "m_misc.h" 52 #include "w_wad.h" 53 #include "d_main.h" 54 #include "doomdef.h" 55 #include "../timidity/timidity.h" 56 #include "../timidity/controls.h" 57 58 #include "sound/snd_local.h" 59 60 #include <xaudio2.h> 61 #include <x3daudio.h> 62 63 #pragma warning ( disable : 4244 ) 64 65 #define MIDI_CHANNELS 2 66 #if 1 67 #define MIDI_RATE 22050 68 #define MIDI_SAMPLETYPE XAUDIOSAMPLETYPE_8BITPCM 69 #define MIDI_FORMAT AUDIO_U8 70 #define MIDI_FORMAT_BYTES 1 71 #else 72 #define MIDI_RATE 48000 73 #define MIDI_SAMPLETYPE XAUDIOSAMPLETYPE_16BITPCM 74 #define MIDI_FORMAT AUDIO_S16MSB 75 #define MIDI_FORMAT_BYTES 2 76 #endif 77 78 IXAudio2SourceVoice* pMusicSourceVoice; 79 MidiSong* doomMusic; 80 byte* musicBuffer; 81 int totalBufferSize; 82 83 HANDLE hMusicThread; 84 bool waitingForMusic; 85 bool musicReady; 86 87 88 typedef struct tagActiveSound_t { 89 IXAudio2SourceVoice* m_pSourceVoice; // Source voice 90 X3DAUDIO_DSP_SETTINGS m_DSPSettings; 91 X3DAUDIO_EMITTER m_Emitter; 92 X3DAUDIO_CONE m_Cone; 93 int id; 94 int valid; 95 int start; 96 int player; 97 bool localSound; 98 mobj_t *originator; 99 } activeSound_t; 100 101 102 // cheap little struct to hold a sound 103 typedef struct { 104 int vol; 105 int player; 106 int pitch; 107 int priority; 108 mobj_t *originator; 109 mobj_t *listener; 110 } soundEvent_t; 111 112 // array of all the possible sounds 113 // in split screen we only process the loudest sound of each type per frame 114 soundEvent_t soundEvents[128]; 115 extern int PLAYERCOUNT; 116 117 // Real volumes 118 const float GLOBAL_VOLUME_MULTIPLIER = 0.5f; 119 120 float x_SoundVolume = GLOBAL_VOLUME_MULTIPLIER; 121 float x_MusicVolume = GLOBAL_VOLUME_MULTIPLIER; 122 123 // The actual lengths of all sound effects. 124 static int lengths[NUMSFX]; 125 activeSound_t activeSounds[NUM_SOUNDBUFFERS] = {0}; 126 127 int S_initialized = 0; 128 bool Music_initialized = false; 129 130 // XAUDIO 131 float g_EmitterAzimuths [] = { 0.f }; 132 static int numOutputChannels = 0; 133 static bool soundHardwareInitialized = false; 134 135 136 X3DAUDIO_HANDLE X3DAudioInstance; 137 138 X3DAUDIO_LISTENER doom_Listener; 139 140 //float localSoundVolumeEntries[] = { 0.f, 0.f, 0.9f, 0.5f, 0.f, 0.f }; 141 float localSoundVolumeEntries[] = { 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f }; 142 143 144 void I_InitSoundChannel( int channel, int numOutputChannels_ ); 145 146 /* 147 ====================== 148 getsfx 149 ====================== 150 */ 151 // This function loads the sound data from the WAD lump, 152 // for single sound. 153 // 154 void* getsfx ( char* sfxname, int* len ) 155 { 156 unsigned char* sfx; 157 unsigned char* sfxmem; 158 int size; 159 char name[20]; 160 int sfxlump; 161 float scale = 1.0f; 162 163 // Get the sound data from the WAD, allocate lump 164 // in zone memory. 165 sprintf(name, "ds%s", sfxname); 166 167 // Scale down the plasma gun, it clips 168 if ( strcmp( sfxname, "plasma" ) == 0 ) { 169 scale = 0.75f; 170 } 171 if ( strcmp( sfxname, "itemup" ) == 0 ) { 172 scale = 1.333f; 173 } 174 175 // If sound requested is not found in current WAD, use pistol as default 176 if ( W_CheckNumForName(name) == -1 ) 177 sfxlump = W_GetNumForName("dspistol"); 178 else 179 sfxlump = W_GetNumForName(name); 180 181 // Sound lump headers are 8 bytes. 182 const int SOUND_LUMP_HEADER_SIZE_IN_BYTES = 8; 183 184 size = W_LumpLength( sfxlump ) - SOUND_LUMP_HEADER_SIZE_IN_BYTES; 185 186 sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_CACHE_SHARED ); 187 const unsigned char * sfxSampleStart = sfx + SOUND_LUMP_HEADER_SIZE_IN_BYTES; 188 189 // Allocate from zone memory. 190 //sfxmem = (float*)DoomLib::Z_Malloc( size*(sizeof(float)), PU_SOUND_SHARED, 0 ); 191 sfxmem = (unsigned char*)malloc( size * sizeof(unsigned char) ); 192 193 // Now copy, and convert to Xbox360 native float samples, do initial volume ramp, and scale 194 for ( int i=0; i<size; i++ ) { 195 sfxmem[i] = sfxSampleStart[i];// * scale; 196 } 197 198 // Remove the cached lump. 199 Z_Free( sfx ); 200 201 // Set length. 202 *len = size; 203 204 // Return allocated padded data. 205 return (void *) (sfxmem); 206 } 207 208 /* 209 ====================== 210 I_SetChannels 211 ====================== 212 */ 213 void I_SetChannels() { 214 // Original Doom set up lookup tables here 215 } 216 217 /* 218 ====================== 219 I_SetSfxVolume 220 ====================== 221 */ 222 void I_SetSfxVolume(int volume) { 223 x_SoundVolume = ((float)volume / 15.f) * GLOBAL_VOLUME_MULTIPLIER; 224 } 225 226 /* 227 ====================== 228 I_GetSfxLumpNum 229 ====================== 230 */ 231 // 232 // Retrieve the raw data lump index 233 // for a given SFX name. 234 // 235 int I_GetSfxLumpNum(sfxinfo_t* sfx) 236 { 237 char namebuf[9]; 238 sprintf(namebuf, "ds%s", sfx->name); 239 return W_GetNumForName(namebuf); 240 } 241 242 /* 243 ====================== 244 I_StartSound2 245 ====================== 246 */ 247 // Starting a sound means adding it 248 // to the current list of active sounds 249 // in the internal channels. 250 // As the SFX info struct contains 251 // e.g. a pointer to the raw data, 252 // it is ignored. 253 // As our sound handling does not handle 254 // priority, it is ignored. 255 // Pitching (that is, increased speed of playback) is set 256 // 257 int I_StartSound2 ( int id, int player, mobj_t *origin, mobj_t *listener_origin, int pitch, int priority ) { 258 if ( !soundHardwareInitialized ) { 259 return id; 260 } 261 262 int i; 263 XAUDIO2_VOICE_STATE state; 264 activeSound_t* sound = 0; 265 int oldest = 0, oldestnum = -1; 266 267 // these id's should not overlap 268 if ( id == sfx_sawup || id == sfx_sawidl || id == sfx_sawful || id == sfx_sawhit || id == sfx_stnmov ) { 269 // Loop all channels, check. 270 for (i=0 ; i < NUM_SOUNDBUFFERS ; i++) 271 { 272 sound = &activeSounds[i]; 273 274 if (sound->valid && ( sound->id == id && sound->player == player ) ) { 275 I_StopSound( sound->id, player ); 276 break; 277 } 278 } 279 } 280 281 // find a valid channel, or one that has finished playing 282 for (i = 0; i < NUM_SOUNDBUFFERS; ++i) { 283 sound = &activeSounds[i]; 284 285 if (!sound->valid) 286 break; 287 288 if (!oldest || oldest > sound->start) { 289 oldestnum = i; 290 oldest = sound->start; 291 } 292 293 sound->m_pSourceVoice->GetState( &state ); 294 if ( state.BuffersQueued == 0 ) { 295 break; 296 } 297 } 298 299 // none found, so use the oldest one 300 if (i == NUM_SOUNDBUFFERS) 301 { 302 i = oldestnum; 303 sound = &activeSounds[i]; 304 } 305 306 // stop the sound with a FlushPackets 307 sound->m_pSourceVoice->Stop(); 308 sound->m_pSourceVoice->FlushSourceBuffers(); 309 310 // Set up packet 311 XAUDIO2_BUFFER Packet = { 0 }; 312 Packet.Flags = XAUDIO2_END_OF_STREAM; 313 Packet.AudioBytes = lengths[id]; 314 Packet.pAudioData = (BYTE*)S_sfx[id].data; 315 Packet.PlayBegin = 0; 316 Packet.PlayLength = 0; 317 Packet.LoopBegin = XAUDIO2_NO_LOOP_REGION; 318 Packet.LoopLength = 0; 319 Packet.LoopCount = 0; 320 Packet.pContext = NULL; 321 322 323 // Set voice volumes 324 sound->m_pSourceVoice->SetVolume( x_SoundVolume ); 325 326 // Set voice pitch 327 sound->m_pSourceVoice->SetFrequencyRatio( 1 + ((float)pitch-128.f)/95.f ); 328 329 // Set initial spatialization 330 if ( origin && origin != listener_origin ) { 331 // Update Emitter Position 332 sound->m_Emitter.Position.x = (float)(origin->x >> FRACBITS); 333 sound->m_Emitter.Position.y = 0.f; 334 sound->m_Emitter.Position.z = (float)(origin->y >> FRACBITS); 335 336 // Calculate 3D positioned speaker volumes 337 DWORD dwCalculateFlags = X3DAUDIO_CALCULATE_MATRIX; 338 X3DAudioCalculate( X3DAudioInstance, &doom_Listener, &sound->m_Emitter, dwCalculateFlags, &sound->m_DSPSettings ); 339 340 // Pan the voice according to X3DAudio calculation 341 sound->m_pSourceVoice->SetOutputMatrix( NULL, 1, numOutputChannels, sound->m_DSPSettings.pMatrixCoefficients ); 342 343 sound->localSound = false; 344 } else { 345 // Local(or Global) sound, fixed speaker volumes 346 sound->m_pSourceVoice->SetOutputMatrix( NULL, 1, numOutputChannels, localSoundVolumeEntries ); 347 348 sound->localSound = true; 349 } 350 351 // Submit packet 352 HRESULT hr; 353 if( FAILED( hr = sound->m_pSourceVoice->SubmitSourceBuffer( &Packet ) ) ) { 354 int fail = 1; 355 } 356 357 // Play the source voice 358 if( FAILED( hr = sound->m_pSourceVoice->Start( 0 ) ) ) { 359 int fail = 1; 360 } 361 362 // set id, and start time 363 sound->id = id; 364 sound->start = ::g->gametic; 365 sound->valid = 1; 366 sound->player = player; 367 sound->originator = origin; 368 369 return id; 370 } 371 372 /* 373 ====================== 374 I_ProcessSoundEvents 375 ====================== 376 */ 377 void I_ProcessSoundEvents( void ) { 378 for( int i = 0; i < 128; i++ ) { 379 if( soundEvents[i].pitch ) { 380 I_StartSound2( i, soundEvents[i].player, soundEvents[i].originator, soundEvents[i].listener, soundEvents[i].pitch, soundEvents[i].priority ); 381 } 382 } 383 memset( soundEvents, 0, sizeof( soundEvents ) ); 384 } 385 386 /* 387 ====================== 388 I_StartSound 389 ====================== 390 */ 391 int I_StartSound ( int id, mobj_t *origin, mobj_t *listener_origin, int vol, int pitch, int priority ) { 392 // only allow player 0s sounds in intermission and finale screens 393 if( ::g->gamestate != GS_LEVEL && DoomLib::GetPlayer() != 0 ) { 394 return 0; 395 } 396 397 // if we're only one player or we're trying to play the chainsaw sound, do it normal 398 // otherwise only allow one sound of each type per frame 399 if( PLAYERCOUNT == 1 || id == sfx_sawup || id == sfx_sawidl || id == sfx_sawful || id == sfx_sawhit ) { 400 return I_StartSound2( id, ::g->consoleplayer, origin, listener_origin, pitch, priority ); 401 } 402 else { 403 if( soundEvents[ id ].vol < vol ) { 404 soundEvents[ id ].player = DoomLib::GetPlayer(); 405 soundEvents[ id ].pitch = pitch; 406 soundEvents[ id ].priority = priority; 407 soundEvents[ id ].vol = vol; 408 soundEvents[ id ].originator = origin; 409 soundEvents[ id ].listener = listener_origin; 410 } 411 return id; 412 } 413 } 414 415 /* 416 ====================== 417 I_StopSound 418 ====================== 419 */ 420 void I_StopSound (int handle, int player) 421 { 422 // You need the handle returned by StartSound. 423 // Would be looping all channels, 424 // tracking down the handle, 425 // an setting the channel to zero. 426 427 int i; 428 activeSound_t* sound = 0; 429 430 for (i = 0; i < NUM_SOUNDBUFFERS; ++i) 431 { 432 sound = &activeSounds[i]; 433 if (!sound->valid || sound->id != handle || (player >= 0 && sound->player != player) ) 434 continue; 435 break; 436 } 437 438 if (i == NUM_SOUNDBUFFERS) 439 return; 440 441 // stop the sound 442 if ( sound->m_pSourceVoice != NULL ) { 443 sound->m_pSourceVoice->Stop( 0 ); 444 } 445 446 sound->valid = 0; 447 sound->player = -1; 448 } 449 450 /* 451 ====================== 452 I_SoundIsPlaying 453 ====================== 454 */ 455 int I_SoundIsPlaying(int handle) { 456 if ( !soundHardwareInitialized ) { 457 return 0; 458 } 459 460 int i; 461 XAUDIO2_VOICE_STATE state; 462 activeSound_t* sound; 463 464 for (i = 0; i < NUM_SOUNDBUFFERS; ++i) 465 { 466 sound = &activeSounds[i]; 467 if (!sound->valid || sound->id != handle) 468 continue; 469 470 sound->m_pSourceVoice->GetState( &state ); 471 if ( state.BuffersQueued > 0 ) { 472 return 1; 473 } 474 } 475 476 return 0; 477 } 478 479 /* 480 ====================== 481 I_UpdateSound 482 ====================== 483 */ 484 // Update Listener Position and go through all the 485 // channels and update speaker volumes for 3D sound. 486 void I_UpdateSound( void ) { 487 if ( !soundHardwareInitialized ) { 488 return; 489 } 490 491 int i; 492 XAUDIO2_VOICE_STATE state; 493 activeSound_t* sound; 494 495 for ( i=0; i < NUM_SOUNDBUFFERS; i++ ) { 496 sound = &activeSounds[i]; 497 498 if ( !sound->valid || sound->localSound ) { 499 continue; 500 } 501 502 sound->m_pSourceVoice->GetState( &state ); 503 504 if ( state.BuffersQueued > 0 ) { 505 mobj_t *playerObj = ::g->players[ sound->player ].mo; 506 507 // Update Listener Orientation and Position 508 angle_t pAngle = playerObj->angle; 509 fixed_t fx, fz; 510 511 pAngle >>= ANGLETOFINESHIFT; 512 513 fx = finecosine[pAngle]; 514 fz = finesine[pAngle]; 515 516 doom_Listener.OrientFront.x = (float)(fx) / 65535.f; 517 doom_Listener.OrientFront.y = 0.f; 518 doom_Listener.OrientFront.z = (float)(fz) / 65535.f; 519 520 doom_Listener.Position.x = (float)(playerObj->x >> FRACBITS); 521 doom_Listener.Position.y = 0.f; 522 doom_Listener.Position.z = (float)(playerObj->y >> FRACBITS); 523 524 // Update Emitter Position 525 sound->m_Emitter.Position.x = (float)(sound->originator->x >> FRACBITS); 526 sound->m_Emitter.Position.y = 0.f; 527 sound->m_Emitter.Position.z = (float)(sound->originator->y >> FRACBITS); 528 529 // Calculate 3D positioned speaker volumes 530 DWORD dwCalculateFlags = X3DAUDIO_CALCULATE_MATRIX; 531 X3DAudioCalculate( X3DAudioInstance, &doom_Listener, &sound->m_Emitter, dwCalculateFlags, &sound->m_DSPSettings ); 532 533 // Pan the voice according to X3DAudio calculation 534 sound->m_pSourceVoice->SetOutputMatrix( NULL, 1, numOutputChannels, sound->m_DSPSettings.pMatrixCoefficients ); 535 } 536 } 537 } 538 539 /* 540 ====================== 541 I_UpdateSoundParams 542 ====================== 543 */ 544 void I_UpdateSoundParams( int handle, int vol, int sep, int pitch) { 545 } 546 547 /* 548 ====================== 549 I_ShutdownSound 550 ====================== 551 */ 552 void I_ShutdownSound(void) { 553 int done = 0; 554 int i; 555 556 if ( S_initialized ) { 557 // Stop all sounds, but don't destroy the XAudio2 buffers. 558 for ( i = 0; i < NUM_SOUNDBUFFERS; ++i ) { 559 activeSound_t * sound = &activeSounds[i]; 560 561 if ( sound == NULL ) { 562 continue; 563 } 564 565 I_StopSound( sound->id, 0 ); 566 567 if ( sound->m_pSourceVoice ) { 568 sound->m_pSourceVoice->FlushSourceBuffers(); 569 } 570 } 571 572 for (i=1 ; i<NUMSFX ; i++) { 573 if ( S_sfx[i].data && !(S_sfx[i].link) ) { 574 //Z_Free( S_sfx[i].data ); 575 free( S_sfx[i].data ); 576 } 577 } 578 } 579 580 I_StopSong( 0 ); 581 582 S_initialized = 0; 583 // Done. 584 return; 585 } 586 587 /* 588 ====================== 589 I_InitSoundHardware 590 591 Called from the tech4x initialization code. Sets up Doom classic's 592 sound channels. 593 ====================== 594 */ 595 void I_InitSoundHardware( int numOutputChannels_, int channelMask ) { 596 ::numOutputChannels = numOutputChannels_; 597 598 // Initialize the X3DAudio 599 // Speaker geometry configuration on the final mix, specifies assignment of channels 600 // to speaker positions, defined as per WAVEFORMATEXTENSIBLE.dwChannelMask 601 // SpeedOfSound - not used by doomclassic 602 X3DAudioInitialize( channelMask, 340.29f, X3DAudioInstance ); 603 604 for ( int i = 0; i < NUM_SOUNDBUFFERS; ++i ) { 605 // Initialize source voices 606 I_InitSoundChannel( i, numOutputChannels ); 607 } 608 609 I_InitMusic(); 610 611 soundHardwareInitialized = true; 612 } 613 614 615 /* 616 ====================== 617 I_ShutdownitSoundHardware 618 619 Called from the tech4x shutdown code. Tears down Doom classic's 620 sound channels. 621 ====================== 622 */ 623 void I_ShutdownSoundHardware() { 624 soundHardwareInitialized = false; 625 626 I_ShutdownMusic(); 627 628 for ( int i = 0; i < NUM_SOUNDBUFFERS; ++i ) { 629 activeSound_t * sound = &activeSounds[i]; 630 631 if ( sound == NULL ) { 632 continue; 633 } 634 635 if ( sound->m_pSourceVoice ) { 636 sound->m_pSourceVoice->Stop(); 637 sound->m_pSourceVoice->FlushSourceBuffers(); 638 sound->m_pSourceVoice->DestroyVoice(); 639 sound->m_pSourceVoice = NULL; 640 } 641 642 if ( sound->m_DSPSettings.pMatrixCoefficients ) { 643 delete [] sound->m_DSPSettings.pMatrixCoefficients; 644 sound->m_DSPSettings.pMatrixCoefficients = NULL; 645 } 646 } 647 } 648 649 /* 650 ====================== 651 I_InitSoundChannel 652 ====================== 653 */ 654 void I_InitSoundChannel( int channel, int numOutputChannels_ ) { 655 activeSound_t *soundchannel = &activeSounds[ channel ]; 656 657 X3DAUDIO_VECTOR ZeroVector = { 0.0f, 0.0f, 0.0f }; 658 659 // Set up emitter parameters 660 soundchannel->m_Emitter.OrientFront.x = 0.0f; 661 soundchannel->m_Emitter.OrientFront.y = 0.0f; 662 soundchannel->m_Emitter.OrientFront.z = 1.0f; 663 soundchannel->m_Emitter.OrientTop.x = 0.0f; 664 soundchannel->m_Emitter.OrientTop.y = 1.0f; 665 soundchannel->m_Emitter.OrientTop.z = 0.0f; 666 soundchannel->m_Emitter.Position = ZeroVector; 667 soundchannel->m_Emitter.Velocity = ZeroVector; 668 soundchannel->m_Emitter.pCone = &(soundchannel->m_Cone); 669 soundchannel->m_Emitter.pCone->InnerAngle = 0.0f; // Setting the inner cone angles to X3DAUDIO_2PI and 670 // outer cone other than 0 causes 671 // the emitter to act like a point emitter using the 672 // INNER cone settings only. 673 soundchannel->m_Emitter.pCone->OuterAngle = 0.0f; // Setting the outer cone angles to zero causes 674 // the emitter to act like a point emitter using the 675 // OUTER cone settings only. 676 soundchannel->m_Emitter.pCone->InnerVolume = 0.0f; 677 soundchannel->m_Emitter.pCone->OuterVolume = 1.0f; 678 soundchannel->m_Emitter.pCone->InnerLPF = 0.0f; 679 soundchannel->m_Emitter.pCone->OuterLPF = 1.0f; 680 soundchannel->m_Emitter.pCone->InnerReverb = 0.0f; 681 soundchannel->m_Emitter.pCone->OuterReverb = 1.0f; 682 683 soundchannel->m_Emitter.ChannelCount = 1; 684 soundchannel->m_Emitter.ChannelRadius = 0.0f; 685 soundchannel->m_Emitter.pVolumeCurve = NULL; 686 soundchannel->m_Emitter.pLFECurve = NULL; 687 soundchannel->m_Emitter.pLPFDirectCurve = NULL; 688 soundchannel->m_Emitter.pLPFReverbCurve = NULL; 689 soundchannel->m_Emitter.pReverbCurve = NULL; 690 soundchannel->m_Emitter.CurveDistanceScaler = 1200.0f; 691 soundchannel->m_Emitter.DopplerScaler = 1.0f; 692 soundchannel->m_Emitter.pChannelAzimuths = g_EmitterAzimuths; 693 694 soundchannel->m_DSPSettings.SrcChannelCount = 1; 695 soundchannel->m_DSPSettings.DstChannelCount = numOutputChannels_; 696 soundchannel->m_DSPSettings.pMatrixCoefficients = new FLOAT[ numOutputChannels_ ]; 697 698 // Create Source voice 699 WAVEFORMATEX voiceFormat = {0}; 700 voiceFormat.wFormatTag = WAVE_FORMAT_PCM; 701 voiceFormat.nChannels = 1; 702 voiceFormat.nSamplesPerSec = 11025; 703 voiceFormat.nAvgBytesPerSec = 11025; 704 voiceFormat.nBlockAlign = 1; 705 voiceFormat.wBitsPerSample = 8; 706 voiceFormat.cbSize = 0; 707 708 soundSystemLocal.hardware.GetIXAudio2()->CreateSourceVoice( &soundchannel->m_pSourceVoice, (WAVEFORMATEX *)&voiceFormat ); 709 } 710 711 /* 712 ====================== 713 I_InitSound 714 ====================== 715 */ 716 void I_InitSound() { 717 718 if (S_initialized == 0) { 719 int i; 720 721 X3DAUDIO_VECTOR ZeroVector = { 0.0f, 0.0f, 0.0f }; 722 723 // Set up listener parameters 724 doom_Listener.OrientFront.x = 0.0f; 725 doom_Listener.OrientFront.y = 0.0f; 726 doom_Listener.OrientFront.z = 1.0f; 727 doom_Listener.OrientTop.x = 0.0f; 728 doom_Listener.OrientTop.y = 1.0f; 729 doom_Listener.OrientTop.z = 0.0f; 730 doom_Listener.Position = ZeroVector; 731 doom_Listener.Velocity = ZeroVector; 732 733 for (i=1 ; i<NUMSFX ; i++) 734 { 735 // Alias? Example is the chaingun sound linked to pistol. 736 if (!S_sfx[i].link) 737 { 738 // Load data from WAD file. 739 S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] ); 740 } 741 else 742 { 743 // Previously loaded already? 744 S_sfx[i].data = S_sfx[i].link->data; 745 lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)]; 746 } 747 } 748 749 S_initialized = 1; 750 } 751 } 752 753 /* 754 ====================== 755 I_SubmitSound 756 ====================== 757 */ 758 void I_SubmitSound(void) 759 { 760 // Only do this for player 0, it will still handle positioning 761 // for other players, but it can't be outside the game 762 // frame like the soundEvents are. 763 if ( DoomLib::GetPlayer() == 0 ) { 764 // Do 3D positioning of sounds 765 I_UpdateSound(); 766 767 // Check for XMP notifications 768 I_UpdateMusic(); 769 } 770 } 771 772 773 // ========================================================= 774 // ========================================================= 775 // Background Music 776 // ========================================================= 777 // ========================================================= 778 779 /* 780 ====================== 781 I_SetMusicVolume 782 ====================== 783 */ 784 void I_SetMusicVolume(int volume) 785 { 786 x_MusicVolume = (float)volume / 15.f; 787 } 788 789 /* 790 ====================== 791 I_InitMusic 792 ====================== 793 */ 794 void I_InitMusic(void) 795 { 796 if ( !Music_initialized ) { 797 // Initialize Timidity 798 Timidity_Init( MIDI_RATE, MIDI_FORMAT, MIDI_CHANNELS, MIDI_RATE, "classicmusic/gravis.cfg" ); 799 800 hMusicThread = NULL; 801 musicBuffer = NULL; 802 totalBufferSize = 0; 803 waitingForMusic = false; 804 musicReady = false; 805 806 // Create Source voice 807 WAVEFORMATEX voiceFormat = {0}; 808 voiceFormat.wFormatTag = WAVE_FORMAT_PCM; 809 voiceFormat.nChannels = 2; 810 voiceFormat.nSamplesPerSec = MIDI_RATE; 811 voiceFormat.nAvgBytesPerSec = MIDI_RATE * MIDI_FORMAT_BYTES * 2; 812 voiceFormat.nBlockAlign = MIDI_FORMAT_BYTES * 2; 813 voiceFormat.wBitsPerSample = MIDI_FORMAT_BYTES * 8; 814 voiceFormat.cbSize = 0; 815 816 soundSystemLocal.hardware.GetIXAudio2()->CreateSourceVoice( &pMusicSourceVoice, (WAVEFORMATEX *)&voiceFormat, XAUDIO2_VOICE_MUSIC ); 817 818 Music_initialized = true; 819 } 820 } 821 822 /* 823 ====================== 824 I_ShutdownMusic 825 ====================== 826 */ 827 void I_ShutdownMusic(void) 828 { 829 I_StopSong( 0 ); 830 831 if ( Music_initialized ) { 832 if ( pMusicSourceVoice ) { 833 pMusicSourceVoice->Stop(); 834 pMusicSourceVoice->FlushSourceBuffers(); 835 pMusicSourceVoice->DestroyVoice(); 836 pMusicSourceVoice = NULL; 837 } 838 839 if ( hMusicThread ) { 840 DWORD rc; 841 842 do { 843 GetExitCodeThread( hMusicThread, &rc ); 844 if ( rc == STILL_ACTIVE ) { 845 Sleep( 1 ); 846 } 847 } while( rc == STILL_ACTIVE ); 848 849 CloseHandle( hMusicThread ); 850 } 851 if ( musicBuffer ) { 852 free( musicBuffer ); 853 } 854 855 Timidity_Shutdown(); 856 } 857 858 pMusicSourceVoice = NULL; 859 hMusicThread = NULL; 860 musicBuffer = NULL; 861 862 totalBufferSize = 0; 863 waitingForMusic = false; 864 musicReady = false; 865 866 Music_initialized = false; 867 } 868 869 int Mus2Midi(unsigned char* bytes, unsigned char* out, int* len); 870 871 namespace { 872 const int MaxMidiConversionSize = 1024 * 1024; 873 unsigned char midiConversionBuffer[MaxMidiConversionSize]; 874 } 875 876 /* 877 ====================== 878 I_LoadSong 879 ====================== 880 */ 881 DWORD WINAPI I_LoadSong( LPVOID songname ) { 882 idStr lumpName = "d_"; 883 lumpName += static_cast< const char * >( songname ); 884 885 unsigned char * musFile = static_cast< unsigned char * >( W_CacheLumpName( lumpName.c_str(), PU_STATIC_SHARED ) ); 886 887 int length = 0; 888 Mus2Midi( musFile, midiConversionBuffer, &length ); 889 890 doomMusic = Timidity_LoadSongMem( midiConversionBuffer, length ); 891 892 if ( doomMusic ) { 893 musicBuffer = (byte *)malloc( MIDI_CHANNELS * MIDI_FORMAT_BYTES * doomMusic->samples ); 894 totalBufferSize = doomMusic->samples * MIDI_CHANNELS * MIDI_FORMAT_BYTES; 895 896 Timidity_Start( doomMusic ); 897 898 int rc = RC_NO_RETURN_VALUE; 899 int num_bytes = 0; 900 int offset = 0; 901 902 do { 903 rc = Timidity_PlaySome( musicBuffer + offset, MIDI_RATE, &num_bytes ); 904 offset += num_bytes; 905 } while ( rc != RC_TUNE_END ); 906 907 Timidity_Stop(); 908 Timidity_FreeSong( doomMusic ); 909 } 910 911 musicReady = true; 912 913 return ERROR_SUCCESS; 914 } 915 916 /* 917 ====================== 918 I_PlaySong 919 ====================== 920 */ 921 void I_PlaySong( const char *songname, int looping) 922 { 923 if ( !Music_initialized ) { 924 return; 925 } 926 927 if ( pMusicSourceVoice != NULL ) { 928 // Stop the voice and flush packets before freeing the musicBuffer 929 pMusicSourceVoice->Stop(); 930 pMusicSourceVoice->FlushSourceBuffers(); 931 } 932 933 // Make sure voice is stopped before we free the buffer 934 bool isStopped = false; 935 int d = 0; 936 while ( !isStopped ) { 937 XAUDIO2_VOICE_STATE test; 938 939 if ( pMusicSourceVoice != NULL ) { 940 pMusicSourceVoice->GetState( &test ); 941 } 942 943 if ( test.pCurrentBufferContext == NULL && test.BuffersQueued == 0 ) { 944 isStopped = true; 945 } 946 //I_Printf( "waiting to stop (%d)\n", d++ ); 947 } 948 949 // Clear old state 950 if ( musicBuffer != NULL ) { 951 free( musicBuffer ); 952 musicBuffer = NULL; 953 } 954 955 musicReady = false; 956 I_LoadSong( (LPVOID)songname ); 957 waitingForMusic = true; 958 959 if ( DoomLib::GetPlayer() >= 0 ) { 960 ::g->mus_looping = looping; 961 } 962 } 963 964 /* 965 ====================== 966 I_UpdateMusic 967 ====================== 968 */ 969 void I_UpdateMusic( void ) { 970 if ( !Music_initialized ) { 971 return; 972 } 973 974 if ( waitingForMusic ) { 975 976 if ( musicReady && pMusicSourceVoice != NULL ) { 977 978 if ( musicBuffer ) { 979 // Set up packet 980 XAUDIO2_BUFFER Packet = { 0 }; 981 Packet.Flags = XAUDIO2_END_OF_STREAM; 982 Packet.AudioBytes = totalBufferSize; 983 Packet.pAudioData = (BYTE*)musicBuffer; 984 Packet.PlayBegin = 0; 985 Packet.PlayLength = 0; 986 Packet.LoopBegin = 0; 987 Packet.LoopLength = 0; 988 Packet.LoopCount = ::g->mus_looping ? XAUDIO2_LOOP_INFINITE : 0; 989 Packet.pContext = NULL; 990 991 // Submit packet 992 HRESULT hr; 993 if( FAILED( hr = pMusicSourceVoice->SubmitSourceBuffer( &Packet ) ) ) { 994 int fail = 1; 995 } 996 997 // Play the source voice 998 if( FAILED( hr = pMusicSourceVoice->Start( 0 ) ) ) { 999 int fail = 1; 1000 } 1001 } 1002 1003 waitingForMusic = false; 1004 } 1005 } 1006 1007 if ( pMusicSourceVoice != NULL ) { 1008 // Set the volume 1009 pMusicSourceVoice->SetVolume( x_MusicVolume * GLOBAL_VOLUME_MULTIPLIER ); 1010 } 1011 } 1012 1013 /* 1014 ====================== 1015 I_PauseSong 1016 ====================== 1017 */ 1018 void I_PauseSong (int handle) 1019 { 1020 if ( !Music_initialized ) { 1021 return; 1022 } 1023 1024 if ( pMusicSourceVoice != NULL ) { 1025 // Stop the music source voice 1026 pMusicSourceVoice->Stop( 0 ); 1027 } 1028 } 1029 1030 /* 1031 ====================== 1032 I_ResumeSong 1033 ====================== 1034 */ 1035 void I_ResumeSong (int handle) 1036 { 1037 if ( !Music_initialized ) { 1038 return; 1039 } 1040 1041 // Stop the music source voice 1042 if ( pMusicSourceVoice != NULL ) { 1043 pMusicSourceVoice->Start( 0 ); 1044 } 1045 } 1046 1047 /* 1048 ====================== 1049 I_StopSong 1050 ====================== 1051 */ 1052 void I_StopSong(int handle) 1053 { 1054 if ( !Music_initialized ) { 1055 return; 1056 } 1057 1058 // Stop the music source voice 1059 if ( pMusicSourceVoice != NULL ) { 1060 pMusicSourceVoice->Stop( 0 ); 1061 } 1062 } 1063 1064 /* 1065 ====================== 1066 I_UnRegisterSong 1067 ====================== 1068 */ 1069 void I_UnRegisterSong(int handle) 1070 { 1071 // does nothing 1072 } 1073 1074 /* 1075 ====================== 1076 I_RegisterSong 1077 ====================== 1078 */ 1079 int I_RegisterSong(void* data, int length) 1080 { 1081 // does nothing 1082 return 0; 1083 } 1084