the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "..\..\..\Minecraft.World\net.minecraft.world.entity.h"
3#include "..\..\..\Minecraft.World\Mth.h"
4#include "..\..\..\Minecraft.World\Random.h"
5#include "..\..\..\Minecraft.World\LevelData.h"
6#include "..\..\Minecraft.h"
7#include "..\..\MultiplayerLocalPlayer.h"
8#include "SoundEngine.h"
9#include "..\..\TexturePackRepository.h"
10#include "..\..\TexturePack.h"
11#include "..\..\Common\DLC\DLCAudioFile.h"
12#include "..\..\DLCTexturePack.h"
13
14
15IXAudio2* g_pXAudio2 = NULL; // pointer to XAudio2 instance used by QNet and XACT
16IXAudio2MasteringVoice* g_pXAudio2MasteringVoice = NULL; // pointer to XAudio2 mastering voice
17
18IXACT3Engine *SoundEngine::m_pXACT3Engine = NULL;
19IXACT3WaveBank *SoundEngine::m_pWaveBank = NULL;
20IXACT3WaveBank *SoundEngine::m_pWaveBank2 = NULL;
21IXACT3WaveBank *SoundEngine::m_pStreamedWaveBank = NULL;
22IXACT3WaveBank *SoundEngine::m_pStreamedWaveBankAdditional = NULL;
23IXACT3SoundBank *SoundEngine::m_pSoundBank = NULL;
24IXACT3SoundBank *SoundEngine::m_pSoundBank2 = NULL;
25CRITICAL_SECTION SoundEngine::m_CS;
26
27X3DAUDIO_HANDLE SoundEngine::m_xact3dInstance;
28vector<SoundEngine::soundInfo *> SoundEngine::currentSounds;
29X3DAUDIO_DSP_SETTINGS SoundEngine::m_DSPSettings;
30X3DAUDIO_EMITTER SoundEngine::m_emitter;
31X3DAUDIO_LISTENER SoundEngine::m_listeners[4];
32int SoundEngine::m_validListenerCount = 0;
33
34X3DAUDIO_DISTANCE_CURVE_POINT SoundEngine::m_VolumeCurvePoints[2] = {
35 {0.0f, 1.0f},
36 {1.0f, 0.0f},
37};
38
39X3DAUDIO_DISTANCE_CURVE_POINT SoundEngine::m_DragonVolumeCurvePoints[2] = {
40 {0.0f, 1.0f},
41 {1.0f, 0.5f},
42};
43X3DAUDIO_DISTANCE_CURVE_POINT SoundEngine::m_VolumeCurvePointsNoDecay[2] = {
44 {0.0f, 1.0f},
45 {1.0f, 1.0f},
46};
47
48X3DAUDIO_DISTANCE_CURVE SoundEngine::m_VolumeCurve;
49X3DAUDIO_DISTANCE_CURVE SoundEngine::m_DragonVolumeCurve;
50X3DAUDIO_DISTANCE_CURVE SoundEngine::m_VolumeCurveNoDecay;
51
52void SoundEngine::setXACTEngine( IXACT3Engine *pXACT3Engine)
53{
54 m_pXACT3Engine = pXACT3Engine;
55}
56
57void SoundEngine::destroy()
58{
59}
60
61SoundEngine::SoundEngine()
62{
63 random = new Random();
64 noMusicDelay = random->nextInt(20 * 60 * 10);
65
66 ZeroMemory(&m_MusicInfo,sizeof(soundInfo));
67 //bIsPlayingStreamingCDMusic=false;
68 //m_bIsPlayingStreamingGameMusic=false;
69 SetIsPlayingEndMusic(false);
70 SetIsPlayingNetherMusic(false);
71 m_VolumeCurve.PointCount = 2;
72 m_VolumeCurve.pPoints = m_VolumeCurvePoints;
73 m_DragonVolumeCurve.PointCount = 2;
74 m_DragonVolumeCurve.pPoints = m_DragonVolumeCurvePoints;
75 m_VolumeCurveNoDecay.PointCount = 2;
76 m_VolumeCurveNoDecay.pPoints = m_VolumeCurvePointsNoDecay;
77
78 m_bStreamingMusicReady=false;
79 m_bStreamingWaveBank1Ready=false;
80 m_bStreamingWaveBank2Ready=false;
81}
82
83void SoundEngine::init(Options *pOptions)
84{
85 InitializeCriticalSection(&m_CS);
86
87 // Iniatialise XACT itself
88 HRESULT hr;
89 if ( FAILED ( hr = XACT3CreateEngine( 0, &m_pXACT3Engine ) ) )
90 {
91 app.FatalLoadError();
92 assert( false );
93 return;
94 }
95
96 // Load global settings file
97 // 4J-PB - move this to the title update, since we've corrected it to allow sounds to be pitch varied when they weren't before
98 HANDLE file;
99#ifdef _TU_BUILD
100 file = CreateFile("UPDATE:\\res\\audio\\Minecraft.xgs", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
101#else
102 file = CreateFile("GAME:\\res\\TitleUpdate\\audio\\Minecraft.xgs", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
103#endif
104 if( file == INVALID_HANDLE_VALUE )
105 {
106 app.FatalLoadError();
107 assert(false);
108 return;
109 }
110 DWORD dwFileSize = GetFileSize(file,NULL);
111 DWORD bytesRead = 0;
112 DWORD memFlags = MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_PHYSICAL);
113 void *pvGlobalSettings = XMemAlloc(dwFileSize, memFlags);
114 ReadFile(file,pvGlobalSettings,dwFileSize,&bytesRead,NULL);
115 CloseHandle(file);
116
117 XACT_RUNTIME_PARAMETERS EngineParameters = {0};
118 EngineParameters.lookAheadTime = XACT_ENGINE_LOOKAHEAD_DEFAULT;
119 EngineParameters.fnNotificationCallback = &this->XACTNotificationCallback;
120 EngineParameters.pGlobalSettingsBuffer = pvGlobalSettings;
121 EngineParameters.globalSettingsBufferSize = dwFileSize;
122 EngineParameters.globalSettingsFlags = XACT_FLAG_GLOBAL_SETTINGS_MANAGEDATA;
123 EngineParameters.pXAudio2 = g_pXAudio2;
124 EngineParameters.pMasteringVoice = g_pXAudio2MasteringVoice;
125
126 if ( FAILED ( hr = m_pXACT3Engine->Initialize( &EngineParameters ) ) )
127 {
128 app.FatalLoadError();
129 assert( false );
130 return;
131 }
132
133 // printf("XACT initialisation complete\n");
134
135 // Initialise X3D
136 XACT3DInitialize(m_pXACT3Engine,m_xact3dInstance);
137
138 // Set up common structures that can be re-used between sounds & just have required bits updated
139 memset(&m_DSPSettings,0,sizeof(X3DAUDIO_DSP_SETTINGS));
140 WAVEFORMATEXTENSIBLE format;
141 m_pXACT3Engine->GetFinalMixFormat(&format);
142 m_DSPSettings.SrcChannelCount = 1;
143 m_DSPSettings.DstChannelCount = format.Format.nChannels;
144 // printf("%d channels\n", format.Format.nChannels);
145 m_DSPSettings.pMatrixCoefficients = new FLOAT32[m_DSPSettings.SrcChannelCount * m_DSPSettings.DstChannelCount];
146
147 for( int i = 0; i < 4; i++ )
148 {
149 memset(&m_listeners[i],0,sizeof(X3DAUDIO_LISTENER));
150 m_listeners[i].OrientFront.z = 1.0f;
151 m_listeners[i].OrientTop.y = 1.0f;
152 }
153 m_validListenerCount = 1;
154 memset(&m_emitter,0,sizeof(X3DAUDIO_EMITTER));
155 m_emitter.ChannelCount = 1;
156 m_emitter.pVolumeCurve = &m_VolumeCurve;
157 m_emitter.pLFECurve = &m_VolumeCurve;
158 m_emitter.CurveDistanceScaler = 16.0f;
159 m_emitter.OrientFront.z = 1.0f;
160 m_emitter.OrientTop.y = 1.0f;
161
162 // Create resident wave bank - leave memory for this managed by xact so it can free it
163
164 file = CreateFile("GAME:\\res\\audio\\resident.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
165 if( file == INVALID_HANDLE_VALUE )
166 {
167 app.FatalLoadError();
168 assert(false);
169 return;
170 }
171
172 dwFileSize = GetFileSize(file,NULL);
173 void *pvWaveBank = XMemAlloc(dwFileSize, memFlags);
174 ReadFile(file,pvWaveBank,dwFileSize,&bytesRead,NULL);
175 CloseHandle(file);
176
177 if ( FAILED( hr = m_pXACT3Engine->CreateInMemoryWaveBank( pvWaveBank, dwFileSize, XACT_FLAG_ENGINE_CREATE_MANAGEDATA, memFlags, &m_pWaveBank ) ) )
178 {
179 app.FatalLoadError();
180 assert(false);
181 return;
182 }
183
184 // 4J-PB - add new sounds wavebank
185#ifdef _TU_BUILD
186 file = CreateFile("UPDATE:\\res\\audio\\additional.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
187#else
188 file = CreateFile("GAME:\\res\\TitleUpdate\\audio\\additional.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
189#endif
190 if( file == INVALID_HANDLE_VALUE )
191 {
192 app.FatalLoadError();
193 assert(false);
194 return;
195 }
196
197 dwFileSize = GetFileSize(file,NULL);
198 void *pvWaveBank2 = XMemAlloc(dwFileSize, memFlags);
199 ReadFile(file,pvWaveBank2,dwFileSize,&bytesRead,NULL);
200 CloseHandle(file);
201
202 if ( FAILED( hr = m_pXACT3Engine->CreateInMemoryWaveBank( pvWaveBank2, dwFileSize, XACT_FLAG_ENGINE_CREATE_MANAGEDATA, memFlags, &m_pWaveBank2 ) ) )
203 {
204 app.FatalLoadError();
205 assert(false);
206 return;
207 }
208
209 // Create streamed sound bank
210
211 file = CreateFile("GAME:\\res\\audio\\streamed.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
212
213 if( file == INVALID_HANDLE_VALUE )
214 {
215 app.FatalLoadError();
216 assert(false);
217 return;
218 }
219
220 XACT_WAVEBANK_STREAMING_PARAMETERS streamParams;
221 streamParams.file = file;
222 streamParams.offset = 0;
223 streamParams.flags = 0;
224 streamParams.packetSize = 16; // Not sure what to pick for this - suggests a "multiple of 16" for DVD playback
225
226 if ( FAILED( hr = m_pXACT3Engine->CreateStreamingWaveBank( &streamParams, &m_pStreamedWaveBank ) ) )
227 {
228 app.FatalLoadError();
229 assert(false);
230 return;
231 }
232
233 // Create streamed sound bank
234
235 //file = CreateFile("GAME:\\res\\audio\\AdditionalMusic.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
236#ifdef _TU_BUILD
237 file = CreateFile("UPDATE:\\res\\audio\\AdditionalMusic.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
238#else
239 file = CreateFile("GAME:\\res\\TitleUpdate\\audio\\AdditionalMusic.xwb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
240#endif
241 if( file == INVALID_HANDLE_VALUE )
242 {
243 app.FatalLoadError();
244 assert(false);
245 return;
246 }
247
248 streamParams.file = file;
249 streamParams.offset = 0;
250 streamParams.flags = 0;
251 streamParams.packetSize = 16; // Not sure what to pick for this - suggests a "multiple of 16" for DVD playback
252
253 if ( FAILED( hr = m_pXACT3Engine->CreateStreamingWaveBank( &streamParams, &m_pStreamedWaveBankAdditional ) ) )
254 {
255 app.FatalLoadError();
256 assert(false);
257 return;
258 }
259
260 // Create sound bank - leave memory for this managed by xact so it can free it
261 // 4J-PB - updated for the TU
262 //file = CreateFile("GAME:\\res\\audio\\minecraft.xsb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
263#ifdef _TU_BUILD
264 file = CreateFile("UPDATE:\\res\\audio\\minecraft.xsb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
265#else
266 file = CreateFile("GAME:\\res\\TitleUpdate\\audio\\minecraft.xsb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
267#endif
268 if( file == INVALID_HANDLE_VALUE )
269 {
270 app.FatalLoadError();
271 assert(false);
272 return;
273 }
274 dwFileSize = GetFileSize(file,NULL);
275 void *pvSoundBank = XMemAlloc(dwFileSize, memFlags);
276 ReadFile(file,pvSoundBank,dwFileSize,&bytesRead,NULL);
277 CloseHandle(file);
278
279 if ( FAILED( hr = m_pXACT3Engine->CreateSoundBank( pvSoundBank, dwFileSize, XACT_FLAG_ENGINE_CREATE_MANAGEDATA, memFlags, &m_pSoundBank ) ) )
280 {
281 app.FatalLoadError();
282 assert(false);
283 return;
284 }
285
286 // Create sound bank2 - leave memory for this managed by xact so it can free it
287
288#ifdef _TU_BUILD
289 file = CreateFile("UPDATE:\\res\\audio\\additional.xsb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
290#else
291 file = CreateFile("GAME:\\res\\TitleUpdate\\audio\\additional.xsb", GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
292#endif
293 if( file == INVALID_HANDLE_VALUE )
294 {
295 app.FatalLoadError();
296 assert(false);
297 return;
298 }
299 dwFileSize = GetFileSize(file,NULL);
300 void *pvSoundBank2 = XMemAlloc(dwFileSize, memFlags);
301 ReadFile(file,pvSoundBank2,dwFileSize,&bytesRead,NULL);
302 CloseHandle(file);
303
304 if ( FAILED( hr = m_pXACT3Engine->CreateSoundBank( pvSoundBank2, dwFileSize, XACT_FLAG_ENGINE_CREATE_MANAGEDATA, memFlags, &m_pSoundBank2 ) ) )
305 {
306 app.FatalLoadError();
307 assert(false);
308 return;
309 }
310
311 XACT_NOTIFICATION_DESCRIPTION desc = {0};
312 desc.flags = XACT_FLAG_NOTIFICATION_PERSIST;
313 desc.type = XACTNOTIFICATIONTYPE_WAVEBANKPREPARED;
314 desc.pvContext=this;
315 m_pXACT3Engine->RegisterNotification(&desc);
316
317 // get the category to manage the sfx (Default)
318 m_xactSFX = m_pXACT3Engine->GetCategory("Default");
319 m_xactMusic = m_pXACT3Engine->GetCategory("Music");
320}
321
322void SoundEngine::CreateStreamingWavebank(const char *pchName, IXACT3WaveBank **ppStreamedWaveBank)
323{
324 // Create streamed sound bank
325 HRESULT hr;
326
327 HANDLE file = CreateFile(pchName, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
328
329 if( file == INVALID_HANDLE_VALUE )
330 {
331 app.FatalLoadError();
332 assert(false);
333 return;
334 }
335
336 XACT_WAVEBANK_STREAMING_PARAMETERS streamParams;
337 streamParams.file = file;
338 streamParams.offset = 0;
339 streamParams.flags = 0;
340 streamParams.packetSize = 16; // Not sure what to pick for this - suggests a "multiple of 16" for DVD playback
341
342 if ( FAILED( hr = m_pXACT3Engine->CreateStreamingWaveBank( &streamParams, ppStreamedWaveBank ) ) )
343 {
344 app.FatalLoadError();
345 assert(false);
346 return;
347 }
348}
349
350void SoundEngine::CreateSoundbank(const char *pchName, IXACT3SoundBank **ppSoundBank)
351{
352 HRESULT hr;
353 HANDLE file = CreateFile(pchName, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
354
355 if( file == INVALID_HANDLE_VALUE )
356 {
357 app.FatalLoadError();
358 assert(false);
359 return;
360 }
361 DWORD dwFileSize = GetFileSize(file,NULL);
362 DWORD bytesRead = 0;
363 DWORD memFlags = MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_PHYSICAL);
364 void *pvSoundBank = XMemAlloc(dwFileSize, memFlags);
365 ReadFile(file,pvSoundBank,dwFileSize,&bytesRead,NULL);
366 CloseHandle(file);
367
368 if ( FAILED( hr = m_pXACT3Engine->CreateSoundBank( pvSoundBank, dwFileSize, XACT_FLAG_ENGINE_CREATE_MANAGEDATA, memFlags, ppSoundBank ) ) )
369 {
370 app.FatalLoadError();
371 assert(false);
372 return;
373 }
374}
375
376bool SoundEngine::isStreamingWavebankReady()
377{
378 if(m_bStreamingMusicReady==false)
379 {
380 DWORD dwState;
381 m_pSoundBank->GetState(&dwState);
382 if(dwState&XACT_WAVEBANKSTATE_PREPARED)
383 {
384 m_bStreamingWaveBank1Ready=true;
385 }
386 m_pSoundBank2->GetState(&dwState);
387 if(dwState&XACT_WAVEBANKSTATE_PREPARED)
388 {
389 m_bStreamingWaveBank2Ready=true;
390 }
391
392 if(m_bStreamingWaveBank1Ready && m_bStreamingWaveBank2Ready)
393 {
394 m_bStreamingMusicReady=true;
395 }
396 }
397
398 return m_bStreamingMusicReady;
399}
400
401#ifdef _XBOX
402bool SoundEngine::isStreamingWavebankReady(IXACT3WaveBank *pWaveBank)
403{
404 DWORD dwState;
405 pWaveBank->GetState(&dwState);
406 if(dwState&XACT_WAVEBANKSTATE_PREPARED)
407 {
408 return true;
409 }
410 else
411 {
412 return false;
413 }
414}
415#endif
416
417void SoundEngine::XACTNotificationCallback( const XACT_NOTIFICATION* pNotification )
418{
419 if(pNotification->pvContext!= NULL)
420 {
421 if(pNotification->type==XACTNOTIFICATIONTYPE_WAVEBANKPREPARED)
422 {
423 SoundEngine *pSoundEngine=(SoundEngine *)pNotification->pvContext;
424 if(pNotification->waveBank.pWaveBank==pSoundEngine->m_pStreamedWaveBank)
425 {
426 pSoundEngine->m_bStreamingWaveBank1Ready=true;
427 }
428 if(pNotification->waveBank.pWaveBank==pSoundEngine->m_pStreamedWaveBankAdditional)
429 {
430 pSoundEngine->m_bStreamingWaveBank2Ready=true;
431 }
432
433 if(pSoundEngine->m_bStreamingWaveBank1Ready && pSoundEngine->m_bStreamingWaveBank2Ready)
434 {
435 pSoundEngine->m_bStreamingMusicReady=true;
436 }
437 }
438 }
439}
440
441char *SoundEngine::ConvertSoundPathToName(const wstring& name, bool bConvertSpaces)
442{
443 static char buf[256];
444 assert(name.length()<256);
445 for(unsigned int i = 0; i < name.length(); i++ )
446 {
447 wchar_t c = name[i];
448 if(c=='.') c='_';
449 buf[i] = (char)c;
450 }
451 buf[name.length()] = 0;
452 return buf;
453}
454
455void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch)
456{
457 if(iSound==-1)
458 {
459 app.DebugPrintf(6,"PlaySound with sound of -1 !!!!!!!!!!!!!!!\n");
460 return;
461 }
462
463 bool bSoundbank1=(iSound<=eSoundType_STEP_SAND);
464
465 if( (m_pSoundBank == NULL ) || (m_pSoundBank2 == NULL))return;
466
467 if( currentSounds.size() > MAX_POLYPHONY )
468 {
469 return;
470 }
471 wstring name = wchSoundNames[iSound];
472 //const unsigned char *name=ucSoundNames[iSound];
473
474 char *xboxName = ConvertSoundPathToName(name);
475 XACTINDEX idx;
476
477 if(bSoundbank1)
478 {
479 idx = m_pSoundBank->GetCueIndex(xboxName);
480 }
481 else
482 {
483 idx = m_pSoundBank2->GetCueIndex(xboxName);
484 }
485
486 if( idx == XACTINDEX_INVALID )
487 {
488#ifndef _CONTENT_PACKAGE
489#ifdef _DEBUG
490 __debugbreak();
491#endif
492 //wprintf(L"WARNING: Sound cue not found - %ls\n", name.c_str() );
493 app.DebugPrintf("Not found: %s\n",xboxName);
494#endif
495 return;
496 }
497
498 // 4J-PB - check how many of this cue are already playing and ignore if there are loads
499 int iSameSoundC=0;
500 for( unsigned int i = 0; i < currentSounds.size(); i++ )
501 {
502 SoundEngine::soundInfo *info = currentSounds[i];
503
504 if((info->idx==idx) && (info->iSoundBank==(bSoundbank1?0:1)))
505 {
506 iSameSoundC++;
507 }
508 }
509
510 if(iSameSoundC>MAX_SAME_SOUNDS_PLAYING)
511 {
512 return;
513 }
514
515 IXACT3Cue *cueInstance;
516 HRESULT hr;
517 MemSect(31);
518
519 if(bSoundbank1)
520 {
521 if( FAILED( hr = m_pSoundBank->Prepare(idx, 0, 0, &cueInstance ) ) )
522 {
523 MemSect(0);
524 // printf("Sound prep failed\n");
525 return;
526 }
527 }
528 else
529 {
530 if( FAILED( hr = m_pSoundBank2->Prepare(idx, 0, 0, &cueInstance ) ) )
531 {
532 MemSect(0);
533 // printf("Sound prep failed\n");
534 return;
535 }
536 }
537
538 MemSect(0);
539
540 // Register to receive callbacks for cues stopping so we can keep a track of active sounds
541
542 soundInfo *info = new soundInfo();
543 info->idx = idx;
544 info->eSoundID = (eSOUND_TYPE)iSound;
545 info->iSoundBank = bSoundbank1?0:1;
546 info->x = x;
547 info->y = y;
548 info->z = z;
549 info->volume = volume;//*m_fSoundEffectsVolume;
550 info->pitch = pitch;
551 info->pCue = cueInstance;
552 info->updatePos = true;
553 EnterCriticalSection(&m_CS);
554 currentSounds.push_back(info);
555 LeaveCriticalSection(&m_CS);
556
557 XACTVARIABLEINDEX vidx = cueInstance->GetVariableIndex("Pitch");
558 if( vidx != XACTVARIABLEINDEX_INVALID )
559 {
560 // Convert pitch multiplier to semitones
561 float semiTones = (log(pitch)/log(2.0f)) * 12.0f;
562 cueInstance->SetVariable( vidx, semiTones );
563 }
564
565 update3DPosition(info);
566 cueInstance->Play();
567}
568
569void SoundEngine::playUI(int iSound, float, float)
570{
571 bool bSoundBank1=(iSound<=eSoundType_STEP_SAND);
572
573 if( (m_pSoundBank == NULL ) || (m_pSoundBank2 == NULL)) return;
574
575 if( currentSounds.size() > MAX_POLYPHONY )
576 {
577 return;
578 }
579 wstring name = wchSoundNames[iSound];
580
581 char *xboxName = (char *)ConvertSoundPathToName(name);
582
583 XACTINDEX idx = m_pSoundBank->GetCueIndex(xboxName);
584
585 if( idx == XACTINDEX_INVALID )
586 {
587 // check soundbank 2
588 idx = m_pSoundBank2->GetCueIndex(xboxName);
589 if( idx == XACTINDEX_INVALID )
590 {
591#ifndef _CONTENT_PACKAGE
592 printf("Not found UI: %s\n",xboxName);
593#endif
594 return;
595 }
596 bSoundBank1=false;
597 }
598
599 IXACT3Cue *cueInstance;
600 HRESULT hr;
601
602 if(bSoundBank1)
603 {
604 if( FAILED( hr = m_pSoundBank->Prepare(idx, 0, 0, &cueInstance ) ) )
605 {
606 // printf("Sound prep failed\n");
607 return;
608 }
609 }
610 else
611 {
612 if( FAILED( hr = m_pSoundBank2->Prepare(idx, 0, 0, &cueInstance ) ) )
613 {
614 // printf("Sound prep failed\n");
615 return;
616 }
617 }
618
619 // Add sound info just so we can detect end of this sound
620 soundInfo *info = new soundInfo();
621 info->eSoundID = (eSOUND_TYPE)0;
622 info->iSoundBank = bSoundBank1?0:1;
623 info->idx =idx;
624 info->x = 0.0f;
625 info->y = 0.0f;
626 info->z = 0.0f;
627 info->volume = 0.0f;
628 info->pitch = 0.0f;
629 info->pCue = cueInstance;
630 info->updatePos = false;
631 EnterCriticalSection(&m_CS);
632 currentSounds.push_back(info);
633 LeaveCriticalSection(&m_CS);
634
635 cueInstance->Play();
636}
637
638void SoundEngine::playStreaming(const wstring& name, float x, float y, float z, float vol, float pitch, bool bMusicDelay)
639{
640 IXACT3SoundBank *pSoundBank=NULL;
641
642 bool bSoundBank2=false;
643 MemSect(34);
644 if(m_MusicInfo.pCue!=NULL)
645 {
646 m_MusicInfo.pCue->Stop(0);
647 m_MusicInfo.pCue->Destroy();
648 m_MusicInfo.pCue = NULL;
649 }
650
651 m_MusicInfo.volume = 1.0f;//m_fMusicVolume;
652 m_MusicInfo.pitch = 1.0f;
653
654 SetIsPlayingEndMusic(false);
655 SetIsPlayingNetherMusic(false);
656
657 if(name.empty())
658 {
659 SetIsPlayingStreamingCDMusic(false);
660 SetIsPlayingStreamingGameMusic(false);// will be set to true when the sound is started in the tick
661 if(bMusicDelay)
662 {
663 noMusicDelay = random->nextInt(20 * 60 * 10) + 20 * 60 * 10;
664 }
665 else
666 {
667 noMusicDelay=0;
668 }
669 // Check if we have a local player in The Nether or in The End, and play that music if they are
670 Minecraft *pMinecraft=Minecraft::GetInstance();
671 bool playerInEnd=false;
672 bool playerInNether=false;
673
674 for(unsigned int i=0;i<XUSER_MAX_COUNT;i++)
675 {
676 if(pMinecraft->localplayers[i]!=NULL)
677 {
678 if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END)
679 {
680 playerInEnd=true;
681 }
682 else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER)
683 {
684 playerInNether=true;
685 }
686 }
687 }
688 TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected();
689
690 if(Minecraft::GetInstance()->skins->isUsingDefaultSkin() || pTexPack->hasAudio()==false)
691 {
692 if(playerInEnd || playerInNether)
693 {
694 pSoundBank=m_pSoundBank2;
695 }
696 else
697 {
698 pSoundBank=m_pSoundBank;
699 }
700 }
701 else
702 {
703 // get the dlc texture pack
704 DLCTexturePack *pDLCTexPack=(DLCTexturePack *)pTexPack;
705 pSoundBank=pDLCTexPack->m_pSoundBank;
706
707 // check we can play the sound
708 if(isStreamingWavebankReady(pDLCTexPack->m_pStreamedWaveBank)==false)
709 {
710 return;
711 }
712 }
713
714 if(playerInEnd)
715 {
716 m_musicIDX = pSoundBank->GetCueIndex("the_end_dragon");
717 SetIsPlayingEndMusic(true);
718 bSoundBank2=true;
719 }
720 else if(playerInNether)
721 {
722 m_musicIDX = pSoundBank->GetCueIndex("nether");
723 SetIsPlayingNetherMusic(true);
724 bSoundBank2=true;
725 }
726 else
727 {
728 m_musicIDX = pSoundBank->GetCueIndex("music");
729 }
730 }
731 else
732 {
733 pSoundBank=m_pSoundBank;
734 SetIsPlayingStreamingCDMusic(true);
735 SetIsPlayingStreamingGameMusic(false);
736
737 m_musicIDX = pSoundBank->GetCueIndex(ConvertSoundPathToName(name));
738 }
739
740 HRESULT hr;
741
742 if( FAILED( hr = pSoundBank->Prepare(m_musicIDX, 0, 0, &m_MusicInfo.pCue ) ) )
743 {
744 // printf("Sound prep failed\n");
745 m_musicIDX = XACTINDEX_INVALID; // don't do anything in the tick
746 m_MusicInfo.pCue=NULL;
747 MemSect(0);
748 return;
749 }
750
751
752 if(GetIsPlayingStreamingCDMusic())
753 {
754 m_MusicInfo.x = x;
755 m_MusicInfo.y = y;
756 m_MusicInfo.z = z;
757 m_MusicInfo.updatePos = true;
758 update3DPosition(&m_MusicInfo, false);
759 m_MusicInfo.pCue->Play();
760 }
761 else
762 {
763 // don't play the game music - it will start playing in the tick when noMusicDelay is 0
764
765 m_MusicInfo.x = 0.0f; // will be overridden by the bPlaceEmitterAtListener
766 m_MusicInfo.y = 0.0f; // will be overridden by the bPlaceEmitterAtListener
767 m_MusicInfo.z = 0.0f; // will be overridden by the bPlaceEmitterAtListener
768 m_MusicInfo.updatePos = false;
769
770 update3DPosition(&m_MusicInfo, true);
771 }
772
773 MemSect(0);
774}
775void SoundEngine::playMusicTick()
776{
777 if( (m_pSoundBank == NULL ) || (m_pSoundBank2 == NULL)) return;
778
779 if( m_musicIDX == XACTINDEX_INVALID )
780 {
781 // printf("Not found music\n");
782 return;
783 }
784
785 // check to see if the sound has stopped playing
786 DWORD state;
787 HRESULT hr;
788 if(m_MusicInfo.pCue!=NULL)
789 {
790 if( FAILED( hr = m_MusicInfo.pCue->GetState(&state) ) )
791 {
792 assert(false);
793 }
794 else
795 {
796 if( state == XACT_CUESTATE_STOPPED )
797 {
798 // remove the sound and reset the music
799 playStreaming(L"", 0, 0, 0, 0, 0);
800 return;
801 }
802 }
803 }
804
805 if(GetIsPlayingStreamingGameMusic())
806 {
807 if(m_MusicInfo.pCue!=NULL)
808 {
809 bool playerInEnd = false;
810 bool playerInNether=false;
811 Minecraft *pMinecraft = Minecraft::GetInstance();
812 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i)
813 {
814 if(pMinecraft->localplayers[i]!=NULL)
815 {
816 if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END)
817 {
818 playerInEnd=true;
819 }
820 else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER)
821 {
822 playerInNether=true;
823 }
824 }
825 }
826
827 if((playerInEnd && !GetIsPlayingEndMusic()) ||(!playerInEnd && GetIsPlayingEndMusic()))
828 {
829 // remove the sound and reset the music
830 playStreaming(L"", 0, 0, 0, 0, 0);
831 }
832 else if ((playerInNether && !GetIsPlayingNetherMusic()) ||(!playerInNether && GetIsPlayingNetherMusic()))
833 {
834 // remove the sound and reset the music
835 playStreaming(L"", 0, 0, 0, 0, 0);
836 }
837 }
838 // not positional so doesn't need ticked
839 return;
840 }
841
842 // is this cd music? If so, we need to tick it
843 if(GetIsPlayingStreamingCDMusic())
844 {
845 update3DPosition(&m_MusicInfo, false, true);
846 }
847 else
848 {
849 if (noMusicDelay > 0)
850 {
851 noMusicDelay--;
852 return;
853 }
854
855 if(m_MusicInfo.pCue!=NULL)
856 {
857 update3DPosition(&m_MusicInfo, true);
858 SetIsPlayingStreamingGameMusic(true);
859 // and play the game music here
860 m_MusicInfo.pCue->Play();
861 }
862 }
863}
864
865void SoundEngine::updateMusicVolume(float fVal)
866{
867 XACTVOLUME xactVol=fVal;
868 HRESULT hr=m_pXACT3Engine->SetVolume(m_xactMusic,fVal);
869}
870
871void SoundEngine::updateSystemMusicPlaying(bool isPlaying)
872{
873}
874
875void SoundEngine::updateSoundEffectVolume(float fVal)
876{
877 XACTVOLUME xactVol=fVal;
878 HRESULT hr=m_pXACT3Engine->SetVolume(m_xactSFX,fVal);
879}
880
881void SoundEngine::update3DPosition(SoundEngine::soundInfo *pInfo, bool bPlaceEmitterAtListener,bool bIsCDMusic)
882{
883 X3DAUDIO_LISTENER *listener = &m_listeners[0]; // Default case for single listener
884
885 if( ( m_validListenerCount > 1 ) && !bPlaceEmitterAtListener )
886 {
887 // More than one listener. Find out which one is closest
888 float nearDistSq = ( listener->Position.x - pInfo->x ) * ( listener->Position.x - pInfo->x ) +
889 ( listener->Position.y - pInfo->y ) * ( listener->Position.y - pInfo->y ) +
890 ( listener->Position.z + pInfo->z ) * ( listener->Position.z + pInfo->z );
891
892 for( int i = 1; i < m_validListenerCount; i++ )
893 {
894 float distSq = ( m_listeners[i].Position.x - pInfo->x ) * ( m_listeners[i].Position.x - pInfo->x ) +
895 ( m_listeners[i].Position.y - pInfo->y ) * ( m_listeners[i].Position.y - pInfo->y ) +
896 ( m_listeners[i].Position.z + pInfo->z ) * ( m_listeners[i].Position.z + pInfo->z );
897 if( distSq < nearDistSq )
898 {
899 listener = &m_listeners[i];
900 nearDistSq = distSq;
901 }
902 }
903
904 // More than one listener, don't do directional sounds - point our listener towards the sound
905 float xzDist = sqrtf( ( listener->Position.x - pInfo->x ) * ( listener->Position.x - pInfo->x ) +
906 ( listener->Position.z + pInfo->z ) * ( listener->Position.z + pInfo->z ) );
907 // Don't orientate if its too near to work out a distance
908 if( xzDist > 0.001f)
909 {
910 listener->OrientFront.x = ( pInfo->x - listener->Position.x ) / xzDist;
911 listener->OrientFront.y = 0.0f;
912 listener->OrientFront.z = ( - pInfo->z - listener->Position.z ) / xzDist;
913 }
914 }
915
916 if(bPlaceEmitterAtListener)
917 {
918 m_emitter.Position.x = listener->Position.x;
919 m_emitter.Position.y = listener->Position.y;
920 m_emitter.Position.z = listener->Position.z;
921 }
922 else
923 {
924 // Update the position of the emitter - we aren't dynamically changing anything else
925 m_emitter.Position.x = pInfo->x;
926 m_emitter.Position.y = pInfo->y;
927 m_emitter.Position.z = -pInfo->z; // Flipped sign of z as x3daudio is expecting left handed coord system
928 }
929
930 // If this is the CD music, then make the distance scaler 4 x normal
931 if(bIsCDMusic)
932 {
933 m_emitter.CurveDistanceScaler=64.0f;
934 }
935 else
936 {
937 switch(pInfo->eSoundID)
938 {
939 // Is this the Dragon?
940 case eSoundType_MOB_ENDERDRAGON_GROWL:
941 case eSoundType_MOB_ENDERDRAGON_MOVE:
942 case eSoundType_MOB_ENDERDRAGON_END:
943 case eSoundType_MOB_ENDERDRAGON_HIT:
944 m_emitter.CurveDistanceScaler=100.0f;
945 break;
946 case eSoundType_MOB_GHAST_MOAN:
947 case eSoundType_MOB_GHAST_SCREAM:
948 case eSoundType_MOB_GHAST_DEATH:
949 case eSoundType_MOB_GHAST_CHARGE:
950 case eSoundType_MOB_GHAST_FIREBALL:
951 m_emitter.CurveDistanceScaler=30.0f;
952 break;
953 }
954 }
955
956 // 10000.0f is passed as the volume for thunder... treat this as a special case, and use a volume curve that doesn't decay with distance
957 // rather than just trying to guess at making something really really loud...
958 if( pInfo->volume == 10000.0f )
959 {
960 m_emitter.pVolumeCurve = &m_VolumeCurveNoDecay;
961 }
962 else
963 {
964 m_emitter.pVolumeCurve = &m_VolumeCurve;
965 }
966
967 // Calculate all the 3D things
968 XACT3DCalculate( m_xact3dInstance, listener, &m_emitter, &m_DSPSettings );
969
970 // Put volume curve back to default in case something else is depending on this
971 m_emitter.pVolumeCurve = &m_VolumeCurve;
972 //m_emitter.pLFECurve = &m_VolumeCurve;
973 m_emitter.CurveDistanceScaler=16.0f;
974 // Apply our general volume too by scaling the calculated coefficients - so long as this isn't our special case of 10000.0f (see comment above)
975 if( pInfo->volume != 10000.0f )
976 {
977 for(unsigned int i = 0; i < m_DSPSettings.DstChannelCount; i++ )
978 {
979 m_DSPSettings.pMatrixCoefficients[i] *= pInfo->volume;
980 }
981 }
982
983 // Finally apply to the cue
984 XACT3DApply( &m_DSPSettings, pInfo->pCue);
985}
986
987void SoundEngine::tick(shared_ptr<Mob> *players, float a)
988{
989 if( m_pXACT3Engine == NULL ) return;
990
991 // Creater listener array from the local players
992 int listenerCount = 0;
993 bool doPosUpdate = true;
994 if( players )
995 {
996 for( int i = 0; i < 4; i++ )
997 {
998 if( players[i] != NULL )
999 {
1000 float yRot = players[i]->yRotO + (players[i]->yRot - players[i]->yRotO) * a;
1001
1002 m_listeners[listenerCount].Position.x = (float) (players[i]->xo + (players[i]->x - players[i]->xo) * a);
1003 m_listeners[listenerCount].Position.y = (float) (players[i]->yo + (players[i]->y - players[i]->yo) * a);
1004 m_listeners[listenerCount].Position.z = -(float) (players[i]->zo + (players[i]->z - players[i]->zo) * a); // Flipped sign of z as x3daudio is expecting left handed coord system
1005
1006 float yCos = (float)cos(-yRot * Mth::RAD_TO_GRAD - PI);
1007 float ySin = (float)sin(-yRot * Mth::RAD_TO_GRAD - PI);
1008
1009 m_listeners[listenerCount].OrientFront.x = -ySin;
1010 m_listeners[listenerCount].OrientFront.y = 0;
1011 m_listeners[listenerCount].OrientFront.z = yCos; // Flipped sign of z as x3daudio is expecting left handed coord system
1012
1013 listenerCount++;
1014 }
1015 }
1016 }
1017 // If there were no valid players set, make up a default listener
1018 if( listenerCount == 0 )
1019 {
1020 doPosUpdate = false; // Don't bother updating positions of sounds already placed
1021 m_listeners[listenerCount].Position.x = 0;
1022 m_listeners[listenerCount].Position.y = 0;
1023 m_listeners[listenerCount].Position.z = 0;
1024 m_listeners[listenerCount].OrientFront.x = 0;
1025 m_listeners[listenerCount].OrientFront.y = 0;
1026 m_listeners[listenerCount].OrientFront.z = 1.0f;
1027 listenerCount++;
1028 }
1029 m_validListenerCount = listenerCount;
1030
1031 EnterCriticalSection(&m_CS);
1032 for( unsigned int i = 0; i < currentSounds.size(); i++ )
1033 {
1034 SoundEngine::soundInfo *info = currentSounds[i];
1035
1036 DWORD state;
1037 HRESULT hr;
1038 if( FAILED( hr = info->pCue->GetState(&state) ) )
1039 {
1040 assert(false);
1041 }
1042 else
1043 {
1044 if( state == XACT_CUESTATE_STOPPED )
1045 {
1046 info->pCue->Destroy();
1047 delete currentSounds[i];
1048 currentSounds[i] = currentSounds.back();
1049 currentSounds.pop_back();
1050 }
1051 else
1052 {
1053 if( info->updatePos )
1054 {
1055 if( doPosUpdate )
1056 {
1057 update3DPosition(info);
1058 }
1059 }
1060 }
1061 }
1062 }
1063
1064 LeaveCriticalSection(&m_CS);
1065 m_pXACT3Engine->DoWork();
1066}
1067
1068void SoundEngine::add(const wstring& name, File *file)
1069{
1070}
1071
1072void SoundEngine::addMusic(const wstring& name, File *file)
1073{
1074}
1075
1076void SoundEngine::addStreaming(const wstring& name, File *file)
1077{
1078}