| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907 |
- /******************************************************************************/
- #include "stdafx.h"
- namespace EE{
- /******************************************************************************
- All 'SoundBuffer' methods (and thus Sound API) are called only by Sound Threads,
- they manage the Locking, so we don't need to do any locks here,
- therefore SOUND_API_LOCK_WEAK is marked as an empty macro.
- /******************************************************************************/
- #define SOUND_API_LOCK_FORCE SyncLocker locker(SoundAPILock);
- #define SOUND_API_LOCK_WEAK //SOUND_API_LOCK_FORCE not needed
- #define OPERATION_SET (!XAUDIO2_COMMIT_NOW) // make sure that this is not XAUDIO2_COMMIT_NOW
- #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
- #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
- #if DIRECT_SOUND
- static IDirectSound *DS;
- static IDirectSound3DListener *DSL;
- static VIRTUALIZATION_MODE Virtualization=VIRT_HIGH;
- #elif XAUDIO
- IXAudio2 *XAudio;
- static IXAudio2MasteringVoice *XAudioMasteringVoice;
- static X3DAUDIO_HANDLE X3DAudio;
- static X3DAUDIO_LISTENER X3DListener;
- static Int XAudioChannels;
- #elif OPEN_AL
- static ALCcontext *ALContext;
- static ALCdevice *ALDevice;
- #elif OPEN_SL
- static SLObjectItf SLEngineObject;
- static SLEngineItf SLEngineEngine;
- static SLObjectItf SLOutputMixObject;
- static SLEnvironmentalReverbItf SLOutputMixEnvironmentalReverb;
- static SLObjectItf SLListenerObject;
- static SL3DLocationItf SLListenerLocation;
- static SL3DDopplerItf SLListenerDoppler;
- static SL3DCommitItf SLListenerCommit;
- #define SL_POS_UNIT 0.001f // milimeter
- #endif
- Bool SoundAPI, SoundFunc;
- ListenerClass Listener;
- /******************************************************************************/
- void SoundBuffer::zero()
- {
- _par.zero();
- #if DIRECT_SOUND
- _lock_data=null;
- _lock_size=0;
- _s =null;
- _s3d =null;
- #elif XAUDIO
- _sv=null;
- _3d=false;
- #elif OPEN_AL
- _3d=false;
- _source=0;
- _buffer[0]=_buffer[1]=0;
- #elif OPEN_SL
- _3d =false;
- _processed =0;
- _volume=_range =1;
- _pos .zero();
- player_object =null;
- player_play =null;
- player_volume =null;
- player_playback_rate=null;
- player_buffer_queue =null;
- player_location =null;
- player_doppler =null;
- player_source =null;
- #endif
- }
- SoundBuffer::SoundBuffer() {zero();}
- /******************************************************************************/
- void SoundBuffer::del()
- {
- SOUND_API_LOCK_WEAK;
- stop();
- #if DIRECT_SOUND
- if(DS)
- {
- RELEASE(_s3d);
- RELEASE(_s );
- }
- #elif XAUDIO
- if(XAudio)
- {
- if(_sv)_sv->DestroyVoice();
- }
- _data.del(); // delete the buffer after '_sv'
- #elif OPEN_AL
- if(ALContext)
- {
- if(_source )alDeleteSources(1, &_source );
- if(_buffer[0])alDeleteBuffers(1, &_buffer[0]);
- if(_buffer[1])alDeleteBuffers(1, &_buffer[1]);
- }
- #elif OPEN_SL
- if(SLOutputMixObject)
- {
- if(player_object)(*player_object)->Destroy(player_object);
- }
- _data.del(); // delete the buffer after 'player_object'
- #endif
- zero();
- }
- /******************************************************************************/
- #if XAUDIO
- /*static struct XAudioVoiceCallback : IXAudio2VoiceCallback
- {
- virtual void OnVoiceProcessingPassStart(UINT32 BytesRequired)override {}
- virtual void OnVoiceProcessingPassEnd()override {}
- virtual void OnStreamEnd()override {}
- virtual void OnBufferStart(Ptr user)override {}
- virtual void OnBufferEnd(Ptr user)override {}
- virtual void OnLoopEnd(Ptr user)override {}
- virtual void OnVoiceError(Ptr user, HRESULT error)override {}
- }XAVC;*/
- #elif OPEN_SL
- static void PlayerCallback(SLAndroidSimpleBufferQueueItf buffer_queue, void *context)
- {
- if(SoundBuffer *buffer=(SoundBuffer*)context)
- {
- AtomicInc(buffer->_processed);
- }
- }
- #endif
- 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
- {
- #if OPEN_SL
- if(player_buffer_queue)
- {
- SOUND_API_LOCK_FORCE;
- (*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
- }
- #endif
- }
- Bool SoundBuffer::create(Int frequency, Int bits, Int channels, Int samples, Bool is3D)
- {
- del();
- if(SoundAPI && frequency>=1 && (bits==8 || bits==16 || bits==24) && (channels>=1 && channels<=2) && samples>0)
- {
- C Int bytes=bits/8;
- #if OPEN_AL
- if(is3D)channels=1; // OpenAL supports only mono 3D
- #endif
- _par.frequency=frequency;
- _par.bytes =bytes;
- _par.channels =channels;
- _par.block =channels*bytes;
- _par.bit_rate =channels*bits*frequency;
- _par.size =_par.block*samples;
- #if DIRECT_SOUND || XAUDIO
- WAVEFORMATEX wf; Zero(wf);
- wf.wFormatTag =WAVE_FORMAT_PCM;
- wf.nChannels =channels;
- wf.nSamplesPerSec =frequency;
- wf.wBitsPerSample =bits;
- wf.nBlockAlign =_par.block;
- wf.nAvgBytesPerSec=_par.block*frequency;
- #endif
- #if DIRECT_SOUND
- DSBUFFERDESC dsbd; Zero(dsbd);
- dsbd.dwSize =SIZE(DSBUFFERDESC);
- dsbd.dwFlags =(is3D ? DSBCAPS_CTRL3D : DSBCAPS_CTRLPAN)|DSBCAPS_CTRLVOLUME|DSBCAPS_CTRLFREQUENCY|DSBCAPS_STATIC|((App.flag&APP_WORK_IN_BACKGROUND) ? DSBCAPS_GLOBALFOCUS : 0);
- dsbd.dwBufferBytes=_par.size;
- dsbd.lpwfxFormat =&wf;
-
- SOUND_API_LOCK_WEAK;
- Bool ok=false;
- if(!is3D)ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));else
- {
- if(!ok && Virtualization>=VIRT_HIGH){dsbd.guid3DAlgorithm=DS3DALG_HRTF_FULL ; ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));}
- if(!ok && Virtualization>=VIRT_LOW ){dsbd.guid3DAlgorithm=DS3DALG_HRTF_LIGHT ; ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));}
- if(!ok && Virtualization>=VIRT_NONE){dsbd.guid3DAlgorithm=DS3DALG_NO_VIRTUALIZATION; ok=OK(DS->CreateSoundBuffer(&dsbd, &_s, null));}
- if( ok && !OK(_s->QueryInterface(IID_IDirectSound3DBuffer, (Ptr*)&_s3d)))ok=false;
- }
- if(ok)return true;
- #elif XAUDIO
- SOUND_API_LOCK_WEAK;
- if(OK(XAudio->CreateSourceVoice(&_sv, &wf, 0, MAX_SOUND_SPEED/*, &XAVC*/)))
- {
- _3d=is3D; // if sound will be 3 dimensional
- _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
- return true;
- }
- #elif OPEN_AL
- if(frequency<=192000)
- {
- SOUND_API_LOCK_WEAK;
- alGenBuffers(Elms(_buffer), _buffer);
- alGenSources( 1, &_source);
- _3d=is3D; // if sound will be 3 dimensional
- if(!_3d)alSourcei(_source, AL_SOURCE_RELATIVE, true); // 2d sounds are relative to listener
- return true;
- }
- #elif OPEN_SL
- if(frequency<=192000)
- {
- ASSERT(SL_SAMPLINGRATE_48==48000000); // verify the scale
- Bool try3D=(is3D && SLListenerLocation);
- SLDataLocator_AndroidSimpleBufferQueue buffer_queue={SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
- 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};
- SLDataSource audio_src ={&buffer_queue, &format_pcm};
- SLDataLocator_OutputMix output_mix ={SL_DATALOCATOR_OUTPUTMIX, SLOutputMixObject};
- SLDataSink audio_sink ={&output_mix, null};
- // 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
- REPD(t3 , try3D ? 2 : 1)
- REPD(vol , 2)
- REPD(speed, 2)
- {
- SLInterfaceID ids []={SL_IID_BUFFERQUEUE, SL_IID_VOLUME , SL_IID_PLAYBACKRATE };
- SLboolean required []={SL_BOOLEAN_TRUE , vol ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE, speed ? SL_BOOLEAN_TRUE : SL_BOOLEAN_FALSE};
- 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
- 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*/};
- SOUND_API_LOCK_WEAK;
- if((*SLEngineEngine )->CreateAudioPlayer(SLEngineEngine, &player_object, &audio_src, &audio_sink, t3 ? Elms(ids3D) : Elms(ids), t3 ? ids3D : ids, t3 ? required3D : required)==SL_RESULT_SUCCESS)
- if((*player_object )->Realize (player_object, SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
- if((*player_object )->GetInterface (player_object, SL_IID_PLAY , &player_play )==SL_RESULT_SUCCESS)
- if((*player_object )->GetInterface (player_object, SL_IID_BUFFERQUEUE, &player_buffer_queue)==SL_RESULT_SUCCESS)
- if((*player_buffer_queue)->RegisterCallback (player_buffer_queue, PlayerCallback, this )==SL_RESULT_SUCCESS)
- {
- _3d=is3D; // if sound will be 3 dimensional
- _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
- (*player_object)->GetInterface(player_object, SL_IID_VOLUME , &player_volume ); // this is optional
- (*player_object)->GetInterface(player_object, SL_IID_PLAYBACKRATE, &player_playback_rate); // this is optional
- if(t3)(*player_object)->GetInterface(player_object, SL_IID_3DLOCATION , &player_location ); // this is optional
- if(t3)(*player_object)->GetInterface(player_object, SL_IID_3DSOURCE , &player_source ); // this is optional
- if(t3)(*player_object)->GetInterface(player_object, SL_IID_3DDOPPLER , &player_doppler ); // this is optional
- if(_3d && !player_location && player_volume) // if should be 3D but not available, then volume will be adjusted manually
- (*player_volume)->EnableStereoPosition(player_volume, SL_BOOLEAN_TRUE); // enable stereo panning
- return true;
- }
- }
- }
- #endif
- del();
- }
- return false;
- }
- /******************************************************************************/
- #if DIRECT_SOUND
- Bool SoundBuffer::lock(Int pos, Int size)
- {
- if(_s && !_lock_data)
- {
- if(size<0)size=_par.size-pos;
- DWORD dw; SOUND_API_LOCK_WEAK; if(OK(_s->Lock(pos, size, &_lock_data, &dw, null, null, 0))){_lock_size=dw; return true;}
- _lock_data=null;
- _lock_size=0;
- }
- return false;
- }
- void SoundBuffer::unlock()
- {
- if(_s && _lock_data)
- {
- SOUND_API_LOCK_WEAK; _s->Unlock(_lock_data, _lock_size, null, 0);
- _lock_data=null;
- _lock_size=0;
- }
- }
- #endif
- /******************************************************************************/
- #if DIRECT_SOUND
- Bool SoundBuffer::is ()C {return _s !=null;}
- Bool SoundBuffer::is3D()C {return _s3d!=null;}
- #elif XAUDIO
- Bool SoundBuffer::is ()C {return _sv!=null;}
- Bool SoundBuffer::is3D()C {return _3d ;}
- #elif OPEN_AL
- Bool SoundBuffer::is ()C {return _source!=0;}
- Bool SoundBuffer::is3D()C {return _3d ;}
- #elif OPEN_SL
- Bool SoundBuffer::is ()C {return player_object!=null;}
- Bool SoundBuffer::is3D()C {return _3d ;}
- #else
- Bool SoundBuffer::is ()C {return false;}
- Bool SoundBuffer::is3D()C {return false;}
- #endif
- /******************************************************************************/
- void SoundBuffer::raw(Int raw)
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; _s->SetCurrentPosition(raw);}
- #elif XAUDIO
- // XAudio does not support setting buffer position
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; alSourcei(_source, AL_BYTE_OFFSET, raw);}
- #elif OPEN_SL
- // OpenSL does not support setting buffer position
- #endif
- }
- Int SoundBuffer::raw()C
- {
- #if DIRECT_SOUND
- if(_s){DWORD play=0, write=0; SOUND_API_LOCK_WEAK; if(OK(_s->GetCurrentPosition(&play, &write)))return play;}
- #elif XAUDIO
- if(_sv)
- {
- SOUND_API_LOCK_WEAK; XAUDIO2_VOICE_STATE state;
- #if WINDOWS_OLD
- _sv->GetState(&state);
- #else
- _sv->GetState(&state, 0);
- #endif
- return (state.SamplesPlayed*_par.block)%_par.size;
- }
- #elif OPEN_AL
- if(_source){Int raw=0; SOUND_API_LOCK_WEAK; alGetSourcei(_source, AL_BYTE_OFFSET, &raw); return raw;}
- #elif OPEN_SL
- if(player_play && _par.block && _par.frequency)
- {
- SLmillisecond time=0;
- SOUND_API_LOCK_WEAK;
- 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)
- //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
- 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
- }
- #endif
- return 0;
- }
- /******************************************************************************/
- void SoundBuffer::pan(Flt pan) // 'pan' should be in range -1..1
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; _s->SetPan(Round(pan*DSBPAN_RIGHT));} ASSERT(-(DSBPAN_LEFT)==DSBPAN_RIGHT);
- #elif XAUDIO
- if(_sv){Flt vols[]={Sat(1-pan), Sat(1+pan)}; SOUND_API_LOCK_WEAK; _sv->SetChannelVolumes(2, vols, OPERATION_SET);}
- #elif OPEN_AL
- //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
- #elif OPEN_SL
- if(player_volume){SOUND_API_LOCK_WEAK; (*player_volume)->SetStereoPosition(player_volume, Round(pan*1000));} // will work only if 'EnableStereoPosition' was called
- #endif
- }
- #if OPEN_SL
- Bool SoundBuffer::emulate3D()
- {
- if(_3d && !player_location && player_volume) // if should be 3D, but it's not available, then adjust volume manually
- {
- Vec delta =_pos-Listener.pos();
- Flt dist =delta.length(),
- volume=T._volume;
- if( dist>_range)volume*=_range/dist;
- 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
- Flt pan=Dot(delta, Listener.right());
- SOUND_API_LOCK_WEAK;
- T.pan(pan);
- SLmillibel linear=Max(SL_MILLIBEL_MIN, Round(Lerp(-10000, 0, Pow(volume, 0.1f)))); // this matches DirectSound version and sounds ok
- (*player_volume)->SetVolumeLevel(player_volume, linear);
- return true;
- }
- return false;
- }
- #endif
- void SoundBuffer::volume(Flt volume) // 'volume' should be in range 0..1
- {
- #if DIRECT_SOUND
- if(_s)
- {
- 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
- Int linear=Round(Lerp(DSBVOLUME_MIN, DSBVOLUME_MAX, Pow(volume, 0.1f)));
- SOUND_API_LOCK_WEAK; _s->SetVolume(linear);
- }
- #elif XAUDIO
- if(_sv)
- {
- 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)
- SOUND_API_LOCK_WEAK; _sv->SetVolume(volume, OPERATION_SET);
- }
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; alSourcef(_source, AL_GAIN, volume);}
- #elif OPEN_SL
- if(player_volume)
- {
- T._volume=volume;
- if(!emulate3D()) // if not emulating 3D
- {
- SLmillibel linear=Max(SL_MILLIBEL_MIN, Round(Lerp(-10000, 0, Pow(T._volume, 0.1f)))); // this matches DirectSound version and sounds ok
- SOUND_API_LOCK_WEAK; (*player_volume)->SetVolumeLevel(player_volume, linear);
- }
- }
- #endif
- }
- #if XAUDIO
- static Flt ChannelAzimuths[16]; // all zeros
- void SoundBuffer::setParams(C _Sound &sound, Bool pos_range, Bool doppler)
- {
- if(_sv)
- {
- MemtN<Flt, 2*8*4> matrix; // default channels for a sound = 1..2, max supported number of speakers = 8, mul by 4 for safety
- X3DAUDIO_EMITTER emitter;
- X3DAUDIO_DSP_SETTINGS dsp;
- UInt flag=0;
- if(pos_range) // !! process this first because of "Zero(emitter)" !!
- {
- flag|=X3DAUDIO_CALCULATE_MATRIX;
- Zero(emitter);
- emitter.ChannelCount=_par.channels;
- emitter.pChannelAzimuths=ChannelAzimuths; DEBUG_ASSERT(emitter.ChannelCount<=Elms(ChannelAzimuths), "ChannelAzimuths");
- 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
- emitter.CurveDistanceScaler=Max(FLT_MIN, sound._range);
- dsp.SrcChannelCount=_par.channels;
- dsp.DstChannelCount=XAudioChannels;
- dsp.pMatrixCoefficients=matrix.setNum(dsp.SrcChannelCount*dsp.DstChannelCount).data();
- }
- if(doppler)
- {
- flag|=X3DAUDIO_CALCULATE_DOPPLER;
- emitter.Velocity.x=sound._vel.x; emitter.Velocity.y=sound._vel.y; emitter.Velocity.z=sound._vel.z;
- emitter.DopplerScaler=1;
- }
- emitter.Position.x=sound._pos.x; emitter.Position.y=sound._pos.y; emitter.Position.z=sound._pos.z; // this is needed for both
- X3DAudioCalculate(X3DAudio, &X3DListener, &emitter, flag, &dsp);
- SOUND_API_LOCK_WEAK;
- if(pos_range)_sv->SetOutputMatrix (XAudioMasteringVoice, _par.channels, XAudioChannels, matrix.data(), OPERATION_SET); // 'SetOutputMatrix' and 'SetVolume' can be set independently
- if(doppler )_sv->SetFrequencyRatio( SoundSpeed(sound._actual_speed*dsp.DopplerFactor), OPERATION_SET);
- }
- }
- #endif
- void SoundBuffer::frequency(Int frequency)
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; _s->SetFrequency(Mid(frequency, DSBFREQUENCY_MIN, DSBFREQUENCY_MAX));}
- #elif XAUDIO || OPEN_AL || OPEN_SL
- speed(frequency/Flt(_par.frequency));
- #endif
- }
- void SoundBuffer::speed(Flt speed)
- {
- #if DIRECT_SOUND
- frequency(Round(_par.frequency*speed));
- #elif XAUDIO
- if(_sv){SOUND_API_LOCK_WEAK; _sv->SetFrequencyRatio(speed, OPERATION_SET);}
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; alSourcef(_source, AL_PITCH, speed);}
- #elif OPEN_SL
- if(player_playback_rate)
- {
- 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)
- SOUND_API_LOCK_WEAK;
- (*player_playback_rate)->GetRateRange(player_playback_rate, 0, &min_rate, &max_rate, &step_size, &capabilities);
- (*player_playback_rate)->SetRate (player_playback_rate, Mid(Round(speed*1000), min_rate, max_rate));
- }
- #endif
- }
- void SoundBuffer::pos(C Vec &pos)
- {
- #if DIRECT_SOUND
- if(_s3d){SOUND_API_LOCK_WEAK; _s3d->SetPosition(pos.x, pos.y, pos.z, DS3D_DEFERRED);}
- #elif XAUDIO
- // handled in 'setParams'
- #elif OPEN_AL
- if(_source && _3d){SOUND_API_LOCK_WEAK; alSource3f(_source, AL_POSITION, pos.x, pos.y, pos.z);}
- #elif OPEN_SL
- T._pos=pos;
- if(!emulate3D() && player_location)
- {
- 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);
- SOUND_API_LOCK_WEAK; (*player_location)->SetLocationCartesian(player_location, &location);
- }
- #endif
- }
- Vec SoundBuffer::pos()C
- {
- #if DIRECT_SOUND
- if(_s3d){D3DVECTOR pos; SOUND_API_LOCK_WEAK; if(OK(_s3d->GetPosition(&pos)))return Vec(pos.x, pos.y, pos.z);}
- #elif XAUDIO
- // unavailable
- #elif OPEN_AL
- if(_source && _3d){Vec pos; SOUND_API_LOCK_WEAK; alGetSource3f(_source, AL_POSITION, &pos.x, &pos.y, &pos.z); return pos;}
- #elif OPEN_SL
- #if 1 // faster
- return _pos;
- #else
- if(player_location)
- {
- SLVec3D pos;
- SOUND_API_LOCK_WEAK;
- if((*player_location)->GetLocationCartesian(player_location, &pos)==SL_RESULT_SUCCESS)
- return Vec(pos.x*SL_POS_UNIT, pos.y*SL_POS_UNIT, pos.z*SL_POS_UNIT);
- }
- #endif
- #endif
- return VecZero;
- }
- void SoundBuffer::vel(C Vec &vel)
- {
- #if DIRECT_SOUND
- if(_s3d){SOUND_API_LOCK_WEAK; _s3d->SetVelocity(vel.x, vel.y, vel.z, DS3D_DEFERRED);}
- #elif XAUDIO
- // handled in 'setParams'
- #elif OPEN_AL
- if(_source && _3d){SOUND_API_LOCK_WEAK; alSource3f(_source, AL_VELOCITY, vel.x, vel.y, vel.z);}
- #elif OPEN_SL
- if(player_doppler)
- {
- 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);
- SOUND_API_LOCK_WEAK; (*player_doppler)->SetVelocityCartesian(player_doppler, &velocity);
- }
- #endif
- }
- Vec SoundBuffer::vel()C
- {
- #if DIRECT_SOUND
- if(_s3d){D3DVECTOR vel; SOUND_API_LOCK_WEAK; if(OK(_s3d->GetVelocity(&vel)))return Vec(vel.x, vel.y, vel.z);}
- #elif XAUDIO
- // unavailable
- #elif OPEN_AL
- if(_source && _3d){Vec vel; SOUND_API_LOCK_WEAK; alGetSource3f(_source, AL_VELOCITY, &vel.x, &vel.y, &vel.z); return vel;}
- #elif OPEN_SL
- if(player_doppler)
- {
- SLVec3D vel;
- SOUND_API_LOCK_WEAK;
- if((*player_doppler)->GetVelocityCartesian(player_doppler, &vel)==SL_RESULT_SUCCESS)
- return Vec(vel.x*SL_POS_UNIT, vel.y*SL_POS_UNIT, vel.z*SL_POS_UNIT);
- }
- #endif
- return VecZero;
- }
- void SoundBuffer::range(Flt range)
- {
- MAX(range, 0.0f);
- #if DIRECT_SOUND
- if(_s3d){SOUND_API_LOCK_WEAK; _s3d->SetMinDistance(range*DIRECT_SOUND_RANGE_SCALE, DS3D_DEFERRED);}
- #elif XAUDIO
- // handled in 'setParams'
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; alSourcef(_source, AL_REFERENCE_DISTANCE, range*OPEN_AL_RANGE_SCALE);}
- #elif OPEN_SL
- T._range=range;
- if(!emulate3D() && player_source){SOUND_API_LOCK_WEAK; (*player_source)->SetRolloffDistances(player_source, RoundPos(range/SL_POS_UNIT), SL_MILLIMETER_MAX);}
- #endif
- }
- Flt SoundBuffer::range()C
- {
- #if DIRECT_SOUND
- if(_s3d){Flt range=0; SOUND_API_LOCK_WEAK; if(OK(_s3d->GetMinDistance(&range)))return range/DIRECT_SOUND_RANGE_SCALE;}
- #elif XAUDIO
- // unavailable
- #elif OPEN_AL
- Flt range=0; if(_source){SOUND_API_LOCK_WEAK; alGetSourcef(_source, AL_REFERENCE_DISTANCE, &range);} return range/OPEN_AL_RANGE_SCALE;
- #elif OPEN_SL
- #if 1 // faster
- return _range;
- #else
- if(player_source)
- {
- SLmillimeter min, max;
- SOUND_API_LOCK_WEAK;
- if((*player_source)->GetRolloffDistances(player_source, &min, &max)==SL_RESULT_SUCCESS)
- return min*SL_POS_UNIT;
- }
- #endif
- #endif
- return 0;
- }
- /******************************************************************************/
- void SoundBuffer::stop()
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; _s->Stop(); raw(0);}
- #elif XAUDIO
- if(_sv){SOUND_API_LOCK_WEAK; _sv->Stop(0, OPERATION_SET); _sv->FlushSourceBuffers();} // 'FlushSourceBuffers' - removes all pending audio buffers from this voice's queue
- #elif OPEN_AL
- 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
- #elif OPEN_SL
- SOUND_API_LOCK_WEAK;
- if(player_play )(*player_play )->SetPlayState(player_play , SL_PLAYSTATE_STOPPED);
- if(player_buffer_queue)(*player_buffer_queue)->Clear (player_buffer_queue ); _processed=0; // clear the queue
- #endif
- }
- void SoundBuffer::pause()
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; _s->Stop();}
- #elif XAUDIO
- if(_sv){SOUND_API_LOCK_WEAK; _sv->Stop(0, OPERATION_SET);}
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; alSourcePause(_source);}
- #elif OPEN_SL
- if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->SetPlayState(player_play, SL_PLAYSTATE_PAUSED);}
- #endif
- }
- void SoundBuffer::toggle(Bool loop)
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; if(playing())_s->Stop();else _s->Play(0, 0, loop ? DSBPLAY_LOOPING : 0);}
- #elif XAUDIO
- // unavailable
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; if(playing())alSourcePause(_source);else alSourcePlay(_source);}
- #elif OPEN_SL
- if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->SetPlayState(player_play, playing() ? SL_PLAYSTATE_PAUSED : SL_PLAYSTATE_PLAYING);}
- #endif
- }
- Bool SoundBuffer::playing()C
- {
- #if DIRECT_SOUND
- DWORD status=0; if(_s){SOUND_API_LOCK_WEAK; _s->GetStatus(&status);} return FlagTest(status, DSBSTATUS_PLAYING);
- #elif XAUDIO
- // unavailable
- return false;
- #elif OPEN_AL
- Int state=AL_STOPPED; if(_source){SOUND_API_LOCK_WEAK; alGetSourcei(_source, AL_SOURCE_STATE, &state);} return state==AL_PLAYING;
- #elif OPEN_SL
- SLuint32 state=SL_PLAYSTATE_STOPPED; if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->GetPlayState(player_play, &state);} return state==SL_PLAYSTATE_PLAYING;
- #else
- return false;
- #endif
- }
- void SoundBuffer::play(Bool loop)
- {
- #if DIRECT_SOUND
- if(_s){SOUND_API_LOCK_WEAK; _s->Play(0, 0, loop ? DSBPLAY_LOOPING : 0);}
- #elif XAUDIO
- if(_sv){SOUND_API_LOCK_WEAK; _sv->Start(0, OPERATION_SET);}
- #elif OPEN_AL
- if(_source){SOUND_API_LOCK_WEAK; alSourcePlay(_source);} // don't touch AL_LOOPING because OpenAL buffers won't swap
- #elif OPEN_SL
- if(player_play){SOUND_API_LOCK_WEAK; (*player_play)->SetPlayState(player_play, SL_PLAYSTATE_PLAYING);}
- #endif
- }
- /******************************************************************************/
- // 3D SOUND LISTENER
- /******************************************************************************/
- #if 0 // this is cached in members
- Vec ListenerClass::pos()
- {
- #if DIRECT_SOUND
- if(DSL){D3DVECTOR pos; SOUND_API_LOCK_WEAK; if(OK(DSL->GetPosition(&pos)))return Vec(pos.x, pos.y, pos.z);}
- #elif XAUDIO
- return Vec(X3DListener.Position.x, X3DListener.Position.y, X3DListener.Position.z);
- #elif OPEN_AL
- Vec pos; SOUND_API_LOCK_WEAK; alGetListener3f(AL_POSITION, &pos.x, &pos.y, &pos.z); return pos;
- #elif OPEN_SL
- if(SLListenerLocation)
- {
- SLVec3D pos;
- SOUND_API_LOCK_WEAK;
- if((*SLListenerLocation)->GetLocationCartesian(SLListenerLocation, &pos)==SL_RESULT_SUCCESS)
- return Vec(pos.x*SL_POS_UNIT, pos.y*SL_POS_UNIT, pos.z*SL_POS_UNIT);
- }
- #endif
- return VecZero;
- }
- #endif
- 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
- 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
- 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
- ListenerClass& ListenerClass::orn(C Vec &dir, C Vec &up)
- {
- Orient orn(dir, up); orn.fixPerp();
- if(SCAST(Orient, T._orn)!=orn)
- {
- SCAST(Orient, T._orn)=orn;
- AtomicOr(_flag, SOUND_CHANGED_ORN); // modify first and enable flag at the end
- }
- return T;
- }
- UInt ListenerClass::updateNoLock() // requires 'SoundAPILock'
- {
- if(_flag)
- {
- 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
- #if DIRECT_SOUND
- if(DSL)
- {
- if(flag&SOUND_CHANGED_POS)DSL->SetPosition (pos().x, pos().y, pos().z, DS3D_DEFERRED);
- if(flag&SOUND_CHANGED_VEL)DSL->SetVelocity (vel().x, vel().y, vel().z, DS3D_DEFERRED);
- if(flag&SOUND_CHANGED_ORN)DSL->SetOrientation(dir().x, dir().y, dir().z, up().x, up().y, up().z, DS3D_DEFERRED);
- }
- #elif XAUDIO
- if(flag&SOUND_CHANGED_POS){X3DListener.Position .x=pos().x; X3DListener.Position .y=pos().y; X3DListener.Position .z=pos().z;}
- if(flag&SOUND_CHANGED_VEL){X3DListener.Velocity .x=vel().x; X3DListener.Velocity .y=vel().y; X3DListener.Velocity .z=vel().z;}
- if(flag&SOUND_CHANGED_ORN){X3DListener.OrientFront.x=dir().x; X3DListener.OrientFront.y=dir().y; X3DListener.OrientFront.z=dir().z;
- X3DListener.OrientTop .x=up ().x; X3DListener.OrientTop .y=up ().y; X3DListener.OrientTop .z=up ().z;}
- #elif OPEN_AL
- if(ALContext)
- {
- if(flag&SOUND_CHANGED_POS)alListener3f(AL_POSITION, pos().x, pos().y, pos().z);
- if(flag&SOUND_CHANGED_VEL)alListener3f(AL_VELOCITY, vel().x, vel().y, vel().z);
- if(flag&SOUND_CHANGED_ORN){Flt f[]={-dir().x, -dir().y, -dir().z, up().x, up().y, up().z}; alListenerfv(AL_ORIENTATION, f);}
- }
- #elif OPEN_SL
- if(SLListenerLocation)
- {
- if(flag&SOUND_CHANGED_POS)
- {
- 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);
- (*SLListenerLocation)->SetLocationCartesian(SLListenerLocation, &location);
- }
- if(flag&SOUND_CHANGED_ORN)
- {
- SLVec3D front; front.x=Round(dir().x*1024); front.y=Round(dir().y*1024); front.z=Round(dir().z*1024);
- SLVec3D above; above.x=Round(up ().x*1024); above.y=Round(up ().y*1024); above.z=Round(up ().z*1024);
- (*SLListenerLocation)->SetOrientationVectors(SLListenerLocation, &front, &above); // length of vectors is free of choice
- }
- }
- if(flag&SOUND_CHANGED_VEL)if(SLListenerDoppler)
- {
- 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);
- (*SLListenerDoppler)->SetVelocityCartesian(SLListenerDoppler, &velocity);
- }
- #endif
- return flag;
- }
- return 0;
- }
- void ListenerClass::commitNoLock() // requires 'SoundAPILock', also because of 'EmulateSound3D'
- {
- // 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
- #if DIRECT_SOUND
- if(DSL)DSL->CommitDeferredSettings();
- #elif XAUDIO
- if(XAudio)XAudio->CommitChanges(XAUDIO2_COMMIT_ALL);
- #elif OPEN_AL
- // alcProcessContext alcSuspendContext are not used because they seem to be a no-op and there's no way to test them
- #elif OPEN_SL
- if(SLListenerCommit)(*SLListenerCommit)->Commit(SLListenerCommit);else EmulateSound3D(); // if listener is not available then it means 3D Audio is simulated manually
- #endif
- }
- Bool ListenerClass::create()
- {
- #if DIRECT_SOUND
- if(DS)
- {
- DSBUFFERDESC dsbd; Zero(dsbd);
- dsbd.dwSize =SIZE(DSBUFFERDESC);
- dsbd.dwFlags=DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;
- SOUND_API_LOCK_FORCE;
- IDirectSoundBuffer *DSB; if(!OK(DS->CreateSoundBuffer(&dsbd, &DSB, null)))return false;
- DSB->QueryInterface(IID_IDirectSound3DListener, (Ptr*)&DSL);
- RELEASE(DSB);
- }
- return DSL!=null;
- #elif XAUDIO
- if(XAudioMasteringVoice)
- {
- #if WINDOWS_OLD
- XAUDIO2_DEVICE_DETAILS details; if(OK(XAudio->GetDeviceDetails(0, &details)))
- {
- X3DAudioInitialize(details.OutputFormat.dwChannelMask, X3DAUDIO_SPEED_OF_SOUND, X3DAudio);
- return true;
- }
- #else
- DWORD channel_mask;
- if(OK(XAudioMasteringVoice->GetChannelMask(&channel_mask)))
- if(OK(X3DAudioInitialize(channel_mask, X3DAUDIO_SPEED_OF_SOUND, X3DAudio)))return true;
- #endif
- }
- #elif OPEN_AL
- return true;
- #elif OPEN_SL
- return true;
- #endif
- return false;
- }
- /******************************************************************************/
- // MAIN
- /******************************************************************************/
- #pragma runtime_checks("", off)
- static UInt GetSpeakerConfig()
- {
- #if DIRECT_SOUND
- if(DS)
- {
- DWORD config; DS->GetSpeakerConfig(&config);
- SetLastError(0); // clear error 14007
- return DSSPEAKER_CONFIG(config);
- }
- #endif
- return 0;
- }
- #pragma runtime_checks("", restore)
- void InitSound()
- {
- if(SoundFunc)return; // return if it was already created
- if(LogInit)LogN("InitSound");
- SOUND_API_LOCK_FORCE;
- SoundFunc=true;
- #if DIRECT_SOUND
- if(OK(DirectSoundCreate(null, &DS, null)))
- if(OK(DS->SetCooperativeLevel(App.Hwnd(), DSSCL_PRIORITY)))
- #elif XAUDIO
- if(OK(XAudio2Create(&XAudio, 0)))
- 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
- {
- XAUDIO2_VOICE_DETAILS details; XAudioMasteringVoice->GetVoiceDetails(&details);
- XAudioChannels=details.InputChannels;
- }
- if(XAudioMasteringVoice)
- #elif OPEN_AL
- if(ALDevice=alcOpenDevice(null))
- {
- if(ALContext=alcCreateContext(ALDevice, null))
- {
- Str desc=alcGetString(ALDevice, ALC_DEVICE_SPECIFIER);
- alcMakeContextCurrent(ALContext);
- }else
- {
- alcCloseDevice(ALDevice); ALDevice=null;
- }
- }
- if(ALContext)
- #elif OPEN_SL
- SLInterfaceID om_ids []={SL_IID_NULL };
- SLboolean om_required[]={SL_BOOLEAN_FALSE};
- // SL_ENGINEOPTION_THREADSAFE is disabled for better performance since we don't need it
- if( slCreateEngine(&SLEngineObject , 0, null, 0, null, null )==SL_RESULT_SUCCESS)
- if((*SLEngineObject )->Realize ( SLEngineObject , SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
- if((*SLEngineObject )->GetInterface ( SLEngineObject , SL_IID_ENGINE, &SLEngineEngine )==SL_RESULT_SUCCESS)
- if((*SLEngineEngine )->CreateOutputMix( SLEngineEngine , &SLOutputMixObject, Elms(om_ids), om_ids, om_required)==SL_RESULT_SUCCESS)
- if((*SLOutputMixObject)->Realize ( SLOutputMixObject, SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
- {
- // create optional stuff
- // 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
- /*if((*SLOutputMixObject)->GetInterface(SLOutputMixObject, SL_IID_ENVIRONMENTALREVERB, &SLOutputMixEnvironmentalReverb)==SL_RESULT_SUCCESS)
- {
- (*SLOutputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(SLOutputMixEnvironmentalReverb, &reverbSettings);
- }*/
- SLInterfaceID l_ids []={SL_IID_3DLOCATION, SL_IID_3DCOMMIT /*, SL_IID_3DDOPPLER*/}; // don't create doppler effect to increase performance
- SLboolean l_required[]={SL_BOOLEAN_TRUE , SL_BOOLEAN_FALSE/*, SL_BOOLEAN_FALSE*/};
- if((*SLEngineEngine )->CreateListener(SLEngineEngine , &SLListenerObject, Elms(l_ids), l_ids, l_required)==SL_RESULT_SUCCESS)
- if((*SLListenerObject)->Realize (SLListenerObject, SL_BOOLEAN_FALSE )==SL_RESULT_SUCCESS)
- if((*SLListenerObject)->GetInterface (SLListenerObject, SL_IID_3DLOCATION, &SLListenerLocation )==SL_RESULT_SUCCESS)
- {
- // create optional stuff
- (*SLListenerObject)->GetInterface(SLListenerObject, SL_IID_3DDOPPLER, &SLListenerDoppler);
- if((*SLListenerObject)->GetInterface(SLListenerObject, SL_IID_3DCOMMIT, &SLListenerCommit)==SL_RESULT_SUCCESS)
- {
- (*SLListenerCommit)->SetDeferred(SLListenerCommit, SL_BOOLEAN_TRUE); // set deferred 3D committing
- }
- }
- }
- if(SLOutputMixObject)
- #endif
- {
- #if WINDOWS_OLD
- SetLastError(0); // clear error 1407
- #endif
- Listener.create();
- SoundAPI=true;
- }
- InitSound2(); // create the thread even when SoundAPI failed so we can still process sounds without playing them
- }
- void ShutSound()
- {
- SoundFunc=SoundAPI=false; // this also disables creation of new objects
- ShutSound2(); // destroy thread and sounds
- ShutMusic ();
- SOUND_API_LOCK_FORCE; // lock after deleting 'SoundThread'
- #if DIRECT_SOUND
- RELEASE(DSL);
- RELEASE(DS );
- #elif XAUDIO
- if(XAudioMasteringVoice){XAudioMasteringVoice->DestroyVoice(); XAudioMasteringVoice=null;}
- RELEASE(XAudio);
- #elif OPEN_AL
- alcMakeContextCurrent(null );
- if(ALContext){alcDestroyContext (ALContext); ALContext=null;}
- if(ALDevice ){alcCloseDevice (ALDevice ); ALDevice =null;}
- #elif OPEN_SL
- SLListenerLocation=null;
- SLListenerDoppler =null;
- SLListenerCommit =null;
- if(SLListenerObject){(*SLListenerObject)->Destroy(SLListenerObject); SLListenerObject=null;}
- if(SLOutputMixObject){(*SLOutputMixObject)->Destroy(SLOutputMixObject); SLOutputMixObject=null;}
- SLEngineEngine=null;
- if(SLEngineObject){(*SLEngineObject)->Destroy(SLEngineObject); SLEngineObject=null;}
- #endif
- AppVolume.del();
- }
- /******************************************************************************/
- }
- /******************************************************************************/
|