Sound Buffer.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. All 'SoundBuffer' methods (and thus Sound API) are called only by Sound Threads,
  6. they manage the Locking, so we don't need to do any locks here,
  7. therefore SOUND_API_LOCK_WEAK is marked as an empty macro.
  8. /******************************************************************************/
  9. #define SOUND_API_LOCK_FORCE SyncLocker locker(SoundAPILock);
  10. #define SOUND_API_LOCK_WEAK //SOUND_API_LOCK_FORCE not needed
  11. #define OPERATION_SET (!XAUDIO2_COMMIT_NOW) // make sure that this is not XAUDIO2_COMMIT_NOW
  12. #define DIRECT_SOUND_RANGE_SCALE 1.75f // this was tested by playing sound at different positions (1,0,0), (2,0,0), (4,0,0) with range 1 and comparing recorded volume to XAudio version
  13. #define OPEN_AL_RANGE_SCALE 0.75f // this was tested by playing sound at different positions (1,0,0), (2,0,0), (4,0,0) with range 1 and comparing recorded volume to XAudio version
  14. #if DIRECT_SOUND
  15. static IDirectSound *DS;
  16. static IDirectSound3DListener *DSL;
  17. static VIRTUALIZATION_MODE Virtualization=VIRT_HIGH;
  18. #elif XAUDIO
  19. IXAudio2 *XAudio;
  20. static IXAudio2MasteringVoice *XAudioMasteringVoice;
  21. static X3DAUDIO_HANDLE X3DAudio;
  22. static X3DAUDIO_LISTENER X3DListener;
  23. static Int XAudioChannels;
  24. #elif OPEN_AL
  25. static ALCcontext *ALContext;
  26. static ALCdevice *ALDevice;
  27. #elif OPEN_SL
  28. static SLObjectItf SLEngineObject;
  29. static SLEngineItf SLEngineEngine;
  30. static SLObjectItf SLOutputMixObject;
  31. static SLEnvironmentalReverbItf SLOutputMixEnvironmentalReverb;
  32. static SLObjectItf SLListenerObject;
  33. static SL3DLocationItf SLListenerLocation;
  34. static SL3DDopplerItf SLListenerDoppler;
  35. static SL3DCommitItf SLListenerCommit;
  36. #define SL_POS_UNIT 0.001f // milimeter
  37. #endif
  38. Bool SoundAPI, SoundFunc;
  39. ListenerClass Listener;
  40. /******************************************************************************/
  41. void SoundBuffer::zero()
  42. {
  43. _par.zero();
  44. #if DIRECT_SOUND
  45. _lock_data=null;
  46. _lock_size=0;
  47. _s =null;
  48. _s3d =null;
  49. #elif XAUDIO
  50. _sv=null;
  51. _3d=false;
  52. #elif OPEN_AL
  53. _3d=false;
  54. _source=0;
  55. _buffer[0]=_buffer[1]=0;
  56. #elif OPEN_SL
  57. _3d =false;
  58. _processed =0;
  59. _volume=_range =1;
  60. _pos .zero();
  61. player_object =null;
  62. player_play =null;
  63. player_volume =null;
  64. player_playback_rate=null;
  65. player_buffer_queue =null;
  66. player_location =null;
  67. player_doppler =null;
  68. player_source =null;
  69. #endif
  70. }
  71. SoundBuffer::SoundBuffer() {zero();}
  72. /******************************************************************************/
  73. void SoundBuffer::del()
  74. {
  75. SOUND_API_LOCK_WEAK;
  76. stop();
  77. #if DIRECT_SOUND
  78. if(DS)
  79. {
  80. RELEASE(_s3d);
  81. RELEASE(_s );
  82. }
  83. #elif XAUDIO
  84. if(XAudio)
  85. {
  86. if(_sv)_sv->DestroyVoice();
  87. }
  88. _data.del(); // delete the buffer after '_sv'
  89. #elif OPEN_AL
  90. if(ALContext)
  91. {
  92. if(_source )alDeleteSources(1, &_source );
  93. if(_buffer[0])alDeleteBuffers(1, &_buffer[0]);
  94. if(_buffer[1])alDeleteBuffers(1, &_buffer[1]);
  95. }
  96. #elif OPEN_SL
  97. if(SLOutputMixObject)
  98. {
  99. if(player_object)(*player_object)->Destroy(player_object);
  100. }
  101. _data.del(); // delete the buffer after 'player_object'
  102. #endif
  103. zero();
  104. }
  105. /******************************************************************************/
  106. #if XAUDIO
  107. /*static struct XAudioVoiceCallback : IXAudio2VoiceCallback
  108. {
  109. virtual void OnVoiceProcessingPassStart(UINT32 BytesRequired)override {}
  110. virtual void OnVoiceProcessingPassEnd()override {}
  111. virtual void OnStreamEnd()override {}
  112. virtual void OnBufferStart(Ptr user)override {}
  113. virtual void OnBufferEnd(Ptr user)override {}
  114. virtual void OnLoopEnd(Ptr user)override {}
  115. virtual void OnVoiceError(Ptr user, HRESULT error)override {}
  116. }XAVC;*/
  117. #elif OPEN_SL
  118. static void PlayerCallback(SLAndroidSimpleBufferQueueItf buffer_queue, void *context)
  119. {
  120. if(SoundBuffer *buffer=(SoundBuffer*)context)
  121. {
  122. AtomicInc(buffer->_processed);
  123. }
  124. }
  125. #endif
  126. void SoundBuffer::memAddressChanged() // !! can't be called when the SoundBuffer is playing/paused !! this is a special case which should handle locking !! because it's rarely called and should lock only when needed
  127. {
  128. #if OPEN_SL
  129. if(player_buffer_queue)
  130. {
  131. SOUND_API_LOCK_FORCE;
  132. (*player_buffer_queue)->RegisterCallback(player_buffer_queue, PlayerCallback, this); // !! this can be changed only in SL_PLAYSTATE_STOPPED state !! https://www.khronos.org/registry/sles/specs/OpenSL_ES_Specification_1.0.1.pdf
  133. }
  134. #endif
  135. }
  136. Bool SoundBuffer::create(Int frequency, Int bits, Int channels, Int samples, Bool is3D)
  137. {
  138. del();
  139. if(SoundAPI && frequency>=1 && (bits==8 || bits==16 || bits==24) && (channels>=1 && channels<=2) && samples>0)
  140. {
  141. C Int bytes=bits/8;
  142. #if OPEN_AL
  143. if(is3D)channels=1; // OpenAL supports only mono 3D
  144. #endif
  145. _par.frequency=frequency;
  146. _par.bytes =bytes;
  147. _par.channels =channels;
  148. _par.block =channels*bytes;
  149. _par.bit_rate =channels*bits*frequency;
  150. _par.size =_par.block*samples;
  151. #if DIRECT_SOUND || XAUDIO
  152. WAVEFORMATEX wf; Zero(wf);
  153. wf.wFormatTag =WAVE_FORMAT_PCM;
  154. wf.nChannels =channels;
  155. wf.nSamplesPerSec =frequency;
  156. wf.wBitsPerSample =bits;
  157. wf.nBlockAlign =_par.block;
  158. wf.nAvgBytesPerSec=_par.block*frequency;
  159. #endif
  160. #if DIRECT_SOUND
  161. DSBUFFERDESC dsbd; Zero(dsbd);
  162. dsbd.dwSize =SIZE(DSBUFFERDESC);
  163. dsbd.dwFlags =(is3D ? DSBCAPS_CTRL3D : DSBCAPS_CTRLPAN)|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY|DSBCAPS_STATIC|((App.flag&APP_WORK_IN_BACKGROUND) ? DSBCAPS_GLOBALFOCUS : 0);
  164. dsbd.dwBufferBytes=_par.size;
  165. dsbd.lpwfxFormat =&wf;
  166. SOUND_API_LOCK_WEAK;
  167. Bool ok=false;
  168. if(!is3D)ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));else
  169. {
  170. if(!ok && Virtualization>=VIRT_HIGH){dsbd.guid3DAlgorithm=DS3DALG_HRTF_FULL ; ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));}
  171. if(!ok && Virtualization>=VIRT_LOW ){dsbd.guid3DAlgorithm=DS3DALG_HRTF_LIGHT ; ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));}
  172. if(!ok && Virtualization>=VIRT_NONE){dsbd.guid3DAlgorithm=DS3DALG_NO_VIRTUALIZATION; ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));}
  173. if( ok && !OK(_s->QueryInterface(IID_IDirectSound3DBuffer, (Ptr*)&_s3d)))ok=false;
  174. }
  175. if(ok)return true;
  176. #elif XAUDIO
  177. SOUND_API_LOCK_WEAK;
  178. if(OK(XAudio->CreateSourceVoice(&_sv, &wf, 0, MAX_SOUND_SPEED/*, &XAVC*/)))
  179. {
  180. _3d=is3D; // if sound will be 3 dimensional
  181. _data.setNum(_par.size); // allocate total buffer size to have memory for sound data, XAudio needs it constantly during playback - "but the actual audio data referenced by pBuffer must remain valid until the buffer has been fully consumed by XAudio2 (which is indicated by the IXAudio2VoiceCallback::OnBufferEnd callback)" https://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.ixaudio2sourcevoice.ixaudio2sourcevoice.submitsourcebuffer(v=vs.85).aspx
  182. return true;
  183. }
  184. #elif OPEN_AL
  185. if(frequency<=192000)
  186. {
  187. SOUND_API_LOCK_WEAK;
  188. alGenBuffers(Elms(_buffer), _buffer);
  189. alGenSources( 1, &_source);
  190. _3d=is3D; // if sound will be 3 dimensional
  191. if(!_3d)alSourcei(_source, AL_SOURCE_RELATIVE, true); // 2d sounds are relative to listener
  192. return true;
  193. }
  194. #elif OPEN_SL
  195. if(frequency<=192000)
  196. {
  197. ASSERT(SL_SAMPLINGRATE_48==48000000); // verify the scale
  198. Bool try3D=(is3D && SLListenerLocation);
  199. SLDataLocator_AndroidSimpleBufferQueue buffer_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
  200. SLDataFormat_PCM format_pcm ={SL_DATAFORMAT_PCM, SLuint32(channels), SLuint32(frequency*1000), SLuint32(bits), SLuint32(bits), (channels==2) ? SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT : SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};
  201. SLDataSource audio_src ={&buffer_queue, &format_pcm};
  202. SLDataLocator_OutputMix output_mix ={SL_DATALOCATOR_OUTPUTMIX, SLOutputMixObject};
  203. SLDataSink audio_sink ={&output_mix, null};
  204. // Asus Transformer Prime and TF300 have buggy OpenSL implementation (specifying SL_BOOLEAN_FALSE for 'required' will always fail even if the interface is available), we need to always try using SL_BOOLEAN_TRUE for required
  205. REPD(t3 , try3D ? 2 : 1)
  206. REPD(vol , 2)
  207. REPD(speed, 2)
  208. {
  209. SLInterfaceID ids []={SL_IID_BUFFERQUEUE, SL_IID_VOLUME , SL_IID_PLAYBACKRATE };
  210. SLboolean required []={SL_BOOLEAN_TRUE , vol ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE, speed ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE};
  211. SLInterfaceID ids3D []={SL_IID_BUFFERQUEUE, SL_IID_VOLUME , SL_IID_PLAYBACKRATE , SL_IID_3DLOCATION, SL_IID_3DSOURCE/*, SL_IID_3DDOPPLER*/}; // don't create doppler to increase performance
  212. SLboolean required3D[]={SL_BOOLEAN_TRUE , vol ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE, speed ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE, SL_BOOLEAN_TRUE , SL_BOOLEAN_TRUE/*, SL_BOOLEAN_FALSE*/};
  213. SOUND_API_LOCK_WEAK;
  214. if((*SLEngineEngine )->CreateAudioPlayer(SLEngineEngine, &player_object, &audio_src, &audio_sink, t3 ? Elms(ids3D) : Elms(ids), t3 ? ids3D : ids, t3 ? required3D : required)==SL_RESULT_SUCCESS)
  215. if((*player_object )->Realize (player_object, SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
  216. if((*player_object )->GetInterface (player_object, SL_IID_PLAY , &player_play )==SL_RESULT_SUCCESS)
  217. if((*player_object )->GetInterface (player_object, SL_IID_BUFFERQUEUE, &player_buffer_queue)==SL_RESULT_SUCCESS)
  218. if((*player_buffer_queue)->RegisterCallback (player_buffer_queue, PlayerCallback, this )==SL_RESULT_SUCCESS)
  219. {
  220. _3d=is3D; // if sound will be 3 dimensional
  221. _data.setNum(_par.size); // allocate total buffer size to have memory for sound data, OpenSL needs it constantly during playback, this was tested, after calling 'Enqueue' the data was zeroed, which resulted in no sound being played, which means that as long as the sound is playing, the buffer data must be present
  222. (*player_object)->GetInterface(player_object, SL_IID_VOLUME , &player_volume ); // this is optional
  223. (*player_object)->GetInterface(player_object, SL_IID_PLAYBACKRATE, &player_playback_rate); // this is optional
  224. if(t3)(*player_object)->GetInterface(player_object, SL_IID_3DLOCATION , &player_location ); // this is optional
  225. if(t3)(*player_object)->GetInterface(player_object, SL_IID_3DSOURCE , &player_source ); // this is optional
  226. if(t3)(*player_object)->GetInterface(player_object, SL_IID_3DDOPPLER , &player_doppler ); // this is optional
  227. if(_3d && !player_location && player_volume) // if should be 3D but not available, then volume will be adjusted manually
  228. (*player_volume)->EnableStereoPosition(player_volume, SL_BOOLEAN_TRUE); // enable stereo panning
  229. return true;
  230. }
  231. }
  232. }
  233. #endif
  234. del();
  235. }
  236. return false;
  237. }
  238. /******************************************************************************/
  239. #if DIRECT_SOUND
  240. Bool SoundBuffer::lock(Int pos, Int size)
  241. {
  242. if(_s && !_lock_data)
  243. {
  244. if(size<0)size=_par.size-pos;
  245. DWORD dw; SOUND_API_LOCK_WEAK; if(OK(_s->Lock(pos, size, &_lock_data, &dw, null, null, 0))){_lock_size=dw; return true;}
  246. _lock_data=null;
  247. _lock_size=0;
  248. }
  249. return false;
  250. }
  251. void SoundBuffer::unlock()
  252. {
  253. if(_s && _lock_data)
  254. {
  255. SOUND_API_LOCK_WEAK; _s->Unlock(_lock_data, _lock_size, null, 0);
  256. _lock_data=null;
  257. _lock_size=0;
  258. }
  259. }
  260. #endif
  261. /******************************************************************************/
  262. #if DIRECT_SOUND
  263. Bool SoundBuffer::is ()C {return _s !=null;}
  264. Bool SoundBuffer::is3D()C {return _s3d!=null;}
  265. #elif XAUDIO
  266. Bool SoundBuffer::is ()C {return _sv!=null;}
  267. Bool SoundBuffer::is3D()C {return _3d ;}
  268. #elif OPEN_AL
  269. Bool SoundBuffer::is ()C {return _source!=0;}
  270. Bool SoundBuffer::is3D()C {return _3d ;}
  271. #elif OPEN_SL
  272. Bool SoundBuffer::is ()C {return player_object!=null;}
  273. Bool SoundBuffer::is3D()C {return _3d ;}
  274. #else
  275. Bool SoundBuffer::is ()C {return false;}
  276. Bool SoundBuffer::is3D()C {return false;}
  277. #endif
  278. /******************************************************************************/
  279. void SoundBuffer::raw(Int raw)
  280. {
  281. #if DIRECT_SOUND
  282. if(_s){SOUND_API_LOCK_WEAK; _s->SetCurrentPosition(raw);}
  283. #elif XAUDIO
  284. // XAudio does not support setting buffer position
  285. #elif OPEN_AL
  286. if(_source){SOUND_API_LOCK_WEAK; alSourcei(_source, AL_BYTE_OFFSET, raw);}
  287. #elif OPEN_SL
  288. // OpenSL does not support setting buffer position
  289. #endif
  290. }
  291. Int SoundBuffer::raw()C
  292. {
  293. #if DIRECT_SOUND
  294. if(_s){DWORD play=0, write=0; SOUND_API_LOCK_WEAK; if(OK(_s->GetCurrentPosition(&play, &write)))return play;}
  295. #elif XAUDIO
  296. if(_sv)
  297. {
  298. SOUND_API_LOCK_WEAK; XAUDIO2_VOICE_STATE state;
  299. #if WINDOWS_OLD
  300. _sv->GetState(&state);
  301. #else
  302. _sv->GetState(&state, 0);
  303. #endif
  304. return (state.SamplesPlayed*_par.block)%_par.size;
  305. }
  306. #elif OPEN_AL
  307. if(_source){Int raw=0; SOUND_API_LOCK_WEAK; alGetSourcei(_source, AL_BYTE_OFFSET, &raw); return raw;}
  308. #elif OPEN_SL
  309. if(player_play && _par.block && _par.frequency)
  310. {
  311. SLmillisecond time=0;
  312. SOUND_API_LOCK_WEAK;
  313. if((*player_play)->GetPosition(player_play, &time)==SL_RESULT_SUCCESS) // this will be in range 0..Inf (not to 0..buffer_time, because of that we need to do mod)
  314. //if(UInt buffer_time=_par.size/_par.block*1000/_par.frequency) // length of sound buffer in milliseconds, this is useless because this is an approximation due to integer division losing fraction
  315. return (U64(time)*_par.frequency/1000*_par.block)%_par.size; // need to convert to U64 so we won't overflow, mul by block at the end to make sure that this is a multiple of block
  316. }
  317. #endif
  318. return 0;
  319. }
  320. /******************************************************************************/
  321. void SoundBuffer::pan(Flt pan) // 'pan' should be in range -1..1
  322. {
  323. #if DIRECT_SOUND
  324. if(_s){SOUND_API_LOCK_WEAK; _s->SetPan(Round(pan*DSBPAN_RIGHT));} ASSERT(-(DSBPAN_LEFT)==DSBPAN_RIGHT);
  325. #elif XAUDIO
  326. if(_sv){Flt vols[]={Sat(1-pan), Sat(1+pan)}; SOUND_API_LOCK_WEAK; _sv->SetChannelVolumes(2, vols, OPERATION_SET);}
  327. #elif OPEN_AL
  328. //if(_source && !_3d){SOUND_API_LOCK_WEAK; alSource3f(_source, AL_POSITION, pan, 0, 0);} this is not smooth and does not work for stereo sounds
  329. #elif OPEN_SL
  330. if(player_volume){SOUND_API_LOCK_WEAK; (*player_volume)->SetStereoPosition(player_volume, Round(pan*1000));} // will work only if 'EnableStereoPosition' was called
  331. #endif
  332. }
  333. #if OPEN_SL
  334. Bool SoundBuffer::emulate3D()
  335. {
  336. if(_3d && !player_location && player_volume) // if should be 3D, but it's not available, then adjust volume manually
  337. {
  338. Vec delta =_pos-Listener.pos();
  339. Flt dist =delta.length(),
  340. volume=T._volume;
  341. if( dist>_range)volume*=_range/dist;
  342. if( dist> 1)delta /=dist; // normalize only if the length is greater than 1 so that we can still have panning when the distance is less than 1
  343. Flt pan=Dot(delta, Listener.right());
  344. SOUND_API_LOCK_WEAK;
  345. T.pan(pan);
  346. SLmillibel linear=Max(SL_MILLIBEL_MIN, Round(Lerp(-10000, 0, Pow(volume, 0.1f)))); // this matches DirectSound version and sounds ok
  347. (*player_volume)->SetVolumeLevel(player_volume, linear);
  348. return true;
  349. }
  350. return false;
  351. }
  352. #endif
  353. void SoundBuffer::volume(Flt volume) // 'volume' should be in range 0..1
  354. {
  355. #if DIRECT_SOUND
  356. if(_s)
  357. {
  358. if(_s3d)volume/=_par.channels; // 3D stereo sounds will play at different volumes than 3D mono, so adjust, do this here and not in 'range' because there we can affect volumes only outside of 'range' and not inside
  359. Int linear=Round(Lerp(DSBVOLUME_MIN, DSBVOLUME_MAX, Pow(volume, 0.1f)));
  360. SOUND_API_LOCK_WEAK; _s->SetVolume(linear);
  361. }
  362. #elif XAUDIO
  363. if(_sv)
  364. {
  365. if(_3d)volume/=_par.channels; // 3D stereo sounds will play at different volumes than 3D mono, so adjust, do this here and not in 'range' because there we can affect volumes only outside of 'range' and not inside (we could adjust the 'dsp.pMatrixCoefficients' however it has much more elements that just one volume, and most likely 'setParams' will be called very frequently, while 'volume' not so much)
  366. SOUND_API_LOCK_WEAK; _sv->SetVolume(volume, OPERATION_SET);
  367. }
  368. #elif OPEN_AL
  369. if(_source){SOUND_API_LOCK_WEAK; alSourcef(_source, AL_GAIN, volume);}
  370. #elif OPEN_SL
  371. if(player_volume)
  372. {
  373. T._volume=volume;
  374. if(!emulate3D()) // if not emulating 3D
  375. {
  376. SLmillibel linear=Max(SL_MILLIBEL_MIN, Round(Lerp(-10000, 0, Pow(T._volume, 0.1f)))); // this matches DirectSound version and sounds ok
  377. SOUND_API_LOCK_WEAK; (*player_volume)->SetVolumeLevel(player_volume, linear);
  378. }
  379. }
  380. #endif
  381. }
  382. #if XAUDIO
  383. static Flt ChannelAzimuths[16]; // all zeros
  384. void SoundBuffer::setParams(C _Sound &sound, Bool pos_range, Bool doppler)
  385. {
  386. if(_sv)
  387. {
  388. MemtN<Flt, 2*8*4> matrix; // default channels for a sound = 1..2, max supported number of speakers = 8, mul by 4 for safety
  389. X3DAUDIO_EMITTER emitter;
  390. X3DAUDIO_DSP_SETTINGS dsp;
  391. UInt flag=0;
  392. if(pos_range) // !! process this first because of "Zero(emitter)" !!
  393. {
  394. flag|=X3DAUDIO_CALCULATE_MATRIX;
  395. Zero(emitter);
  396. emitter.ChannelCount=_par.channels;
  397. emitter.pChannelAzimuths=ChannelAzimuths; DEBUG_ASSERT(emitter.ChannelCount<=Elms(ChannelAzimuths), "ChannelAzimuths");
  398. emitter.InnerRadius=0.15f; // avg dist between ears = 0.2, so radius should be 0.1 or 0.2, let's use average of that
  399. emitter.CurveDistanceScaler=Max(FLT_MIN, sound._range);
  400. dsp.SrcChannelCount=_par.channels;
  401. dsp.DstChannelCount=XAudioChannels;
  402. dsp.pMatrixCoefficients=matrix.setNum(dsp.SrcChannelCount*dsp.DstChannelCount).data();
  403. }
  404. if(doppler)
  405. {
  406. flag|=X3DAUDIO_CALCULATE_DOPPLER;
  407. emitter.Velocity.x=sound._vel.x; emitter.Velocity.y=sound._vel.y; emitter.Velocity.z=sound._vel.z;
  408. emitter.DopplerScaler=1;
  409. }
  410. emitter.Position.x=sound._pos.x; emitter.Position.y=sound._pos.y; emitter.Position.z=sound._pos.z; // this is needed for both
  411. X3DAudioCalculate(X3DAudio, &X3DListener, &emitter, flag, &dsp);
  412. SOUND_API_LOCK_WEAK;
  413. if(pos_range)_sv->SetOutputMatrix (XAudioMasteringVoice, _par.channels, XAudioChannels, matrix.data(), OPERATION_SET); // 'SetOutputMatrix' and 'SetVolume' can be set independently
  414. if(doppler )_sv->SetFrequencyRatio( SoundSpeed(sound._actual_speed*dsp.DopplerFactor), OPERATION_SET);
  415. }
  416. }
  417. #endif
  418. void SoundBuffer::frequency(Int frequency)
  419. {
  420. #if DIRECT_SOUND
  421. if(_s){SOUND_API_LOCK_WEAK; _s->SetFrequency(Mid(frequency, DSBFREQUENCY_MIN, DSBFREQUENCY_MAX));}
  422. #elif XAUDIO || OPEN_AL || OPEN_SL
  423. speed(frequency/Flt(_par.frequency));
  424. #endif
  425. }
  426. void SoundBuffer::speed(Flt speed)
  427. {
  428. #if DIRECT_SOUND
  429. frequency(Round(_par.frequency*speed));
  430. #elif XAUDIO
  431. if(_sv){SOUND_API_LOCK_WEAK; _sv->SetFrequencyRatio(speed, OPERATION_SET);}
  432. #elif OPEN_AL
  433. if(_source){SOUND_API_LOCK_WEAK; alSourcef(_source, AL_PITCH, speed);}
  434. #elif OPEN_SL
  435. if(player_playback_rate)
  436. {
  437. SLpermille min_rate=500, max_rate=2000, step_size; SLuint32 capabilities; // default limit is 0.5 to 2.0 (tested on HTC Evo 3D Android 2.3)
  438. SOUND_API_LOCK_WEAK;
  439. (*player_playback_rate)->GetRateRange(player_playback_rate, 0, &min_rate, &max_rate, &step_size, &capabilities);
  440. (*player_playback_rate)->SetRate (player_playback_rate, Mid(Round(speed*1000), min_rate, max_rate));
  441. }
  442. #endif
  443. }
  444. void SoundBuffer::pos(C Vec &pos)
  445. {
  446. #if DIRECT_SOUND
  447. if(_s3d){SOUND_API_LOCK_WEAK; _s3d->SetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED);}
  448. #elif XAUDIO
  449. // handled in 'setParams'
  450. #elif OPEN_AL
  451. if(_source && _3d){SOUND_API_LOCK_WEAK; alSource3f(_source, AL_POSITION, pos.x, pos.y, pos.z);}
  452. #elif OPEN_SL
  453. T._pos=pos;
  454. if(!emulate3D() && player_location)
  455. {
  456. SLVec3D location; location.x=Round(pos.x/SL_POS_UNIT); location.y=Round(pos.y/SL_POS_UNIT); location.z=Round(pos.z/SL_POS_UNIT);
  457. SOUND_API_LOCK_WEAK; (*player_location)->SetLocationCartesian(player_location, &location);
  458. }
  459. #endif
  460. }
  461. Vec SoundBuffer::pos()C
  462. {
  463. #if DIRECT_SOUND
  464. if(_s3d){D3DVECTOR pos; SOUND_API_LOCK_WEAK; if(OK(_s3d->GetPosition(&pos)))return Vec(pos.x, pos.y, pos.z);}
  465. #elif XAUDIO
  466. // unavailable
  467. #elif OPEN_AL
  468. if(_source && _3d){Vec pos; SOUND_API_LOCK_WEAK; alGetSource3f(_source, AL_POSITION, &pos.x, &pos.y, &pos.z); return pos;}
  469. #elif OPEN_SL
  470. #if 1 // faster
  471. return _pos;
  472. #else
  473. if(player_location)
  474. {
  475. SLVec3D pos;
  476. SOUND_API_LOCK_WEAK;
  477. if((*player_location)->GetLocationCartesian(player_location, &pos)==SL_RESULT_SUCCESS)
  478. return Vec(pos.x*SL_POS_UNIT, pos.y*SL_POS_UNIT, pos.z*SL_POS_UNIT);
  479. }
  480. #endif
  481. #endif
  482. return VecZero;
  483. }
  484. void SoundBuffer::vel(C Vec &vel)
  485. {
  486. #if DIRECT_SOUND
  487. if(_s3d){SOUND_API_LOCK_WEAK; _s3d->SetVelocity(vel.x, vel.y, vel.z, DS3D_DEFERRED);}
  488. #elif XAUDIO
  489. // handled in 'setParams'
  490. #elif OPEN_AL
  491. if(_source && _3d){SOUND_API_LOCK_WEAK; alSource3f(_source, AL_VELOCITY, vel.x, vel.y, vel.z);}
  492. #elif OPEN_SL
  493. if(player_doppler)
  494. {
  495. SLVec3D velocity; velocity.x=Round(vel.x/SL_POS_UNIT); velocity.y=Round(vel.y/SL_POS_UNIT); velocity.z=Round(vel.z/SL_POS_UNIT);
  496. SOUND_API_LOCK_WEAK; (*player_doppler)->SetVelocityCartesian(player_doppler, &velocity);
  497. }
  498. #endif
  499. }
  500. Vec SoundBuffer::vel()C
  501. {
  502. #if DIRECT_SOUND
  503. if(_s3d){D3DVECTOR vel; SOUND_API_LOCK_WEAK; if(OK(_s3d->GetVelocity(&vel)))return Vec(vel.x, vel.y, vel.z);}
  504. #elif XAUDIO
  505. // unavailable
  506. #elif OPEN_AL
  507. if(_source && _3d){Vec vel; SOUND_API_LOCK_WEAK; alGetSource3f(_source, AL_VELOCITY, &vel.x, &vel.y, &vel.z); return vel;}
  508. #elif OPEN_SL
  509. if(player_doppler)
  510. {
  511. SLVec3D vel;
  512. SOUND_API_LOCK_WEAK;
  513. if((*player_doppler)->GetVelocityCartesian(player_doppler, &vel)==SL_RESULT_SUCCESS)
  514. return Vec(vel.x*SL_POS_UNIT, vel.y*SL_POS_UNIT, vel.z*SL_POS_UNIT);
  515. }
  516. #endif
  517. return VecZero;
  518. }
  519. void SoundBuffer::range(Flt range)
  520. {
  521. MAX(range, 0.0f);
  522. #if DIRECT_SOUND
  523. if(_s3d){SOUND_API_LOCK_WEAK; _s3d->SetMinDistance(range*DIRECT_SOUND_RANGE_SCALE, DS3D_DEFERRED);}
  524. #elif XAUDIO
  525. // handled in 'setParams'
  526. #elif OPEN_AL
  527. if(_source){SOUND_API_LOCK_WEAK; alSourcef(_source, AL_REFERENCE_DISTANCE, range*OPEN_AL_RANGE_SCALE);}
  528. #elif OPEN_SL
  529. T._range=range;
  530. if(!emulate3D() && player_source){SOUND_API_LOCK_WEAK; (*player_source)->SetRolloffDistances(player_source, RoundPos(range/SL_POS_UNIT), SL_MILLIMETER_MAX);}
  531. #endif
  532. }
  533. Flt SoundBuffer::range()C
  534. {
  535. #if DIRECT_SOUND
  536. if(_s3d){Flt range=0; SOUND_API_LOCK_WEAK; if(OK(_s3d->GetMinDistance(&range)))return range/DIRECT_SOUND_RANGE_SCALE;}
  537. #elif XAUDIO
  538. // unavailable
  539. #elif OPEN_AL
  540. Flt range=0; if(_source){SOUND_API_LOCK_WEAK; alGetSourcef(_source, AL_REFERENCE_DISTANCE, &range);} return range/OPEN_AL_RANGE_SCALE;
  541. #elif OPEN_SL
  542. #if 1 // faster
  543. return _range;
  544. #else
  545. if(player_source)
  546. {
  547. SLmillimeter min, max;
  548. SOUND_API_LOCK_WEAK;
  549. if((*player_source)->GetRolloffDistances(player_source, &min, &max)==SL_RESULT_SUCCESS)
  550. return min*SL_POS_UNIT;
  551. }
  552. #endif
  553. #endif
  554. return 0;
  555. }
  556. /******************************************************************************/
  557. void SoundBuffer::stop()
  558. {
  559. #if DIRECT_SOUND
  560. if(_s){SOUND_API_LOCK_WEAK; _s->Stop(); raw(0);}
  561. #elif XAUDIO
  562. if(_sv){SOUND_API_LOCK_WEAK; _sv->Stop(0, OPERATION_SET); _sv->FlushSourceBuffers();} // 'FlushSourceBuffers' - removes all pending audio buffers from this voice's queue
  563. #elif OPEN_AL
  564. if(_source){SOUND_API_LOCK_WEAK; alSourceStop(_source); alSourcei(_source, AL_BUFFER, 0);} // calling "alSourcei(_source, AL_BUFFER, 0)" means clearing the buffer queue, this is correct
  565. #elif OPEN_SL
  566. SOUND_API_LOCK_WEAK;
  567. if(player_play )(*player_play )->SetPlayState(player_play , SL_PLAYSTATE_STOPPED);
  568. if(player_buffer_queue)(*player_buffer_queue)->Clear (player_buffer_queue ); _processed=0; // clear the queue
  569. #endif
  570. }
  571. void SoundBuffer::pause()
  572. {
  573. #if DIRECT_SOUND
  574. if(_s){SOUND_API_LOCK_WEAK; _s->Stop();}
  575. #elif XAUDIO
  576. if(_sv){SOUND_API_LOCK_WEAK; _sv->Stop(0, OPERATION_SET);}
  577. #elif OPEN_AL
  578. if(_source){SOUND_API_LOCK_WEAK; alSourcePause(_source);}
  579. #elif OPEN_SL
  580. if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->SetPlayState(player_play, SL_PLAYSTATE_PAUSED);}
  581. #endif
  582. }
  583. void SoundBuffer::toggle(Bool loop)
  584. {
  585. #if DIRECT_SOUND
  586. if(_s){SOUND_API_LOCK_WEAK; if(playing())_s->Stop();else _s->Play(0, 0, loop ? DSBPLAY_LOOPING : 0);}
  587. #elif XAUDIO
  588. // unavailable
  589. #elif OPEN_AL
  590. if(_source){SOUND_API_LOCK_WEAK; if(playing())alSourcePause(_source);else alSourcePlay(_source);}
  591. #elif OPEN_SL
  592. if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->SetPlayState(player_play, playing() ? SL_PLAYSTATE_PAUSED : SL_PLAYSTATE_PLAYING);}
  593. #endif
  594. }
  595. Bool SoundBuffer::playing()C
  596. {
  597. #if DIRECT_SOUND
  598. DWORD status=0; if(_s){SOUND_API_LOCK_WEAK; _s->GetStatus(&status);} return FlagTest(status, DSBSTATUS_PLAYING);
  599. #elif XAUDIO
  600. // unavailable
  601. return false;
  602. #elif OPEN_AL
  603. Int state=AL_STOPPED; if(_source){SOUND_API_LOCK_WEAK; alGetSourcei(_source, AL_SOURCE_STATE, &state);} return state==AL_PLAYING;
  604. #elif OPEN_SL
  605. SLuint32 state=SL_PLAYSTATE_STOPPED; if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->GetPlayState(player_play, &state);} return state==SL_PLAYSTATE_PLAYING;
  606. #else
  607. return false;
  608. #endif
  609. }
  610. void SoundBuffer::play(Bool loop)
  611. {
  612. #if DIRECT_SOUND
  613. if(_s){SOUND_API_LOCK_WEAK; _s->Play(0, 0, loop ? DSBPLAY_LOOPING : 0);}
  614. #elif XAUDIO
  615. if(_sv){SOUND_API_LOCK_WEAK; _sv->Start(0, OPERATION_SET);}
  616. #elif OPEN_AL
  617. if(_source){SOUND_API_LOCK_WEAK; alSourcePlay(_source);} // don't touch AL_LOOPING because OpenAL buffers won't swap
  618. #elif OPEN_SL
  619. if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->SetPlayState(player_play, SL_PLAYSTATE_PLAYING);}
  620. #endif
  621. }
  622. /******************************************************************************/
  623. // 3D SOUND LISTENER
  624. /******************************************************************************/
  625. #if 0 // this is cached in members
  626. Vec ListenerClass::pos()
  627. {
  628. #if DIRECT_SOUND
  629. if(DSL){D3DVECTOR pos; SOUND_API_LOCK_WEAK; if(OK(DSL->GetPosition(&pos)))return Vec(pos.x, pos.y, pos.z);}
  630. #elif XAUDIO
  631. return Vec(X3DListener.Position.x, X3DListener.Position.y, X3DListener.Position.z);
  632. #elif OPEN_AL
  633. Vec pos; SOUND_API_LOCK_WEAK; alGetListener3f(AL_POSITION, &pos.x, &pos.y, &pos.z); return pos;
  634. #elif OPEN_SL
  635. if(SLListenerLocation)
  636. {
  637. SLVec3D pos;
  638. SOUND_API_LOCK_WEAK;
  639. if((*SLListenerLocation)->GetLocationCartesian(SLListenerLocation, &pos)==SL_RESULT_SUCCESS)
  640. return Vec(pos.x*SL_POS_UNIT, pos.y*SL_POS_UNIT, pos.z*SL_POS_UNIT);
  641. }
  642. #endif
  643. return VecZero;
  644. }
  645. #endif
  646. ListenerClass::ListenerClass() {_orn.pos.zero(); _orn.dir.set(0, 0, 1); _orn.perp.set(0, 1, 0); _vel.zero(); _flag=SOUND_CHANGED_POS|SOUND_CHANGED_VEL|SOUND_CHANGED_ORN;} // set flag to make sure that we set params in case the SoundAPI uses different initial values
  647. ListenerClass& ListenerClass::pos(C Vec &pos) {if(T.pos()!=pos){T._orn.pos=pos; AtomicOr(_flag, SOUND_CHANGED_POS);} return T;} // modify first and enable flag at the end
  648. ListenerClass& ListenerClass::vel(C Vec &vel) {if(T.vel()!=vel){T._vel =vel; AtomicOr(_flag, SOUND_CHANGED_VEL);} return T;} // modify first and enable flag at the end
  649. ListenerClass& ListenerClass::orn(C Vec &dir, C Vec &up)
  650. {
  651. Orient orn(dir, up); orn.fixPerp();
  652. if(SCAST(Orient, T._orn)!=orn)
  653. {
  654. SCAST(Orient, T._orn)=orn;
  655. AtomicOr(_flag, SOUND_CHANGED_ORN); // modify first and enable flag at the end
  656. }
  657. return T;
  658. }
  659. UInt ListenerClass::updateNoLock() // requires 'SoundAPILock'
  660. {
  661. if(_flag)
  662. {
  663. UInt flag=AtomicDisable(_flag, SOUND_CHANGED_POS|SOUND_CHANGED_VEL|SOUND_CHANGED_ORN); // disable these flags first, so in case the user modifies listener parameters while this function is running, it will be activated again
  664. #if DIRECT_SOUND
  665. if(DSL)
  666. {
  667. if(flag&SOUND_CHANGED_POS)DSL->SetPosition (pos().x, pos().y, pos().z, DS3D_DEFERRED);
  668. if(flag&SOUND_CHANGED_VEL)DSL->SetVelocity (vel().x, vel().y, vel().z, DS3D_DEFERRED);
  669. if(flag&SOUND_CHANGED_ORN)DSL->SetOrientation(dir().x, dir().y, dir().z, up().x, up().y, up().z, DS3D_DEFERRED);
  670. }
  671. #elif XAUDIO
  672. if(flag&SOUND_CHANGED_POS){X3DListener.Position .x=pos().x; X3DListener.Position .y=pos().y; X3DListener.Position .z=pos().z;}
  673. if(flag&SOUND_CHANGED_VEL){X3DListener.Velocity .x=vel().x; X3DListener.Velocity .y=vel().y; X3DListener.Velocity .z=vel().z;}
  674. if(flag&SOUND_CHANGED_ORN){X3DListener.OrientFront.x=dir().x; X3DListener.OrientFront.y=dir().y; X3DListener.OrientFront.z=dir().z;
  675. X3DListener.OrientTop .x=up ().x; X3DListener.OrientTop .y=up ().y; X3DListener.OrientTop .z=up ().z;}
  676. #elif OPEN_AL
  677. if(ALContext)
  678. {
  679. if(flag&SOUND_CHANGED_POS)alListener3f(AL_POSITION, pos().x, pos().y, pos().z);
  680. if(flag&SOUND_CHANGED_VEL)alListener3f(AL_VELOCITY, vel().x, vel().y, vel().z);
  681. if(flag&SOUND_CHANGED_ORN){Flt f[]={-dir().x, -dir().y, -dir().z, up().x, up().y, up().z}; alListenerfv(AL_ORIENTATION, f);}
  682. }
  683. #elif OPEN_SL
  684. if(SLListenerLocation)
  685. {
  686. if(flag&SOUND_CHANGED_POS)
  687. {
  688. SLVec3D location; location.x=Round(pos().x/SL_POS_UNIT); location.y=Round(pos().y/SL_POS_UNIT); location.z=Round(pos().z/SL_POS_UNIT);
  689. (*SLListenerLocation)->SetLocationCartesian(SLListenerLocation, &location);
  690. }
  691. if(flag&SOUND_CHANGED_ORN)
  692. {
  693. SLVec3D front; front.x=Round(dir().x*1024); front.y=Round(dir().y*1024); front.z=Round(dir().z*1024);
  694. SLVec3D above; above.x=Round(up ().x*1024); above.y=Round(up ().y*1024); above.z=Round(up ().z*1024);
  695. (*SLListenerLocation)->SetOrientationVectors(SLListenerLocation, &front, &above); // length of vectors is free of choice
  696. }
  697. }
  698. if(flag&SOUND_CHANGED_VEL)if(SLListenerDoppler)
  699. {
  700. SLVec3D velocity; velocity.x=Round(vel().x/SL_POS_UNIT); velocity.y=Round(vel().y/SL_POS_UNIT); velocity.z=Round(vel().z/SL_POS_UNIT);
  701. (*SLListenerDoppler)->SetVelocityCartesian(SLListenerDoppler, &velocity);
  702. }
  703. #endif
  704. return flag;
  705. }
  706. return 0;
  707. }
  708. void ListenerClass::commitNoLock() // requires 'SoundAPILock', also because of 'EmulateSound3D'
  709. {
  710. // commit changes, do this always, not only on Listener change, because sound positions on DirectSound are called with DS3D_DEFERRED and on XAudio not just 3D is deferred but most of the operations
  711. #if DIRECT_SOUND
  712. if(DSL)DSL->CommitDeferredSettings();
  713. #elif XAUDIO
  714. if(XAudio)XAudio->CommitChanges(XAUDIO2_COMMIT_ALL);
  715. #elif OPEN_AL
  716. // alcProcessContext alcSuspendContext are not used because they seem to be a no-op and there's no way to test them
  717. #elif OPEN_SL
  718. if(SLListenerCommit)(*SLListenerCommit)->Commit(SLListenerCommit);else EmulateSound3D(); // if listener is not available then it means 3D Audio is simulated manually
  719. #endif
  720. }
  721. Bool ListenerClass::create()
  722. {
  723. #if DIRECT_SOUND
  724. if(DS)
  725. {
  726. DSBUFFERDESC dsbd; Zero(dsbd);
  727. dsbd.dwSize =SIZE(DSBUFFERDESC);
  728. dsbd.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
  729. SOUND_API_LOCK_FORCE;
  730. IDirectSoundBuffer *DSB; if(!OK(DS->CreateSoundBuffer(&dsbd, &DSB, null)))return false;
  731. DSB->QueryInterface(IID_IDirectSound3DListener, (Ptr*)&DSL);
  732. RELEASE(DSB);
  733. }
  734. return DSL!=null;
  735. #elif XAUDIO
  736. if(XAudioMasteringVoice)
  737. {
  738. #if WINDOWS_OLD
  739. XAUDIO2_DEVICE_DETAILS details; if(OK(XAudio->GetDeviceDetails(0, &details)))
  740. {
  741. X3DAudioInitialize(details.OutputFormat.dwChannelMask, X3DAUDIO_SPEED_OF_SOUND, X3DAudio);
  742. return true;
  743. }
  744. #else
  745. DWORD channel_mask;
  746. if(OK(XAudioMasteringVoice->GetChannelMask(&channel_mask)))
  747. if(OK(X3DAudioInitialize(channel_mask, X3DAUDIO_SPEED_OF_SOUND, X3DAudio)))return true;
  748. #endif
  749. }
  750. #elif OPEN_AL
  751. return true;
  752. #elif OPEN_SL
  753. return true;
  754. #endif
  755. return false;
  756. }
  757. /******************************************************************************/
  758. // MAIN
  759. /******************************************************************************/
  760. #pragma runtime_checks("", off)
  761. static UInt GetSpeakerConfig()
  762. {
  763. #if DIRECT_SOUND
  764. if(DS)
  765. {
  766. DWORD config; DS->GetSpeakerConfig(&config);
  767. SetLastError(0); // clear error 14007
  768. return DSSPEAKER_CONFIG(config);
  769. }
  770. #endif
  771. return 0;
  772. }
  773. #pragma runtime_checks("", restore)
  774. void InitSound()
  775. {
  776. if(SoundFunc)return; // return if it was already created
  777. if(LogInit)LogN("InitSound");
  778. SOUND_API_LOCK_FORCE;
  779. SoundFunc=true;
  780. #if DIRECT_SOUND
  781. if(OK(DirectSoundCreate(null, &DS, null)))
  782. if(OK(DS->SetCooperativeLevel(App.Hwnd(), DSSCL_PRIORITY)))
  783. #elif XAUDIO
  784. if(OK(XAudio2Create(&XAudio, 0)))
  785. if(OK(XAudio->CreateMasteringVoice(&XAudioMasteringVoice))) // even though it is not used for anything, it is still needed because sound buffer creation would fail without it
  786. {
  787. XAUDIO2_VOICE_DETAILS details; XAudioMasteringVoice->GetVoiceDetails(&details);
  788. XAudioChannels=details.InputChannels;
  789. }
  790. if(XAudioMasteringVoice)
  791. #elif OPEN_AL
  792. if(ALDevice=alcOpenDevice(null))
  793. {
  794. if(ALContext=alcCreateContext(ALDevice, null))
  795. {
  796. Str desc=alcGetString(ALDevice, ALC_DEVICE_SPECIFIER);
  797. alcMakeContextCurrent(ALContext);
  798. }else
  799. {
  800. alcCloseDevice(ALDevice); ALDevice=null;
  801. }
  802. }
  803. if(ALContext)
  804. #elif OPEN_SL
  805. SLInterfaceID om_ids []={SL_IID_NULL };
  806. SLboolean om_required[]={SL_BOOLEAN_FALSE};
  807. // SL_ENGINEOPTION_THREADSAFE is disabled for better performance since we don't need it
  808. if( slCreateEngine(&SLEngineObject , 0, null, 0, null, null )==SL_RESULT_SUCCESS)
  809. if((*SLEngineObject )->Realize ( SLEngineObject , SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
  810. if((*SLEngineObject )->GetInterface ( SLEngineObject , SL_IID_ENGINE, &SLEngineEngine )==SL_RESULT_SUCCESS)
  811. if((*SLEngineEngine )->CreateOutputMix( SLEngineEngine , &SLOutputMixObject, Elms(om_ids), om_ids, om_required)==SL_RESULT_SUCCESS)
  812. if((*SLOutputMixObject)->Realize ( SLOutputMixObject, SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
  813. {
  814. // create optional stuff
  815. // this could fail if the environmental reverb effect is not available, because the feature is not present, excessive CPU load, or the required MODIFY_AUDIO_SETTINGS permission was not requested and granted
  816. /*if((*SLOutputMixObject)->GetInterface(SLOutputMixObject, SL_IID_ENVIRONMENTALREVERB, &SLOutputMixEnvironmentalReverb)==SL_RESULT_SUCCESS)
  817. {
  818. (*SLOutputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(SLOutputMixEnvironmentalReverb, &reverbSettings);
  819. }*/
  820. SLInterfaceID l_ids []={SL_IID_3DLOCATION, SL_IID_3DCOMMIT /*, SL_IID_3DDOPPLER*/}; // don't create doppler effect to increase performance
  821. SLboolean l_required[]={SL_BOOLEAN_TRUE , SL_BOOLEAN_FALSE/*, SL_BOOLEAN_FALSE*/};
  822. if((*SLEngineEngine )->CreateListener(SLEngineEngine , &SLListenerObject, Elms(l_ids), l_ids, l_required)==SL_RESULT_SUCCESS)
  823. if((*SLListenerObject)->Realize (SLListenerObject, SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
  824. if((*SLListenerObject)->GetInterface (SLListenerObject, SL_IID_3DLOCATION, &SLListenerLocation )==SL_RESULT_SUCCESS)
  825. {
  826. // create optional stuff
  827. (*SLListenerObject)->GetInterface(SLListenerObject, SL_IID_3DDOPPLER, &SLListenerDoppler);
  828. if((*SLListenerObject)->GetInterface(SLListenerObject, SL_IID_3DCOMMIT, &SLListenerCommit)==SL_RESULT_SUCCESS)
  829. {
  830. (*SLListenerCommit)->SetDeferred(SLListenerCommit, SL_BOOLEAN_TRUE); // set deferred 3D committing
  831. }
  832. }
  833. }
  834. if(SLOutputMixObject)
  835. #endif
  836. {
  837. #if WINDOWS_OLD
  838. SetLastError(0); // clear error 1407
  839. #endif
  840. Listener.create();
  841. SoundAPI=true;
  842. }
  843. InitSound2(); // create the thread even when SoundAPI failed so we can still process sounds without playing them
  844. }
  845. void ShutSound()
  846. {
  847. SoundFunc=SoundAPI=false; // this also disables creation of new objects
  848. ShutSound2(); // destroy thread and sounds
  849. ShutMusic ();
  850. SOUND_API_LOCK_FORCE; // lock after deleting 'SoundThread'
  851. #if DIRECT_SOUND
  852. RELEASE(DSL);
  853. RELEASE(DS );
  854. #elif XAUDIO
  855. if(XAudioMasteringVoice){XAudioMasteringVoice->DestroyVoice(); XAudioMasteringVoice=null;}
  856. RELEASE(XAudio);
  857. #elif OPEN_AL
  858. alcMakeContextCurrent(null );
  859. if(ALContext){alcDestroyContext (ALContext); ALContext=null;}
  860. if(ALDevice ){alcCloseDevice (ALDevice ); ALDevice =null;}
  861. #elif OPEN_SL
  862. SLListenerLocation=null;
  863. SLListenerDoppler =null;
  864. SLListenerCommit =null;
  865. if(SLListenerObject){(*SLListenerObject)->Destroy(SLListenerObject); SLListenerObject=null;}
  866. if(SLOutputMixObject){(*SLOutputMixObject)->Destroy(SLOutputMixObject); SLOutputMixObject=null;}
  867. SLEngineEngine=null;
  868. if(SLEngineObject){(*SLEngineObject)->Destroy(SLEngineObject); SLEngineObject=null;}
  869. #endif
  870. AppVolume.del();
  871. }
  872. /******************************************************************************/
  873. }
  874. /******************************************************************************/