Removed: OpenAL music implementation
--HG-- branch : sound_dev
This commit is contained in:
parent
dd02d76df8
commit
8491bd4829
7 changed files with 100 additions and 827 deletions
|
@ -145,9 +145,8 @@ void CListenerAL::getOrientation( NLMISC::CVector& front, NLMISC::CVector& u
|
||||||
*/
|
*/
|
||||||
void CListenerAL::setGain( float gain )
|
void CListenerAL::setGain( float gain )
|
||||||
{
|
{
|
||||||
CSoundDriverAL::getInstance()->setGain(gain);
|
alListenerf( AL_GAIN, gain );
|
||||||
// alListenerf( AL_GAIN, gain );
|
alTestError();
|
||||||
// alTestError();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,15 +155,14 @@ void CListenerAL::setGain( float gain )
|
||||||
*/
|
*/
|
||||||
float CListenerAL::getGain() const
|
float CListenerAL::getGain() const
|
||||||
{
|
{
|
||||||
return CSoundDriverAL::getInstance()->getGain();
|
ALfloat gain;
|
||||||
// ALfloat gain;
|
#ifdef NL_OS_WINDOWS
|
||||||
//#ifdef NL_OS_WINDOWS
|
alGetListenerf( AL_GAIN, &gain );
|
||||||
// alGetListenerf( AL_GAIN, &gain );
|
#else
|
||||||
//#else
|
alGetListenerfv( AL_GAIN, &gain );
|
||||||
// alGetListenerfv( AL_GAIN, &gain );
|
#endif
|
||||||
//#endif
|
alTestError();
|
||||||
// alTestError();
|
return gain;
|
||||||
// return gain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,328 +0,0 @@
|
||||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
||||||
// Copyright (C) 2010 Winch Gate Property Limited
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#include "stdopenal.h"
|
|
||||||
|
|
||||||
// Project includes
|
|
||||||
#include "sound_driver_al.h"
|
|
||||||
#include "source_al.h"
|
|
||||||
#include "buffer_al.h"
|
|
||||||
#include "music_channel_al.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace NLMISC;
|
|
||||||
|
|
||||||
namespace NLSOUND
|
|
||||||
{
|
|
||||||
|
|
||||||
CMusicChannelAL::CMusicChannelAL(CSoundDriverAL *soundDriver)
|
|
||||||
: _SoundDriver(soundDriver), _MusicBuffer(NULL), _Thread(NULL), _Buffer(NULL), _Source(NULL), _Playing(false), _Async(false), _Gain(1.0)
|
|
||||||
{
|
|
||||||
// create a default source for music streaming
|
|
||||||
_Source = static_cast<CSourceAL*>(_SoundDriver->createSource());
|
|
||||||
_Source->setType(SourceMusic);
|
|
||||||
_Source->setStreamingBufferSize(32768);
|
|
||||||
}
|
|
||||||
|
|
||||||
CMusicChannelAL::~CMusicChannelAL()
|
|
||||||
{
|
|
||||||
release();
|
|
||||||
if (_SoundDriver) { _SoundDriver->removeMusicChannel(this); _SoundDriver = NULL; }
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMusicChannelAL::release()
|
|
||||||
{
|
|
||||||
// stop thread before deleting it
|
|
||||||
stop();
|
|
||||||
|
|
||||||
// delete thread
|
|
||||||
if (_Thread)
|
|
||||||
{
|
|
||||||
delete _Thread;
|
|
||||||
_Thread = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete source
|
|
||||||
if (_Source)
|
|
||||||
{
|
|
||||||
delete _Source;
|
|
||||||
_Source = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fill IBuffer with data from IMusicBuffer
|
|
||||||
bool CMusicChannelAL::fillBuffer(IBuffer *buffer, uint length)
|
|
||||||
{
|
|
||||||
if (!buffer || !length)
|
|
||||||
{
|
|
||||||
nlwarning("AL: No data to stream");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill buffer with music data
|
|
||||||
uint8 *tmp = buffer->lock(length);
|
|
||||||
if (tmp == NULL)
|
|
||||||
{
|
|
||||||
nlwarning("AL: Can't allocate %u bytes for buffer", length);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 size = _MusicBuffer->getNextBytes(tmp, length, length);
|
|
||||||
buffer->unlock(size);
|
|
||||||
|
|
||||||
return size > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Use buffer format from IMusicBuffer
|
|
||||||
void CMusicChannelAL::setBufferFormat(IBuffer *buffer)
|
|
||||||
{
|
|
||||||
if (!buffer)
|
|
||||||
{
|
|
||||||
nlwarning("AL: No buffer specified");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the same format as music for buffers
|
|
||||||
buffer->setFormat(IBuffer::FormatPcm, _MusicBuffer->getChannels(),
|
|
||||||
_MusicBuffer->getBitsPerSample(), _MusicBuffer->getSamplesPerSec());
|
|
||||||
}
|
|
||||||
|
|
||||||
void CMusicChannelAL::run()
|
|
||||||
{
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
// use queued buffers
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// buffers to update
|
|
||||||
std::vector<CBufferAL*> buffers;
|
|
||||||
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
// get all buffers to queue
|
|
||||||
_Source->getStreamingBuffers(buffers);
|
|
||||||
|
|
||||||
// set format for each buffer
|
|
||||||
for(uint i = 0; i < buffers.size(); ++i)
|
|
||||||
setBufferFormat(buffers[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// get unqueued buffers
|
|
||||||
_Source->getProcessedStreamingBuffers(buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill buffers
|
|
||||||
for(uint i = 0; i < buffers.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!fillBuffer(buffers[i], _Source->getStreamingBufferSize()))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// add buffer to streaming buffers queue
|
|
||||||
_Source->submitStreamingBuffer(buffers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// play the source
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
_Source->play();
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait 100ms before rechecking buffers
|
|
||||||
nlSleep(100);
|
|
||||||
}
|
|
||||||
while(!_MusicBuffer->isMusicEnded() && _Playing);
|
|
||||||
|
|
||||||
|
|
||||||
// music finished without interruption
|
|
||||||
if (_Playing)
|
|
||||||
{
|
|
||||||
// wait until source is not playing
|
|
||||||
while(_Source->isPlaying() && _Playing) nlSleep(1000);
|
|
||||||
|
|
||||||
_Source->stop();
|
|
||||||
|
|
||||||
_Playing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Play sync music
|
|
||||||
bool CMusicChannelAL::playSync()
|
|
||||||
{
|
|
||||||
// use an unique buffer managed by CMusicChannelAL
|
|
||||||
_Buffer = _SoundDriver->createBuffer();
|
|
||||||
|
|
||||||
// set format
|
|
||||||
setBufferFormat(_Buffer);
|
|
||||||
|
|
||||||
// fill data
|
|
||||||
fillBuffer(_Buffer, _MusicBuffer->getUncompressedSize());
|
|
||||||
|
|
||||||
// we don't need _MusicBuffer anymore because all is loaded into memory
|
|
||||||
if (_MusicBuffer)
|
|
||||||
{
|
|
||||||
delete _MusicBuffer;
|
|
||||||
_MusicBuffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete previous queued buffers
|
|
||||||
_Source->setStreamingBuffersMax(0);
|
|
||||||
|
|
||||||
// use this buffer as source
|
|
||||||
_Source->setStaticBuffer(_Buffer);
|
|
||||||
|
|
||||||
// play the source
|
|
||||||
return _Source->play();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Play some music (.ogg etc...)
|
|
||||||
* NB: if an old music was played, it is first stop with stopMusic()
|
|
||||||
* \param filepath file path, CPath::lookup is done here
|
|
||||||
* \param async stream music from hard disk, preload in memory if false
|
|
||||||
* \param loop must be true to play the music in loop.
|
|
||||||
*/
|
|
||||||
bool CMusicChannelAL::play(const std::string &filepath, bool async, bool loop)
|
|
||||||
{
|
|
||||||
// stop a previous music
|
|
||||||
stop();
|
|
||||||
|
|
||||||
// when not using async, we must load the whole file once
|
|
||||||
_MusicBuffer = IMusicBuffer::createMusicBuffer(filepath, async, async ? loop:false);
|
|
||||||
|
|
||||||
if (_MusicBuffer)
|
|
||||||
{
|
|
||||||
_Async = async;
|
|
||||||
_Playing = true;
|
|
||||||
|
|
||||||
_Source->setSourceRelativeMode(true);
|
|
||||||
|
|
||||||
if (_Async)
|
|
||||||
{
|
|
||||||
// create the thread if it's not yet created
|
|
||||||
if (!_Thread) _Thread = IThread::create(this);
|
|
||||||
|
|
||||||
if (!_Thread)
|
|
||||||
{
|
|
||||||
nlwarning("AL: Can't create a new thread");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use 4 queued buffers
|
|
||||||
_Source->setStreamingBuffersMax(4);
|
|
||||||
|
|
||||||
// we need to loop the source only if not async
|
|
||||||
_Source->setLooping(false);
|
|
||||||
|
|
||||||
// start the thread
|
|
||||||
_Thread->start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we need to loop the source only if not async
|
|
||||||
_Source->setLooping(loop);
|
|
||||||
|
|
||||||
return playSync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nlwarning("AL: Can't stream file %s", filepath.c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stop the music previously loaded and played (the Memory is also freed)
|
|
||||||
void CMusicChannelAL::stop()
|
|
||||||
{
|
|
||||||
_Playing = false;
|
|
||||||
|
|
||||||
_Source->stop();
|
|
||||||
|
|
||||||
// if not using async streaming, we manage static buffer ourself
|
|
||||||
if (!_Async && _Buffer)
|
|
||||||
{
|
|
||||||
_Source->setStaticBuffer(NULL);
|
|
||||||
delete _Buffer;
|
|
||||||
_Buffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until thread is finished
|
|
||||||
if (_Thread)
|
|
||||||
_Thread->wait();
|
|
||||||
|
|
||||||
if (_MusicBuffer)
|
|
||||||
{
|
|
||||||
delete _MusicBuffer;
|
|
||||||
_MusicBuffer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pause the music previously loaded and played (the Memory is not freed)
|
|
||||||
void CMusicChannelAL::pause()
|
|
||||||
{
|
|
||||||
_Source->pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resume the music previously paused
|
|
||||||
void CMusicChannelAL::resume()
|
|
||||||
{
|
|
||||||
_Source->play();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if a song is finished.
|
|
||||||
bool CMusicChannelAL::isEnded()
|
|
||||||
{
|
|
||||||
return !_Playing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if the song is still loading asynchronously and hasn't started playing yet (false if not async), used to delay fading
|
|
||||||
bool CMusicChannelAL::isLoadingAsync()
|
|
||||||
{
|
|
||||||
return _Async && _Playing && !_Source->isPlaying();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the total length (in second) of the music currently played
|
|
||||||
float CMusicChannelAL::getLength()
|
|
||||||
{
|
|
||||||
if (_MusicBuffer) return _MusicBuffer->getLength();
|
|
||||||
else return .0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set the music volume (if any music played). (volume value inside [0 , 1]) (default: 1)
|
|
||||||
* NB: in OpenAL driver, the volume of music IS affected by IListener::setGain()
|
|
||||||
*/
|
|
||||||
void CMusicChannelAL::setVolume(float gain)
|
|
||||||
{
|
|
||||||
_Gain = gain;
|
|
||||||
_Source->setGain(gain);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update music
|
|
||||||
void CMusicChannelAL::update()
|
|
||||||
{
|
|
||||||
// stop sync music once finished playing
|
|
||||||
if (_Playing && !_Async && !_Source->isPlaying())
|
|
||||||
{
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace NLSOUND */
|
|
||||||
|
|
||||||
/* end of file */
|
|
|
@ -1,106 +0,0 @@
|
||||||
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
||||||
// Copyright (C) 2010 Winch Gate Property Limited
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
#ifndef NLSOUND_MUSIC_CHANNEL_AL_H
|
|
||||||
#define NLSOUND_MUSIC_CHANNEL_AL_H
|
|
||||||
|
|
||||||
#include "nel/sound/driver/music_channel.h"
|
|
||||||
|
|
||||||
namespace NLSOUND
|
|
||||||
{
|
|
||||||
class CSoundDriverAL;
|
|
||||||
class IMusicBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief CMusicChannelAL
|
|
||||||
* \date 2010-07-27 16:56GMT
|
|
||||||
* \author Kervala
|
|
||||||
* CMusicChannelAL is an implementation of the IMusicChannel interface to run on OpenAL.
|
|
||||||
*/
|
|
||||||
class CMusicChannelAL : public IMusicChannel, public NLMISC::IRunnable
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
// outside pointers
|
|
||||||
CSoundDriverAL* _SoundDriver;
|
|
||||||
|
|
||||||
// pointers
|
|
||||||
IMusicBuffer* _MusicBuffer;
|
|
||||||
NLMISC::IThread* _Thread;
|
|
||||||
|
|
||||||
IBuffer* _Buffer;
|
|
||||||
CSourceAL* _Source;
|
|
||||||
bool _Playing;
|
|
||||||
bool _Async;
|
|
||||||
|
|
||||||
float _Gain;
|
|
||||||
|
|
||||||
/// Fill IBuffer with data from IMusicBuffer
|
|
||||||
bool fillBuffer(IBuffer *buffer, uint length);
|
|
||||||
|
|
||||||
/// Use buffer format from IMusicBuffer
|
|
||||||
void setBufferFormat(IBuffer *buffer);
|
|
||||||
|
|
||||||
/// Declared in NLMISC::IRunnable interface
|
|
||||||
virtual void run();
|
|
||||||
|
|
||||||
public:
|
|
||||||
CMusicChannelAL(CSoundDriverAL *soundDriver);
|
|
||||||
virtual ~CMusicChannelAL();
|
|
||||||
void release();
|
|
||||||
|
|
||||||
/** Play some music (.ogg etc...)
|
|
||||||
* NB: if an old music was played, it is first stop with stopMusic()
|
|
||||||
* \param filepath file path, CPath::lookup is done here
|
|
||||||
* \param async stream music from hard disk, preload in memory if false
|
|
||||||
* \param loop must be true to play the music in loop.
|
|
||||||
*/
|
|
||||||
virtual bool play(const std::string &filepath, bool async, bool loop);
|
|
||||||
|
|
||||||
/// Stop the music previously loaded and played (the Memory is also freed)
|
|
||||||
virtual void stop();
|
|
||||||
|
|
||||||
/// Pause the music previously loaded and played (the Memory is not freed)
|
|
||||||
virtual void pause();
|
|
||||||
|
|
||||||
/// Resume the music previously paused
|
|
||||||
virtual void resume();
|
|
||||||
|
|
||||||
/// Return true if a song is finished.
|
|
||||||
virtual bool isEnded();
|
|
||||||
|
|
||||||
/// Return true if the song is still loading asynchronously and hasn't started playing yet (false if not async), used to delay fading
|
|
||||||
virtual bool isLoadingAsync();
|
|
||||||
|
|
||||||
/// Return the total length (in second) of the music currently played
|
|
||||||
virtual float getLength();
|
|
||||||
|
|
||||||
/** Set the music volume (if any music played). (volume value inside [0 , 1]) (default: 1)
|
|
||||||
* NB: in OpenAL driver, the volume of music IS affected by IListener::setGain()
|
|
||||||
*/
|
|
||||||
virtual void setVolume(float gain);
|
|
||||||
|
|
||||||
/// Play sync music
|
|
||||||
bool playSync();
|
|
||||||
|
|
||||||
/// Update music
|
|
||||||
void update();
|
|
||||||
}; /* class CMusicChannelAL */
|
|
||||||
|
|
||||||
} /* namespace NLSOUND */
|
|
||||||
|
|
||||||
#endif /* #ifndef NLSOUND_MUSIC_CHANNEL_AL_H */
|
|
||||||
|
|
||||||
/* end of file */
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include "stdopenal.h"
|
#include "stdopenal.h"
|
||||||
#include "sound_driver_al.h"
|
#include "sound_driver_al.h"
|
||||||
#include "music_channel_al.h"
|
|
||||||
#include "buffer_al.h"
|
#include "buffer_al.h"
|
||||||
#include "listener_al.h"
|
#include "listener_al.h"
|
||||||
#include "source_al.h"
|
#include "source_al.h"
|
||||||
|
@ -174,7 +173,7 @@ uint32 NLSOUND_interfaceVersion ()
|
||||||
*/
|
*/
|
||||||
CSoundDriverAL::CSoundDriverAL(ISoundDriver::IStringMapperProvider *stringMapper)
|
CSoundDriverAL::CSoundDriverAL(ISoundDriver::IStringMapperProvider *stringMapper)
|
||||||
: _StringMapper(stringMapper), _AlDevice(NULL), _AlContext(NULL),
|
: _StringMapper(stringMapper), _AlDevice(NULL), _AlContext(NULL),
|
||||||
_NbExpBuffers(0), _NbExpSources(0), _RolloffFactor(1.f), _MasterGain(1.f)
|
_NbExpBuffers(0), _NbExpSources(0), _RolloffFactor(1.f)
|
||||||
{
|
{
|
||||||
alExtInit();
|
alExtInit();
|
||||||
}
|
}
|
||||||
|
@ -184,21 +183,13 @@ _NbExpBuffers(0), _NbExpSources(0), _RolloffFactor(1.f), _MasterGain(1.f)
|
||||||
*/
|
*/
|
||||||
CSoundDriverAL::~CSoundDriverAL()
|
CSoundDriverAL::~CSoundDriverAL()
|
||||||
{
|
{
|
||||||
// Release internal resources of all remaining IMusicChannel instances
|
|
||||||
if (_MusicChannels.size())
|
|
||||||
{
|
|
||||||
nlwarning("AL: _MusicChannels.size(): '%u'", (uint32)_MusicChannels.size());
|
|
||||||
set<CMusicChannelAL *>::iterator it(_MusicChannels.begin()), end(_MusicChannels.end());
|
|
||||||
for (; it != end; ++it) delete *it;
|
|
||||||
_MusicChannels.clear();
|
|
||||||
}
|
|
||||||
// Remove the allocated (but not exported) source and buffer names-
|
// Remove the allocated (but not exported) source and buffer names-
|
||||||
// Release internal resources of all remaining ISource instances
|
// Release internal resources of all remaining ISource instances
|
||||||
if (_Sources.size())
|
if (_Sources.size())
|
||||||
{
|
{
|
||||||
nlwarning("AL: _Sources.size(): '%u'", (uint32)_Sources.size());
|
nlwarning("AL: _Sources.size(): '%u'", (uint32)_Sources.size());
|
||||||
set<CSourceAL *>::iterator it(_Sources.begin()), end(_Sources.end());
|
set<CSourceAL *>::iterator it(_Sources.begin()), end(_Sources.end());
|
||||||
for (; it != end; ++it) it->release();
|
for (; it != end; ++it) (*it)->release(); // CSourceAL will be deleted by user
|
||||||
_Sources.clear();
|
_Sources.clear();
|
||||||
}
|
}
|
||||||
if (!_Buffers.empty()) alDeleteBuffers(compactAliveNames(_Buffers, alIsBuffer), &*_Buffers.begin());
|
if (!_Buffers.empty()) alDeleteBuffers(compactAliveNames(_Buffers, alIsBuffer), &*_Buffers.begin());
|
||||||
|
@ -207,7 +198,7 @@ CSoundDriverAL::~CSoundDriverAL()
|
||||||
{
|
{
|
||||||
nlwarning("AL: _Effects.size(): '%u'", (uint32)_Effects.size());
|
nlwarning("AL: _Effects.size(): '%u'", (uint32)_Effects.size());
|
||||||
set<CEffectAL *>::iterator it(_Effects.begin()), end(_Effects.end());
|
set<CEffectAL *>::iterator it(_Effects.begin()), end(_Effects.end());
|
||||||
for (; it != end; ++it) it->release();
|
for (; it != end; ++it) (*it)->release(); // CEffectAL will be deleted by user
|
||||||
_Effects.clear();
|
_Effects.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,9 +613,6 @@ void CSoundDriverAL::commit3DChanges()
|
||||||
for (std::set<CSourceAL *>::iterator it(_Sources.begin()), end(_Sources.end()); it != end; ++it)
|
for (std::set<CSourceAL *>::iterator it(_Sources.begin()), end(_Sources.end()); it != end; ++it)
|
||||||
(*it)->updateManualRolloff();
|
(*it)->updateManualRolloff();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the music (XFade etc...)
|
|
||||||
updateMusic();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write information about the driver to the output stream.
|
/// Write information about the driver to the output stream.
|
||||||
|
@ -652,23 +640,6 @@ void CSoundDriverAL::displayBench(NLMISC::CLog *log)
|
||||||
NLMISC::CHTimer::display(log, CHTimer::TotalTime);
|
NLMISC::CHTimer::display(log, CHTimer::TotalTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get music info. Returns false if the song is not found or the function is not implemented.
|
|
||||||
* \param filepath path to file, CPath::lookup done by driver
|
|
||||||
* \param artist returns the song artist (empty if not available)
|
|
||||||
* \param title returns the title (empty if not available)
|
|
||||||
*/
|
|
||||||
bool CSoundDriverAL::getMusicInfo(const std::string &filepath, std::string &artist, std::string &title)
|
|
||||||
{
|
|
||||||
// add support for additional non-standard music file types info here
|
|
||||||
return IMusicBuffer::getInfo(filepath, artist, title);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSoundDriverAL::updateMusic()
|
|
||||||
{
|
|
||||||
set<CMusicChannelAL *>::iterator it(_MusicChannels.begin()), end(_MusicChannels.end());
|
|
||||||
for (; it != end; ++it) (*it)->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove a buffer
|
/// Remove a buffer
|
||||||
void CSoundDriverAL::removeBuffer(CBufferAL *buffer)
|
void CSoundDriverAL::removeBuffer(CBufferAL *buffer)
|
||||||
{
|
{
|
||||||
|
@ -691,35 +662,6 @@ void CSoundDriverAL::removeEffect(CEffectAL *effect)
|
||||||
else nlwarning("AL: removeEffect already called");
|
else nlwarning("AL: removeEffect already called");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a music channel
|
|
||||||
IMusicChannel *CSoundDriverAL::createMusicChannel()
|
|
||||||
{
|
|
||||||
CMusicChannelAL *music_channel = new CMusicChannelAL(this);
|
|
||||||
_MusicChannels.insert(music_channel);
|
|
||||||
return static_cast<IMusicChannel *>(music_channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// (Internal) Remove a music channel (should be called by the destructor of the music channel class).
|
|
||||||
void CSoundDriverAL::removeMusicChannel(CMusicChannelAL *musicChannel)
|
|
||||||
{
|
|
||||||
if (_MusicChannels.find(musicChannel) != _MusicChannels.end()) _MusicChannels.erase(musicChannel);
|
|
||||||
else nlwarning("AL: removeMusicChannel already called");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the gain
|
|
||||||
void CSoundDriverAL::setGain( float gain )
|
|
||||||
{
|
|
||||||
clamp(gain, 0.f, 1.f);
|
|
||||||
_MasterGain= gain;
|
|
||||||
// TODO: update all sources in not using manual rollof ?
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the gain
|
|
||||||
float CSoundDriverAL::getGain()
|
|
||||||
{
|
|
||||||
return _MasterGain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete a buffer or a source
|
/// Delete a buffer or a source
|
||||||
bool CSoundDriverAL::deleteItem( ALuint name, TDeleteFunctionAL aldeletefunc, vector<ALuint>& names )
|
bool CSoundDriverAL::deleteItem( ALuint name, TDeleteFunctionAL aldeletefunc, vector<ALuint>& names )
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,13 +19,11 @@
|
||||||
|
|
||||||
#include <nel/sound/driver/sound_driver.h>
|
#include <nel/sound/driver/sound_driver.h>
|
||||||
|
|
||||||
namespace NLSOUND
|
namespace NLSOUND {
|
||||||
{
|
|
||||||
class CBufferAL;
|
class CBufferAL;
|
||||||
class CListenerAL;
|
class CListenerAL;
|
||||||
class CSourceAL;
|
class CSourceAL;
|
||||||
class CEffectAL;
|
class CEffectAL;
|
||||||
class CMusicChannelAL;
|
|
||||||
|
|
||||||
// alGenBuffers, alGenSources
|
// alGenBuffers, alGenSources
|
||||||
//typedef ALAPI ALvoid ALAPIENTRY (*TGenFunctionAL) ( ALsizei, ALuint* );
|
//typedef ALAPI ALvoid ALAPIENTRY (*TGenFunctionAL) ( ALsizei, ALuint* );
|
||||||
|
@ -82,8 +80,6 @@ private:
|
||||||
std::set<CSourceAL *> _Sources;
|
std::set<CSourceAL *> _Sources;
|
||||||
// Allocated effects
|
// Allocated effects
|
||||||
std::set<CEffectAL *> _Effects;
|
std::set<CEffectAL *> _Effects;
|
||||||
/// Array with the allocated music channels created by client code.
|
|
||||||
std::set<CMusicChannelAL *> _MusicChannels;
|
|
||||||
// Number of exported buffers (including any deleted buffers)
|
// Number of exported buffers (including any deleted buffers)
|
||||||
uint _NbExpBuffers;
|
uint _NbExpBuffers;
|
||||||
// Number of exported sources (including any deleted sources)
|
// Number of exported sources (including any deleted sources)
|
||||||
|
@ -101,6 +97,10 @@ public:
|
||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~CSoundDriverAL();
|
virtual ~CSoundDriverAL();
|
||||||
|
|
||||||
|
inline ALCdevice *getAlDevice() { return _AlDevice; }
|
||||||
|
inline ALCcontext *getAlContext() { return _AlContext; }
|
||||||
|
inline float getRolloffFactor() { return _RolloffFactor; }
|
||||||
|
|
||||||
/// Return a list of available devices for the user. The value at index 0 is empty, and is used for automatic device selection.
|
/// Return a list of available devices for the user. The value at index 0 is empty, and is used for automatic device selection.
|
||||||
virtual void getDevices(std::vector<std::string> &devices);
|
virtual void getDevices(std::vector<std::string> &devices);
|
||||||
/// Initialize the driver with a user selected device. If device.empty(), the default or most appropriate device is used.
|
/// Initialize the driver with a user selected device. If device.empty(), the default or most appropriate device is used.
|
||||||
|
@ -111,73 +111,46 @@ public:
|
||||||
/// Return if an option is enabled (including those that cannot be disabled on this driver).
|
/// Return if an option is enabled (including those that cannot be disabled on this driver).
|
||||||
virtual bool getOption(TSoundOptions option);
|
virtual bool getOption(TSoundOptions option);
|
||||||
|
|
||||||
/// Commit all the changes made to 3D settings of listener and sources
|
/// Create a sound buffer
|
||||||
virtual void commit3DChanges();
|
virtual IBuffer *createBuffer();
|
||||||
|
|
||||||
/// Create the listener instance
|
/// Create the listener instance
|
||||||
virtual IListener *createListener();
|
virtual IListener *createListener();
|
||||||
/// Create a source, destroy with delete
|
/// Create a source
|
||||||
virtual ISource *createSource();
|
virtual ISource *createSource();
|
||||||
/// Create a sound buffer, destroy with delete
|
|
||||||
virtual IBuffer *createBuffer();
|
|
||||||
/// Create a reverb effect
|
/// Create a reverb effect
|
||||||
virtual IReverbEffect *createReverbEffect();
|
virtual IReverbEffect *createReverbEffect();
|
||||||
/// Return the maximum number of sources that can created
|
/// Return the maximum number of sources that can created
|
||||||
virtual uint countMaxSources();
|
virtual uint countMaxSources();
|
||||||
/// Return the maximum number of effects that can be created
|
/// Return the maximum number of effects that can be created
|
||||||
virtual uint countMaxEffects();
|
virtual uint countMaxEffects();
|
||||||
|
|
||||||
/// Write information about the driver to the output stream.
|
|
||||||
virtual void writeProfile(std::string& /* out */);
|
|
||||||
|
|
||||||
virtual void startBench();
|
virtual void startBench();
|
||||||
virtual void endBench();
|
virtual void endBench();
|
||||||
virtual void displayBench(NLMISC::CLog * /* log */);
|
virtual void displayBench(NLMISC::CLog * /* log */);
|
||||||
|
|
||||||
/// Create a music channel, destroy with destroyMusicChannel.
|
|
||||||
virtual IMusicChannel *createMusicChannel();
|
|
||||||
|
|
||||||
/** Get music info. Returns false if the song is not found or the function is not implemented.
|
|
||||||
* \param filepath path to file, CPath::lookup done by driver
|
|
||||||
* \param artist returns the song artist (empty if not available)
|
|
||||||
* \param title returns the title (empty if not available)
|
|
||||||
*/
|
|
||||||
virtual bool getMusicInfo(const std::string &filepath, std::string &artist, std::string &title);
|
|
||||||
|
|
||||||
/// Get audio/container extensions that are supported natively by the driver implementation.
|
|
||||||
virtual void getMusicExtensions(std::vector<std::string> & /* extensions */) const { }
|
|
||||||
/// Return if a music extension is supported by the driver's music channel.
|
|
||||||
virtual bool isMusicExtensionSupported(const std::string & /* extension */) const { return false; }
|
|
||||||
|
|
||||||
ALCdevice *getAlDevice() { return _AlDevice; }
|
|
||||||
ALCcontext *getAlContext() { return _AlContext; }
|
|
||||||
float getRolloffFactor() { return _RolloffFactor; }
|
|
||||||
|
|
||||||
/// Change the rolloff factor and apply to all sources
|
/// Change the rolloff factor and apply to all sources
|
||||||
void applyRolloffFactor(float f);
|
void applyRolloffFactor(float f);
|
||||||
|
|
||||||
|
/// Commit all the changes made to 3D settings of listener and sources
|
||||||
|
virtual void commit3DChanges();
|
||||||
|
|
||||||
|
/// Write information about the driver to the output stream.
|
||||||
|
virtual void writeProfile(std::string& /* out */);
|
||||||
|
|
||||||
/// Remove a buffer
|
/// Remove a buffer
|
||||||
void removeBuffer(CBufferAL *buffer);
|
void removeBuffer(CBufferAL *buffer);
|
||||||
/// Remove a source
|
/// Remove a source
|
||||||
void removeSource(CSourceAL *source);
|
void removeSource(CSourceAL *source);
|
||||||
/// Remove an effect
|
/// Remove an effect
|
||||||
void removeEffect(CEffectAL *effect);
|
void removeEffect(CEffectAL *effect);
|
||||||
/// (Internal) Remove music channel (should be called by the destructor of the music channel class).
|
|
||||||
void removeMusicChannel(CMusicChannelAL *musicChannel);
|
|
||||||
|
|
||||||
/** Set the gain (volume value inside [0 , 1]). (default: 1)
|
/// Get audio/container extensions that are supported natively by the driver implementation.
|
||||||
* 0.0 -> silence
|
virtual void getMusicExtensions(std::vector<std::string> & /* extensions */) const { }
|
||||||
* 0.5 -> -6dB
|
/// Return if a music extension is supported by the driver's music channel.
|
||||||
* 1.0 -> no attenuation
|
virtual bool isMusicExtensionSupported(const std::string & /* extension */) const { return false; }
|
||||||
* values > 1 (amplification) not supported by most drivers
|
|
||||||
*/
|
|
||||||
void setGain( float gain );
|
|
||||||
|
|
||||||
/// Get the gain
|
|
||||||
float getGain();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateMusic();
|
|
||||||
|
|
||||||
/// Allocate nb new buffers or sources
|
/// Allocate nb new buffers or sources
|
||||||
void allocateNewItems( TGenFunctionAL algenfunc, TTestFunctionAL altestfunc,
|
void allocateNewItems( TGenFunctionAL algenfunc, TTestFunctionAL altestfunc,
|
||||||
|
@ -195,9 +168,6 @@ protected:
|
||||||
|
|
||||||
/// Delete a buffer or a source
|
/// Delete a buffer or a source
|
||||||
bool deleteItem( ALuint name, TDeleteFunctionAL aldeletefunc, std::vector<ALuint>& names );
|
bool deleteItem( ALuint name, TDeleteFunctionAL aldeletefunc, std::vector<ALuint>& names );
|
||||||
|
|
||||||
/// Master Volume [0,1]
|
|
||||||
float _MasterGain;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,55 +15,36 @@
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "stdopenal.h"
|
#include "stdopenal.h"
|
||||||
#include "source_al.h"
|
|
||||||
#include "sound_driver_al.h"
|
#include "sound_driver_al.h"
|
||||||
#include "listener_al.h"
|
#include "listener_al.h"
|
||||||
#include "effect_al.h"
|
#include "effect_al.h"
|
||||||
#include "buffer_al.h"
|
#include "buffer_al.h"
|
||||||
|
#include "source_al.h"
|
||||||
#include "ext_al.h"
|
#include "ext_al.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace NLMISC;
|
using namespace NLMISC;
|
||||||
|
|
||||||
namespace NLSOUND
|
namespace NLSOUND {
|
||||||
|
|
||||||
|
CSourceAL::CSourceAL(CSoundDriverAL *soundDriver) :
|
||||||
|
_SoundDriver(NULL), _Buffer(NULL), _Source(AL_NONE),
|
||||||
|
_DirectFilter(AL_FILTER_NULL), _EffectFilter(AL_FILTER_NULL),
|
||||||
|
_IsPlaying(false), _IsPaused(false), _StartTime(0),
|
||||||
|
_Pos(0.0f, 0.0f, 0.0f), _Gain(NLSOUND_DEFAULT_GAIN), _Alpha(1.0),
|
||||||
|
_MinDistance(1.0f), _MaxDistance(numeric_limits<float>::max()),
|
||||||
|
_Effect(NULL), _Direct(true),
|
||||||
|
_DirectGain(NLSOUND_DEFAULT_DIRECT_GAIN), _EffectGain(NLSOUND_DEFAULT_EFFECT_GAIN),
|
||||||
|
_DirectFilterType(ISource::FilterLowPass), _EffectFilterType(ISource::FilterLowPass),
|
||||||
|
_DirectFilterEnabled(false), _EffectFilterEnabled(false),
|
||||||
|
_DirectFilterPassGain(NLSOUND_DEFAULT_FILTER_PASS_GAIN), _EffectFilterPassGain(NLSOUND_DEFAULT_FILTER_PASS_GAIN)
|
||||||
{
|
{
|
||||||
|
|
||||||
CSourceAL::CSourceAL(CSoundDriverAL *soundDriver):ISource(), _SoundDriver(NULL), _Source(AL_NONE),
|
|
||||||
_DirectFilter(AL_FILTER_NULL), _EffectFilter(AL_FILTER_NULL)
|
|
||||||
{
|
|
||||||
_IsPlaying = false;
|
|
||||||
_IsPaused = false;
|
|
||||||
_StartTime = 0;
|
|
||||||
|
|
||||||
_Type = SourceSound;
|
|
||||||
_Buffer = NULL;
|
|
||||||
_BuffersMax = 0;
|
|
||||||
_BufferSize = 32768;
|
|
||||||
|
|
||||||
_PosRelative = false;
|
|
||||||
_Gain = NLSOUND_DEFAULT_GAIN;
|
|
||||||
_Alpha = 0.0;
|
|
||||||
_Pos = CVector::Null;
|
|
||||||
_MinDistance = 1.0f;
|
|
||||||
_MaxDistance = numeric_limits<float>::max();
|
|
||||||
|
|
||||||
_Effect = NULL;
|
|
||||||
_Direct = true;
|
|
||||||
_DirectGain = NLSOUND_DEFAULT_DIRECT_GAIN;
|
|
||||||
_EffectGain = NLSOUND_DEFAULT_EFFECT_GAIN;
|
|
||||||
_DirectFilterType = ISource::FilterLowPass;
|
|
||||||
_EffectFilterType = ISource::FilterLowPass;
|
|
||||||
_DirectFilterEnabled = false;
|
|
||||||
_EffectFilterEnabled = false;
|
|
||||||
_DirectFilterPassGain = NLSOUND_DEFAULT_FILTER_PASS_GAIN;
|
|
||||||
_EffectFilterPassGain = NLSOUND_DEFAULT_FILTER_PASS_GAIN;
|
|
||||||
|
|
||||||
// create the al source
|
// create the al source
|
||||||
alGenSources(1, &_Source);
|
alGenSources(1, &_Source);
|
||||||
alTestError();
|
alTestError();
|
||||||
|
|
||||||
// configure rolloff
|
// configure rolloff
|
||||||
if (!soundDriver || soundDriver->getOption(ISoundDriver::OptionManualRolloff))
|
if (soundDriver->getOption(ISoundDriver::OptionManualRolloff))
|
||||||
{
|
{
|
||||||
alSourcef(_Source, AL_ROLLOFF_FACTOR, 0);
|
alSourcef(_Source, AL_ROLLOFF_FACTOR, 0);
|
||||||
alTestError();
|
alTestError();
|
||||||
|
@ -73,16 +54,15 @@ CSourceAL::CSourceAL(CSoundDriverAL *soundDriver):ISource(), _SoundDriver(NULL),
|
||||||
alSourcef(_Source, AL_ROLLOFF_FACTOR, soundDriver->getRolloffFactor());
|
alSourcef(_Source, AL_ROLLOFF_FACTOR, soundDriver->getRolloffFactor());
|
||||||
alTestError();
|
alTestError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// create filters
|
// create filters
|
||||||
if (soundDriver && soundDriver->getOption(ISoundDriver::OptionEnvironmentEffects))
|
if (soundDriver->getOption(ISoundDriver::OptionEnvironmentEffects))
|
||||||
{
|
{
|
||||||
alGenFilters(1, &_DirectFilter);
|
alGenFilters(1, &_DirectFilter);
|
||||||
alFilteri(_DirectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
|
alFilteri(_DirectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
|
||||||
alFilterf(_DirectFilter, AL_LOWPASS_GAIN, NLSOUND_DEFAULT_DIRECT_GAIN);
|
alFilterf(_DirectFilter, AL_LOWPASS_GAIN, NLSOUND_DEFAULT_DIRECT_GAIN);
|
||||||
alFilterf(_DirectFilter, AL_LOWPASS_GAINHF, NLSOUND_DEFAULT_FILTER_PASS_GAIN);
|
alFilterf(_DirectFilter, AL_LOWPASS_GAINHF, NLSOUND_DEFAULT_FILTER_PASS_GAIN);
|
||||||
alTestError();
|
alTestError();
|
||||||
|
|
||||||
alGenFilters(1, &_EffectFilter);
|
alGenFilters(1, &_EffectFilter);
|
||||||
alFilteri(_EffectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
|
alFilteri(_EffectFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
|
||||||
alFilterf(_EffectFilter, AL_LOWPASS_GAIN, NLSOUND_DEFAULT_EFFECT_GAIN);
|
alFilterf(_EffectFilter, AL_LOWPASS_GAIN, NLSOUND_DEFAULT_EFFECT_GAIN);
|
||||||
|
@ -103,8 +83,6 @@ CSourceAL::~CSourceAL()
|
||||||
|
|
||||||
void CSourceAL::release()
|
void CSourceAL::release()
|
||||||
{
|
{
|
||||||
unqueueBuffers();
|
|
||||||
removeBuffers();
|
|
||||||
if (_Source != AL_NONE) { alDeleteSources(1, &_Source); _Source = AL_NONE; }
|
if (_Source != AL_NONE) { alDeleteSources(1, &_Source); _Source = AL_NONE; }
|
||||||
if (_DirectFilter != AL_FILTER_NULL) { alDeleteFilters(1, &_DirectFilter); _DirectFilter = AL_FILTER_NULL; }
|
if (_DirectFilter != AL_FILTER_NULL) { alDeleteFilters(1, &_DirectFilter); _DirectFilter = AL_FILTER_NULL; }
|
||||||
if (_EffectFilter != AL_FILTER_NULL) { alDeleteFilters(1, &_EffectFilter); _EffectFilter = AL_FILTER_NULL; }
|
if (_EffectFilter != AL_FILTER_NULL) { alDeleteFilters(1, &_EffectFilter); _EffectFilter = AL_FILTER_NULL; }
|
||||||
|
@ -114,37 +92,13 @@ void CSourceAL::release()
|
||||||
/// (Internal) Update the 3d changes.
|
/// (Internal) Update the 3d changes.
|
||||||
void CSourceAL::updateManualRolloff()
|
void CSourceAL::updateManualRolloff()
|
||||||
{
|
{
|
||||||
CVector pos = getPos();
|
CVector distanceVector = _Pos - CListenerAL::getInstance()->getPos();
|
||||||
|
float distanceSquare = distanceVector.sqrnorm();
|
||||||
// make relative to listener (if not already!)
|
float rolloff = ISource::computeManualRolloff(_Alpha, distanceSquare, _MinDistance, _MaxDistance);
|
||||||
if (!_PosRelative)
|
alSourcef(_Source, AL_GAIN, _Gain * rolloff);
|
||||||
pos -= CListenerAL::getInstance()->getPos();
|
|
||||||
|
|
||||||
float sqrdist = pos.sqrnorm();
|
|
||||||
float rolloff = ISource::computeManualRolloff(_Alpha, sqrdist, _MinDistance, _MaxDistance);
|
|
||||||
float volume = _Gain * rolloff;
|
|
||||||
|
|
||||||
// apply SFX volume
|
|
||||||
if (_SoundDriver && _Type == SourceSound)
|
|
||||||
volume *= _SoundDriver->getGain();
|
|
||||||
|
|
||||||
// set the attenuated volume
|
|
||||||
alSourcef(_Source, AL_GAIN, volume);
|
|
||||||
alTestError();
|
alTestError();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set type of the source
|
|
||||||
void CSourceAL::setType(TSourceType type)
|
|
||||||
{
|
|
||||||
_Type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get type of the source
|
|
||||||
TSourceType CSourceAL::getType() const
|
|
||||||
{
|
|
||||||
return _Type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enable or disable streaming mode. Source must be stopped to call this.
|
/// Enable or disable streaming mode. Source must be stopped to call this.
|
||||||
void CSourceAL::setStreaming(bool /* streaming */)
|
void CSourceAL::setStreaming(bool /* streaming */)
|
||||||
{
|
{
|
||||||
|
@ -199,11 +153,10 @@ void CSourceAL::submitStreamingBuffer(IBuffer *buffer)
|
||||||
CBufferAL *bufferAL = static_cast<CBufferAL *>(buffer);
|
CBufferAL *bufferAL = static_cast<CBufferAL *>(buffer);
|
||||||
ALuint bufferName = bufferAL->bufferName();
|
ALuint bufferName = bufferAL->bufferName();
|
||||||
nlassert(bufferName);
|
nlassert(bufferName);
|
||||||
|
|
||||||
// queue the buffer
|
|
||||||
alSourceQueueBuffers(_Source, 1, &bufferName);
|
alSourceQueueBuffers(_Source, 1, &bufferName);
|
||||||
alTestError();
|
alTestError();
|
||||||
|
_QueuedBuffers.push(bufferAL);
|
||||||
|
|
||||||
// Resume playback if the internal OpenAL source stopped due to buffer underrun.
|
// Resume playback if the internal OpenAL source stopped due to buffer underrun.
|
||||||
ALint srcstate;
|
ALint srcstate;
|
||||||
alGetSourcei(_Source, AL_SOURCE_STATE, &srcstate);
|
alGetSourcei(_Source, AL_SOURCE_STATE, &srcstate);
|
||||||
|
@ -218,11 +171,23 @@ void CSourceAL::submitStreamingBuffer(IBuffer *buffer)
|
||||||
/// Return the amount of buffers in the queue (playing and waiting). 3 buffers is optimal.
|
/// Return the amount of buffers in the queue (playing and waiting). 3 buffers is optimal.
|
||||||
uint CSourceAL::countStreamingBuffers() const
|
uint CSourceAL::countStreamingBuffers() const
|
||||||
{
|
{
|
||||||
|
// a bit ugly here, but makes a much easier/simpler implementation on both drivers
|
||||||
|
ALint buffersProcessed;
|
||||||
|
alGetSourcei(_Source, AL_BUFFERS_PROCESSED, &buffersProcessed);
|
||||||
|
while (buffersProcessed)
|
||||||
|
{
|
||||||
|
ALuint bufferName = _QueuedBuffers.front()->bufferName();
|
||||||
|
alSourceUnqueueBuffers(_Source, 1, &bufferName);
|
||||||
|
alTestError();
|
||||||
|
const_cast<std::queue<CBufferAL *> &>(_QueuedBuffers).pop();
|
||||||
|
--buffersProcessed;
|
||||||
|
}
|
||||||
// return how many are left in the queue
|
// return how many are left in the queue
|
||||||
ALint buffersQueued;
|
//ALint buffersQueued;
|
||||||
alGetSourcei(_Source, AL_BUFFERS_QUEUED, &buffersQueued);
|
//alGetSourcei(_SourceName, AL_BUFFERS_QUEUED, &buffersQueued);
|
||||||
alTestError();
|
//alTestError();
|
||||||
return (uint)buffersQueued;
|
//return (uint)buffersQueued;
|
||||||
|
return (uint)_QueuedBuffers.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set looping on/off for future playbacks (default: off)
|
/// Set looping on/off for future playbacks (default: off)
|
||||||
|
@ -260,7 +225,7 @@ bool CSourceAL::play()
|
||||||
_IsPaused = false;
|
_IsPaused = false;
|
||||||
alSourcePlay(_Source);
|
alSourcePlay(_Source);
|
||||||
_IsPlaying = true;
|
_IsPlaying = true;
|
||||||
_StartTime = CTime::getLocalTime();
|
_StartTime = CTime::getLocalTime(); // TODO: Played time should freeze when buffering fails, and be calculated based on the number of buffers played plus passed time. This is necessary for synchronizing animation with sound.
|
||||||
return true;
|
return true;
|
||||||
// Streaming mode
|
// Streaming mode
|
||||||
//nlwarning("AL: Cannot play null buffer; streaming not implemented" );
|
//nlwarning("AL: Cannot play null buffer; streaming not implemented" );
|
||||||
|
@ -288,8 +253,14 @@ void CSourceAL::stop()
|
||||||
_IsPaused = false;
|
_IsPaused = false;
|
||||||
alSourceStop(_Source);
|
alSourceStop(_Source);
|
||||||
alTestError();
|
alTestError();
|
||||||
|
// unqueue buffers
|
||||||
unqueueBuffers();
|
while (_QueuedBuffers.size())
|
||||||
|
{
|
||||||
|
ALuint bufferName = _QueuedBuffers.front()->bufferName();
|
||||||
|
alSourceUnqueueBuffers(_Source, 1, &bufferName);
|
||||||
|
_QueuedBuffers.pop();
|
||||||
|
alTestError();
|
||||||
|
}
|
||||||
// Streaming mode
|
// Streaming mode
|
||||||
//nlwarning("AL: Cannot stop null buffer; streaming not implemented" );
|
//nlwarning("AL: Cannot stop null buffer; streaming not implemented" );
|
||||||
//nlstop;
|
//nlstop;
|
||||||
|
@ -379,8 +350,7 @@ bool CSourceAL::isPaused() const
|
||||||
uint32 CSourceAL::getTime()
|
uint32 CSourceAL::getTime()
|
||||||
{
|
{
|
||||||
if (!_StartTime) return 0;
|
if (!_StartTime) return 0;
|
||||||
|
return (uint32)(CTime::getLocalTime() - _StartTime);
|
||||||
return (uint32)(CTime::getLocalTime() - _StartTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the position vector.
|
/// Set the position vector.
|
||||||
|
@ -438,16 +408,9 @@ void CSourceAL::getDirection( NLMISC::CVector& dir ) const
|
||||||
void CSourceAL::setGain(float gain)
|
void CSourceAL::setGain(float gain)
|
||||||
{
|
{
|
||||||
_Gain = std::min(std::max(gain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
|
_Gain = std::min(std::max(gain, NLSOUND_MIN_GAIN), NLSOUND_MAX_GAIN);
|
||||||
|
if (!_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
|
||||||
if ((_SoundDriver == NULL) || !_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
|
|
||||||
{
|
{
|
||||||
float gain = _Gain;
|
alSourcef(_Source, AL_GAIN, _Gain);
|
||||||
|
|
||||||
// apply SFX volume
|
|
||||||
if (_SoundDriver && _Type == SourceSound)
|
|
||||||
gain *= _SoundDriver->getGain();
|
|
||||||
|
|
||||||
alSourcef(_Source, AL_GAIN, gain);
|
|
||||||
alTestError();
|
alTestError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,7 +444,6 @@ float CSourceAL::getPitch() const
|
||||||
/// Set the source relative mode. If true, positions are interpreted relative to the listener position.
|
/// Set the source relative mode. If true, positions are interpreted relative to the listener position.
|
||||||
void CSourceAL::setSourceRelativeMode( bool mode )
|
void CSourceAL::setSourceRelativeMode( bool mode )
|
||||||
{
|
{
|
||||||
_PosRelative = mode;
|
|
||||||
alSourcei(_Source, AL_SOURCE_RELATIVE, mode?AL_TRUE:AL_FALSE );
|
alSourcei(_Source, AL_SOURCE_RELATIVE, mode?AL_TRUE:AL_FALSE );
|
||||||
alTestError();
|
alTestError();
|
||||||
}
|
}
|
||||||
|
@ -489,29 +451,19 @@ void CSourceAL::setSourceRelativeMode( bool mode )
|
||||||
/// Get the source relative mode (3D mode only)
|
/// Get the source relative mode (3D mode only)
|
||||||
bool CSourceAL::getSourceRelativeMode() const
|
bool CSourceAL::getSourceRelativeMode() const
|
||||||
{
|
{
|
||||||
return _PosRelative;
|
ALint b;
|
||||||
// ALint b;
|
alGetSourcei(_Source, AL_SOURCE_RELATIVE, &b );
|
||||||
// alGetSourcei(_Source, AL_SOURCE_RELATIVE, &b );
|
alTestError();
|
||||||
// alTestError();
|
return (b==AL_TRUE);
|
||||||
// return (b==AL_TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the min and max distances (3D mode only)
|
/// Set the min and max distances (3D mode only)
|
||||||
void CSourceAL::setMinMaxDistances( float mindist, float maxdist, bool /* deferred */)
|
void CSourceAL::setMinMaxDistances( float mindist, float maxdist, bool /* deferred */)
|
||||||
{
|
{
|
||||||
nlassert( (mindist >= 0.0f) && (maxdist >= 0.0f) );
|
nlassert( (mindist >= 0.0f) && (maxdist >= 0.0f) );
|
||||||
|
|
||||||
static float maxSqrt = sqrt(std::numeric_limits<float>::max());
|
|
||||||
if (maxdist >= maxSqrt)
|
|
||||||
{
|
|
||||||
nlwarning("SOUND_DEV (OpenAL): Ridiculously high max distance set on source");
|
|
||||||
maxdist = maxSqrt;
|
|
||||||
}
|
|
||||||
|
|
||||||
_MinDistance = mindist;
|
_MinDistance = mindist;
|
||||||
_MaxDistance = maxdist;
|
_MaxDistance = maxdist;
|
||||||
|
if (!_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
|
||||||
if (!_SoundDriver || !_SoundDriver->getOption(ISoundDriver::OptionManualRolloff))
|
|
||||||
{
|
{
|
||||||
alSourcef(_Source, AL_REFERENCE_DISTANCE, mindist);
|
alSourcef(_Source, AL_REFERENCE_DISTANCE, mindist);
|
||||||
alSourcef(_Source, AL_MAX_DISTANCE, maxdist);
|
alSourcef(_Source, AL_MAX_DISTANCE, maxdist);
|
||||||
|
@ -813,122 +765,4 @@ float CSourceAL::getEffectFilterPassGain() const
|
||||||
return _EffectFilterPassGain;
|
return _EffectFilterPassGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get already processed buffers and unqueue them
|
|
||||||
void CSourceAL::getProcessedStreamingBuffers(std::vector<CBufferAL*> &buffers)
|
|
||||||
{
|
|
||||||
// get the number of processed buffers
|
|
||||||
ALint buffersProcessed;
|
|
||||||
alGetSourcei(_Source, AL_BUFFERS_PROCESSED, &buffersProcessed);
|
|
||||||
alTestError();
|
|
||||||
|
|
||||||
// exit if more processed buffer than allocated ones
|
|
||||||
if ((uint)buffersProcessed > _BuffersMax) return;
|
|
||||||
|
|
||||||
// unqueue all previously processed buffers and get their name
|
|
||||||
alSourceUnqueueBuffers(_Source, buffersProcessed, &(_BuffersName[0]));
|
|
||||||
alTestError();
|
|
||||||
|
|
||||||
// add each processed buffer to the array
|
|
||||||
for(uint i = 0; i < (uint)buffersProcessed; ++i)
|
|
||||||
{
|
|
||||||
// if buffer is found, return it
|
|
||||||
std::map<uint, CBufferAL*>::const_iterator it = _Buffers.find(_BuffersName[i]);
|
|
||||||
if (it != _Buffers.end())
|
|
||||||
buffers.push_back(it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all existing buffers
|
|
||||||
void CSourceAL::getStreamingBuffers(std::vector<CBufferAL*> &buffers)
|
|
||||||
{
|
|
||||||
std::map<uint, CBufferAL*>::const_iterator it = _Buffers.begin(), iend = _Buffers.end();
|
|
||||||
while(it != iend)
|
|
||||||
{
|
|
||||||
buffers.push_back(it->second);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unqueue all buffers
|
|
||||||
void CSourceAL::unqueueBuffers()
|
|
||||||
{
|
|
||||||
// get count of buffers in queue
|
|
||||||
uint count = countStreamingBuffers();
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
// unqueue all of them
|
|
||||||
alSourceUnqueueBuffers(_Source, count, &(_BuffersName[0]));
|
|
||||||
alTestError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Delete all allocated buffers
|
|
||||||
void CSourceAL::removeBuffers()
|
|
||||||
{
|
|
||||||
// delete each buffer
|
|
||||||
std::map<uint, CBufferAL*>::const_iterator it = _Buffers.begin(), iend = _Buffers.end();
|
|
||||||
while(it != iend)
|
|
||||||
{
|
|
||||||
delete it->second;
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Buffers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get available streaming buffers count
|
|
||||||
uint CSourceAL::getStreamingBuffersMax() const
|
|
||||||
{
|
|
||||||
return _BuffersMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set available streaming buffers count and allocate them
|
|
||||||
void CSourceAL::setStreamingBuffersMax(uint buffers)
|
|
||||||
{
|
|
||||||
// remember previous value
|
|
||||||
uint oldBuffersMax = _BuffersMax;
|
|
||||||
|
|
||||||
_BuffersMax = buffers;
|
|
||||||
|
|
||||||
// resize the temporary buffer names array
|
|
||||||
_BuffersName.resize(buffers);
|
|
||||||
|
|
||||||
// remove all buffers
|
|
||||||
unqueueBuffers();
|
|
||||||
removeBuffers();
|
|
||||||
|
|
||||||
for(uint i = 0; i < _BuffersMax; ++i)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// create a new buffer
|
|
||||||
CBufferAL *buffer = static_cast<CBufferAL*>(_SoundDriver->createBuffer());
|
|
||||||
// use StorageSoftware because buffers will be reused
|
|
||||||
// deleting and recreating them is a waste of time
|
|
||||||
buffer->setStorageMode(IBuffer::StorageSoftware);
|
|
||||||
_Buffers[buffer->bufferName()] = buffer;
|
|
||||||
}
|
|
||||||
catch(const ESoundDriverGenBuf &e)
|
|
||||||
{
|
|
||||||
nlwarning("Cannot create %d buffers. openal fails after %d buffers", buffers, i);
|
|
||||||
_BuffersMax = i;
|
|
||||||
_BuffersName.resize(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the default size for streaming buffers
|
|
||||||
void CSourceAL::setStreamingBufferSize(uint size)
|
|
||||||
{
|
|
||||||
_BufferSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the default size for streaming buffers
|
|
||||||
uint CSourceAL::getStreamingBufferSize() const
|
|
||||||
{
|
|
||||||
return _BufferSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // NLSOUND
|
} // NLSOUND
|
||||||
|
|
|
@ -17,17 +17,14 @@
|
||||||
#ifndef NL_SOURCE_AL_H
|
#ifndef NL_SOURCE_AL_H
|
||||||
#define NL_SOURCE_AL_H
|
#define NL_SOURCE_AL_H
|
||||||
|
|
||||||
#include "nel/sound/driver/source.h"
|
#include <nel/sound/driver/source.h>
|
||||||
|
|
||||||
namespace NLSOUND
|
namespace NLSOUND {
|
||||||
{
|
|
||||||
class IBuffer;
|
class IBuffer;
|
||||||
class CBufferAL;
|
class CBufferAL;
|
||||||
class CSoundDriverAL;
|
class CSoundDriverAL;
|
||||||
class CEffectAL;
|
class CEffectAL;
|
||||||
|
|
||||||
enum TSourceType { SourceSound, SourceMusic };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpenAL sound source
|
* OpenAL sound source
|
||||||
*
|
*
|
||||||
|
@ -50,29 +47,19 @@ private:
|
||||||
/// Sound driver
|
/// Sound driver
|
||||||
CSoundDriverAL *_SoundDriver;
|
CSoundDriverAL *_SoundDriver;
|
||||||
|
|
||||||
|
/// Assigned buffer object
|
||||||
|
CBufferAL *_Buffer;
|
||||||
|
std::queue<CBufferAL *> _QueuedBuffers;
|
||||||
|
|
||||||
/// AL Handles
|
/// AL Handles
|
||||||
ALuint _Source;
|
ALuint _Source;
|
||||||
ALuint _DirectFilter, _EffectFilter;
|
ALuint _DirectFilter, _EffectFilter;
|
||||||
|
|
||||||
/// Assigned buffer object
|
|
||||||
CBufferAL *_Buffer;
|
|
||||||
/// Queued buffers map (uint is buffer name)
|
|
||||||
std::map<uint, CBufferAL *> _Buffers;
|
|
||||||
|
|
||||||
/// Temporary queued buffers array
|
|
||||||
std::vector<ALuint> _BuffersName;
|
|
||||||
/// Max count of queued buffers allowed
|
|
||||||
uint _BuffersMax;
|
|
||||||
/// Default size of a buffer
|
|
||||||
uint _BufferSize;
|
|
||||||
|
|
||||||
/// Position is relative to listener
|
|
||||||
bool _PosRelative;
|
|
||||||
|
|
||||||
/// Playing status
|
/// Playing status
|
||||||
bool _IsPlaying;
|
bool _IsPlaying;
|
||||||
bool _IsPaused;
|
bool _IsPaused;
|
||||||
NLMISC::TTime _StartTime;
|
NLMISC::TTime _StartTime;
|
||||||
|
|
||||||
NLMISC::CVector _Pos;
|
NLMISC::CVector _Pos;
|
||||||
float _Gain;
|
float _Gain;
|
||||||
double _Alpha;
|
double _Alpha;
|
||||||
|
@ -90,9 +77,6 @@ private:
|
||||||
TFilter _DirectFilterType, _EffectFilterType;
|
TFilter _DirectFilterType, _EffectFilterType;
|
||||||
bool _DirectFilterEnabled, _EffectFilterEnabled;
|
bool _DirectFilterEnabled, _EffectFilterEnabled;
|
||||||
float _DirectFilterPassGain, _EffectFilterPassGain;
|
float _DirectFilterPassGain, _EffectFilterPassGain;
|
||||||
|
|
||||||
/// Source type can be SourceSound or SourceMusic
|
|
||||||
TSourceType _Type;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -104,13 +88,8 @@ public:
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
/// Return the OpenAL source name
|
/// Return the OpenAL source name
|
||||||
ALuint getSource() const { return _Source; }
|
inline ALuint getSource() const { return _Source; }
|
||||||
|
|
||||||
/// Set type of the source
|
|
||||||
void setType(TSourceType type);
|
|
||||||
/// Get type of the source
|
|
||||||
TSourceType getType() const;
|
|
||||||
|
|
||||||
/// (Internal) Set the effect send for this source, NULL to disable.
|
/// (Internal) Set the effect send for this source, NULL to disable.
|
||||||
void setEffect(CEffectAL *effect);
|
void setEffect(CEffectAL *effect);
|
||||||
/// (Internal) Setup the direct send filter.
|
/// (Internal) Setup the direct send filter.
|
||||||
|
@ -275,22 +254,6 @@ public:
|
||||||
virtual float getEffectFilterPassGain() const;
|
virtual float getEffectFilterPassGain() const;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/// Get already processed buffers and unqueue them
|
|
||||||
void getProcessedStreamingBuffers(std::vector<CBufferAL*> &buffers);
|
|
||||||
/// Get all existing buffers
|
|
||||||
void getStreamingBuffers(std::vector<CBufferAL*> &buffers);
|
|
||||||
/// Unqueue all buffers
|
|
||||||
void unqueueBuffers();
|
|
||||||
/// Delete all allocated buffers
|
|
||||||
void removeBuffers();
|
|
||||||
/// Get available streaming buffers count
|
|
||||||
uint getStreamingBuffersMax() const;
|
|
||||||
/// Set available streaming buffers count and allocate them
|
|
||||||
void setStreamingBuffersMax(uint max);
|
|
||||||
/// Set the default size for streaming buffers
|
|
||||||
void setStreamingBufferSize(uint size);
|
|
||||||
/// Get the default size for streaming buffers
|
|
||||||
uint getStreamingBufferSize() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // NLSOUND
|
} // NLSOUND
|
||||||
|
|
Loading…
Reference in a new issue