the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 1716 lines 49 kB view raw
1#include "stdafx.h" 2 3#include "SoundEngine.h" 4#include "..\Consoles_App.h" 5#include "..\..\MultiplayerLocalPlayer.h" 6#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" 7#include "..\..\Minecraft.World\leveldata.h" 8#include "..\..\Minecraft.World\mth.h" 9#include "..\..\TexturePackRepository.h" 10#include "..\..\DLCTexturePack.h" 11#include "Common\DLC\DLCAudioFile.h" 12 13#ifdef __PSVITA__ 14#include <audioout.h> 15#endif 16 17#ifdef _WINDOWS64 18#include "..\..\Minecraft.Client\Windows64\Windows64_App.h" 19#include "..\..\Minecraft.Client\Windows64\Miles\include\imssapi.h" 20#endif 21 22#ifdef __ORBIS__ 23#include <audioout.h> 24//#define __DISABLE_MILES__ // MGH disabled for now as it crashes if we call sceNpMatching2Initialize 25#endif 26 27// take out Orbis until they are done 28#if defined _XBOX 29 30SoundEngine::SoundEngine() {} 31void SoundEngine::init(Options *pOptions) 32{ 33} 34 35void SoundEngine::tick(shared_ptr<Mob> *players, float a) 36{ 37} 38void SoundEngine::destroy() {} 39void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) 40{ 41 app.DebugPrintf("PlaySound - %d\n",iSound); 42} 43void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay) {} 44void SoundEngine::playUI(int iSound, float volume, float pitch) {} 45 46void SoundEngine::updateMusicVolume(float fVal) {} 47void SoundEngine::updateSoundEffectVolume(float fVal) {} 48 49void SoundEngine::add(const wstring& name, File *file) {} 50void SoundEngine::addMusic(const wstring& name, File *file) {} 51void SoundEngine::addStreaming(const wstring& name, File *file) {} 52char *SoundEngine::ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) { return NULL; } 53bool SoundEngine::isStreamingWavebankReady() { return true; } 54void SoundEngine::playMusicTick() {}; 55 56#else 57 58#ifdef _WINDOWS64 59char SoundEngine::m_szSoundPath[]={"Windows64Media\\Sound\\"}; 60char SoundEngine::m_szMusicPath[]={"music\\"}; 61char SoundEngine::m_szRedistName[]={"redist64"}; 62#elif defined _DURANGO 63char SoundEngine::m_szSoundPath[]={"Sound\\"}; 64char SoundEngine::m_szMusicPath[]={"music\\"}; 65char SoundEngine::m_szRedistName[]={"redist64"}; 66#elif defined __ORBIS__ 67 68#ifdef _CONTENT_PACKAGE 69char SoundEngine::m_szSoundPath[]={"Sound/"}; 70#elif defined _ART_BUILD 71char SoundEngine::m_szSoundPath[]={"Sound/"}; 72#else 73// just use the host Durango folder for the sound. In the content package, we'll have moved this in the .gp4 file 74char SoundEngine::m_szSoundPath[]={"Durango/Sound/"}; 75#endif 76char SoundEngine::m_szMusicPath[]={"music/"}; 77char SoundEngine::m_szRedistName[]={"redist64"}; 78#elif defined __PSVITA__ 79char SoundEngine::m_szSoundPath[]={"PSVita/Sound/"}; 80char SoundEngine::m_szMusicPath[]={"music/"}; 81char SoundEngine::m_szRedistName[]={"redist"}; 82#elif defined __PS3__ 83//extern const char* getPS3HomePath(); 84char SoundEngine::m_szSoundPath[]={"PS3/Sound/"}; 85char SoundEngine::m_szMusicPath[]={"music/"}; 86char SoundEngine::m_szRedistName[]={"redist"}; 87 88#define USE_SPURS 89 90#ifdef USE_SPURS 91#include <cell/spurs.h> 92#else 93#include <sys/spu_image.h> 94#endif 95 96#endif 97 98F32 AILCALLBACK custom_falloff_function (HSAMPLE S, 99 F32 distance, 100 F32 rolloff_factor, 101 F32 min_dist, 102 F32 max_dist); 103 104char *SoundEngine::m_szStreamFileA[eStream_Max]= 105{ 106 "calm1", 107 "calm2", 108 "calm3", 109 "hal1", 110 "hal2", 111 "hal3", 112 "hal4", 113 "nuance1", 114 "nuance2", 115#ifndef _XBOX 116 // add the new music tracks 117 "creative1", 118 "creative2", 119 "creative3", 120 "creative4", 121 "creative5", 122 "creative6", 123 "menu1", 124 "menu2", 125 "menu3", 126 "menu4", 127#endif 128 "piano1", 129 "piano2", 130 "piano3", 131 132 // Nether 133 "nether1", 134 "nether2", 135 "nether3", 136 "nether4", 137 // The End 138 "the_end_dragon_alive", 139 "the_end_end", 140 // CDs 141 "11", 142 "13", 143 "blocks", 144 "cat", 145 "chirp", 146 "far", 147 "mall", 148 "mellohi", 149 "stal", 150 "strad", 151 "ward", 152 "where_are_we_now" 153}; 154 155///////////////////////////////////////////// 156// 157// ErrorCallback 158// 159///////////////////////////////////////////// 160void AILCALL ErrorCallback(S64 i_Id, char const* i_Details) 161{ 162 char *pchLastError=AIL_last_error(); 163 164 if(pchLastError[0]!=0) 165 { 166 app.DebugPrintf("\rErrorCallback Error Category: %s\n", pchLastError); 167 } 168 169 if (i_Details) 170 { 171 app.DebugPrintf("ErrorCallback - Details: %s\n", i_Details); 172 } 173} 174 175#ifdef __PSVITA__ 176// AP - this is the callback when the driver is about to mix. At this point the mutex is locked by Miles so we can now call all Miles functions without 177// the possibility of incurring a stall. 178static bool SoundEngine_Change = false; // has tick been called? 179static CRITICAL_SECTION SoundEngine_MixerMutex; 180 181void AILCALL MilesMixerCB(HDIGDRIVER dig) 182{ 183 // has the tick function been called since the last callback 184 if( SoundEngine_Change ) 185 { 186 SoundEngine_Change = false; 187 188 EnterCriticalSection(&SoundEngine_MixerMutex); 189 190 Minecraft *pMinecraft = Minecraft::GetInstance(); 191 pMinecraft->soundEngine->updateMiles(); 192 pMinecraft->soundEngine->playMusicUpdate(); 193 194 LeaveCriticalSection(&SoundEngine_MixerMutex); 195 } 196} 197#endif 198 199///////////////////////////////////////////// 200// 201// init 202// 203///////////////////////////////////////////// 204void SoundEngine::init(Options *pOptions) 205{ 206 app.DebugPrintf("---SoundEngine::init\n"); 207#ifdef __DISABLE_MILES__ 208 return; 209#endif 210#ifdef __ORBIS__ 211 C4JThread::PushAffinityAllCores(); 212#endif 213#if defined _DURANGO || defined __ORBIS__ || defined __PS3__ || defined __PSVITA__ 214 Register_RIB(BinkADec); 215#endif 216 217 char *redistpath; 218 219#if (defined _WINDOWS64 || defined __PSVITA__)// || defined _DURANGO || defined __ORBIS__ ) 220 redistpath=AIL_set_redist_directory(m_szRedistName); 221#endif 222 223 app.DebugPrintf("---SoundEngine::init - AIL_startup\n"); 224 S32 ret = AIL_startup(); 225 226 int iNumberOfChannels=initAudioHardware(8); 227 228 // Create a driver to render our audio - 44khz, 16 bit, 229#ifdef __PS3__ 230 // On the Sony PS3, the driver is always opened in 48 kHz, 32-bit floating point. The only meaningful configurations are MSS_MC_STEREO, MSS_MC_51_DISCRETE, and MSS_MC_71_DISCRETE. 231 m_hDriver = AIL_open_digital_driver( 48000, 16, iNumberOfChannels, AIL_OPEN_DIGITAL_USE_SPU0 ); 232#elif defined __PSVITA__ 233 234 // maximum of 16 samples 235 AIL_set_preference(DIG_MIXER_CHANNELS, 16); 236 237 m_hDriver = AIL_open_digital_driver( 48000, 16, MSS_MC_STEREO, 0 ); 238 239 // AP - For some reason the submit thread defaults to a priority of zero (invalid). Make sure it has the highest priority to avoid audio breakup. 240 SceUID threadID; 241 AIL_platform_property( m_hDriver, PSP2_SUBMIT_THREAD, &threadID, 0, 0); 242 S32 g_DefaultCPU = sceKernelGetThreadCpuAffinityMask(threadID); 243 S32 Old = sceKernelChangeThreadPriority(threadID, 64); 244 245 // AP - register a callback when the mixer starts 246 AILMIXERCB temp = AIL_register_mix_callback(m_hDriver, MilesMixerCB); 247 248 InitializeCriticalSection(&SoundEngine_MixerMutex); 249 250#elif defined(__ORBIS__) 251 m_hDriver = AIL_open_digital_driver( 48000, 16, 2, 0 ); 252 app.DebugPrintf("---SoundEngine::init - AIL_open_digital_driver\n"); 253 254#else 255 m_hDriver = AIL_open_digital_driver(44100, 16, MSS_MC_USE_SYSTEM_CONFIG, 0); 256#endif 257 if (m_hDriver == 0) 258 { 259 app.DebugPrintf("Couldn't open digital sound driver. (%s)\n", AIL_last_error()); 260 AIL_shutdown(); 261#ifdef __ORBIS__ 262 C4JThread::PopAffinity(); 263#endif 264 return; 265 } 266 app.DebugPrintf("---SoundEngine::init - driver opened\n"); 267 268#ifdef __PSVITA__ 269 270 // set high falloff power for maximum spatial effect in software mode 271 AIL_set_speaker_configuration( m_hDriver, 0, 0, 4.0F ); 272 273#endif 274 275 AIL_set_event_error_callback(ErrorCallback); 276 277 AIL_set_3D_rolloff_factor(m_hDriver,1.0); 278 279 // Create an event system tied to that driver - let Miles choose memory defaults. 280 //if (AIL_startup_event_system(m_hDriver, 0, 0, 0) == 0) 281 // 4J-PB - Durango complains that the default memory (64k)isn't enough 282 // Error: MilesEvent: Out of event system memory (pool passed to event system startup exhausted). 283 // AP - increased command buffer from the default 5K to 20K for Vita 284 285 if (AIL_startup_event_system(m_hDriver, 1024*20, 0, 1024*128) == 0) 286 { 287 app.DebugPrintf("Couldn't init event system (%s).\n", AIL_last_error()); 288 AIL_close_digital_driver(m_hDriver); 289 AIL_shutdown(); 290#ifdef __ORBIS__ 291 C4JThread::PopAffinity(); 292#endif 293 app.DebugPrintf("---SoundEngine::init - AIL_startup_event_system failed\n"); 294 return; 295 } 296 char szBankName[255]; 297#if defined __PS3__ 298 if(app.GetBootedFromDiscPatch()) 299 { 300 char szTempSoundFilename[255]; 301 sprintf(szTempSoundFilename,"%s%s",m_szSoundPath, "Minecraft.msscmp" ); 302 303 app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) looking for %s\n",szTempSoundFilename); 304 sprintf(szBankName,"%s/%s",app.GetBDUsrDirPath(szTempSoundFilename), m_szSoundPath ); 305 app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) music path - %s\n",szBankName); 306 } 307 else 308 { 309 sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); 310 } 311 312#elif defined __PSVITA__ 313 sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); 314#elif defined __ORBIS__ 315 sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); 316#else 317 strcpy((char *)szBankName,m_szSoundPath); 318#endif 319 320 strcat((char *)szBankName,"Minecraft.msscmp"); 321 322 m_hBank=AIL_add_soundbank(szBankName, 0); 323 324 if(m_hBank == NULL) 325 { 326 char *Error=AIL_last_error(); 327 app.DebugPrintf("Couldn't open soundbank: %s (%s)\n", szBankName, Error); 328 AIL_close_digital_driver(m_hDriver); 329 AIL_shutdown(); 330#ifdef __ORBIS__ 331 C4JThread::PopAffinity(); 332#endif 333 return; 334 } 335 336 //#ifdef _DEBUG 337 HMSSENUM token = MSS_FIRST; 338 char const* Events[1] = {0}; 339 S32 EventCount = 0; 340 while (AIL_enumerate_events(m_hBank, &token, 0, &Events[0])) 341 { 342 app.DebugPrintf(4,"%d - %s\n", EventCount, Events[0]); 343 344 EventCount++; 345 } 346 //#endif 347 348 U64 u64Result; 349 u64Result=AIL_enqueue_event_by_name("Minecraft/CacheSounds"); 350 351 m_MasterMusicVolume=1.0f; 352 m_MasterEffectsVolume=1.0f; 353 354 //AIL_set_variable_float(0,"UserEffectVol",1); 355 356 m_bSystemMusicPlaying = false; 357 358 m_openStreamThread = NULL; 359 360#ifdef __ORBIS__ 361 C4JThread::PopAffinity(); 362#endif 363 364#ifdef __PSVITA__ 365 // AP - By default the mixer won't start up and nothing will process. Kick off a blank sample to force the mixer to start up. 366 HSAMPLE Sample = AIL_allocate_sample_handle(m_hDriver); 367 AIL_init_sample(Sample, DIG_F_STEREO_16); 368 static U64 silence = 0; 369 AIL_set_sample_address(Sample, &silence, sizeof(U64)); 370 AIL_start_sample(Sample); 371 372 // wait for 1 mix... 373 AIL_release_sample_handle(Sample); 374#endif 375} 376 377#ifdef __ORBIS__ 378// void SoundEngine::SetHandle(int32_t hAudio) 379// { 380// //m_hAudio=hAudio; 381// } 382#endif 383 384void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1) 385{ 386 m_iStream_Overworld_Min=iOverworldMin; 387 m_iStream_Overworld_Max=iOverWorldMax; 388 m_iStream_Nether_Min=iNetherMin; 389 m_iStream_Nether_Max=iNetherMax; 390 m_iStream_End_Min=iEndMin; 391 m_iStream_End_Max=iEndMax; 392 m_iStream_CD_1=iCD1; 393 394 // array to monitor recently played tracks 395 if(m_bHeardTrackA) 396 { 397 delete [] m_bHeardTrackA; 398 } 399 m_bHeardTrackA = new bool[iEndMax+1]; 400 memset(m_bHeardTrackA,0,sizeof(bool)*iEndMax+1); 401} 402 403// AP - moved to a separate function so it can be called from the mixer callback on Vita 404void SoundEngine::updateMiles() 405{ 406#ifdef __PSVITA__ 407 //CD - We must check for Background Music [BGM] at any point 408 //If it's playing disable our audio, otherwise enable 409 int NoBGMPlaying = sceAudioOutGetAdopt(SCE_AUDIO_OUT_PORT_TYPE_BGM); 410 updateSystemMusicPlaying( !NoBGMPlaying ); 411#elif defined __ORBIS__ 412 // is the system playing background music? 413 SceAudioOutPortState outPortState; 414 sceAudioOutGetPortState(m_hBGMAudio,&outPortState); 415 updateSystemMusicPlaying( outPortState.output==SCE_AUDIO_OUT_STATE_OUTPUT_UNKNOWN ); 416#endif 417 418 if( m_validListenerCount == 1 ) 419 { 420 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 421 { 422 // set the listener as the first player we find 423 if( m_ListenerA[i].bValid ) 424 { 425 AIL_set_listener_3D_position(m_hDriver,m_ListenerA[i].vPosition.x,m_ListenerA[i].vPosition.y,-m_ListenerA[i].vPosition.z); // Flipped sign of z as Miles is expecting left handed coord system 426 AIL_set_listener_3D_orientation(m_hDriver,-m_ListenerA[i].vOrientFront.x,m_ListenerA[i].vOrientFront.y,m_ListenerA[i].vOrientFront.z,0,1,0); // Flipped sign of z as Miles is expecting left handed coord system 427 break; 428 } 429 } 430 } 431 else 432 { 433 // 4J-PB - special case for splitscreen 434 // the shortest distance between any listener and a sound will be used to play a sound a set distance away down the z axis. 435 // The listener position will be set to 0,0,0, and the orientation will be facing down the z axis 436 437 AIL_set_listener_3D_position(m_hDriver,0,0,0); 438 AIL_set_listener_3D_orientation(m_hDriver,0,0,1,0,1,0); 439 } 440 441 AIL_begin_event_queue_processing(); 442 443 // Iterate over the sounds 444 S32 StartedCount = 0, CompletedCount = 0, TotalCount = 0; 445 HMSSENUM token = MSS_FIRST; 446 MILESEVENTSOUNDINFO SoundInfo; 447 int Playing = 0; 448 while (AIL_enumerate_sound_instances(0, &token, 0, 0, 0, &SoundInfo)) 449 { 450 AUDIO_INFO* game_data= (AUDIO_INFO*)( SoundInfo.UserBuffer ); 451 452 if( SoundInfo.Status == MILESEVENT_SOUND_STATUS_PLAYING ) 453 { 454 Playing += 1; 455 } 456 457 if ( SoundInfo.Status != MILESEVENT_SOUND_STATUS_COMPLETE ) 458 { 459 // apply the master volume 460 // watch for the 'special' volume levels 461 bool isThunder = false; 462 if( game_data->volume == 10000.0f ) 463 { 464 isThunder = true; 465 } 466 if(game_data->volume>1) 467 { 468 game_data->volume=1; 469 } 470 AIL_set_sample_volume_levels( SoundInfo.Sample, game_data->volume*m_MasterEffectsVolume, game_data->volume*m_MasterEffectsVolume); 471 472 float distanceScaler = 16.0f; 473 switch(SoundInfo.Status) 474 { 475 case MILESEVENT_SOUND_STATUS_PENDING: 476 // 4J-PB - causes the falloff to be calculated on the PPU instead of the SPU, and seems to resolve our distorted sound issue 477 AIL_register_falloff_function_callback(SoundInfo.Sample,&custom_falloff_function); 478 479 if(game_data->bIs3D) 480 { 481 AIL_set_sample_is_3D( SoundInfo.Sample, 1 ); 482 483 int iSound = game_data->iSound - eSFX_MAX; 484 switch(iSound) 485 { 486 // Is this the Dragon? 487 case eSoundType_MOB_ENDERDRAGON_GROWL: 488 case eSoundType_MOB_ENDERDRAGON_MOVE: 489 case eSoundType_MOB_ENDERDRAGON_END: 490 case eSoundType_MOB_ENDERDRAGON_HIT: 491 distanceScaler=100.0f; 492 break; 493 case eSoundType_FIREWORKS_BLAST: 494 case eSoundType_FIREWORKS_BLAST_FAR: 495 case eSoundType_FIREWORKS_LARGE_BLAST: 496 case eSoundType_FIREWORKS_LARGE_BLAST_FAR: 497 distanceScaler=100.0f; 498 break; 499 case eSoundType_MOB_GHAST_MOAN: 500 case eSoundType_MOB_GHAST_SCREAM: 501 case eSoundType_MOB_GHAST_DEATH: 502 case eSoundType_MOB_GHAST_CHARGE: 503 case eSoundType_MOB_GHAST_FIREBALL: 504 distanceScaler=30.0f; 505 break; 506 } 507 508 // Set a special distance scaler for thunder, which we respond to by having no attenutation 509 if( isThunder ) 510 { 511 distanceScaler = 10000.0f; 512 } 513 } 514 else 515 { 516 AIL_set_sample_is_3D( SoundInfo.Sample, 0 ); 517 } 518 519 AIL_set_sample_3D_distances(SoundInfo.Sample,distanceScaler,1,0); 520 // set the pitch 521 if(!game_data->bUseSoundsPitchVal) 522 { 523 AIL_set_sample_playback_rate_factor(SoundInfo.Sample,game_data->pitch); 524 } 525 526 if(game_data->bIs3D) 527 { 528 if(m_validListenerCount>1) 529 { 530 float fClosest=10000.0f; 531 int iClosestListener=0; 532 float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; 533 // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision 534 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 535 { 536 if( m_ListenerA[i].bValid ) 537 { 538 float x,y,z; 539 540 x=fabs(m_ListenerA[i].vPosition.x-game_data->x); 541 y=fabs(m_ListenerA[i].vPosition.y-game_data->y); 542 z=fabs(m_ListenerA[i].vPosition.z-game_data->z); 543 fDist=x+y+z; 544 545 if(fDist<fClosest) 546 { 547 fClosest=fDist; 548 fClosestX=x; 549 fClosestY=y; 550 fClosestZ=z; 551 iClosestListener=i; 552 } 553 } 554 } 555 556 // our distances in the world aren't very big, so floats rather than casts to doubles should be fine 557 fDist=sqrtf((fClosestX*fClosestX)+(fClosestY*fClosestY)+(fClosestZ*fClosestZ)); 558 AIL_set_sample_3D_position( SoundInfo.Sample, 0, 0, fDist ); 559 560 //app.DebugPrintf("Playing sound %d %f from nearest listener [%d]\n",SoundInfo.EventID,fDist,iClosestListener); 561 } 562 else 563 { 564 AIL_set_sample_3D_position( SoundInfo.Sample, game_data->x, game_data->y, -game_data->z ); // Flipped sign of z as Miles is expecting left handed coord system 565 } 566 } 567 break; 568 569 default: 570 if(game_data->bIs3D) 571 { 572 if(m_validListenerCount>1) 573 { 574 float fClosest=10000.0f; 575 int iClosestListener=0; 576 float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; 577 // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision 578 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 579 { 580 if( m_ListenerA[i].bValid ) 581 { 582 float x,y,z; 583 584 x=fabs(m_ListenerA[i].vPosition.x-game_data->x); 585 y=fabs(m_ListenerA[i].vPosition.y-game_data->y); 586 z=fabs(m_ListenerA[i].vPosition.z-game_data->z); 587 fDist=x+y+z; 588 589 if(fDist<fClosest) 590 { 591 fClosest=fDist; 592 fClosestX=x; 593 fClosestY=y; 594 fClosestZ=z; 595 iClosestListener=i; 596 } 597 } 598 } 599 // our distances in the world aren't very big, so floats rather than casts to doubles should be fine 600 fDist=sqrtf((fClosestX*fClosestX)+(fClosestY*fClosestY)+(fClosestZ*fClosestZ)); 601 AIL_set_sample_3D_position( SoundInfo.Sample, 0, 0, fDist ); 602 603 //app.DebugPrintf("Playing sound %d %f from nearest listener [%d]\n",SoundInfo.EventID,fDist,iClosestListener); 604 } 605 else 606 { 607 AIL_set_sample_3D_position( SoundInfo.Sample, game_data->x, game_data->y, -game_data->z ); // Flipped sign of z as Miles is expecting left handed coord system 608 } 609 } 610 break; 611 } 612 } 613 } 614 AIL_complete_event_queue_processing(); 615} 616 617//#define DISTORTION_TEST 618#ifdef DISTORTION_TEST 619static float fVal=0.0f; 620#endif 621///////////////////////////////////////////// 622// 623// tick 624// 625///////////////////////////////////////////// 626 627#ifdef __PSVITA__ 628static S32 running = AIL_ms_count(); 629#endif 630 631void SoundEngine::tick(shared_ptr<Mob> *players, float a) 632{ 633 ConsoleSoundEngine::tick(); 634#ifdef __DISABLE_MILES__ 635 return; 636#endif 637 638#ifdef __PSVITA__ 639 EnterCriticalSection(&SoundEngine_MixerMutex); 640#endif 641 642 // update the listener positions 643 int listenerCount = 0; 644#ifdef DISTORTION_TEST 645 float fX,fY,fZ; 646#endif 647 if( players ) 648 { 649 bool bListenerPostionSet=false; 650 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 651 { 652 if( players[i] != NULL ) 653 { 654 m_ListenerA[i].bValid=true; 655 F32 x,y,z; 656 x=players[i]->xo + (players[i]->x - players[i]->xo) * a; 657 y=players[i]->yo + (players[i]->y - players[i]->yo) * a; 658 z=players[i]->zo + (players[i]->z - players[i]->zo) * a; 659 660 float yRot = players[i]->yRotO + (players[i]->yRot - players[i]->yRotO) * a; 661 float yCos = (float)cos(-yRot * Mth::RAD_TO_GRAD - PI); 662 float ySin = (float)sin(-yRot * Mth::RAD_TO_GRAD - PI); 663 664 // store the listener positions for splitscreen 665 m_ListenerA[i].vPosition.x = x; 666 m_ListenerA[i].vPosition.y = y; 667 m_ListenerA[i].vPosition.z = z; 668 669 m_ListenerA[i].vOrientFront.x = ySin; 670 m_ListenerA[i].vOrientFront.y = 0; 671 m_ListenerA[i].vOrientFront.z = yCos; 672 673 listenerCount++; 674 } 675 else 676 { 677 m_ListenerA[i].bValid=false; 678 } 679 } 680 } 681 682 683 // If there were no valid players set, make up a default listener 684 if( listenerCount == 0 ) 685 { 686 m_ListenerA[0].vPosition.x = 0; 687 m_ListenerA[0].vPosition.y = 0; 688 m_ListenerA[0].vPosition.z = 0; 689 m_ListenerA[0].vOrientFront.x = 0; 690 m_ListenerA[0].vOrientFront.y = 0; 691 m_ListenerA[0].vOrientFront.z = 1.0f; 692 listenerCount++; 693 } 694 m_validListenerCount = listenerCount; 695 696#ifdef __PSVITA__ 697 // AP - Show that a change has occurred so we know to update the values at the next Mixer callback 698 SoundEngine_Change = true; 699 700 LeaveCriticalSection(&SoundEngine_MixerMutex); 701#else 702 updateMiles(); 703#endif 704} 705 706///////////////////////////////////////////// 707// 708// SoundEngine 709// 710///////////////////////////////////////////// 711SoundEngine::SoundEngine() 712{ 713 random = new Random(); 714 m_hStream=0; 715 m_StreamState=eMusicStreamState_Idle; 716 m_iMusicDelay=0; 717 m_validListenerCount=0; 718 719 m_bHeardTrackA=NULL; 720 721 // Start the streaming music playing some music from the overworld 722 SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3, 723 eStream_Nether1,eStream_Nether4, 724 eStream_end_dragon,eStream_end_end, 725 eStream_CD_1); 726 727 m_musicID=getMusicID(LevelData::DIMENSION_OVERWORLD); 728 729 m_StreamingAudioInfo.bIs3D=false; 730 m_StreamingAudioInfo.x=0; 731 m_StreamingAudioInfo.y=0; 732 m_StreamingAudioInfo.z=0; 733 m_StreamingAudioInfo.volume=1; 734 m_StreamingAudioInfo.pitch=1; 735 736 memset(CurrentSoundsPlaying,0,sizeof(int)*(eSoundType_MAX+eSFX_MAX)); 737 memset(m_ListenerA,0,sizeof(AUDIO_LISTENER)*XUSER_MAX_COUNT); 738 739#ifdef __ORBIS__ 740 m_hBGMAudio=GetAudioBGMHandle(); 741#endif 742} 743 744void SoundEngine::destroy() {} 745 746#ifdef _DEBUG 747void SoundEngine::GetSoundName(char *szSoundName,int iSound) 748{ 749 strcpy((char *)szSoundName,"Minecraft/"); 750 wstring name = wchSoundNames[iSound]; 751 char *SoundName = (char *)ConvertSoundPathToName(name); 752 strcat((char *)szSoundName,SoundName); 753} 754#endif 755 756///////////////////////////////////////////// 757// 758// play 759// 760///////////////////////////////////////////// 761void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) 762{ 763 U8 szSoundName[256]; 764 765 if(iSound==-1) 766 { 767 app.DebugPrintf(6,"PlaySound with sound of -1 !!!!!!!!!!!!!!!\n"); 768 return; 769 } 770 771 // AP removed old counting system. Now relying on Miles' Play Count Limit 772 /* // if we are already playing loads of this sounds ignore this one 773 if(CurrentSoundsPlaying[iSound+eSFX_MAX]>MAX_SAME_SOUNDS_PLAYING) 774 { 775 // wstring name = wchSoundNames[iSound]; 776 // char *SoundName = (char *)ConvertSoundPathToName(name); 777 // app.DebugPrintf("Too many %s sounds playing!\n",SoundName); 778 return; 779 }*/ 780 781 //if (iSound != eSoundType_MOB_IRONGOLEM_WALK) return; 782 783 // build the name 784 strcpy((char *)szSoundName,"Minecraft/"); 785 786#ifdef DISTORTION_TEST 787 wstring name = wchSoundNames[eSoundType_MOB_ENDERDRAGON_GROWL]; 788#else 789 wstring name = wchSoundNames[iSound]; 790#endif 791 792 char *SoundName = (char *)ConvertSoundPathToName(name); 793 strcat((char *)szSoundName,SoundName); 794 795// app.DebugPrintf(6,"PlaySound - %d - %s - %s (%f %f %f, vol %f, pitch %f)\n",iSound, SoundName, szSoundName,x,y,z,volume,pitch); 796 797 AUDIO_INFO AudioInfo; 798 AudioInfo.x=x; 799 AudioInfo.y=y; 800 AudioInfo.z=z; 801 AudioInfo.volume=volume; 802 AudioInfo.pitch=pitch; 803 AudioInfo.bIs3D=true; 804 AudioInfo.bUseSoundsPitchVal=false; 805 AudioInfo.iSound=iSound+eSFX_MAX; 806#ifdef _DEBUG 807 strncpy(AudioInfo.chName,(char *)szSoundName,64); 808#endif 809 810 S32 token = AIL_enqueue_event_start(); 811 AIL_enqueue_event_buffer(&token, &AudioInfo, sizeof(AUDIO_INFO), 0); 812 AIL_enqueue_event_end_named(token, (char *)szSoundName); 813} 814 815///////////////////////////////////////////// 816// 817// playUI 818// 819///////////////////////////////////////////// 820void SoundEngine::playUI(int iSound, float volume, float pitch) 821{ 822 U8 szSoundName[256]; 823 wstring name; 824 // we have some game sounds played as UI sounds... 825 // Not the best way to do this, but it seems to only be the portal sounds 826 827 if(iSound>=eSFX_MAX) 828 { 829 // AP removed old counting system. Now relying on Miles' Play Count Limit 830 /* // if we are already playing loads of this sounds ignore this one 831 if(CurrentSoundsPlaying[iSound+eSFX_MAX]>MAX_SAME_SOUNDS_PLAYING) return;*/ 832 833 // build the name 834 strcpy((char *)szSoundName,"Minecraft/"); 835 name = wchSoundNames[iSound]; 836 } 837 else 838 { 839 // AP removed old counting system. Now relying on Miles' Play Count Limit 840 /* // if we are already playing loads of this sounds ignore this one 841 if(CurrentSoundsPlaying[iSound]>MAX_SAME_SOUNDS_PLAYING) return;*/ 842 843 // build the name 844 strcpy((char *)szSoundName,"Minecraft/UI/"); 845 name = wchUISoundNames[iSound]; 846 } 847 848 char *SoundName = (char *)ConvertSoundPathToName(name); 849 strcat((char *)szSoundName,SoundName); 850// app.DebugPrintf("UI: Playing %s, volume %f, pitch %f\n",SoundName,volume,pitch); 851 852 //app.DebugPrintf("PlaySound - %d - %s\n",iSound, SoundName); 853 854 AUDIO_INFO AudioInfo; 855 memset(&AudioInfo,0,sizeof(AUDIO_INFO)); 856 AudioInfo.volume=volume; // will be multiplied by the master volume 857 AudioInfo.pitch=pitch; 858 AudioInfo.bUseSoundsPitchVal=true; 859 if(iSound>=eSFX_MAX) 860 { 861 AudioInfo.iSound=iSound+eSFX_MAX; 862 } 863 else 864 { 865 AudioInfo.iSound=iSound; 866 } 867#ifdef _DEBUG 868 strncpy(AudioInfo.chName,(char *)szSoundName,64); 869#endif 870 871 // 4J-PB - not going to stop UI events happening based on the number of currently playing sounds 872 S32 token = AIL_enqueue_event_start(); 873 AIL_enqueue_event_buffer(&token, &AudioInfo, sizeof(AUDIO_INFO), 0); 874 AIL_enqueue_event_end_named(token, (char *)szSoundName); 875} 876 877///////////////////////////////////////////// 878// 879// playStreaming 880// 881///////////////////////////////////////////// 882void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay) 883{ 884 // This function doesn't actually play a streaming sound, just sets states and an id for the music tick to play it 885 // Level audio will be played when a play with an empty name comes in 886 // CD audio will be played when a named stream comes in 887 888 m_StreamingAudioInfo.x=x; 889 m_StreamingAudioInfo.y=y; 890 m_StreamingAudioInfo.z=z; 891 m_StreamingAudioInfo.volume=volume; 892 m_StreamingAudioInfo.pitch=pitch; 893 894 if(m_StreamState==eMusicStreamState_Playing) 895 { 896 m_StreamState=eMusicStreamState_Stop; 897 } 898 else if(m_StreamState==eMusicStreamState_Opening) 899 { 900 m_StreamState=eMusicStreamState_OpeningCancel; 901 } 902 903 if(name.empty()) 904 { 905 // music, or stop CD 906 m_StreamingAudioInfo.bIs3D=false; 907 908 // we need a music id 909 // random delay of up to 3 minutes for music 910 m_iMusicDelay = random->nextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10; 911 912#ifdef _DEBUG 913 m_iMusicDelay=0; 914#endif 915 Minecraft *pMinecraft=Minecraft::GetInstance(); 916 917 bool playerInEnd=false; 918 bool playerInNether=false; 919 920 for(unsigned int i=0;i<MAX_LOCAL_PLAYERS;i++) 921 { 922 if(pMinecraft->localplayers[i]!=NULL) 923 { 924 if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END) 925 { 926 playerInEnd=true; 927 } 928 else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER) 929 { 930 playerInNether=true; 931 } 932 } 933 } 934 if(playerInEnd) 935 { 936 m_musicID = getMusicID(LevelData::DIMENSION_END); 937 } 938 else if(playerInNether) 939 { 940 m_musicID = getMusicID(LevelData::DIMENSION_NETHER); 941 } 942 else 943 { 944 m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); 945 } 946 } 947 else 948 { 949 // jukebox 950 m_StreamingAudioInfo.bIs3D=true; 951 m_musicID=getMusicID(name); 952 m_iMusicDelay=0; 953 } 954} 955 956 957int SoundEngine::GetRandomishTrack(int iStart,int iEnd) 958{ 959 // 4J-PB - make it more likely that we'll get a track we've not heard for a while, although repeating tracks sometimes is fine 960 961 // if all tracks have been heard, clear the flags 962 bool bAllTracksHeard=true; 963 int iVal=iStart; 964 for(int i=iStart;i<=iEnd;i++) 965 { 966 if(m_bHeardTrackA[i]==false) 967 { 968 bAllTracksHeard=false; 969 app.DebugPrintf("Not heard all tracks yet\n"); 970 break; 971 } 972 } 973 974 if(bAllTracksHeard) 975 { 976 app.DebugPrintf("Heard all tracks - resetting the tracking array\n"); 977 978 for(int i=iStart;i<=iEnd;i++) 979 { 980 m_bHeardTrackA[i]=false; 981 } 982 } 983 984 // trying to get a track we haven't heard, but not too hard 985 for(int i=0;i<=((iEnd-iStart)/2);i++) 986 { 987 // random->nextInt(1) will always return 0 988 iVal=random->nextInt((iEnd-iStart)+1)+iStart; 989 if(m_bHeardTrackA[iVal]==false) 990 { 991 // not heard this 992 app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal); 993 m_bHeardTrackA[iVal]=true; 994 break; 995 } 996 else 997 { 998 app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal); 999 } 1000 } 1001 1002 app.DebugPrintf("Select track %d\n",iVal); 1003 return iVal; 1004} 1005///////////////////////////////////////////// 1006// 1007// getMusicID 1008// 1009///////////////////////////////////////////// 1010int SoundEngine::getMusicID(int iDomain) 1011{ 1012 int iRandomVal=0; 1013 Minecraft *pMinecraft=Minecraft::GetInstance(); 1014 1015 // Before the game has started? 1016 if(pMinecraft==NULL) 1017 { 1018 // any track from the overworld 1019 return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); 1020 } 1021 1022 if(pMinecraft->skins->isUsingDefaultSkin()) 1023 { 1024 switch(iDomain) 1025 { 1026 case LevelData::DIMENSION_END: 1027 // the end isn't random - it has different music depending on whether the dragon is alive or not, but we've not added the dead dragon music yet 1028 return m_iStream_End_Min; 1029 case LevelData::DIMENSION_NETHER: 1030 return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max); 1031 //return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min); 1032 default: //overworld 1033 //return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min); 1034 return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); 1035 } 1036 } 1037 else 1038 { 1039 // using a texture pack - may have multiple End music tracks 1040 switch(iDomain) 1041 { 1042 case LevelData::DIMENSION_END: 1043 return GetRandomishTrack(m_iStream_End_Min,m_iStream_End_Max); 1044 case LevelData::DIMENSION_NETHER: 1045 //return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min); 1046 return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max); 1047 default: //overworld 1048 //return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min); 1049 return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); 1050 } 1051 } 1052} 1053 1054///////////////////////////////////////////// 1055// 1056// getMusicID 1057// 1058///////////////////////////////////////////// 1059// check what the CD is 1060int SoundEngine::getMusicID(const wstring& name) 1061{ 1062 int iCD=0; 1063 char *SoundName = (char *)ConvertSoundPathToName(name,true); 1064 1065 // 4J-PB - these will always be the game cds, so use the m_szStreamFileA for this 1066 for(int i=0;i<12;i++) 1067 { 1068 if(strcmp(SoundName,m_szStreamFileA[i+eStream_CD_1])==0) 1069 { 1070 iCD=i; 1071 break; 1072 } 1073 } 1074 1075 // adjust for cd start position on normal or mash-up pack 1076 return iCD+m_iStream_CD_1; 1077} 1078 1079///////////////////////////////////////////// 1080// 1081// getMasterMusicVolume 1082// 1083///////////////////////////////////////////// 1084float SoundEngine::getMasterMusicVolume() 1085{ 1086 if( m_bSystemMusicPlaying ) 1087 { 1088 return 0.0f; 1089 } 1090 else 1091 { 1092 return m_MasterMusicVolume; 1093 } 1094} 1095 1096///////////////////////////////////////////// 1097// 1098// updateMusicVolume 1099// 1100///////////////////////////////////////////// 1101void SoundEngine::updateMusicVolume(float fVal) 1102{ 1103 m_MasterMusicVolume=fVal; 1104} 1105 1106///////////////////////////////////////////// 1107// 1108// updateSystemMusicPlaying 1109// 1110///////////////////////////////////////////// 1111void SoundEngine::updateSystemMusicPlaying(bool isPlaying) 1112{ 1113 m_bSystemMusicPlaying = isPlaying; 1114} 1115 1116///////////////////////////////////////////// 1117// 1118// updateSoundEffectVolume 1119// 1120///////////////////////////////////////////// 1121void SoundEngine::updateSoundEffectVolume(float fVal) 1122{ 1123 m_MasterEffectsVolume=fVal; 1124 //AIL_set_variable_float(0,"UserEffectVol",fVal); 1125} 1126 1127void SoundEngine::add(const wstring& name, File *file) {} 1128void SoundEngine::addMusic(const wstring& name, File *file) {} 1129void SoundEngine::addStreaming(const wstring& name, File *file) {} 1130bool SoundEngine::isStreamingWavebankReady() { return true; } 1131 1132int SoundEngine::OpenStreamThreadProc( void* lpParameter ) 1133{ 1134#ifdef __DISABLE_MILES__ 1135 return 0; 1136#endif 1137 SoundEngine *soundEngine = (SoundEngine *)lpParameter; 1138 soundEngine->m_hStream = AIL_open_stream(soundEngine->m_hDriver,soundEngine->m_szStreamName,0); 1139 1140 if(soundEngine->m_hStream==0) 1141 { 1142 app.DebugPrintf("SoundEngine::OpenStreamThreadProc - Could not open - %s\n",soundEngine->m_szStreamName); 1143 } 1144 return 0; 1145} 1146 1147///////////////////////////////////////////// 1148// 1149// playMusicTick 1150// 1151///////////////////////////////////////////// 1152void SoundEngine::playMusicTick() 1153{ 1154// AP - vita will update the music during the mixer callback 1155#ifndef __PSVITA__ 1156 playMusicUpdate(); 1157#endif 1158} 1159 1160// AP - moved to a separate function so it can be called from the mixer callback on Vita 1161void SoundEngine::playMusicUpdate() 1162{ 1163 //return; 1164 static bool firstCall = true; 1165 static float fMusicVol = 0.0f; 1166 if( firstCall ) 1167 { 1168 fMusicVol = getMasterMusicVolume(); 1169 firstCall = false; 1170 } 1171 1172 switch(m_StreamState) 1173 { 1174 case eMusicStreamState_Idle: 1175 1176 // start a stream playing 1177 if (m_iMusicDelay > 0) 1178 { 1179 m_iMusicDelay--; 1180 return; 1181 } 1182 1183 if(m_musicID!=-1) 1184 { 1185 // start playing it 1186 1187 1188#if ( defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ ) 1189 1190#ifdef __PS3__ 1191 // 4J-PB - Need to check if we are a patched BD build 1192 if(app.GetBootedFromDiscPatch()) 1193 { 1194 sprintf(m_szStreamName,"%s/%s",app.GetBDUsrDirPath(m_szMusicPath), m_szMusicPath ); 1195 app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) music path - %s",m_szStreamName); 1196 } 1197 else 1198 { 1199 sprintf(m_szStreamName,"%s/%s",getUsrDirPath(), m_szMusicPath ); 1200 } 1201#else 1202 sprintf(m_szStreamName,"%s/%s",getUsrDirPath(), m_szMusicPath ); 1203#endif 1204 1205#else 1206 strcpy((char *)m_szStreamName,m_szMusicPath); 1207#endif 1208 // are we using a mash-up pack? 1209 //if(pMinecraft && !pMinecraft->skins->isUsingDefaultSkin() && pMinecraft->skins->getSelected()->hasAudio()) 1210 if(Minecraft::GetInstance()->skins->getSelected()->hasAudio()) 1211 { 1212 // It's a mash-up - need to use the DLC path for the music 1213 TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected(); 1214 DLCTexturePack *pDLCTexPack=(DLCTexturePack *)pTexPack; 1215 DLCPack *pack = pDLCTexPack->getDLCInfoParentPack(); 1216 DLCAudioFile *dlcAudioFile = (DLCAudioFile *) pack->getFile(DLCManager::e_DLCType_Audio, 0); 1217 1218 app.DebugPrintf("Mashup pack \n"); 1219 1220 // build the name 1221 1222 // if the music ID is beyond the end of the texture pack music files, then it's a CD 1223 if(m_musicID<m_iStream_CD_1) 1224 { 1225 SetIsPlayingStreamingGameMusic(true); 1226 SetIsPlayingStreamingCDMusic(false); 1227 m_MusicType=eMusicType_Game; 1228 m_StreamingAudioInfo.bIs3D=false; 1229 1230#ifdef _XBOX_ONE 1231 wstring &wstrSoundName=dlcAudioFile->GetSoundName(m_musicID); 1232 wstring wstrFile=L"TPACK:\\Data\\" + wstrSoundName +L".binka"; 1233 std::wstring mountedPath = StorageManager.GetMountedPath(wstrFile); 1234 wcstombs(m_szStreamName,mountedPath.c_str(),255); 1235#else 1236 wstring &wstrSoundName=dlcAudioFile->GetSoundName(m_musicID); 1237 char szName[255]; 1238 wcstombs(szName,wstrSoundName.c_str(),255); 1239 1240#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ 1241 string strFile="TPACK:/Data/" + string(szName) + ".binka"; 1242#else 1243 string strFile="TPACK:\\Data\\" + string(szName) + ".binka"; 1244#endif 1245 std::string mountedPath = StorageManager.GetMountedPath(strFile); 1246 strcpy(m_szStreamName,mountedPath.c_str()); 1247#endif 1248 } 1249 else 1250 { 1251 SetIsPlayingStreamingGameMusic(false); 1252 SetIsPlayingStreamingCDMusic(true); 1253 m_MusicType=eMusicType_CD; 1254 m_StreamingAudioInfo.bIs3D=true; 1255 1256 // Need to adjust to index into the cds in the game's m_szStreamFileA 1257 strcat((char *)m_szStreamName,"cds/"); 1258 strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID-m_iStream_CD_1+eStream_CD_1]); 1259 strcat((char *)m_szStreamName,".binka"); 1260 } 1261 } 1262 else 1263 { 1264 // 4J-PB - if this is a PS3 disc patch, we have to check if the music file is in the patch data 1265#ifdef __PS3__ 1266 if(app.GetBootedFromDiscPatch() && (m_musicID<m_iStream_CD_1)) 1267 { 1268 // rebuild the path for the music 1269 strcpy((char *)m_szStreamName,m_szMusicPath); 1270 strcat((char *)m_szStreamName,"music/"); 1271 strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID]); 1272 strcat((char *)m_szStreamName,".binka"); 1273 1274 // check if this is in the patch data 1275 sprintf(m_szStreamName,"%s/%s",app.GetBDUsrDirPath(m_szStreamName), m_szMusicPath ); 1276 strcat((char *)m_szStreamName,"music/"); 1277 strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID]); 1278 strcat((char *)m_szStreamName,".binka"); 1279 1280 SetIsPlayingStreamingGameMusic(true); 1281 SetIsPlayingStreamingCDMusic(false); 1282 m_MusicType=eMusicType_Game; 1283 m_StreamingAudioInfo.bIs3D=false; 1284 } 1285 else if(m_musicID<m_iStream_CD_1) 1286 { 1287 SetIsPlayingStreamingGameMusic(true); 1288 SetIsPlayingStreamingCDMusic(false); 1289 m_MusicType=eMusicType_Game; 1290 m_StreamingAudioInfo.bIs3D=false; 1291 // build the name 1292 strcat((char *)m_szStreamName,"music/"); 1293 strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID]); 1294 strcat((char *)m_szStreamName,".binka"); 1295 } 1296 1297 else 1298 { 1299 SetIsPlayingStreamingGameMusic(false); 1300 SetIsPlayingStreamingCDMusic(true); 1301 m_MusicType=eMusicType_CD; 1302 m_StreamingAudioInfo.bIs3D=true; 1303 // build the name 1304 strcat((char *)m_szStreamName,"cds/"); 1305 strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID]); 1306 strcat((char *)m_szStreamName,".binka"); 1307 } 1308#else 1309 if(m_musicID<m_iStream_CD_1) 1310 { 1311 SetIsPlayingStreamingGameMusic(true); 1312 SetIsPlayingStreamingCDMusic(false); 1313 m_MusicType=eMusicType_Game; 1314 m_StreamingAudioInfo.bIs3D=false; 1315 // build the name 1316 strcat((char *)m_szStreamName,"music/"); 1317 } 1318 else 1319 { 1320 SetIsPlayingStreamingGameMusic(false); 1321 SetIsPlayingStreamingCDMusic(true); 1322 m_MusicType=eMusicType_CD; 1323 m_StreamingAudioInfo.bIs3D=true; 1324 // build the name 1325 strcat((char *)m_szStreamName,"cds/"); 1326 } 1327 strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID]); 1328 strcat((char *)m_szStreamName,".binka"); 1329 1330#endif 1331 } 1332 1333 // wstring name = m_szStreamFileA[m_musicID]; 1334 // char *SoundName = (char *)ConvertSoundPathToName(name); 1335 // strcat((char *)szStreamName,SoundName); 1336 1337 const bool isCD = (m_musicID >= m_iStream_CD_1); 1338 const char* folder = isCD ? "cds/" : "music/"; 1339 1340 FILE* pFile = nullptr; 1341 if (fopen_s(&pFile, reinterpret_cast<char*>(m_szStreamName), "rb") == 0 && pFile) 1342 { 1343 fclose(pFile); 1344 } 1345 else 1346 { 1347 const char* extensions[] = { ".wav" }; // only wav works outside of binka files to my knowledge, i've only tested ogg, wav, mp3 and only wav worked out of the bunch 1348 size_t count = sizeof(extensions) / sizeof(extensions[0]); 1349 bool found = false; 1350 1351 for (size_t i = 0; i < count; i++) 1352 { 1353 int n = sprintf_s(reinterpret_cast<char*>(m_szStreamName), 512, "%s%s%s%s", m_szMusicPath, folder, m_szStreamFileA[m_musicID], extensions[i]); 1354 if (n < 0) continue; 1355 1356 if (fopen_s(&pFile, reinterpret_cast<char*>(m_szStreamName), "rb") == 0 && pFile) 1357 { 1358 fclose(pFile); 1359 found = true; 1360 break; 1361 } 1362 } 1363 1364 if (!found) 1365 { 1366 return; 1367 } 1368 } 1369 1370 app.DebugPrintf("Starting streaming - %s\n",m_szStreamName); 1371 1372 // Don't actually open in this thread, as it can block for ~300ms. 1373 m_openStreamThread = new C4JThread(OpenStreamThreadProc, this, "OpenStreamThreadProc"); 1374 m_openStreamThread->Run(); 1375 m_StreamState = eMusicStreamState_Opening; 1376 } 1377 break; 1378 1379 case eMusicStreamState_Opening: 1380 // If the open stream thread is complete, then we are ready to proceed to actually playing 1381 if( !m_openStreamThread->isRunning() ) 1382 { 1383 delete m_openStreamThread; 1384 m_openStreamThread = NULL; 1385 1386 HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); 1387 1388 // 4J-PB - causes the falloff to be calculated on the PPU instead of the SPU, and seems to resolve our distorted sound issue 1389 AIL_register_falloff_function_callback(hSample,&custom_falloff_function); 1390 1391 if(m_StreamingAudioInfo.bIs3D) 1392 { 1393 AIL_set_sample_3D_distances(hSample,64.0f,1,0); // Larger distance scaler for music discs 1394 if(m_validListenerCount>1) 1395 { 1396 float fClosest=10000.0f; 1397 int iClosestListener=0; 1398 float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; 1399 // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision 1400 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 1401 { 1402 if( m_ListenerA[i].bValid ) 1403 { 1404 float x,y,z; 1405 1406 x=fabs(m_ListenerA[i].vPosition.x-m_StreamingAudioInfo.x); 1407 y=fabs(m_ListenerA[i].vPosition.y-m_StreamingAudioInfo.y); 1408 z=fabs(m_ListenerA[i].vPosition.z-m_StreamingAudioInfo.z); 1409 fDist=x+y+z; 1410 1411 if(fDist<fClosest) 1412 { 1413 fClosest=fDist; 1414 fClosestX=x; 1415 fClosestY=y; 1416 fClosestZ=z; 1417 iClosestListener=i; 1418 } 1419 } 1420 } 1421 1422 // our distances in the world aren't very big, so floats rather than casts to doubles should be fine 1423 fDist=sqrtf((fClosestX*fClosestX)+(fClosestY*fClosestY)+(fClosestZ*fClosestZ)); 1424 AIL_set_sample_3D_position( hSample, 0, 0, fDist ); 1425 } 1426 else 1427 { 1428 AIL_set_sample_3D_position( hSample, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, -m_StreamingAudioInfo.z ); // Flipped sign of z as Miles is expecting left handed coord system 1429 } 1430 } 1431 else 1432 { 1433 // clear the 3d flag on the stream after a jukebox finishes and streaming music starts 1434 AIL_set_sample_is_3D( hSample, 0 ); 1435 } 1436 // set the pitch 1437 app.DebugPrintf("Sample rate:%d\n", AIL_sample_playback_rate(hSample)); 1438 AIL_set_sample_playback_rate_factor(hSample,m_StreamingAudioInfo.pitch); 1439 // set the volume 1440 AIL_set_sample_volume_levels( hSample, m_StreamingAudioInfo.volume*getMasterMusicVolume(), m_StreamingAudioInfo.volume*getMasterMusicVolume()); 1441 1442 AIL_start_stream( m_hStream ); 1443 1444 m_StreamState=eMusicStreamState_Playing; 1445 } 1446 break; 1447 case eMusicStreamState_OpeningCancel: 1448 if( !m_openStreamThread->isRunning() ) 1449 { 1450 delete m_openStreamThread; 1451 m_openStreamThread = NULL; 1452 m_StreamState = eMusicStreamState_Stop; 1453 } 1454 break; 1455 case eMusicStreamState_Stop: 1456 // should gradually take the volume down in steps 1457 AIL_pause_stream(m_hStream,1); 1458 AIL_close_stream(m_hStream); 1459 m_hStream=0; 1460 SetIsPlayingStreamingCDMusic(false); 1461 SetIsPlayingStreamingGameMusic(false); 1462 m_StreamState=eMusicStreamState_Idle; 1463 break; 1464 case eMusicStreamState_Stopping: 1465 break; 1466 case eMusicStreamState_Play: 1467 break; 1468 case eMusicStreamState_Playing: 1469 if(GetIsPlayingStreamingGameMusic()) 1470 { 1471 //if(m_MusicInfo.pCue!=NULL) 1472 { 1473 bool playerInEnd = false; 1474 bool playerInNether=false; 1475 Minecraft *pMinecraft = Minecraft::GetInstance(); 1476 for(unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++i) 1477 { 1478 if(pMinecraft->localplayers[i]!=NULL) 1479 { 1480 if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END) 1481 { 1482 playerInEnd=true; 1483 } 1484 else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER) 1485 { 1486 playerInNether=true; 1487 } 1488 } 1489 } 1490 1491 if(playerInEnd && !GetIsPlayingEndMusic()) 1492 { 1493 m_StreamState=eMusicStreamState_Stop; 1494 1495 // Set the end track 1496 m_musicID = getMusicID(LevelData::DIMENSION_END); 1497 SetIsPlayingEndMusic(true); 1498 SetIsPlayingNetherMusic(false); 1499 } 1500 else if(!playerInEnd && GetIsPlayingEndMusic()) 1501 { 1502 if(playerInNether) 1503 { 1504 m_StreamState=eMusicStreamState_Stop; 1505 1506 // Set the end track 1507 m_musicID = getMusicID(LevelData::DIMENSION_NETHER); 1508 SetIsPlayingEndMusic(false); 1509 SetIsPlayingNetherMusic(true); 1510 } 1511 else 1512 { 1513 m_StreamState=eMusicStreamState_Stop; 1514 1515 // Set the end track 1516 m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); 1517 SetIsPlayingEndMusic(false); 1518 SetIsPlayingNetherMusic(false); 1519 } 1520 } 1521 else if (playerInNether && !GetIsPlayingNetherMusic()) 1522 { 1523 m_StreamState=eMusicStreamState_Stop; 1524 // set the Nether track 1525 m_musicID = getMusicID(LevelData::DIMENSION_NETHER); 1526 SetIsPlayingNetherMusic(true); 1527 SetIsPlayingEndMusic(false); 1528 } 1529 else if(!playerInNether && GetIsPlayingNetherMusic()) 1530 { 1531 if(playerInEnd) 1532 { 1533 m_StreamState=eMusicStreamState_Stop; 1534 // set the Nether track 1535 m_musicID = getMusicID(LevelData::DIMENSION_END); 1536 SetIsPlayingNetherMusic(false); 1537 SetIsPlayingEndMusic(true); 1538 } 1539 else 1540 { 1541 m_StreamState=eMusicStreamState_Stop; 1542 // set the Nether track 1543 m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); 1544 SetIsPlayingNetherMusic(false); 1545 SetIsPlayingEndMusic(false); 1546 } 1547 } 1548 1549 // volume change required? 1550 if(fMusicVol!=getMasterMusicVolume()) 1551 { 1552 fMusicVol=getMasterMusicVolume(); 1553 HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); 1554 //AIL_set_sample_3D_position( hSample, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, m_StreamingAudioInfo.z ); 1555 AIL_set_sample_volume_levels( hSample, fMusicVol, fMusicVol); 1556 } 1557 } 1558 } 1559 else 1560 { 1561 // Music disc playing - if it's a 3D stream, then set the position - we don't have any streaming audio in the world that moves, so this isn't 1562 // required unless we have more than one listener, and are setting the listening position to the origin and setting a fake position 1563 // for the sound down the z axis 1564 if(m_StreamingAudioInfo.bIs3D) 1565 { 1566 if(m_validListenerCount>1) 1567 { 1568 float fClosest=10000.0f; 1569 int iClosestListener=0; 1570 float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; 1571 1572 // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision 1573 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 1574 { 1575 if( m_ListenerA[i].bValid ) 1576 { 1577 float x,y,z; 1578 1579 x=fabs(m_ListenerA[i].vPosition.x-m_StreamingAudioInfo.x); 1580 y=fabs(m_ListenerA[i].vPosition.y-m_StreamingAudioInfo.y); 1581 z=fabs(m_ListenerA[i].vPosition.z-m_StreamingAudioInfo.z); 1582 fDist=x+y+z; 1583 1584 if(fDist<fClosest) 1585 { 1586 fClosest=fDist; 1587 fClosestX=x; 1588 fClosestY=y; 1589 fClosestZ=z; 1590 iClosestListener=i; 1591 } 1592 } 1593 } 1594 1595 // our distances in the world aren't very big, so floats rather than casts to doubles should be fine 1596 HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); 1597 fDist=sqrtf((fClosestX*fClosestX)+(fClosestY*fClosestY)+(fClosestZ*fClosestZ)); 1598 AIL_set_sample_3D_position( hSample, 0, 0, fDist ); 1599 } 1600 } 1601 } 1602 1603 break; 1604 1605 case eMusicStreamState_Completed: 1606 { 1607 // random delay of up to 3 minutes for music 1608 m_iMusicDelay = random->nextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10; 1609 // Check if we have a local player in The Nether or in The End, and play that music if they are 1610 Minecraft *pMinecraft=Minecraft::GetInstance(); 1611 bool playerInEnd=false; 1612 bool playerInNether=false; 1613 1614 for(unsigned int i=0;i<MAX_LOCAL_PLAYERS;i++) 1615 { 1616 if(pMinecraft->localplayers[i]!=NULL) 1617 { 1618 if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END) 1619 { 1620 playerInEnd=true; 1621 } 1622 else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER) 1623 { 1624 playerInNether=true; 1625 } 1626 } 1627 } 1628 if(playerInEnd) 1629 { 1630 m_musicID = getMusicID(LevelData::DIMENSION_END); 1631 SetIsPlayingEndMusic(true); 1632 SetIsPlayingNetherMusic(false); 1633 } 1634 else if(playerInNether) 1635 { 1636 m_musicID = getMusicID(LevelData::DIMENSION_NETHER); 1637 SetIsPlayingNetherMusic(true); 1638 SetIsPlayingEndMusic(false); 1639 } 1640 else 1641 { 1642 m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); 1643 SetIsPlayingNetherMusic(false); 1644 SetIsPlayingEndMusic(false); 1645 } 1646 1647 m_StreamState=eMusicStreamState_Idle; 1648 } 1649 break; 1650 } 1651 1652 // check the status of the stream - this is for when a track completes rather than is stopped by the user action 1653 1654 if(m_hStream!=0) 1655 { 1656 if(AIL_stream_status(m_hStream)==SMP_DONE ) // SMP_DONE 1657 { 1658 AIL_close_stream(m_hStream); 1659 m_hStream=0; 1660 SetIsPlayingStreamingCDMusic(false); 1661 SetIsPlayingStreamingGameMusic(false); 1662 1663 m_StreamState=eMusicStreamState_Completed; 1664 } 1665 } 1666} 1667 1668 1669///////////////////////////////////////////// 1670// 1671// ConvertSoundPathToName 1672// 1673///////////////////////////////////////////// 1674char *SoundEngine::ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) 1675{ 1676 static char buf[256]; 1677 assert(name.length()<256); 1678 for(unsigned int i = 0; i < name.length(); i++ ) 1679 { 1680 wchar_t c = name[i]; 1681 if(c=='.') c='/'; 1682 if(bConvertSpaces) 1683 { 1684 if(c==' ') c='_'; 1685 } 1686 buf[i] = (char)c; 1687 } 1688 buf[name.length()] = 0; 1689 return buf; 1690} 1691 1692#endif 1693 1694 1695F32 AILCALLBACK custom_falloff_function (HSAMPLE S, 1696 F32 distance, 1697 F32 rolloff_factor, 1698 F32 min_dist, 1699 F32 max_dist) 1700{ 1701 F32 result; 1702 1703 // This is now emulating the linear fall-off function that we used on the Xbox 360. The parameter which is passed as "max_dist" is the only one actually used, 1704 // and is generally used as CurveDistanceScaler is used on XACT on the Xbox. A special value of 10000.0f is passed for thunder, which has no attenuation 1705 1706 if( max_dist == 10000.0f ) 1707 { 1708 return 1.0f; 1709 } 1710 1711 result = 1.0f - ( distance / max_dist ); 1712 if( result < 0.0f ) result = 0.0f; 1713 if( result > 1.0f ) result = 1.0f; 1714 1715 return result; 1716}