Added: #795 Streamed audio file sound source
This commit is contained in:
parent
30240f6e52
commit
fe70efdc6c
16 changed files with 621 additions and 12 deletions
|
@ -403,6 +403,7 @@ public:
|
||||||
|
|
||||||
/// Add a source for play as possible (for non discadable sound)
|
/// Add a source for play as possible (for non discadable sound)
|
||||||
void addSourceWaitingForPlay(CSourceCommon *source);
|
void addSourceWaitingForPlay(CSourceCommon *source);
|
||||||
|
void removeSourceWaitingForPlay(CSourceCommon *source);
|
||||||
|
|
||||||
/// Read all user controled var sheets
|
/// Read all user controled var sheets
|
||||||
void initUserVar();
|
void initUserVar();
|
||||||
|
|
|
@ -142,6 +142,8 @@ private:
|
||||||
/// True when the sound is played muted and until the mixer event notifying the end.
|
/// True when the sound is played muted and until the mixer event notifying the end.
|
||||||
bool _PlayMuted;
|
bool _PlayMuted;
|
||||||
|
|
||||||
|
bool _WaitingForPlay;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -61,8 +61,9 @@ public:
|
||||||
SOUND_COMPLEX,
|
SOUND_COMPLEX,
|
||||||
SOUND_BACKGROUND,
|
SOUND_BACKGROUND,
|
||||||
SOUND_CONTEXT,
|
SOUND_CONTEXT,
|
||||||
SOUND_MUSIC,
|
SOUND_MUSIC, // soon to be deprecated hopefully
|
||||||
SOUND_STREAM
|
SOUND_STREAM,
|
||||||
|
SOUND_STREAM_FILE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ public:
|
||||||
SOURCE_COMPLEX,
|
SOURCE_COMPLEX,
|
||||||
SOURCE_BACKGROUND,
|
SOURCE_BACKGROUND,
|
||||||
SOURCE_MUSIC, // DEPRECATED
|
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.
|
/// 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.
|
||||||
|
|
94
code/nel/include/nel/sound/stream_file_sound.h
Normal file
94
code/nel/include/nel/sound/stream_file_sound.h
Normal file
|
@ -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
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NLSOUND_STREAM_FILE_SOUND_H
|
||||||
|
#define NLSOUND_STREAM_FILE_SOUND_H
|
||||||
|
#include <nel/misc/types_nl.h>
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
|
||||||
|
// NeL includes
|
||||||
|
|
||||||
|
// Project includes
|
||||||
|
#include <nel/sound/stream_sound.h>
|
||||||
|
|
||||||
|
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<std::pair<std::string, CSound*> > &/* 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 */
|
105
code/nel/include/nel/sound/stream_file_source.h
Normal file
105
code/nel/include/nel/sound/stream_file_source.h
Normal file
|
@ -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
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NLSOUND_STREAM_FILE_SOURCE_H
|
||||||
|
#define NLSOUND_STREAM_FILE_SOURCE_H
|
||||||
|
#include <nel/misc/types_nl.h>
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
|
||||||
|
// NeL includes
|
||||||
|
#include <nel/misc/thread.h>
|
||||||
|
|
||||||
|
// Project includes
|
||||||
|
#include <nel/sound/stream_source.h>
|
||||||
|
#include <nel/sound/stream_file_sound.h>
|
||||||
|
|
||||||
|
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<CStreamFileSound *>(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 */
|
|
@ -114,7 +114,7 @@ private:
|
||||||
CStreamSource(const CStreamSource &);
|
CStreamSource(const CStreamSource &);
|
||||||
CStreamSource &operator=(const CStreamSource &);
|
CStreamSource &operator=(const CStreamSource &);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
/// Return the source type
|
/// Return the source type
|
||||||
TSOURCE_TYPE getType() const { return SOURCE_STREAM; }
|
TSOURCE_TYPE getType() const { return SOURCE_STREAM; }
|
||||||
|
|
||||||
|
@ -162,7 +162,13 @@ private:
|
||||||
|
|
||||||
/// The bytes per second according to the buffer format
|
/// The bytes per second according to the buffer format
|
||||||
uint m_BytesPerSecond;
|
uint m_BytesPerSecond;
|
||||||
|
|
||||||
|
/// Waiting for play for high priority sources
|
||||||
|
bool m_WaitingForPlay;
|
||||||
|
|
||||||
|
/// Inverse pitch
|
||||||
|
float m_PitchInv;
|
||||||
|
|
||||||
}; /* class CStreamSource */
|
}; /* class CStreamSource */
|
||||||
|
|
||||||
} /* namespace NLSOUND */
|
} /* namespace NLSOUND */
|
||||||
|
|
|
@ -58,6 +58,8 @@ FILE(GLOB STREAM
|
||||||
FILE(GLOB STREAM_FILE
|
FILE(GLOB STREAM_FILE
|
||||||
audio_decoder.cpp ../../include/nel/sound/audio_decoder.h
|
audio_decoder.cpp ../../include/nel/sound/audio_decoder.h
|
||||||
audio_decoder_vorbis.cpp ../../include/nel/sound/audio_decoder_vorbis.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
|
FILE(GLOB USER_CLASSES
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "nel/sound/context_sound.h"
|
#include "nel/sound/context_sound.h"
|
||||||
#include "nel/sound/music_source.h"
|
#include "nel/sound/music_source.h"
|
||||||
#include "nel/sound/stream_source.h"
|
#include "nel/sound/stream_source.h"
|
||||||
|
#include "nel/sound/stream_file_source.h"
|
||||||
#include "nel/sound/simple_sound.h"
|
#include "nel/sound/simple_sound.h"
|
||||||
#include "nel/sound/music_sound.h"
|
#include "nel/sound/music_sound.h"
|
||||||
#include "nel/sound/stream_sound.h"
|
#include "nel/sound/stream_sound.h"
|
||||||
|
@ -250,6 +251,16 @@ void CAudioMixerUser::addSourceWaitingForPlay(CSourceCommon *source)
|
||||||
_SourceWaitingForPlay.push_back(source);
|
_SourceWaitingForPlay.push_back(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ******************************************************************
|
||||||
|
|
||||||
|
void CAudioMixerUser::removeSourceWaitingForPlay(CSourceCommon *source)
|
||||||
|
{
|
||||||
|
std::list<CSourceCommon *>::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<CGroupController *>(groupController));
|
ret = new CStreamSource(streamSound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CSound::SOUND_STREAM_FILE:
|
||||||
|
{
|
||||||
|
CStreamFileSound *streamFileSound = static_cast<CStreamFileSound *>(id);
|
||||||
|
// This is a stream file thingy.
|
||||||
|
ret = new CStreamFileSource(streamFileSound, spawn, cb, userParam, cluster, static_cast<CGroupController *>(groupController));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CSound::SOUND_COMPLEX:
|
case CSound::SOUND_COMPLEX:
|
||||||
{
|
{
|
||||||
CComplexSound *complexSound = static_cast<CComplexSound *>(id);
|
CComplexSound *complexSound = static_cast<CComplexSound *>(id);
|
||||||
|
|
|
@ -32,7 +32,8 @@ CSimpleSource::CSimpleSource(CSimpleSound *simpleSound, bool spawn, TSpawnEndCal
|
||||||
: CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster, groupController),
|
: CSourceCommon(simpleSound, spawn, cb, cbUserParam, cluster, groupController),
|
||||||
_SimpleSound(simpleSound),
|
_SimpleSound(simpleSound),
|
||||||
_Track(NULL),
|
_Track(NULL),
|
||||||
_PlayMuted(false)
|
_PlayMuted(false),
|
||||||
|
_WaitingForPlay(false)
|
||||||
{
|
{
|
||||||
nlassert(_SimpleSound != 0);
|
nlassert(_SimpleSound != 0);
|
||||||
|
|
||||||
|
@ -183,6 +184,7 @@ void CSimpleSource::play()
|
||||||
{
|
{
|
||||||
// This sound is not discardable, add it in waiting playlist
|
// This sound is not discardable, add it in waiting playlist
|
||||||
mixer->addSourceWaitingForPlay(this);
|
mixer->addSourceWaitingForPlay(this);
|
||||||
|
_WaitingForPlay = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// there is no available track, just do a 'muted' play
|
// there is no available track, just do a 'muted' play
|
||||||
|
@ -193,6 +195,7 @@ void CSimpleSource::play()
|
||||||
}
|
}
|
||||||
|
|
||||||
CSourceCommon::play();
|
CSourceCommon::play();
|
||||||
|
_WaitingForPlay = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mixer event call when doing muted play
|
/// Mixer event call when doing muted play
|
||||||
|
@ -219,6 +222,13 @@ void CSimpleSource::stop()
|
||||||
// nldebug("CSimpleSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
|
// nldebug("CSimpleSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
|
||||||
// nlassert(_Playing);
|
// nlassert(_Playing);
|
||||||
|
|
||||||
|
if (_WaitingForPlay)
|
||||||
|
{
|
||||||
|
nlassert(!_Playing); // cannot already be playing if waiting for play
|
||||||
|
CAudioMixerUser *mixer = CAudioMixerUser::instance();
|
||||||
|
mixer->removeSourceWaitingForPlay(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_Playing)
|
if (!_Playing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "nel/sound/context_sound.h"
|
#include "nel/sound/context_sound.h"
|
||||||
#include "nel/sound/music_sound.h"
|
#include "nel/sound/music_sound.h"
|
||||||
#include "nel/sound/stream_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.h"
|
||||||
#include "nel/sound/group_controller_root.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 = new CStreamSound();
|
||||||
ret->importForm(filename, formRoot);
|
ret->importForm(filename, formRoot);
|
||||||
}
|
}
|
||||||
|
else if (dfnName == "stream_file_sound.dfn")
|
||||||
|
{
|
||||||
|
ret = new CStreamFileSound();
|
||||||
|
ret->importForm(filename, formRoot);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nlassertex(false, ("SoundType unsuported : %s", dfnName.c_str()));
|
nlassertex(false, ("SoundType unsuported : %s", dfnName.c_str()));
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "nel/sound/background_sound.h"
|
#include "nel/sound/background_sound.h"
|
||||||
#include "nel/sound/music_sound.h"
|
#include "nel/sound/music_sound.h"
|
||||||
#include "nel/sound/stream_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_loader.h"
|
||||||
#include "nel/georges/u_form_elm.h"
|
#include "nel/georges/u_form_elm.h"
|
||||||
|
@ -194,6 +195,9 @@ public:
|
||||||
case CSound::SOUND_STREAM:
|
case CSound::SOUND_STREAM:
|
||||||
Sound = new CStreamSound();
|
Sound = new CStreamSound();
|
||||||
break;
|
break;
|
||||||
|
case CSound::SOUND_STREAM_FILE:
|
||||||
|
Sound = new CStreamFileSound();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Sound = 0;
|
Sound = 0;
|
||||||
}
|
}
|
||||||
|
|
91
code/nel/src/sound/stream_file_sound.cpp
Normal file
91
code/nel/src/sound/stream_file_sound.cpp
Normal file
|
@ -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
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdsound.h"
|
||||||
|
#include <nel/sound/stream_file_sound.h>
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
|
||||||
|
// NeL includes
|
||||||
|
// #include <nel/misc/debug.h>
|
||||||
|
|
||||||
|
// 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 */
|
244
code/nel/src/sound/stream_file_source.cpp
Normal file
244
code/nel/src/sound/stream_file_source.cpp
Normal file
|
@ -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
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdsound.h"
|
||||||
|
#include <nel/sound/stream_file_source.h>
|
||||||
|
|
||||||
|
// STL includes
|
||||||
|
|
||||||
|
// NeL includes
|
||||||
|
// #include <nel/misc/debug.h>
|
||||||
|
|
||||||
|
// Project includes
|
||||||
|
#include <nel/sound/audio_mixer_user.h>
|
||||||
|
#include <nel/sound/audio_decoder.h>
|
||||||
|
|
||||||
|
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 */
|
|
@ -35,14 +35,15 @@ CStreamSound::~CStreamSound()
|
||||||
|
|
||||||
void CStreamSound::importForm(const std::string &filename, NLGEORGES::UFormElm &root)
|
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;
|
std::string dfnName;
|
||||||
|
|
||||||
// some basic checking.
|
// some basic checking.
|
||||||
root.getNodeByName(&psoundType, ".SoundType");
|
root.getNodeByName(&psoundType, ".SoundType");
|
||||||
nlassert(psoundType != NULL);
|
nlassert(psoundType != NULL);
|
||||||
psoundType->getDfnName(dfnName);
|
psoundType->getDfnName(dfnName);
|
||||||
nlassert(dfnName == "stream_sound.dfn");
|
nlassert(dfnName == "stream_sound.dfn");*/
|
||||||
|
|
||||||
// Call the base class
|
// Call the base class
|
||||||
CSound::importForm(filename, root);
|
CSound::importForm(filename, root);
|
||||||
|
|
|
@ -36,12 +36,15 @@ CStreamSource::CStreamSource(CStreamSound *streamSound, bool spawn, TSpawnEndCal
|
||||||
m_FreeBuffers(3),
|
m_FreeBuffers(3),
|
||||||
m_NextBuffer(0),
|
m_NextBuffer(0),
|
||||||
m_LastSize(0),
|
m_LastSize(0),
|
||||||
m_BytesPerSecond(0)
|
m_BytesPerSecond(0),
|
||||||
|
m_WaitingForPlay(false),
|
||||||
|
m_PitchInv(1.0f)
|
||||||
{
|
{
|
||||||
nlassert(m_StreamSound != 0);
|
nlassert(m_StreamSound != 0);
|
||||||
|
|
||||||
// get a local copy of the stream sound parameter
|
// get a local copy of the stream sound parameter
|
||||||
m_Alpha = m_StreamSound->getAlpha();//m_Buffers
|
m_Alpha = m_StreamSound->getAlpha();//m_Buffers
|
||||||
|
m_PitchInv = 1.0f / _Pitch;
|
||||||
|
|
||||||
// create the three buffer objects
|
// create the three buffer objects
|
||||||
CAudioMixerUser *mixer = CAudioMixerUser::instance();
|
CAudioMixerUser *mixer = CAudioMixerUser::instance();
|
||||||
|
@ -107,6 +110,8 @@ bool CStreamSource::isPlaying()
|
||||||
/// Set looping on/off for future playbacks (default: off)
|
/// Set looping on/off for future playbacks (default: off)
|
||||||
void CStreamSource::setLooping(bool l)
|
void CStreamSource::setLooping(bool l)
|
||||||
{
|
{
|
||||||
|
CSourceCommon::setLooping(l);
|
||||||
|
|
||||||
//CAutoMutex<CMutex> autoMutex(m_BufferMutex);
|
//CAutoMutex<CMutex> autoMutex(m_BufferMutex);
|
||||||
//
|
//
|
||||||
//CSourceCommon::setLooping(l);
|
//CSourceCommon::setLooping(l);
|
||||||
|
@ -166,7 +171,9 @@ void CStreamSource::play()
|
||||||
ISource *pSource = getPhysicalSource();
|
ISource *pSource = getPhysicalSource();
|
||||||
nlassert(pSource != NULL);
|
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->submitStreamingBuffer(m_Buffers[i]);
|
||||||
|
|
||||||
// pSource->setPos( _Position, false);
|
// pSource->setPos( _Position, false);
|
||||||
|
@ -184,6 +191,7 @@ void CStreamSource::play()
|
||||||
pSource->setAlpha(m_Alpha);
|
pSource->setAlpha(m_Alpha);
|
||||||
|
|
||||||
// and play the sound
|
// and play the sound
|
||||||
|
nlassert(nbS); // must have buffered already!
|
||||||
play = pSource->play();
|
play = pSource->play();
|
||||||
// nldebug("CStreamSource %p : REAL play done", (CAudioMixerUser::IMixerEvent*)this);
|
// 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
|
// This sound is not discardable, add it in waiting playlist
|
||||||
mixer->addSourceWaitingForPlay(this);
|
mixer->addSourceWaitingForPlay(this);
|
||||||
|
m_WaitingForPlay = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -209,10 +218,15 @@ void CStreamSource::play()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (play)
|
if (play)
|
||||||
|
{
|
||||||
CSourceCommon::play();
|
CSourceCommon::play();
|
||||||
|
m_WaitingForPlay = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NL_DEBUG
|
||||||
nlassert(play);
|
nlassert(play);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop playing
|
/// Stop playing
|
||||||
|
@ -222,6 +236,13 @@ void CStreamSource::stop()
|
||||||
|
|
||||||
// nldebug("CStreamSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
|
// nldebug("CStreamSource %p : stop", (CAudioMixerUser::IMixerEvent*)this);
|
||||||
// nlassert(_Playing);
|
// nlassert(_Playing);
|
||||||
|
|
||||||
|
if (m_WaitingForPlay)
|
||||||
|
{
|
||||||
|
nlassert(!_Playing); // cannot already be playing if waiting for play
|
||||||
|
CAudioMixerUser *mixer = CAudioMixerUser::instance();
|
||||||
|
mixer->removeSourceWaitingForPlay(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_Playing)
|
if (!_Playing)
|
||||||
return;
|
return;
|
||||||
|
@ -305,7 +326,7 @@ void CStreamSource::updateFinalGain()
|
||||||
void CStreamSource::setPitch(float pitch)
|
void CStreamSource::setPitch(float pitch)
|
||||||
{
|
{
|
||||||
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
|
CAutoMutex<CMutex> autoMutex(m_BufferMutex);
|
||||||
|
m_PitchInv = 1.0f / pitch;
|
||||||
CSourceCommon::setPitch(pitch);
|
CSourceCommon::setPitch(pitch);
|
||||||
if (hasPhysicalSource())
|
if (hasPhysicalSource())
|
||||||
getPhysicalSource()->setPitch(pitch);
|
getPhysicalSource()->setPitch(pitch);
|
||||||
|
@ -372,7 +393,9 @@ bool CStreamSource::unlock(uint size)
|
||||||
++m_NextBuffer; m_NextBuffer %= 3;
|
++m_NextBuffer; m_NextBuffer %= 3;
|
||||||
--m_FreeBuffers;
|
--m_FreeBuffers;
|
||||||
if (hasPhysicalSource())
|
if (hasPhysicalSource())
|
||||||
|
{
|
||||||
getPhysicalSource()->submitStreamingBuffer(buffer);
|
getPhysicalSource()->submitStreamingBuffer(buffer);
|
||||||
|
}
|
||||||
m_LastSize = size;
|
m_LastSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +419,7 @@ void CStreamSource::getRecommendedBufferSize(uint &samples, uint &bytes) const
|
||||||
uint32 CStreamSource::getRecommendedSleepTime() const
|
uint32 CStreamSource::getRecommendedSleepTime() const
|
||||||
{
|
{
|
||||||
if (m_FreeBuffers > 0) return 0;
|
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);
|
clamp(sleepTime, (uint32)0, (uint32)1000);
|
||||||
return sleepTime;
|
return sleepTime;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue