Browse Source

Audio: cleaned up the scene graph implementation.

* De-inlined most of the code
 * Reduced includes in headers
 * Formatting
 * Global variables don't need to be exposed publicly
pull/255/head
Vladimír Vondruš 8 years ago
parent
commit
5bb358e05d
  1. 4
      src/Magnum/Audio/CMakeLists.txt
  2. 56
      src/Magnum/Audio/Listener.cpp
  3. 54
      src/Magnum/Audio/Listener.h
  4. 84
      src/Magnum/Audio/Playable.cpp
  5. 81
      src/Magnum/Audio/Playable.h
  6. 109
      src/Magnum/Audio/PlayableGroup.cpp
  7. 90
      src/Magnum/Audio/PlayableGroup.h
  8. 1
      src/Magnum/Audio/Renderer.h
  9. 3
      src/Magnum/Audio/Test/ListenerALTest.cpp
  10. 1
      src/Magnum/Audio/Test/PlayableALTest.cpp

4
src/Magnum/Audio/CMakeLists.txt

@ -58,7 +58,9 @@ if(WITH_SCENEGRAPH)
PlayableGroup.h) PlayableGroup.h)
list(APPEND MagnumAudio_SRCS list(APPEND MagnumAudio_SRCS
Listener.cpp) Listener.cpp
Playable.cpp
PlayableGroup.cpp)
endif() endif()
# Audio library # Audio library

56
src/Magnum/Audio/Listener.cpp

@ -24,21 +24,19 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include "Magnum/Audio/Listener.h" #include "Listener.h"
#include "Magnum/Audio/Playable.h" #include "Magnum/Audio/Playable.h"
#include "Magnum/Audio/PlayableGroup.h" #include "Magnum/Audio/PlayableGroup.h"
#include "Magnum/Audio/Renderer.h"
#include "Magnum/Math/Matrix3.h"
namespace Magnum { namespace Audio { namespace Magnum { namespace Audio {
using namespace SceneGraph;
namespace Implementation {
void* activeListener = nullptr;
}
namespace { namespace {
void* activeListener = nullptr;
/* Create a Matrix4 from a Matrix3/Matrix4 */ /* Create a Matrix4 from a Matrix3/Matrix4 */
inline Matrix4 padMatrix4(const Matrix3& m) { inline Matrix4 padMatrix4(const Matrix3& m) {
return Matrix4{Vector4::pad(m[0]), Vector4::pad(m[1]), Vector4::pad(m[2]), Vector4{}}; return Matrix4{Vector4::pad(m[0]), Vector4::pad(m[1]), Vector4::pad(m[2]), Vector4{}};
@ -50,31 +48,33 @@ inline Matrix4 padMatrix4(const Matrix4& m) {
} }
template<UnsignedInt dimensions> Listener<dimensions>::Listener(SceneGraph::AbstractObject<dimensions, Float>& object): SceneGraph::AbstractFeature<dimensions, Float>(object), _gain{1.0f} {
SceneGraph::AbstractFeature<dimensions, Float>::setCachedTransformations(SceneGraph::CachedTransformation::Absolute);
}
template<UnsignedInt dimensions> Listener<dimensions>::~Listener() = default;
template<UnsignedInt dimensions> void Listener<dimensions>::clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) { template<UnsignedInt dimensions> void Listener<dimensions>::clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) {
if(!isActive()) { /* Only clean if this Listener is active */
/* Only clean if this Listener is active */ if(!isActive()) return;
return;
}
Renderer::setListenerPosition(soundTransformation().transformVector(Vector3::pad(absoluteTransformationMatrix.translation()))); Renderer::setListenerPosition(_soundTransformation.transformVector(Vector3::pad(absoluteTransformationMatrix.translation())));
const Vector3 fwd = soundTransformation().transformVector(-padMatrix4(absoluteTransformationMatrix).backward()); const Vector3 fwd = _soundTransformation.transformVector(-padMatrix4(absoluteTransformationMatrix).backward());
const Vector3 up = soundTransformation().transformVector(padMatrix4(absoluteTransformationMatrix).up()); const Vector3 up = _soundTransformation.transformVector(padMatrix4(absoluteTransformationMatrix).up());
Renderer::setListenerOrientation(fwd, up); Renderer::setListenerOrientation(fwd, up);
Renderer::setListenerGain(_gain); Renderer::setListenerGain(_gain);
/** @todo velocity */ /** @todo velocity */
} }
template<UnsignedInt dimensions> void Listener<dimensions>::update(std::initializer_list<std::reference_wrapper<PlayableGroup<dimensions>>> groups) { template<UnsignedInt dimensions> void Listener<dimensions>::update(std::initializer_list<std::reference_wrapper<PlayableGroup<dimensions>>> groups) {
/* Check if active listener just changed to this */ /* Check if active listener just changed to this */
if(this != Implementation::activeListener) { if(this != activeListener) {
/* Ensure that clean() is called also when switching between (clean) /* Ensure that clean() is called also when switching between (clean)
listeners */ listeners */
Implementation::activeListener = this; activeListener = this;
this->object().setDirty(); this->object().setDirty();
/* Listener gain needs to be updated only when active listener changed /* Listener gain needs to be updated only when active listener changed
@ -84,17 +84,27 @@ template<UnsignedInt dimensions> void Listener<dimensions>::update(std::initiali
/* Add all objects of the Playables in the PlayableGroups to a vector to /* Add all objects of the Playables in the PlayableGroups to a vector to
later setClean() */ later setClean() */
std::vector<std::reference_wrapper<AbstractObject<dimensions, Float>>> objects; std::vector<std::reference_wrapper<SceneGraph::AbstractObject<dimensions, Float>>> objects;
objects.push_back(this->object()); objects.push_back(this->object());
for(PlayableGroup<dimensions>& group : groups) { for(PlayableGroup<dimensions>& group: groups) {
for(UnsignedInt i = 0; i < group.size(); ++i) { for(std::size_t i = 0; i != group.size(); ++i) {
objects.push_back(group[i].object()); objects.push_back(group[i].object());
} }
} }
/* Use the more performant way to set multiple objects clean */ /* Use the more performant way to set multiple objects clean */
AbstractObject<dimensions, Float>::setClean(objects); SceneGraph::AbstractObject<dimensions, Float>::setClean(objects);
}
template<UnsignedInt dimensions> Listener<dimensions>& Listener<dimensions>::setGain(const Float gain) {
_gain = gain;
if(isActive()) Renderer::setListenerGain(_gain);
return *this;
}
template<UnsignedInt dimensions> bool Listener<dimensions>::isActive() const {
return this == activeListener;
} }
/* On non-MinGW Windows the instantiations are already marked with extern /* On non-MinGW Windows the instantiations are already marked with extern

54
src/Magnum/Audio/Listener.h

@ -30,26 +30,13 @@
* @brief Class @ref Magnum::Audio::Listener, @ref Magnum::Audio::Listener2D, @ref Magnum::Audio::Listener3D * @brief Class @ref Magnum::Audio::Listener, @ref Magnum::Audio::Listener2D, @ref Magnum::Audio::Listener3D
*/ */
#include <string> #include "Magnum/Audio/Audio.h"
#include <al.h> #include "Magnum/Audio/visibility.h"
#include "Magnum/Math/Matrix4.h"
#include <Magnum/Math/Matrix3.h> #include "Magnum/SceneGraph/AbstractFeature.h"
#include <Magnum/Math/Matrix4.h>
#include <Magnum/Math/Quaternion.h>
#include <Magnum/SceneGraph/AbstractFeature.h>
#include <Magnum/SceneGraph/AbstractObject.h>
#include "Magnum/Audio/Renderer.h"
#include "Magnum/Audio/PlayableGroup.h"
namespace Magnum { namespace Audio { namespace Magnum { namespace Audio {
namespace Implementation {
/* Pointer to the currently active listener. Should never be dereferenced,
since may be null at any given time. */
extern MAGNUM_AUDIO_EXPORT void* activeListener;
}
/** /**
@brief Listener @brief Listener
@ -109,11 +96,8 @@ a certain world scale. In the later case you might want to instead consider
@see @ref Audio::Renderer, @ref Playable, @ref PlayableGroup @see @ref Audio::Renderer, @ref Playable, @ref PlayableGroup
*/ */
template <UnsignedInt dimensions> class Listener: public SceneGraph::AbstractFeature<dimensions, Float> { template<UnsignedInt dimensions> class Listener: public SceneGraph::AbstractFeature<dimensions, Float> {
friend class ActiveListenerHolder;
public: public:
/** /**
* @brief Constructor * @brief Constructor
* @param object Object this listener belongs to * @param object Object this listener belongs to
@ -124,12 +108,9 @@ template <UnsignedInt dimensions> class Listener: public SceneGraph::AbstractFea
* affected by @p object or via @ref Listener::setSoundTransformation(). * affected by @p object or via @ref Listener::setSoundTransformation().
* @see @ref setGain() * @see @ref setGain()
*/ */
explicit Listener(SceneGraph::AbstractObject<dimensions, Float>& object): explicit Listener(SceneGraph::AbstractObject<dimensions, Float>& object);
SceneGraph::AbstractFeature<dimensions, Float>(object),
_gain{1.0f} ~Listener();
{
SceneGraph::AbstractFeature<dimensions, Float>::setCachedTransformations(SceneGraph::CachedTransformation::Absolute);
}
/** @brief Sound transformation */ /** @brief Sound transformation */
const Matrix4& soundTransformation() const { const Matrix4& soundTransformation() const {
@ -160,36 +141,25 @@ template <UnsignedInt dimensions> class Listener: public SceneGraph::AbstractFea
void update(std::initializer_list<std::reference_wrapper<PlayableGroup<dimensions>>> groups); void update(std::initializer_list<std::reference_wrapper<PlayableGroup<dimensions>>> groups);
/** @brief Listener gain */ /** @brief Listener gain */
Float gain() const { Float gain() const { return _gain; }
return _gain;
}
/** /**
* @brief Set listener gain * @brief Set listener gain
* @param gain Gain * @param gain Gain
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
*/ */
Listener<dimensions>& setGain(Float gain) { Listener<dimensions>& setGain(Float gain);
_gain = gain;
if(isActive()) {
Renderer::setListenerGain(_gain);
}
return *this;
}
/** @brief Whether this listener is the active listener */ /** @brief Whether this listener is the active listener */
bool isActive() const { bool isActive() const;
return this == Implementation::activeListener;
}
private: private:
virtual void clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) override; MAGNUM_AUDIO_LOCAL void clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) override;
Matrix4 _soundTransformation; Matrix4 _soundTransformation;
Float _gain; Float _gain;
}; };
/** /**
* @brief Listener for two dimensional float scenes * @brief Listener for two dimensional float scenes
* *

84
src/Magnum/Audio/Playable.cpp

@ -0,0 +1,84 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
Vladimír Vondruš <mosra@centrum.cz>
Copyright © 2015 Jonathan Hale <squareys@googlemail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "Playable.h"
#include "Magnum/Audio/PlayableGroup.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
namespace Magnum { namespace Audio {
template<UnsignedInt dimensions> Playable<dimensions>::Playable(SceneGraph::AbstractObject<dimensions, Float>& object, PlayableGroup<dimensions>* group): SceneGraph::AbstractGroupedFeature<dimensions, Playable<dimensions>, Float>(object, group), _fwd{}, _gain{1.0f} {
SceneGraph::AbstractFeature<dimensions, Float>::setCachedTransformations(SceneGraph::CachedTransformation::Absolute);
_fwd[dimensions - 1] = -1;
}
template<UnsignedInt dimensions> Playable<dimensions>::~Playable() = default;
template<UnsignedInt dimensions> Playable<dimensions>& Playable<dimensions>::setGain(const Float gain) {
_gain = gain;
cleanGain();
return *this;
}
template<UnsignedInt dimensions> void Playable<dimensions>::clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) {
Vector3 position = Vector3::pad(absoluteTransformationMatrix.translation());
if(playables())
position = playables()->soundTransformation().transformVector(position);
_source.setPosition(position);
_source.setDirection(Vector3::pad(absoluteTransformationMatrix.rotation()*_fwd));
/** @todo velocity */
}
template<UnsignedInt dimensions> PlayableGroup<dimensions>* Playable<dimensions>::playables() {
return static_cast<PlayableGroup<dimensions>*>(this->group());
}
template<UnsignedInt dimensions> const PlayableGroup<dimensions>* Playable<dimensions>::playables() const {
return static_cast<const PlayableGroup<dimensions>*>(this->group());
}
template<UnsignedInt dimensions> void Playable<dimensions>::cleanGain() {
_source.setGain(playables() ? _gain*playables()->gain() : _gain);
}
/* On non-MinGW Windows the instantiations are already marked with extern
template */
#if !defined(CORRADE_TARGET_WINDOWS) || defined(__MINGW32__)
#define MAGNUM_AUDIO_EXPORT_HPP MAGNUM_AUDIO_EXPORT
#else
#define MAGNUM_AUDIO_EXPORT_HPP
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
template class MAGNUM_AUDIO_EXPORT_HPP Playable<2>;
template class MAGNUM_AUDIO_EXPORT_HPP Playable<3>;
#endif
}}

81
src/Magnum/Audio/Playable.h

@ -30,16 +30,9 @@
* @brief Class @ref Magnum::Audio::Playable, typedef @ref Magnum::Audio::Playable2D, @ref Magnum::Audio::Playable3D * @brief Class @ref Magnum::Audio::Playable, typedef @ref Magnum::Audio::Playable2D, @ref Magnum::Audio::Playable3D
*/ */
#include <string>
#include <al.h>
#include <Magnum/SceneGraph/AbstractGroupedFeature.h>
#include <Magnum/Math/Matrix3.h>
#include <Magnum/Math/Matrix4.h>
#include "Magnum/Audio/PlayableGroup.h"
#include "Magnum/Audio/Source.h" #include "Magnum/Audio/Source.h"
#include "Magnum/Audio/visibility.h" #include "Magnum/Math/Vector3.h"
#include "Magnum/SceneGraph/AbstractGroupedFeature.h"
namespace Magnum { namespace Audio { namespace Magnum { namespace Audio {
@ -76,10 +69,7 @@ To manage multiple Playables at once, use @ref PlayableGroup.
@see @ref Source, @ref PlayableGroup, @ref Listener @see @ref Source, @ref PlayableGroup, @ref Listener
*/ */
template<UnsignedInt dimensions> class Playable: public SceneGraph::AbstractGroupedFeature<dimensions, Playable<dimensions>, Float> { template<UnsignedInt dimensions> class Playable: public SceneGraph::AbstractGroupedFeature<dimensions, Playable<dimensions>, Float> {
friend PlayableGroup<dimensions>;
public: public:
/** /**
* @brief Constructor * @brief Constructor
* @param object Object this playable belongs to * @param object Object this playable belongs to
@ -92,25 +82,15 @@ template<UnsignedInt dimensions> class Playable: public SceneGraph::AbstractGrou
* @ref PlayableGroup::setSoundTransformation(). * @ref PlayableGroup::setSoundTransformation().
* @see @ref setGain(), @ref PlayableGroup::add() * @see @ref setGain(), @ref PlayableGroup::add()
*/ */
explicit Playable(SceneGraph::AbstractObject<dimensions, Float>& object, PlayableGroup<dimensions>* group = nullptr): explicit Playable(SceneGraph::AbstractObject<dimensions, Float>& object, PlayableGroup<dimensions>* group = nullptr);
SceneGraph::AbstractGroupedFeature<dimensions, Playable<dimensions>, Float>(object, group),
_fwd(0.0f), ~Playable();
_gain(1.0f),
_source()
{
SceneGraph::AbstractFeature<dimensions, Float>::setCachedTransformations(SceneGraph::CachedTransformation::Absolute);
_fwd[dimensions - 1] = -1;
}
/** @brief Source which is managed by this feature */ /** @brief Source which is managed by this feature */
Source& source() { Source& source() { return _source; }
return _source;
}
/** @brief Gain */ /** @brief Gain */
Float gain() const { Float gain() const { return _gain; }
return _gain;
}
/** /**
* @brief Set gain of the playable and source respecting the PlayableGroups gain * @brief Set gain of the playable and source respecting the PlayableGroups gain
@ -120,46 +100,26 @@ template<UnsignedInt dimensions> class Playable: public SceneGraph::AbstractGrou
* Default for the playables gain is @cpp 1.0f @ce. * Default for the playables gain is @cpp 1.0f @ce.
* @see @ref PlayableGroup::setGain(), @ref Source::setGain() * @see @ref PlayableGroup::setGain(), @ref Source::setGain()
*/ */
Playable& setGain(const Float gain) { Playable& setGain(const Float gain);
_gain = gain;
cleanGain();
return *this;
}
/** /**
* @brief Group containing this playable * @brief Group containing this playable
* *
* If the playable doesn't belong to any group, returns @cpp nullptr @ce. * If the playable doesn't belong to any group, returns @cpp nullptr @ce.
*/ */
PlayableGroup<dimensions>* playables() { PlayableGroup<dimensions>* playables();
return static_cast<PlayableGroup<dimensions>*>(this->group());
}
const PlayableGroup<dimensions>* playables() const { /**< @overload */ const PlayableGroup<dimensions>* playables() const; /**< @overload */
return static_cast<const PlayableGroup<dimensions>*>(this->group());
}
private: private:
void clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) override { friend PlayableGroup<dimensions>;
Vector3 position = Vector3::pad(absoluteTransformationMatrix.translation(), 0);
if(playables()) { MAGNUM_AUDIO_LOCAL void clean(const MatrixTypeFor<dimensions, Float>& absoluteTransformationMatrix) override;
position = playables()->soundTransformation().transformVector(position);
} /* Updates the gain of the underlying source to reflect changes in
_source.setPosition(position); _group and/or _gain. Called from setGain() and
_source.setDirection(Vector3::pad(absoluteTransformationMatrix.rotation()*_fwd)); PlayableGroup::setGain() */
MAGNUM_AUDIO_LOCAL void cleanGain();
/** @todo velocity */
}
/* Update the gain of the underlying source to reflect changes in _group and/or _gain.
Called in Playable::setGain() and PlayableGroup::setGain() */
void cleanGain() {
if(playables()) {
_source.setGain(_gain*playables()->gain());
} else {
_source.setGain(_gain);
}
}
VectorTypeFor<dimensions, Float> _fwd; VectorTypeFor<dimensions, Float> _fwd;
Float _gain; Float _gain;
@ -180,6 +140,11 @@ typedef Playable<2> Playable2D;
*/ */
typedef Playable<3> Playable3D; typedef Playable<3> Playable3D;
#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__)
extern template class MAGNUM_AUDIO_EXPORT Playable<2>;
extern template class MAGNUM_AUDIO_EXPORT Playable<3>;
#endif
}} }}
#endif #endif

109
src/Magnum/Audio/PlayableGroup.cpp

@ -0,0 +1,109 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
Vladimír Vondruš <mosra@centrum.cz>
Copyright © 2015 Jonathan Hale <squareys@googlemail.com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include "PlayableGroup.h"
#include "Magnum/Audio/Playable.h"
#include "Magnum/Audio/Source.h"
#include "Magnum/SceneGraph/AbstractObject.h"
namespace Magnum { namespace Audio {
namespace {
template<UnsignedInt dimensions> std::vector<std::reference_wrapper<Source>> sources(PlayableGroup<dimensions>& group) {
std::vector<std::reference_wrapper<Source>> srcs;
srcs.reserve(group.size());
for(std::size_t i = 0; i != group.size(); ++i)
srcs.push_back(group[i].source());
return srcs;
}
}
template<UnsignedInt dimensions> PlayableGroup<dimensions>::PlayableGroup(): SceneGraph::FeatureGroup<dimensions, Playable<dimensions>, Float>(), _gain{1.0f} {}
template<UnsignedInt dimensions> PlayableGroup<dimensions>::~PlayableGroup() = default;
template<UnsignedInt dimensions> PlayableGroup<dimensions>& PlayableGroup<dimensions>::play() {
Source::play(sources(*this));
return *this;
}
template<UnsignedInt dimensions> PlayableGroup<dimensions>& PlayableGroup<dimensions>::pause() {
Source::pause(sources(*this));
return *this;
}
template<UnsignedInt dimensions> PlayableGroup<dimensions>& PlayableGroup<dimensions>::stop() {
Source::stop(sources(*this));
return *this;
}
template<UnsignedInt dimensions> PlayableGroup<dimensions>& PlayableGroup<dimensions>::setGain(const Float gain) {
_gain = gain;
for(UnsignedInt i = 0; i < this->size(); ++i)
(*this)[i].cleanGain();
return *this;
}
template<UnsignedInt dimensions> PlayableGroup<dimensions>& PlayableGroup<dimensions>::setSoundTransformation(const Matrix4& matrix) {
_soundTransform = matrix;
/* I cannot come up with a use case for which the sound transformation
would be set frequently, so we are setting objects dirty whether the
matrix changed or not. */
for(UnsignedInt i = 0; i < this->size(); ++i)
(*this)[i].object().setDirty();
return *this;
}
template<UnsignedInt dimensions> void PlayableGroup<dimensions>::setClean() {
std::vector<std::reference_wrapper<SceneGraph::AbstractObject<dimensions, Float>>> objects;
objects.reserve(this->size());
for(UnsignedInt i = 0; i < this->size(); ++i)
objects.push_back((*this)[i].object());
SceneGraph::AbstractObject<dimensions, Float>::setClean(objects);
}
/* On non-MinGW Windows the instantiations are already marked with extern
template */
#if !defined(CORRADE_TARGET_WINDOWS) || defined(__MINGW32__)
#define MAGNUM_AUDIO_EXPORT_HPP MAGNUM_AUDIO_EXPORT
#else
#define MAGNUM_AUDIO_EXPORT_HPP
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT
template class MAGNUM_AUDIO_EXPORT_HPP PlayableGroup<2>;
template class MAGNUM_AUDIO_EXPORT_HPP PlayableGroup<3>;
#endif
}}

90
src/Magnum/Audio/PlayableGroup.h

@ -30,18 +30,11 @@
* @brief Class @ref Magnum::Audio::PlayableGroup, typedef @ref Magnum::Audio::PlayableGroup2D, @ref Magnum::Audio::PlayableGroup3D * @brief Class @ref Magnum::Audio::PlayableGroup, typedef @ref Magnum::Audio::PlayableGroup2D, @ref Magnum::Audio::PlayableGroup3D
*/ */
#include <functional> #include "Magnum/Magnum.h"
#include <string>
#include <vector>
#include <Magnum/SceneGraph/AbstractObject.h>
#include <Magnum/SceneGraph/SceneGraph.h>
#include <Magnum/SceneGraph/FeatureGroup.h>
#include "Magnum/Audio/Audio.h" #include "Magnum/Audio/Audio.h"
#include "Magnum/Audio/Playable.h"
#include "Magnum/Audio/Source.h"
#include "Magnum/Audio/visibility.h" #include "Magnum/Audio/visibility.h"
#include "Magnum/Math/Matrix4.h"
#include "Magnum/SceneGraph/FeatureGroup.h"
namespace Magnum { namespace Audio { namespace Magnum { namespace Audio {
@ -78,50 +71,34 @@ For two dimensional scenes simply replace `3D` with `2D`. When using a
@see @ref Playable, @ref SceneGraph::FeatureGroup, @ref Listener @see @ref Playable, @ref SceneGraph::FeatureGroup, @ref Listener
*/ */
template<UnsignedInt dimensions> class PlayableGroup: public SceneGraph::FeatureGroup<dimensions, Playable<dimensions>, Float> { template<UnsignedInt dimensions> class PlayableGroup: public SceneGraph::FeatureGroup<dimensions, Playable<dimensions>, Float> {
friend Playable<dimensions>;
public: public:
explicit PlayableGroup();
/** @brief Constructor */ ~PlayableGroup();
explicit PlayableGroup():
SceneGraph::FeatureGroup<dimensions, Playable<dimensions>, Float>(),
_gain{1.0f}
{}
/** /**
* @brief Play all sound sources in this group * @brief Play all sound sources in this group
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* @see @ref Source::play() * @see @ref Source::play()
*/ */
PlayableGroup<dimensions>& play() { PlayableGroup<dimensions>& play();
Source::play(sources());
return *this;
}
/** /**
* @brief Pause all sound sources in this group * @brief Pause all sound sources in this group
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* @see @ref Source::pause() * @see @ref Source::pause()
*/ */
PlayableGroup& pause() { PlayableGroup<dimensions>& pause();
Source::stop(sources());
return *this;
}
/** /**
* @brief Stop all sound sources in this group * @brief Stop all sound sources in this group
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* @see @ref Source::stop() * @see @ref Source::stop()
*/ */
PlayableGroup& stop() { PlayableGroup<dimensions>& stop();
Source::stop(sources());
return *this;
}
/** @brief Gain */ /** @brief Gain */
Float gain() const { Float gain() const { return _gain; }
return _gain;
}
/** /**
* @brief Set gain for all sound sources of Playables in this group * @brief Set gain for all sound sources of Playables in this group
@ -133,18 +110,10 @@ template<UnsignedInt dimensions> class PlayableGroup: public SceneGraph::Feature
* @cpp sourceGain = playableGain*groupGain @ce. Default of the groups * @cpp sourceGain = playableGain*groupGain @ce. Default of the groups
* gain is @cpp 1.0f @ce. * gain is @cpp 1.0f @ce.
*/ */
PlayableGroup& setGain(const Float gain) { PlayableGroup<dimensions>& setGain(const Float gain);
_gain = gain;
for(UnsignedInt i = 0; i < this->size(); ++i)
(*this)[i].cleanGain();
return *this;
}
/** @brief Sound transformation */ /** @brief Sound transformation */
const Matrix4& soundTransformation() const { const Matrix4& soundTransformation() const { return _soundTransform; }
return _soundTransform;
}
/** /**
* @brief Set transformation of the sounds in this group * @brief Set transformation of the sounds in this group
@ -159,42 +128,12 @@ template<UnsignedInt dimensions> class PlayableGroup: public SceneGraph::Feature
void setClean(); void setClean();
private: private:
friend Playable<dimensions>;
/* @brief Sources of all Playables in this group */
std::vector<std::reference_wrapper<Source>> sources() {
std::vector<std::reference_wrapper<Source>> srcs;
srcs.reserve(this->size());
for(UnsignedInt i = 0; i < this->size(); ++i)
srcs.push_back((*this)[i].source());
return srcs;
}
Matrix4 _soundTransform; Matrix4 _soundTransform;
Float _gain; Float _gain;
}; };
template<UnsignedInt dimensions> inline PlayableGroup<dimensions>& PlayableGroup<dimensions>::setSoundTransformation(const Matrix4& matrix) {
_soundTransform = matrix;
/* I cannot come up with a use case for which the sound
transformation would be set frequently, so we are setting
objects dirty whether the matrix changed or not. */
for(UnsignedInt i = 0; i < this->size(); ++i)
(*this)[i].object().setDirty();
return *this;
}
template<UnsignedInt dimensions> inline void PlayableGroup<dimensions>::setClean() {
std::vector<std::reference_wrapper<SceneGraph::AbstractObject<dimensions, Float>>> objects;
objects.reserve(this->size());
for(UnsignedInt i = 0; i < this->size(); ++i)
objects.push_back((*this)[i].object());
SceneGraph::AbstractObject<dimensions, Float>::setClean(objects);
}
/** /**
* @brief Playable group for two dimensional float scenes * @brief Playable group for two dimensional float scenes
* *
@ -209,6 +148,11 @@ typedef PlayableGroup<2> PlayableGroup2D;
*/ */
typedef PlayableGroup<3> PlayableGroup3D; typedef PlayableGroup<3> PlayableGroup3D;
#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__)
extern template class MAGNUM_AUDIO_EXPORT PlayableGroup<2>;
extern template class MAGNUM_AUDIO_EXPORT PlayableGroup<3>;
#endif
}} }}
#endif #endif

1
src/Magnum/Audio/Renderer.h

@ -30,7 +30,6 @@
*/ */
#include <array> #include <array>
#include <al.h> #include <al.h>
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"

3
src/Magnum/Audio/Test/ListenerALTest.cpp

@ -26,10 +26,11 @@
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include "Magnum/Audio/Playable.h"
#include "Magnum/Audio/Context.h" #include "Magnum/Audio/Context.h"
#include "Magnum/Audio/Listener.h" #include "Magnum/Audio/Listener.h"
#include "Magnum/Audio/Playable.h"
#include "Magnum/Audio/PlayableGroup.h" #include "Magnum/Audio/PlayableGroup.h"
#include "Magnum/Audio/Renderer.h"
#include "Magnum/SceneGraph/Scene.h" #include "Magnum/SceneGraph/Scene.h"
#include "Magnum/SceneGraph/Object.h" #include "Magnum/SceneGraph/Object.h"
#include "Magnum/SceneGraph/MatrixTransformation2D.h" #include "Magnum/SceneGraph/MatrixTransformation2D.h"

1
src/Magnum/Audio/Test/PlayableALTest.cpp

@ -28,6 +28,7 @@
#include "Magnum/Audio/Context.h" #include "Magnum/Audio/Context.h"
#include "Magnum/Audio/Playable.h" #include "Magnum/Audio/Playable.h"
#include "Magnum/Audio/PlayableGroup.h"
#include "Magnum/SceneGraph/Scene.h" #include "Magnum/SceneGraph/Scene.h"
#include "Magnum/SceneGraph/Object.h" #include "Magnum/SceneGraph/Object.h"
#include "Magnum/SceneGraph/MatrixTransformation3D.h" #include "Magnum/SceneGraph/MatrixTransformation3D.h"

Loading…
Cancel
Save