From fe70efdc6c0055c387e28d688d409afa59b0d1ce Mon Sep 17 00:00:00 2001 From: kaetemi Date: Wed, 11 Apr 2012 17:39:46 +0200 Subject: [PATCH] Added: #795 Streamed audio file sound source --- code/nel/include/nel/sound/audio_mixer_user.h | 1 + code/nel/include/nel/sound/simple_source.h | 2 + code/nel/include/nel/sound/sound.h | 5 +- code/nel/include/nel/sound/source_common.h | 3 +- .../nel/include/nel/sound/stream_file_sound.h | 94 +++++++ .../include/nel/sound/stream_file_source.h | 105 ++++++++ code/nel/include/nel/sound/stream_source.h | 10 +- code/nel/src/sound/CMakeLists.txt | 2 + code/nel/src/sound/audio_mixer_user.cpp | 18 ++ code/nel/src/sound/simple_source.cpp | 12 +- code/nel/src/sound/sound.cpp | 6 + code/nel/src/sound/sound_bank.cpp | 4 + code/nel/src/sound/stream_file_sound.cpp | 91 +++++++ code/nel/src/sound/stream_file_source.cpp | 244 ++++++++++++++++++ code/nel/src/sound/stream_sound.cpp | 5 +- code/nel/src/sound/stream_source.cpp | 31 ++- 16 files changed, 621 insertions(+), 12 deletions(-) create mode 100644 code/nel/include/nel/sound/stream_file_sound.h create mode 100644 code/nel/include/nel/sound/stream_file_source.h create mode 100644 code/nel/src/sound/stream_file_sound.cpp create mode 100644 code/nel/src/sound/stream_file_source.cpp diff --git a/code/nel/include/nel/sound/audio_mixer_user.h b/code/nel/include/nel/sound/audio_mixer_user.h index 977fe066b..1316fe34a 100644 --- a/code/nel/include/nel/sound/audio_mixer_user.h +++ b/code/nel/include/nel/sound/audio_mixer_user.h @@ -403,6 +403,7 @@ public: /// Add a source for play as possible (for non discadable sound) void addSourceWaitingForPlay(CSourceCommon *source); + void removeSourceWaitingForPlay(CSourceCommon *source); /// Read all user controled var sheets void initUserVar(); diff --git a/code/nel/include/nel/sound/simple_source.h b/code/nel/include/nel/sound/simple_source.h index 9b21200c9..c330fd7fa 100644 --- a/code/nel/include/nel/sound/simple_source.h +++ b/code/nel/include/nel/sound/simple_source.h @@ -142,6 +142,8 @@ private: /// True when the sound is played muted and until the mixer event notifying the end. bool _PlayMuted; + bool _WaitingForPlay; + }; diff --git a/code/nel/include/nel/sound/sound.h b/code/nel/include/nel/sound/sound.h index 7d7542fc9..e9d4f755c 100644 --- a/code/nel/include/nel/sound/sound.h +++ b/code/nel/include/nel/sound/sound.h @@ -61,8 +61,9 @@ public: SOUND_COMPLEX, SOUND_BACKGROUND, SOUND_CONTEXT, - SOUND_MUSIC, - SOUND_STREAM + SOUND_MUSIC, // soon to be deprecated hopefully + SOUND_STREAM, + SOUND_STREAM_FILE }; diff --git a/code/nel/include/nel/sound/source_common.h b/code/nel/include/nel/sound/source_common.h index ca0a9a2b8..1180fd68e 100644 --- a/code/nel/include/nel/sound/source_common.h +++ b/code/nel/include/nel/sound/source_common.h @@ -37,7 +37,8 @@ public: SOURCE_COMPLEX, SOURCE_BACKGROUND, SOURCE_MUSIC, // DEPRECATED - SOURCE_STREAM + SOURCE_STREAM, + SOURCE_STREAM_FILE }; /// When groupController is NULL it will use the groupcontroller specified in the TSoundId. You should manually specify the groupController if this source is a child of another source, so that the parent source controller of the user-specified .sound file is the one that will be used. diff --git a/code/nel/include/nel/sound/stream_file_sound.h b/code/nel/include/nel/sound/stream_file_sound.h new file mode 100644 index 000000000..2429c3382 --- /dev/null +++ b/code/nel/include/nel/sound/stream_file_sound.h @@ -0,0 +1,94 @@ +/** + * \file stream_file_sound.h + * \brief CStreamFileSound + * \date 2012-04-11 09:57GMT + * \author Jan Boon (Kaetemi) + * CStreamFileSound + */ + +/* + * 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_STREAM_FILE_SOUND_H +#define NLSOUND_STREAM_FILE_SOUND_H +#include + +// STL includes + +// NeL includes + +// Project includes +#include + +namespace NLSOUND { + class CSourceMusicChannel; + +/** + * \brief CStreamFileSound + * \date 2012-04-11 09:57GMT + * \author Jan Boon (Kaetemi) + * CStreamFileSound + */ +class CStreamFileSound : public CStreamSound +{ +public: + friend CSourceMusicChannel; + +public: + CStreamFileSound(); + virtual ~CStreamFileSound(); + + /// Get the type of the sound. + virtual TSOUND_TYPE getSoundType() { return SOUND_STREAM_FILE; } + + /// Load the sound parameters from georges' form + virtual void importForm(const std::string& filename, NLGEORGES::UFormElm& formRoot); + + /// Used by the george sound plugin to check sound recursion (ie sound 'toto' use sound 'titi' witch also use sound 'toto' ...). + virtual void getSubSoundList(std::vector > &/* subsounds */) const { } + + /// Serialize the sound data. + virtual void serial(NLMISC::IStream &s); + + /// Return the length of the sound in ms + virtual uint32 getDuration() { return 0; } + + inline bool getAsync() { return m_Async; } + + inline const std::string &getFilePath() { return m_FilePath; } + +private: + /// Used by CSourceMusicChannel to set the filePath and default settings on other parameters. + void setMusicFilePath(const std::string &filePath, bool async = true, bool loop = false); + +private: + CStreamFileSound(const CStreamFileSound &); + CStreamFileSound &operator=(const CStreamFileSound &); + +private: + bool m_Async; + std::string m_FilePath; + +}; /* class CStreamFileSound */ + +} /* namespace NLSOUND */ + +#endif /* #ifndef NLSOUND_STREAM_FILE_SOUND_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 new file mode 100644 index 000000000..16153d406 --- /dev/null +++ b/code/nel/include/nel/sound/stream_file_source.h @@ -0,0 +1,105 @@ +/** + * \file stream_file_source.h + * \brief CStreamFileSource + * \date 2012-04-11 09:57GMT + * \author Jan Boon (Kaetemi) + * CStreamFileSource + */ + +/* + * 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_STREAM_FILE_SOURCE_H +#define NLSOUND_STREAM_FILE_SOURCE_H +#include + +// STL includes + +// NeL includes +#include + +// Project includes +#include +#include + +namespace NLSOUND { + class IAudioDecoder; + +/** + * \brief CStreamFileSource + * \date 2012-04-11 09:57GMT + * \author Jan Boon (Kaetemi) + * CStreamFileSource + */ +class CStreamFileSource : public CStreamSource, private NLMISC::IRunnable +{ +public: + CStreamFileSource(CStreamFileSound *streamFileSound = NULL, bool spawn = false, TSpawnEndCallback cb = 0, void *cbUserParam = 0, NL3D::CCluster *cluster = 0, CGroupController *groupController = NULL); + virtual ~CStreamFileSource(); + + /// Return the source type + TSOURCE_TYPE getType() const { return SOURCE_STREAM_FILE; } + + /// \name Playback control + //@{ + /// Play + virtual void play(); + /// Stop playing + virtual void stop(); + /// Get playing state. Return false even if the source has stopped on its own. + virtual bool isPlaying(); + /// Pause (following legacy music channel implementation) + void pause(); + /// Resume (following legacy music channel implementation) + void resume(); + /// check if song ended (following legacy music channel implementation) + bool isEnded(); + //@} + + /// \name Decoding thread + //@{ + virtual void getName (std::string &result) const { result = "CStreamFileSource"; } + virtual void run(); + //@} + + // TODO: getTime + +private: + void bufferMore(uint bytes); + +private: + CStreamFileSource(const CStreamFileSource &); + CStreamFileSource &operator=(const CStreamFileSource &); + +private: + inline CStreamFileSound *getStreamFileSound() { return static_cast(m_StreamSound); } + + NLMISC::IThread *m_Thread; + + IAudioDecoder *m_AudioDecoder; + + bool m_Paused; + +}; /* class CStreamFileSource */ + +} /* namespace NLSOUND */ + +#endif /* #ifndef NLSOUND_STREAM_FILE_SOURCE_H */ + +/* end of file */ diff --git a/code/nel/include/nel/sound/stream_source.h b/code/nel/include/nel/sound/stream_source.h index 702a26006..d0a31cf38 100644 --- a/code/nel/include/nel/sound/stream_source.h +++ b/code/nel/include/nel/sound/stream_source.h @@ -114,7 +114,7 @@ private: CStreamSource(const CStreamSource &); CStreamSource &operator=(const CStreamSource &); -private: +protected: /// Return the source type TSOURCE_TYPE getType() const { return SOURCE_STREAM; } @@ -162,7 +162,13 @@ private: /// The bytes per second according to the buffer format uint m_BytesPerSecond; - + + /// Waiting for play for high priority sources + bool m_WaitingForPlay; + + /// Inverse pitch + float m_PitchInv; + }; /* class CStreamSource */ } /* namespace NLSOUND */ diff --git a/code/nel/src/sound/CMakeLists.txt b/code/nel/src/sound/CMakeLists.txt index 80e545d25..fae6ca7a6 100644 --- a/code/nel/src/sound/CMakeLists.txt +++ b/code/nel/src/sound/CMakeLists.txt @@ -58,6 +58,8 @@ FILE(GLOB STREAM FILE(GLOB STREAM_FILE audio_decoder.cpp ../../include/nel/sound/audio_decoder.h audio_decoder_vorbis.cpp ../../include/nel/sound/audio_decoder_vorbis.h + stream_file_sound.cpp ../../include/nel/sound/stream_file_sound.h + stream_file_source.cpp ../../include/nel/sound/stream_file_source.h ) FILE(GLOB USER_CLASSES diff --git a/code/nel/src/sound/audio_mixer_user.cpp b/code/nel/src/sound/audio_mixer_user.cpp index e03b1ae00..5d938a036 100644 --- a/code/nel/src/sound/audio_mixer_user.cpp +++ b/code/nel/src/sound/audio_mixer_user.cpp @@ -45,6 +45,7 @@ #include "nel/sound/context_sound.h" #include "nel/sound/music_source.h" #include "nel/sound/stream_source.h" +#include "nel/sound/stream_file_source.h" #include "nel/sound/simple_sound.h" #include "nel/sound/music_sound.h" #include "nel/sound/stream_sound.h" @@ -250,6 +251,16 @@ void CAudioMixerUser::addSourceWaitingForPlay(CSourceCommon *source) _SourceWaitingForPlay.push_back(source); } +// ****************************************************************** + +void CAudioMixerUser::removeSourceWaitingForPlay(CSourceCommon *source) +{ + std::list::iterator it = find(_SourceWaitingForPlay.begin(), _SourceWaitingForPlay.end(), source); + if (it != _SourceWaitingForPlay.end()) + { + _SourceWaitingForPlay.erase(it); + } +} // ****************************************************************** @@ -1948,6 +1959,13 @@ retrySound: ret = new CStreamSource(streamSound, spawn, cb, userParam, cluster, static_cast(groupController)); } break; + case CSound::SOUND_STREAM_FILE: + { + CStreamFileSound *streamFileSound = static_cast(id); + // This is a stream file thingy. + ret = new CStreamFileSource(streamFileSound, spawn, cb, userParam, cluster, static_cast(groupController)); + } + break; case CSound::SOUND_COMPLEX: { CComplexSound *complexSound = static_cast(id); diff --git a/code/nel/src/sound/simple_source.cpp b/code/nel/src/sound/simple_source.cpp index 695619f91..7c76533e3 100644 --- a/code/nel/src/sound/simple_source.cpp +++ b/code/nel/src/sound/simple_source.cpp @@ -32,7 +32,8 @@ CSimpleSource::CSimpleSource(CSimpleSound *simpleSound, bool spawn, TSpawnEndCal : CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster, groupController), _SimpleSound(simpleSound), _Track(NULL), - _PlayMuted(false) + _PlayMuted(false), + _WaitingForPlay(false) { nlassert(_SimpleSound != 0); @@ -183,6 +184,7 @@ void CSimpleSource::play() { // This sound is not discardable, add it in waiting playlist mixer->addSourceWaitingForPlay(this); + _WaitingForPlay = true; return; } // there is no available track, just do a 'muted' play @@ -193,6 +195,7 @@ void CSimpleSource::play() } CSourceCommon::play(); + _WaitingForPlay = false; } /// Mixer event call when doing muted play @@ -219,6 +222,13 @@ void CSimpleSource::stop() // nldebug("CSimpleSource %p : stop", (CAudioMixerUser::IMixerEvent*)this); // nlassert(_Playing); + if (_WaitingForPlay) + { + nlassert(!_Playing); // cannot already be playing if waiting for play + CAudioMixerUser *mixer = CAudioMixerUser::instance(); + mixer->removeSourceWaitingForPlay(this); + } + if (!_Playing) return; diff --git a/code/nel/src/sound/sound.cpp b/code/nel/src/sound/sound.cpp index 07c10f8ef..4d753bb96 100644 --- a/code/nel/src/sound/sound.cpp +++ b/code/nel/src/sound/sound.cpp @@ -26,6 +26,7 @@ #include "nel/sound/context_sound.h" #include "nel/sound/music_sound.h" #include "nel/sound/stream_sound.h" +#include "nel/sound/stream_file_sound.h" #include "nel/sound/group_controller.h" #include "nel/sound/group_controller_root.h" @@ -84,6 +85,11 @@ CSound *CSound::createSound(const std::string &filename, NLGEORGES::UFormElm& fo ret = new CStreamSound(); ret->importForm(filename, formRoot); } + else if (dfnName == "stream_file_sound.dfn") + { + ret = new CStreamFileSound(); + ret->importForm(filename, formRoot); + } else { nlassertex(false, ("SoundType unsuported : %s", dfnName.c_str())); diff --git a/code/nel/src/sound/sound_bank.cpp b/code/nel/src/sound/sound_bank.cpp index b4031b571..dd2076a72 100644 --- a/code/nel/src/sound/sound_bank.cpp +++ b/code/nel/src/sound/sound_bank.cpp @@ -23,6 +23,7 @@ #include "nel/sound/background_sound.h" #include "nel/sound/music_sound.h" #include "nel/sound/stream_sound.h" +#include "nel/sound/stream_file_sound.h" #include "nel/georges/u_form_loader.h" #include "nel/georges/u_form_elm.h" @@ -194,6 +195,9 @@ public: case CSound::SOUND_STREAM: Sound = new CStreamSound(); break; + case CSound::SOUND_STREAM_FILE: + Sound = new CStreamFileSound(); + break; default: Sound = 0; } diff --git a/code/nel/src/sound/stream_file_sound.cpp b/code/nel/src/sound/stream_file_sound.cpp new file mode 100644 index 000000000..7640d7893 --- /dev/null +++ b/code/nel/src/sound/stream_file_sound.cpp @@ -0,0 +1,91 @@ +/** + * \file stream_file_sound.cpp + * \brief CStreamFileSound + * \date 2012-04-11 09:57GMT + * \author Jan Boon (Kaetemi) + * CStreamFileSound + */ + +/* + * 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 + +// Project includes + +using namespace std; +// using namespace NLMISC; + +namespace NLSOUND { + +CStreamFileSound::CStreamFileSound() +{ + +} + +CStreamFileSound::~CStreamFileSound() +{ + +} + +void CStreamFileSound::importForm(const std::string &filename, NLGEORGES::UFormElm &root) +{ + // Call the base class + CStreamSound::importForm(filename, root); + + // Async + root.getValueByName(m_Async, ".SoundType.Async"); + + // FilePath + root.getValueByName(m_FilePath, ".SoundType.FilePath"); +} + +void CStreamFileSound::serial(NLMISC::IStream &s) +{ + CStreamSound::serial(s); + + s.serial(m_Async); + s.serial(m_FilePath); +} + +void CStreamFileSound::setMusicFilePath(const std::string &filePath, bool async, bool loop) +{ + _ConeInnerAngle = NLMISC::Pi * 2; + _ConeOuterAngle = NLMISC::Pi * 2; + _Looping = loop; + _Gain = 1.0f; + _ConeOuterGain = 1.0f; + _Direction = NLMISC::CVector(0.f, 0.f, 0.f); + _Pitch = 1.0f; + _Priority = HighestPri; + _MaxDist = 9000.0f; + _MinDist = 1000.0f; + m_Async = async; + m_FilePath = filePath; +} + +} /* namespace NLSOUND */ + +/* end of file */ diff --git a/code/nel/src/sound/stream_file_source.cpp b/code/nel/src/sound/stream_file_source.cpp new file mode 100644 index 000000000..4514bf4c5 --- /dev/null +++ b/code/nel/src/sound/stream_file_source.cpp @@ -0,0 +1,244 @@ +/** + * \file stream_file_source.cpp + * \brief CStreamFileSource + * \date 2012-04-11 09:57GMT + * \author Jan Boon (Kaetemi) + * CStreamFileSource + */ + +/* + * 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 + +// Project includes +#include +#include + +using namespace std; +// using namespace NLMISC; + +namespace NLSOUND { + +CStreamFileSource::CStreamFileSource(CStreamFileSound *streamFileSound, bool spawn, TSpawnEndCallback cb, void *cbUserParam, NL3D::CCluster *cluster, CGroupController *groupController) +: CStreamSource(streamFileSound, spawn, cb, cbUserParam, cluster, groupController), m_AudioDecoder(NULL), m_Paused(false) +{ + m_Thread = NLMISC::IThread::create(this); +} + +CStreamFileSource::~CStreamFileSource() +{ + stop(); + m_Thread->wait(); // thread must have stopped for delete! + delete m_Thread; + m_Thread = NULL; + delete m_AudioDecoder; + m_AudioDecoder = NULL; +} + +void CStreamFileSource::play() +{ + // note: CStreamSource will assert crash if already physically playing! + + nldebug("play"); + + if (m_Thread->isRunning() && m_WaitingForPlay) + { + if (m_NextBuffer || !m_FreeBuffers) + { + CStreamSource::play(); + } + else + { + m_WaitingForPlay = true; + CAudioMixerUser *mixer = CAudioMixerUser::instance(); + mixer->addSourceWaitingForPlay(this); + } + } + else if (!_Playing) + { + if (!m_WaitingForPlay) + { + // thread may be stopping from stop call + m_Thread->wait(); + } + nlassert(!_Playing); + m_WaitingForPlay = true; + m_Thread->start(); + m_Thread->setPriority(NLMISC::ThreadPriorityHighest); + CAudioMixerUser *mixer = CAudioMixerUser::instance(); + mixer->addSourceWaitingForPlay(this); + } + + /*if (!m_WaitingForPlay) + { + m_WaitingForPlay = true; + + m_Thread->wait(); // thread must have stopped to restart it! + + m_Thread->start(); + m_Thread->setPriority(NLMISC::ThreadPriorityHighest); + } + + CStreamSource::play();*/ +} + +void CStreamFileSource::stop() +{ + nldebug("stop"); + + CStreamSource::stop(); + + // thread will check _Playing to stop +} + +bool CStreamFileSource::isPlaying() +{ + nldebug("isPlaying"); + + return m_Thread->isRunning(); +} + +void CStreamFileSource::pause() +{ + nldebug("pause"); + + if (!m_Paused) + { + // thread checks for this to not delete the audio decoder + m_Paused = true; + + // stop the underlying system + CStreamSource::stop(); + + // thread will check _Playing to stop + } + else + { + nlwarning("Already paused"); + } +} + +void CStreamFileSource::resume() +{ + nldebug("resume"); + + if (m_Paused) + { + m_Thread->wait(); // thread must have stopped to restart it! + + play(); + } + else + { + nlwarning("Not paused"); + } +} + +bool CStreamFileSource::isEnded() +{ + return (!m_Thread->isRunning() && !_Playing && !m_WaitingForPlay && !m_Paused); +} + +void CStreamFileSource::bufferMore(uint bytes) // buffer from bytes (minimum) to bytes * 2 (maximum) +{ + uint8 *buffer = this->lock(bytes * 2); + if (buffer) + { + uint32 result = m_AudioDecoder->getNextBytes(buffer, bytes, bytes * 2); + this->unlock(result); + } +} + +void CStreamFileSource::run() +{ + nldebug("run"); + + bool looping = _Looping; + if (m_Paused) + { + // handle paused! + m_Paused = false; + } + else if (m_AudioDecoder) // audio decoder should normally not exist when not paused and starting the thread + { + nlwarning("CAudioDecoder already exists, possible thread race bug with pause"); + delete m_AudioDecoder; + m_AudioDecoder = NULL; + } + if (!m_AudioDecoder) + { + // load the file + m_AudioDecoder = IAudioDecoder::createAudioDecoder(getStreamFileSound()->getFilePath(), getStreamFileSound()->getAsync(), getStreamFileSound()->getLooping()); + if (!m_AudioDecoder) + { + nlwarning("Failed to create IAudioDecoder, likely invalid format"); + return; + } + this->setFormat(m_AudioDecoder->getChannels(), m_AudioDecoder->getBitsPerSample(), (uint32)m_AudioDecoder->getSamplesPerSec()); + } + uint samples, bytes; + this->getRecommendedBufferSize(samples, bytes); + bufferMore(bytes); + while (_Playing || m_WaitingForPlay) + { + if (!m_AudioDecoder->isMusicEnded()) + { + bool newLooping = _Looping; + if (looping != newLooping) + { + m_AudioDecoder->setLooping(looping); + looping = newLooping; + } + + bufferMore(bytes); + NLMISC::nlSleep(this->getRecommendedSleepTime()); + } + else + { + // wait until done playing buffers + while (this->hasFilledBuffersAvailable()) + NLMISC::nlSleep(40); + // stop the physical source + // if (hasPhysicalSource()) + // getPhysicalSource()->stop(); + // the audio mixer will call stop on the logical source + break; + } + } + if (m_Paused) + { + // don't delete anything + } + else + { + delete m_AudioDecoder; + m_AudioDecoder = NULL; + } +} + +} /* namespace NLSOUND */ + +/* end of file */ diff --git a/code/nel/src/sound/stream_sound.cpp b/code/nel/src/sound/stream_sound.cpp index 7552e79e5..e16158d4d 100644 --- a/code/nel/src/sound/stream_sound.cpp +++ b/code/nel/src/sound/stream_sound.cpp @@ -35,14 +35,15 @@ CStreamSound::~CStreamSound() void CStreamSound::importForm(const std::string &filename, NLGEORGES::UFormElm &root) { - NLGEORGES::UFormElm *psoundType; + // cannot do this debug check because used also by CStreamFileSound + /*NLGEORGES::UFormElm *psoundType; std::string dfnName; // some basic checking. root.getNodeByName(&psoundType, ".SoundType"); nlassert(psoundType != NULL); psoundType->getDfnName(dfnName); - nlassert(dfnName == "stream_sound.dfn"); + nlassert(dfnName == "stream_sound.dfn");*/ // Call the base class CSound::importForm(filename, root); diff --git a/code/nel/src/sound/stream_source.cpp b/code/nel/src/sound/stream_source.cpp index 2c3188454..7f6b0c608 100644 --- a/code/nel/src/sound/stream_source.cpp +++ b/code/nel/src/sound/stream_source.cpp @@ -36,12 +36,15 @@ CStreamSource::CStreamSource(CStreamSound *streamSound, bool spawn, TSpawnEndCal m_FreeBuffers(3), m_NextBuffer(0), m_LastSize(0), - m_BytesPerSecond(0) + m_BytesPerSecond(0), + m_WaitingForPlay(false), + m_PitchInv(1.0f) { nlassert(m_StreamSound != 0); // get a local copy of the stream sound parameter m_Alpha = m_StreamSound->getAlpha();//m_Buffers + m_PitchInv = 1.0f / _Pitch; // create the three buffer objects CAudioMixerUser *mixer = CAudioMixerUser::instance(); @@ -107,6 +110,8 @@ bool CStreamSource::isPlaying() /// Set looping on/off for future playbacks (default: off) void CStreamSource::setLooping(bool l) { + CSourceCommon::setLooping(l); + //CAutoMutex autoMutex(m_BufferMutex); // //CSourceCommon::setLooping(l); @@ -166,7 +171,9 @@ void CStreamSource::play() ISource *pSource = getPhysicalSource(); nlassert(pSource != NULL); - for (uint i = 0; i < m_NextBuffer; ++i) + uint nbS = m_NextBuffer; + if (!m_NextBuffer && !m_FreeBuffers) nbS = 3; + for (uint i = 0; i < nbS; ++i) pSource->submitStreamingBuffer(m_Buffers[i]); // pSource->setPos( _Position, false); @@ -184,6 +191,7 @@ void CStreamSource::play() pSource->setAlpha(m_Alpha); // and play the sound + nlassert(nbS); // must have buffered already! play = pSource->play(); // nldebug("CStreamSource %p : REAL play done", (CAudioMixerUser::IMixerEvent*)this); } @@ -193,6 +201,7 @@ void CStreamSource::play() { // This sound is not discardable, add it in waiting playlist mixer->addSourceWaitingForPlay(this); + m_WaitingForPlay = true; return; } else @@ -209,10 +218,15 @@ void CStreamSource::play() } if (play) + { CSourceCommon::play(); + m_WaitingForPlay = false; + } } +#ifdef NL_DEBUG nlassert(play); +#endif } /// Stop playing @@ -222,6 +236,13 @@ void CStreamSource::stop() // nldebug("CStreamSource %p : stop", (CAudioMixerUser::IMixerEvent*)this); // nlassert(_Playing); + + if (m_WaitingForPlay) + { + nlassert(!_Playing); // cannot already be playing if waiting for play + CAudioMixerUser *mixer = CAudioMixerUser::instance(); + mixer->removeSourceWaitingForPlay(this); + } if (!_Playing) return; @@ -305,7 +326,7 @@ void CStreamSource::updateFinalGain() void CStreamSource::setPitch(float pitch) { CAutoMutex autoMutex(m_BufferMutex); - + m_PitchInv = 1.0f / pitch; CSourceCommon::setPitch(pitch); if (hasPhysicalSource()) getPhysicalSource()->setPitch(pitch); @@ -372,7 +393,9 @@ bool CStreamSource::unlock(uint size) ++m_NextBuffer; m_NextBuffer %= 3; --m_FreeBuffers; if (hasPhysicalSource()) + { getPhysicalSource()->submitStreamingBuffer(buffer); + } m_LastSize = size; } @@ -396,7 +419,7 @@ void CStreamSource::getRecommendedBufferSize(uint &samples, uint &bytes) const uint32 CStreamSource::getRecommendedSleepTime() const { if (m_FreeBuffers > 0) return 0; - uint32 sleepTime = (uint32)((1000.0f * ((float)m_LastSize) / (float)m_BytesPerSecond) / _Pitch); + uint32 sleepTime = (uint32)((1000.0f * ((float)m_LastSize) / (float)m_BytesPerSecond) * m_PitchInv); clamp(sleepTime, (uint32)0, (uint32)1000); return sleepTime; }