diff --git a/code/nel/include/nel/sound/driver/music_channel.h b/code/nel/include/nel/sound/driver/music_channel.h index 9878744c5..116865628 100644 --- a/code/nel/include/nel/sound/driver/music_channel.h +++ b/code/nel/include/nel/sound/driver/music_channel.h @@ -45,6 +45,9 @@ public: /// Stop the music previously loaded and played (the Memory is also freed) virtual void stop() =0; + /// Makes sure any resources are freed, but keeps available for next play call + virtual void reset() =0; + /// Pause the music previously loaded and played (the Memory is not freed) virtual void pause() =0; diff --git a/code/nel/include/nel/sound/music_channel_fader.h b/code/nel/include/nel/sound/music_channel_fader.h index 4e6d35de4..8513c21e5 100644 --- a/code/nel/include/nel/sound/music_channel_fader.h +++ b/code/nel/include/nel/sound/music_channel_fader.h @@ -87,6 +87,8 @@ public: void init(ISoundDriver *soundDriver); void release(); + void reset(); + void update(); // time in seconds inline bool isInitOk() { return _SoundDriver != NULL; } diff --git a/code/nel/include/nel/sound/source_music_channel.h b/code/nel/include/nel/sound/source_music_channel.h new file mode 100644 index 000000000..7ec71fb66 --- /dev/null +++ b/code/nel/include/nel/sound/source_music_channel.h @@ -0,0 +1,100 @@ +/** + * \file source_music_channel.h + * \brief CSourceMusicChannel + * \date 2012-04-11 16:08GMT + * \author Jan Boon (Kaetemi) + * CSourceMusicChannel + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE. + * RYZOM CORE 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. + * + * RYZOM CORE 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 RYZOM CORE. If not, see + * . + */ + +#ifndef NLSOUND_SOURCE_MUSIC_CHANNEL_H +#define NLSOUND_SOURCE_MUSIC_CHANNEL_H +#include + +// STL includes + +// NeL includes +#include +#include + +// Project includes + +namespace NLSOUND { + class CStreamFileSource; + +/** + * \brief CSourceMusicChannel + * \date 2012-04-11 16:08GMT + * \author Jan Boon (Kaetemi) + * CSourceMusicChannel + */ +class CSourceMusicChannel : public IMusicChannel +{ +public: + CSourceMusicChannel(); + virtual ~CSourceMusicChannel(); + + /** 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(); + + /// Makes sure any resources are freed, but keeps available for next play call + virtual void reset(); + + /// 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: the volume of music is NOT affected by IListener::setGain() + */ + virtual void setVolume(float gain); + +private: + CStreamFileSound m_Sound; + CStreamFileSource *m_Source; + float m_Gain; + +}; /* class CSourceMusicChannel */ + +} /* namespace NLSOUND */ + +#endif /* #ifndef NLSOUND_SOURCE_MUSIC_CHANNEL_H */ + +/* end of file */ diff --git a/code/nel/include/nel/sound/stream_file_source.h b/code/nel/include/nel/sound/stream_file_source.h index 69e85fc8b..4bce66719 100644 --- a/code/nel/include/nel/sound/stream_file_source.h +++ b/code/nel/include/nel/sound/stream_file_source.h @@ -70,6 +70,10 @@ public: void resume(); /// check if song ended (following legacy music channel implementation) bool isEnded(); + /// (following legacy music channel implementation) + float getLength(); + /// check if still loading (following legacy music channel implementation) + bool isLoadingAsync(); //@} /// \name Decoding thread diff --git a/code/nel/include/nel/sound/stream_source.h b/code/nel/include/nel/sound/stream_source.h index d0a31cf38..1c94a5b7a 100644 --- a/code/nel/include/nel/sound/stream_source.h +++ b/code/nel/include/nel/sound/stream_source.h @@ -107,6 +107,9 @@ public: virtual bool hasFilledBuffersAvailable() const; //@} + /// Prepare the buffers in this stream for the given maximum capacity. (TODO: Move this into UStreamSource) + void preAllocate(uint capacity); + /// Return the track CTrack *getTrack() { return m_Track; } diff --git a/code/nel/samples/sound/stream_file/stream_file.cpp b/code/nel/samples/sound/stream_file/stream_file.cpp index bdc866538..6ded512eb 100644 --- a/code/nel/samples/sound/stream_file/stream_file.cpp +++ b/code/nel/samples/sound/stream_file/stream_file.cpp @@ -42,6 +42,8 @@ #define NL_SOUND_DATA "." #endif // NL_SOUND_DATA +#define SAMPLE_OGG "D:/source/kaetemi/toverhex/src/samples/music_stream/data/aeon_1_10_mystic_river.ogg" + using namespace std; using namespace NLMISC; using namespace NLSOUND; @@ -130,6 +132,9 @@ static void runSample() case 'r': s_StreamFileSource->resume(); break; + case 'e': + s_AudioMixer->playMusic(SAMPLE_OGG, 1000, true, false); + break; default: return; } diff --git a/code/nel/src/sound/CMakeLists.txt b/code/nel/src/sound/CMakeLists.txt index fae6ca7a6..e73d0828e 100644 --- a/code/nel/src/sound/CMakeLists.txt +++ b/code/nel/src/sound/CMakeLists.txt @@ -38,6 +38,7 @@ FILE(GLOB MUSIC music_sound.cpp ../../include/nel/sound/music_sound.h music_sound_manager.cpp ../../include/nel/sound/music_sound_manager.h music_source.cpp ../../include/nel/sound/music_source.h + source_music_channel.cpp ../../include/nel/sound/source_music_channel.h ) FILE(GLOB SOUND diff --git a/code/nel/src/sound/audio_mixer_user.cpp b/code/nel/src/sound/audio_mixer_user.cpp index 5d938a036..f47f70413 100644 --- a/code/nel/src/sound/audio_mixer_user.cpp +++ b/code/nel/src/sound/audio_mixer_user.cpp @@ -269,8 +269,8 @@ void CAudioMixerUser::reset() _Leaving = true; _SourceWaitingForPlay.clear(); - - /* TODO: Stop music channels */ + + _MusicChannelFaders->reset(); // Stop tracks uint i; diff --git a/code/nel/src/sound/driver/fmod/music_channel_fmod.cpp b/code/nel/src/sound/driver/fmod/music_channel_fmod.cpp index 9c502ea1a..a64dddcfe 100644 --- a/code/nel/src/sound/driver/fmod/music_channel_fmod.cpp +++ b/code/nel/src/sound/driver/fmod/music_channel_fmod.cpp @@ -249,6 +249,12 @@ void CMusicChannelFMod::stop() _CallBackEnded = false; } +void CMusicChannelFMod::reset() +{ + // don't care + stop(); +} + /** Pause the music previously loaded and played (the Memory is not freed) */ void CMusicChannelFMod::pause() diff --git a/code/nel/src/sound/driver/fmod/music_channel_fmod.h b/code/nel/src/sound/driver/fmod/music_channel_fmod.h index d9a17fd99..e91e38a8b 100644 --- a/code/nel/src/sound/driver/fmod/music_channel_fmod.h +++ b/code/nel/src/sound/driver/fmod/music_channel_fmod.h @@ -87,6 +87,9 @@ public: /// Stop the music previously loaded and played (the Memory is also freed) virtual void stop(); + /// Makes sure any resources are freed, but keeps available for next play call + virtual void reset(); + /// Pause the music previously loaded and played (the Memory is not freed) virtual void pause(); diff --git a/code/nel/src/sound/music_channel_fader.cpp b/code/nel/src/sound/music_channel_fader.cpp index ced739093..2fe9fb13c 100644 --- a/code/nel/src/sound/music_channel_fader.cpp +++ b/code/nel/src/sound/music_channel_fader.cpp @@ -20,6 +20,7 @@ // Project includes #include "nel/sound/driver/sound_driver.h" #include "nel/sound/driver/music_channel.h" +#include "nel/sound/source_music_channel.h" using namespace std; using namespace NLMISC; @@ -49,9 +50,16 @@ void CMusicChannelFader::init(ISoundDriver *soundDriver) _MusicFader[i].MusicChannel = _SoundDriver->createMusicChannel(); if (!_MusicFader[i].MusicChannel) { - release(); - nlwarning("No music channel available!"); - return; + if (_SoundDriver->getOption(ISoundDriver::OptionHasBufferStreaming)) + { + _MusicFader[i].MusicChannel = new CSourceMusicChannel(); + } + else + { + release(); + nlwarning("No music channel available!"); + return; + } } } } @@ -69,6 +77,15 @@ void CMusicChannelFader::release() } } +void CMusicChannelFader::reset() +{ + for (uint i = 0; i < _MaxMusicFader; ++i) if (_MusicFader[i].MusicChannel) + { + if (_MusicFader[i].MusicChannel) + _MusicFader[i].MusicChannel->reset(); + } +} + void CMusicChannelFader::update() { TTime current_time = CTime::getLocalTime(); diff --git a/code/nel/src/sound/sound.cpp b/code/nel/src/sound/sound.cpp index 4d753bb96..b1b644ed2 100644 --- a/code/nel/src/sound/sound.cpp +++ b/code/nel/src/sound/sound.cpp @@ -115,7 +115,8 @@ CSound::CSound() : _Looping(false), _MinDist(1.0f), _MaxDist(1000000.0f), - _UserVarControler(CStringMapper::emptyId()) + _UserVarControler(CStringMapper::emptyId()), + _GroupController(NULL) { } diff --git a/code/nel/src/sound/source_music_channel.cpp b/code/nel/src/sound/source_music_channel.cpp new file mode 100644 index 000000000..4395f3b5e --- /dev/null +++ b/code/nel/src/sound/source_music_channel.cpp @@ -0,0 +1,123 @@ +/** + * \file source_music_channel.cpp + * \brief CSourceMusicChannel + * \date 2012-04-11 16:08GMT + * \author Jan Boon (Kaetemi) + * CSourceMusicChannel + */ + +/* + * Copyright (C) 2012 by authors + * + * This file is part of RYZOM CORE. + * RYZOM CORE 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. + * + * RYZOM CORE 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 RYZOM CORE. If not, see + * . + */ + +#include "stdsound.h" +#include + +// STL includes + +// NeL includes +// #include +#include + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NLSOUND { + +CSourceMusicChannel::CSourceMusicChannel() : m_Source(NULL), m_Gain(1.0f) +{ + +} + +CSourceMusicChannel::~CSourceMusicChannel() +{ + delete m_Source; + m_Source = NULL; +} + +bool CSourceMusicChannel::play(const std::string &filepath, bool async, bool loop) +{ + if (m_Source) + delete m_Source; + + m_Sound.setMusicFilePath(filepath, async, loop); + + m_Source = new CStreamFileSource(&m_Sound, false, NULL, NULL, NULL, NULL); + + m_Source->play(); + + return m_Source->isPlaying(); +} + +void CSourceMusicChannel::stop() +{ + if (m_Source) + m_Source->stop(); +} + +void CSourceMusicChannel::reset() +{ + delete m_Source; + m_Source = NULL; +} + +void CSourceMusicChannel::pause() +{ + if (m_Source) + m_Source->pause(); +} + +void CSourceMusicChannel::resume() +{ + if (m_Source) + m_Source->resume(); +} + +bool CSourceMusicChannel::isEnded() +{ + if (m_Source) + return m_Source->isEnded(); + return true; +} + +bool CSourceMusicChannel::isLoadingAsync() +{ + if (m_Source) + return m_Source->isLoadingAsync(); + return false; +} + +float CSourceMusicChannel::getLength() +{ + if (m_Source) + return m_Source->getLength(); + return 0.0f; +} + +void CSourceMusicChannel::setVolume(float gain) +{ + m_Gain = gain; + if (m_Source) + m_Source->setRelativeGain(gain); +} + +} /* namespace NLSOUND */ + +/* end of file */ diff --git a/code/nel/src/sound/stream_file_sound.cpp b/code/nel/src/sound/stream_file_sound.cpp index 7640d7893..4fc17b51c 100644 --- a/code/nel/src/sound/stream_file_sound.cpp +++ b/code/nel/src/sound/stream_file_sound.cpp @@ -32,6 +32,7 @@ // NeL includes // #include +#include // Project includes @@ -84,6 +85,7 @@ void CStreamFileSound::setMusicFilePath(const std::string &filePath, bool async, _MinDist = 1000.0f; m_Async = async; m_FilePath = filePath; + _GroupController = CGroupControllerRoot::getInstance()->getGroupController(NLSOUND_SHEET_V1_DEFAULT_SOUND_MUSIC_GROUP_CONTROLLER); } } /* namespace NLSOUND */ diff --git a/code/nel/src/sound/stream_file_source.cpp b/code/nel/src/sound/stream_file_source.cpp index 057e20894..35377f0db 100644 --- a/code/nel/src/sound/stream_file_source.cpp +++ b/code/nel/src/sound/stream_file_source.cpp @@ -182,6 +182,16 @@ bool CStreamFileSource::isEnded() return (!m_Thread->isRunning() && !_Playing && !m_WaitingForPlay && !m_Paused); } +float CStreamFileSource::getLength() +{ + return m_AudioDecoder->getLength(); +} + +bool CStreamFileSource::isLoadingAsync() +{ + return m_WaitingForPlay; +} + void CStreamFileSource::prepareDecoder() { // creates a new decoder or keeps going with the current decoder if the stream was paused @@ -208,6 +218,9 @@ void CStreamFileSource::prepareDecoder() } this->setFormat(m_AudioDecoder->getChannels(), m_AudioDecoder->getBitsPerSample(), (uint32)m_AudioDecoder->getSamplesPerSec()); } + uint samples, bytes; + this->getRecommendedBufferSize(samples, bytes); + this->preAllocate(bytes * 2); } void CStreamFileSource::bufferMore(uint bytes) // buffer from bytes (minimum) to bytes * 2 (maximum) diff --git a/code/nel/src/sound/stream_source.cpp b/code/nel/src/sound/stream_source.cpp index 7f6b0c608..7d35d06db 100644 --- a/code/nel/src/sound/stream_source.cpp +++ b/code/nel/src/sound/stream_source.cpp @@ -50,8 +50,11 @@ CStreamSource::CStreamSource(CStreamSound *streamSound, bool spawn, TSpawnEndCal CAudioMixerUser *mixer = CAudioMixerUser::instance(); ISoundDriver *driver = mixer->getSoundDriver(); m_Buffers[0] = driver->createBuffer(); + m_Buffers[0]->setStorageMode(IBuffer::StorageSoftware); m_Buffers[1] = driver->createBuffer(); + m_Buffers[1]->setStorageMode(IBuffer::StorageSoftware); m_Buffers[2] = driver->createBuffer(); + m_Buffers[2]->setStorageMode(IBuffer::StorageSoftware); } CStreamSource::~CStreamSource() @@ -431,6 +434,19 @@ bool CStreamSource::hasFilledBuffersAvailable() const return m_FreeBuffers < 3; } +void CStreamSource::preAllocate(uint capacity) +{ + uint8 *b0 = m_Buffers[0]->lock(capacity); + memset(b0, 0, capacity); + m_Buffers[0]->unlock(capacity); + uint8 *b1 = m_Buffers[1]->lock(capacity); + memset(b1, 0, capacity); + m_Buffers[1]->unlock(capacity); + uint8 *b2 = m_Buffers[2]->lock(capacity); + memset(b2, 0, capacity); + m_Buffers[2]->unlock(capacity); +} + } /* namespace NLSOUND */ /* end of file */