diff --git a/code/nel/include/nel/sound/driver/music_buffer.h b/code/nel/include/nel/sound/driver/music_buffer.h
index a9df6c495..571e27a31 100644
--- a/code/nel/include/nel/sound/driver/music_buffer.h
+++ b/code/nel/include/nel/sound/driver/music_buffer.h
@@ -94,19 +94,22 @@ public:
virtual uint32 getNextBytes(uint8 *buffer, uint32 minimum, uint32 maximum) =0;
/// Get the amount of channels (2 is stereo) in output.
- virtual uint16 getChannels() =0;
+ virtual uint8 getChannels() =0;
/// Get the samples per second (often 44100) in output.
virtual uint32 getSamplesPerSec() =0;
/// Get the bits per sample (often 16) in output.
- virtual uint16 getBitsPerSample() =0;
+ virtual uint8 getBitsPerSample() =0;
/// Get if the music has ended playing (never true if loop).
virtual bool isMusicEnded() =0;
/// Get the total time in seconds.
virtual float getLength() =0;
+
+ /// Get the size of uncompressed data in bytes.
+ virtual uint getUncompressedSize() =0;
}; /* class IMusicBuffer */
} /* namespace NLSOUND */
diff --git a/code/nel/include/nel/sound/driver/music_buffer_vorbis.h b/code/nel/include/nel/sound/driver/music_buffer_vorbis.h
index 8971a8a74..978f393da 100644
--- a/code/nel/include/nel/sound/driver/music_buffer_vorbis.h
+++ b/code/nel/include/nel/sound/driver/music_buffer_vorbis.h
@@ -75,19 +75,22 @@ public:
virtual uint32 getNextBytes(uint8 *buffer, uint32 minimum, uint32 maximum);
/// Get the amount of channels (2 is stereo) in output.
- virtual uint16 getChannels();
+ virtual uint8 getChannels();
/// Get the samples per second (often 44100) in output.
virtual uint32 getSamplesPerSec();
/// Get the bits per sample (often 16) in output.
- virtual uint16 getBitsPerSample();
+ virtual uint8 getBitsPerSample();
/// Get if the music has ended playing (never true if loop).
virtual bool isMusicEnded();
/// Get the total time in seconds.
virtual float getLength();
+
+ /// Get the size of uncompressed data in bytes.
+ virtual uint getUncompressedSize();
}; /* class CMusicBufferVorbis */
} /* namespace NLSOUND */
diff --git a/code/nel/src/sound/driver/music_buffer_vorbis.cpp b/code/nel/src/sound/driver/music_buffer_vorbis.cpp
index e9df6d0d1..a02226046 100644
--- a/code/nel/src/sound/driver/music_buffer_vorbis.cpp
+++ b/code/nel/src/sound/driver/music_buffer_vorbis.cpp
@@ -158,7 +158,7 @@ uint32 CMusicBufferVorbis::getNextBytes(uint8 *buffer, uint32 minimum, uint32 ma
return bytes_read;
}
-uint16 CMusicBufferVorbis::getChannels()
+uint8 CMusicBufferVorbis::getChannels()
{
vorbis_info *vi = ov_info(&_OggVorbisFile, -1);
return (uint16)vi->channels;
@@ -170,7 +170,7 @@ uint32 CMusicBufferVorbis::getSamplesPerSec()
return vi->rate;
}
-uint16 CMusicBufferVorbis::getBitsPerSample()
+uint8 CMusicBufferVorbis::getBitsPerSample()
{
return 16;
}
@@ -185,6 +185,11 @@ float CMusicBufferVorbis::getLength()
return (float)ov_time_total(&_OggVorbisFile, -1);
}
+uint CMusicBufferVorbis::getUncompressedSize()
+{
+ return (uint)ov_pcm_total(&_OggVorbisFile, -1) * (getBitsPerSample() / 2) * getChannels();
+}
+
} /* namespace NLSOUND */
/* end of file */
diff --git a/code/nel/src/sound/driver/openal/driver_openal.vcproj b/code/nel/src/sound/driver/openal/driver_openal.vcproj
index f0607d2d3..13fc8c716 100644
--- a/code/nel/src/sound/driver/openal/driver_openal.vcproj
+++ b/code/nel/src/sound/driver/openal/driver_openal.vcproj
@@ -74,7 +74,7 @@
Name="VCLinkerTool"
AdditionalDependencies="OpenAL32.lib EFX-Util.lib"
OutputFile="..\..\..\..\lib\nel_drv_openal_win_d.dll"
- IgnoreDefaultLibraryNames="msvcrt.lib;libcmt.lib"
+ IgnoreDefaultLibraryNames="msvcrt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="true"
SubSystem="2"
@@ -159,7 +159,7 @@
Name="VCLinkerTool"
AdditionalDependencies="OpenAL32.lib EFX-Util.lib"
OutputFile="..\..\..\..\lib64\nel_drv_openal_win_d.dll"
- IgnoreDefaultLibraryNames="msvcrt.lib;libcmt.lib"
+ IgnoreDefaultLibraryNames="msvcrt.lib"
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="true"
SubSystem="2"
@@ -247,7 +247,7 @@
Name="VCLinkerTool"
AdditionalDependencies="OpenAL32.lib EFX-Util.lib"
OutputFile="..\..\..\..\lib\nel_drv_openal_win_r.dll"
- IgnoreDefaultLibraryNames="libcmt.lib"
+ IgnoreDefaultLibraryNames=""
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="true"
SubSystem="2"
@@ -336,7 +336,7 @@
Name="VCLinkerTool"
AdditionalDependencies="OpenAL32.lib EFX-Util.lib"
OutputFile="..\..\..\..\lib64\nel_drv_openal_win_r.dll"
- IgnoreDefaultLibraryNames="libcmt.lib"
+ IgnoreDefaultLibraryNames=""
ModuleDefinitionFile="$(ProjectName).def"
GenerateDebugInformation="true"
SubSystem="2"
@@ -401,6 +401,14 @@
RelativePath=".\listener_al.h"
>
+
+
+
+
diff --git a/code/nel/src/sound/driver/openal/music_channel_al.cpp b/code/nel/src/sound/driver/openal/music_channel_al.cpp
new file mode 100644
index 000000000..c7146ea3a
--- /dev/null
+++ b/code/nel/src/sound/driver/openal/music_channel_al.cpp
@@ -0,0 +1,303 @@
+// NeL - MMORPG Framework
+// 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 .
+
+#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)
+: _MusicBuffer(NULL), _SoundDriver(soundDriver), _Gain(1.0), _Source(NULL), _Thread(NULL), _Async(false), _Playing(false), _Buffer(NULL)
+{
+ // create a default source for music streaming
+ _Source = static_cast(_SoundDriver->createSource());
+ _Source->setPos(CVector(0, 0, 0));
+ _Source->setVelocity(CVector(0, 0, 0));
+ _Source->setDirection(CVector(0, 0, 0));
+ _Source->setSourceRelativeMode(true);
+ _Source->setStreamingBuffersMax(4);
+ _Source->setStreamingBufferSize(32768);
+// _Source->setStreaming(true);
+}
+
+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);
+
+ // add buffer to streaming buffers queue
+ _Source->submitStreamingBuffer(buffer);
+
+ return true;
+}
+
+/// 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()
+{
+
+ if (_Async)
+ {
+ bool first = true;
+
+ // use queued buffers
+ do
+ {
+ // buffers to update
+ std::vector 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)
+ fillBuffer(buffers[i], _Source->getStreamingBufferSize());
+
+ // play the source
+ if (first)
+ {
+ _Source->play();
+ first = false;
+ }
+
+ // wait 100ms before rechecking buffers
+ nlSleep(100);
+ }
+ while(!_MusicBuffer->isMusicEnded() && _Playing);
+ }
+ else
+ {
+ // 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;
+ }
+
+ // use this buffer as source
+ _Source->setStaticBuffer(_Buffer);
+
+ // play the source
+ _Source->play();
+ }
+
+ // music finished without interruption
+ if (_Playing)
+ {
+ // wait until source is not playing
+ while(_Source->isPlaying() && _Playing) nlSleep(1000);
+
+ _Source->stop();
+
+ _Playing = false;
+ }
+}
+
+/** 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)
+ {
+ // 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;
+ }
+
+ _Async = async;
+ _Playing = true;
+
+ // we need to loop the source only if not async
+ _Source->setLooping(async ? false:loop);
+
+ // start the thread
+ _Thread->start();
+ }
+ 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;
+}
+
+/// 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);
+}
+
+} /* namespace NLSOUND */
+
+/* end of file */
diff --git a/code/nel/src/sound/driver/openal/music_channel_al.h b/code/nel/src/sound/driver/openal/music_channel_al.h
new file mode 100644
index 000000000..dddb5a052
--- /dev/null
+++ b/code/nel/src/sound/driver/openal/music_channel_al.h
@@ -0,0 +1,100 @@
+// NeL - MMORPG Framework
+// 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 .
+
+#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);
+}; /* class CMusicChannelAL */
+
+} /* namespace NLSOUND */
+
+#endif /* #ifndef NLSOUND_MUSIC_CHANNEL_AL_H */
+
+/* end of file */
diff --git a/code/nel/src/sound/driver/openal/stdopenal.h b/code/nel/src/sound/driver/openal/stdopenal.h
index bbdb9e923..12960d57f 100644
--- a/code/nel/src/sound/driver/openal/stdopenal.h
+++ b/code/nel/src/sound/driver/openal/stdopenal.h
@@ -50,10 +50,14 @@
#include "nel/misc/fast_mem.h"
#include "nel/misc/path.h"
#include "nel/misc/dynloadlib.h"
+#include "nel/misc/hierarchical_timer.h"
+#include "nel/misc/thread.h"
+
#include "nel/sound/driver/sound_driver.h"
#include "nel/sound/driver/buffer.h"
#include "nel/sound/driver/source.h"
#include "nel/sound/driver/listener.h"
#include "nel/sound/driver/effect.h"
+#include "nel/sound/driver/music_buffer.h"
/* end of file */