mirror of https://github.com/AxioDL/amuse.git
Initial multiple-referencing submix refactor
This commit is contained in:
parent
596bc66ce6
commit
d3d5595422
|
@ -22,6 +22,7 @@ set(SOURCES
|
||||||
lib/Voice.cpp
|
lib/Voice.cpp
|
||||||
lib/VolumeLUT.cpp
|
lib/VolumeLUT.cpp
|
||||||
lib/Submix.cpp
|
lib/Submix.cpp
|
||||||
|
lib/Studio.cpp
|
||||||
lib/EffectBase.cpp
|
lib/EffectBase.cpp
|
||||||
lib/EffectReverb.cpp
|
lib/EffectReverb.cpp
|
||||||
lib/EffectChorus.cpp
|
lib/EffectChorus.cpp
|
||||||
|
@ -49,6 +50,7 @@ set(HEADERS
|
||||||
include/amuse/SongState.hpp
|
include/amuse/SongState.hpp
|
||||||
include/amuse/Voice.hpp
|
include/amuse/Voice.hpp
|
||||||
include/amuse/Submix.hpp
|
include/amuse/Submix.hpp
|
||||||
|
include/amuse/Studio.hpp
|
||||||
include/amuse/IBackendSubmix.hpp
|
include/amuse/IBackendSubmix.hpp
|
||||||
include/amuse/IBackendVoice.hpp
|
include/amuse/IBackendVoice.hpp
|
||||||
include/amuse/IBackendVoiceAllocator.hpp
|
include/amuse/IBackendVoiceAllocator.hpp
|
||||||
|
|
|
@ -30,11 +30,10 @@ class BooBackendVoice : public IBackendVoice
|
||||||
public:
|
public:
|
||||||
BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox,
|
BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVox,
|
||||||
double sampleRate, bool dynamicPitch);
|
double sampleRate, bool dynamicPitch);
|
||||||
BooBackendVoice(boo::IAudioSubmix& submix, Voice& clientVox,
|
|
||||||
double sampleRate, bool dynamicPitch);
|
|
||||||
void resetSampleRate(double sampleRate);
|
void resetSampleRate(double sampleRate);
|
||||||
void setMatrixCoefficients(const float coefs[8], bool slew);
|
|
||||||
void setSubmixMatrixCoefficients(const float coefs[8], bool slew);
|
void resetChannelLevels();
|
||||||
|
void setChannelLevels(IBackendSubmix* submix, const float coefs[8], bool slew);
|
||||||
void setPitchRatio(double ratio, bool slew);
|
void setPitchRatio(double ratio, bool slew);
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
|
@ -44,6 +43,7 @@ public:
|
||||||
class BooBackendSubmix : public IBackendSubmix
|
class BooBackendSubmix : public IBackendSubmix
|
||||||
{
|
{
|
||||||
friend class BooBackendVoiceAllocator;
|
friend class BooBackendVoiceAllocator;
|
||||||
|
friend class BooBackendVoice;
|
||||||
Submix& m_clientSmx;
|
Submix& m_clientSmx;
|
||||||
struct SubmixCallback : boo::IAudioSubmixCallback
|
struct SubmixCallback : boo::IAudioSubmixCallback
|
||||||
{
|
{
|
||||||
|
@ -60,10 +60,8 @@ class BooBackendSubmix : public IBackendSubmix
|
||||||
} m_cb;
|
} m_cb;
|
||||||
std::unique_ptr<boo::IAudioSubmix> m_booSubmix;
|
std::unique_ptr<boo::IAudioSubmix> m_booSubmix;
|
||||||
public:
|
public:
|
||||||
BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx);
|
BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut);
|
||||||
BooBackendSubmix(boo::IAudioSubmix& parent, Submix& clientSmx);
|
void setSendLevel(IBackendSubmix* submix, float level, bool slew);
|
||||||
void setChannelGains(const float gains[8]);
|
|
||||||
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch);
|
|
||||||
double getSampleRate() const;
|
double getSampleRate() const;
|
||||||
SubmixFormat getSampleFormat() const;
|
SubmixFormat getSampleFormat() const;
|
||||||
};
|
};
|
||||||
|
@ -124,7 +122,7 @@ class BooBackendVoiceAllocator : public IBackendVoiceAllocator
|
||||||
public:
|
public:
|
||||||
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
BooBackendVoiceAllocator(boo::IAudioVoiceEngine& booEngine);
|
||||||
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch);
|
std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch);
|
||||||
std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx);
|
std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx, bool mainOut);
|
||||||
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices();
|
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices();
|
||||||
std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name=nullptr);
|
std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name=nullptr);
|
||||||
void register5MsCallback(std::function<void(double)>&& callback);
|
void register5MsCallback(std::function<void(double)>&& callback);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "Emitter.hpp"
|
#include "Emitter.hpp"
|
||||||
#include "AudioGroupSampleDirectory.hpp"
|
#include "AudioGroupSampleDirectory.hpp"
|
||||||
#include "Sequencer.hpp"
|
#include "Sequencer.hpp"
|
||||||
|
#include "Studio.hpp"
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
@ -37,11 +38,12 @@ class Engine
|
||||||
IBackendVoiceAllocator& m_backend;
|
IBackendVoiceAllocator& m_backend;
|
||||||
AmplitudeMode m_ampMode;
|
AmplitudeMode m_ampMode;
|
||||||
std::unique_ptr<IMIDIReader> m_midiReader;
|
std::unique_ptr<IMIDIReader> m_midiReader;
|
||||||
|
std::shared_ptr<Studio> m_defaultStudio;
|
||||||
std::unordered_map<const AudioGroupData*, std::unique_ptr<AudioGroup>> m_audioGroups;
|
std::unordered_map<const AudioGroupData*, std::unique_ptr<AudioGroup>> m_audioGroups;
|
||||||
std::list<std::shared_ptr<Voice>> m_activeVoices;
|
std::list<std::shared_ptr<Voice>> m_activeVoices;
|
||||||
std::list<std::shared_ptr<Emitter>> m_activeEmitters;
|
std::list<std::shared_ptr<Emitter>> m_activeEmitters;
|
||||||
std::list<std::shared_ptr<Sequencer>> m_activeSequencers;
|
std::list<std::shared_ptr<Sequencer>> m_activeSequencers;
|
||||||
std::list<Submix> m_activeSubmixes;
|
std::list<std::shared_ptr<Studio>> m_activeStudios;
|
||||||
std::unordered_map<uint16_t, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
std::unordered_map<uint16_t, std::tuple<AudioGroup*, int, const SFXGroupIndex::SFXEntry*>> m_sfxLookup;
|
||||||
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
std::linear_congruential_engine<uint32_t, 0x41c64e6d, 0x3039, UINT32_MAX> m_random;
|
||||||
int m_nextVid = 0;
|
int m_nextVid = 0;
|
||||||
|
@ -52,15 +54,15 @@ class Engine
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator
|
std::list<std::shared_ptr<Voice>>::iterator
|
||||||
_allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
|
_allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
|
||||||
bool dynamicPitch, bool emitter, Submix* smx);
|
bool dynamicPitch, bool emitter, std::weak_ptr<Studio> studio);
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator
|
std::list<std::shared_ptr<Sequencer>>::iterator
|
||||||
_allocateSequencer(const AudioGroup& group, int groupId,
|
_allocateSequencer(const AudioGroup& group, int groupId,
|
||||||
int setupId, Submix* smx);
|
int setupId, std::weak_ptr<Studio> studio);
|
||||||
std::list<Submix>::iterator _allocateSubmix(Submix* smx);
|
std::list<std::shared_ptr<Studio>>::iterator _allocateStudio(bool mainOut);
|
||||||
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
|
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator _destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
|
std::list<std::shared_ptr<Sequencer>>::iterator _destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
|
||||||
std::list<Submix>::iterator _destroySubmix(std::list<Submix>::iterator it);
|
std::list<std::shared_ptr<Studio>>::iterator _destroyStudio(std::list<std::shared_ptr<Studio>>::iterator it);
|
||||||
std::list<Submix>::iterator _removeSubmix(std::list<Submix>::iterator it);
|
std::list<std::shared_ptr<Studio>>::iterator _removeStudio(std::list<std::shared_ptr<Studio>>::iterator it);
|
||||||
void _bringOutYourDead();
|
void _bringOutYourDead();
|
||||||
void _5MsCallback(double dt);
|
void _5MsCallback(double dt);
|
||||||
public:
|
public:
|
||||||
|
@ -79,23 +81,34 @@ public:
|
||||||
/** Remove audio group from engine */
|
/** Remove audio group from engine */
|
||||||
void removeAudioGroup(const AudioGroupData& data);
|
void removeAudioGroup(const AudioGroupData& data);
|
||||||
|
|
||||||
/** Create new Submix (a.k.a 'Studio') within root mix engine */
|
/** Access engine's default studio */
|
||||||
Submix* addSubmix(Submix* parent=nullptr);
|
std::shared_ptr<Studio> getDefaultStudio() {return m_defaultStudio;}
|
||||||
|
|
||||||
/** Remove Submix and deallocate */
|
/** Create new Studio within engine */
|
||||||
void removeSubmix(Submix* smx);
|
std::shared_ptr<Studio> addStudio(bool mainOut);
|
||||||
|
|
||||||
|
/** Remove Studio from engine */
|
||||||
|
void removeStudio(std::weak_ptr<Studio> studio);
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups */
|
/** Start soundFX playing from loaded audio groups */
|
||||||
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan, Submix* smx=nullptr);
|
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan, std::weak_ptr<Studio> smx);
|
||||||
|
std::shared_ptr<Voice> fxStart(int sfxId, float vol, float pan)
|
||||||
|
{
|
||||||
|
return fxStart(sfxId, vol, pan, m_defaultStudio);
|
||||||
|
}
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
||||||
std::shared_ptr<Emitter> addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
|
std::shared_ptr<Emitter> addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
|
||||||
float falloff, int sfxId, float minVol, float maxVol,
|
float falloff, int sfxId, float minVol, float maxVol,
|
||||||
Submix* smx=nullptr);
|
std::weak_ptr<Studio> smx);
|
||||||
|
|
||||||
/** Start song playing from loaded audio groups */
|
/** Start song playing from loaded audio groups */
|
||||||
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData,
|
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData,
|
||||||
Submix* smx=nullptr);
|
std::weak_ptr<Studio> smx);
|
||||||
|
std::shared_ptr<Sequencer> seqPlay(int groupId, int songId, const unsigned char* arrData)
|
||||||
|
{
|
||||||
|
return seqPlay(groupId, songId, arrData, m_defaultStudio);
|
||||||
|
}
|
||||||
|
|
||||||
/** Find voice from VoiceId */
|
/** Find voice from VoiceId */
|
||||||
std::shared_ptr<Voice> findVoice(int vid);
|
std::shared_ptr<Voice> findVoice(int vid);
|
||||||
|
|
|
@ -21,11 +21,8 @@ class IBackendSubmix
|
||||||
public:
|
public:
|
||||||
virtual ~IBackendSubmix() = default;
|
virtual ~IBackendSubmix() = default;
|
||||||
|
|
||||||
/** Set channel-gains for submix (AudioChannel enum for array index) */
|
/** Set send level for submix (AudioChannel enum for array index) */
|
||||||
virtual void setChannelGains(const float gains[8])=0;
|
virtual void setSendLevel(IBackendSubmix* submix, float level, bool slew)=0;
|
||||||
|
|
||||||
/** Amuse obtains a new voice from the platform outputting to this submix */
|
|
||||||
virtual std::unique_ptr<IBackendVoice> allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch)=0;
|
|
||||||
|
|
||||||
/** Amuse gets fixed sample rate of submix this way */
|
/** Amuse gets fixed sample rate of submix this way */
|
||||||
virtual double getSampleRate() const=0;
|
virtual double getSampleRate() const=0;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
|
class IBackendSubmix;
|
||||||
|
|
||||||
/** Same channel enums from boo, used for matrix coefficient table index */
|
/** Same channel enums from boo, used for matrix coefficient table index */
|
||||||
enum class AudioChannel
|
enum class AudioChannel
|
||||||
|
@ -34,11 +35,11 @@ public:
|
||||||
/** Set new sample rate into platform voice (may result in artifacts while playing) */
|
/** Set new sample rate into platform voice (may result in artifacts while playing) */
|
||||||
virtual void resetSampleRate(double sampleRate)=0;
|
virtual void resetSampleRate(double sampleRate)=0;
|
||||||
|
|
||||||
/** Set channel-gains for audio source (AudioChannel enum for array index) */
|
/** Reset channel-gains to silence and unbind all submixes */
|
||||||
virtual void setMatrixCoefficients(const float coefs[8], bool slew)=0;
|
virtual void resetChannelLevels()=0;
|
||||||
|
|
||||||
/** Set submix-channel-gains for audio source (AudioChannel enum for array index) */
|
/** Set channel-gains for audio source (AudioChannel enum for array index) */
|
||||||
virtual void setSubmixMatrixCoefficients(const float coefs[8], bool slew)=0;
|
virtual void setChannelLevels(IBackendSubmix* submix, const float coefs[8], bool slew)=0;
|
||||||
|
|
||||||
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
|
/** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */
|
||||||
virtual void setPitchRatio(double ratio, bool slew)=0;
|
virtual void setPitchRatio(double ratio, bool slew)=0;
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
bool dynamicPitch)=0;
|
bool dynamicPitch)=0;
|
||||||
|
|
||||||
/** Amuse obtains a new submix from the platform this way */
|
/** Amuse obtains a new submix from the platform this way */
|
||||||
virtual std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx)=0;
|
virtual std::unique_ptr<IBackendSubmix> allocateSubmix(Submix& clientSmx, bool mainOut)=0;
|
||||||
|
|
||||||
/** Amuse obtains a list of all MIDI devices this way */
|
/** Amuse obtains a list of all MIDI devices this way */
|
||||||
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices()=0;
|
virtual std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices()=0;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class Submix;
|
class Studio;
|
||||||
class Voice;
|
class Voice;
|
||||||
|
|
||||||
/** State of sequencer over lifetime */
|
/** State of sequencer over lifetime */
|
||||||
|
@ -31,7 +31,7 @@ class Sequencer : public Entity
|
||||||
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
|
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup (may be null) */
|
||||||
const SFXGroupIndex* m_sfxGroup = nullptr; /**< SFX Groups are alternatively referenced here */
|
const SFXGroupIndex* m_sfxGroup = nullptr; /**< SFX Groups are alternatively referenced here */
|
||||||
std::vector<const SFXGroupIndex::SFXEntry*> m_sfxMappings; /**< SFX entries are mapped to MIDI keys this via this */
|
std::vector<const SFXGroupIndex::SFXEntry*> m_sfxMappings; /**< SFX entries are mapped to MIDI keys this via this */
|
||||||
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */
|
std::shared_ptr<Studio> m_studio; /**< Studio this sequencer outputs to */
|
||||||
|
|
||||||
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
|
||||||
SongState m_songState; /**< State of current arrangement playback */
|
SongState m_songState; /**< State of current arrangement playback */
|
||||||
|
@ -85,15 +85,15 @@ class Sequencer : public Entity
|
||||||
public:
|
public:
|
||||||
~Sequencer();
|
~Sequencer();
|
||||||
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
const SongGroupIndex* songGroup, int setupId, Submix* smx);
|
const SongGroupIndex* songGroup, int setupId, std::weak_ptr<Studio> studio);
|
||||||
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
const SFXGroupIndex* sfxGroup, Submix* smx);
|
const SFXGroupIndex* sfxGroup, std::weak_ptr<Studio> studio);
|
||||||
|
|
||||||
/** Advance current song data (if any) */
|
/** Advance current song data (if any) */
|
||||||
void advance(double dt);
|
void advance(double dt);
|
||||||
|
|
||||||
/** Obtain pointer to Sequencer's Submix */
|
/** Obtain pointer to Sequencer's Submix */
|
||||||
Submix* getSubmix() {return m_submix;}
|
std::shared_ptr<Studio> getStudio() {return m_studio;}
|
||||||
|
|
||||||
/** Get current state of sequencer */
|
/** Get current state of sequencer */
|
||||||
SequencerState state() const {return m_state;}
|
SequencerState state() const {return m_state;}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
#ifndef __AMUSE_STUDIO_HPP__
|
||||||
|
#define __AMUSE_STUDIO_HPP__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <list>
|
||||||
|
#include "Entity.hpp"
|
||||||
|
#include "Voice.hpp"
|
||||||
|
#include "Submix.hpp"
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
class Studio
|
||||||
|
{
|
||||||
|
friend class Engine;
|
||||||
|
Engine& m_engine;
|
||||||
|
Submix m_auxA;
|
||||||
|
Submix m_auxB;
|
||||||
|
struct StudioSend
|
||||||
|
{
|
||||||
|
std::weak_ptr<Studio> m_targetStudio;
|
||||||
|
float m_dryLevel;
|
||||||
|
float m_auxALevel;
|
||||||
|
float m_auxBLevel;
|
||||||
|
StudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB)
|
||||||
|
: m_targetStudio(studio), m_dryLevel(dry), m_auxALevel(auxA), m_auxBLevel(auxB) {}
|
||||||
|
};
|
||||||
|
std::list<StudioSend> m_studiosOut;
|
||||||
|
bool m_destroyed = false;
|
||||||
|
void _destroy();
|
||||||
|
void _bringOutYourDead();
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool _cyclicCheck(Studio* leaf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public:
|
||||||
|
Studio(Engine& engine, bool mainOut);
|
||||||
|
|
||||||
|
/** Register a target Studio to send this Studio's mixing busses */
|
||||||
|
void addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB);
|
||||||
|
|
||||||
|
~Studio()
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
/* Ensure proper destruction procedure followed */
|
||||||
|
assert(m_destroyed);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** advice submixes of changing sample rate */
|
||||||
|
void resetOutputSampleRate(double sampleRate);
|
||||||
|
|
||||||
|
Submix& getAuxA() {return m_auxA;}
|
||||||
|
Submix& getAuxB() {return m_auxB;}
|
||||||
|
|
||||||
|
Engine& getEngine() {return m_engine;}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __AMUSE_STUDIO_HPP__
|
|
@ -23,14 +23,13 @@ class Submix
|
||||||
friend class Voice;
|
friend class Voice;
|
||||||
friend class Sequencer;
|
friend class Sequencer;
|
||||||
Engine& m_root;
|
Engine& m_root;
|
||||||
Submix* m_submix = nullptr; /**< Parent submix of this submix (or NULL if mixing to main output) */
|
|
||||||
std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */
|
std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */
|
||||||
std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */
|
std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */
|
||||||
bool m_destroyed = false;
|
bool m_destroyed = false;
|
||||||
void _destroy();
|
void _destroy();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Submix(Engine& engine, Submix* smx);
|
Submix(Engine& engine);
|
||||||
~Submix()
|
~Submix()
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -39,9 +38,6 @@ public:
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Obtain pointer to Submix's parent Submix */
|
|
||||||
Submix* getParentSubmix() {return m_submix;}
|
|
||||||
|
|
||||||
/** Add new effect to effect stack and assume ownership */
|
/** Add new effect to effect stack and assume ownership */
|
||||||
template <class T, class ...Args>
|
template <class T, class ...Args>
|
||||||
T& makeEffect(Args... args)
|
T& makeEffect(Args... args)
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
namespace amuse
|
namespace amuse
|
||||||
{
|
{
|
||||||
class IBackendVoice;
|
class IBackendVoice;
|
||||||
class Submix;
|
class Studio;
|
||||||
struct Keymap;
|
struct Keymap;
|
||||||
struct LayerMapping;
|
struct LayerMapping;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class Voice : public Entity
|
||||||
friend class Envelope;
|
friend class Envelope;
|
||||||
int m_vid; /**< VoiceID of this voice instance */
|
int m_vid; /**< VoiceID of this voice instance */
|
||||||
bool m_emitter; /**< Voice is part of an Emitter */
|
bool m_emitter; /**< Voice is part of an Emitter */
|
||||||
Submix* m_submix = nullptr; /**< Submix this voice outputs to (or NULL for the main output mix) */
|
std::shared_ptr<Studio> m_studio; /**< Studio this voice outputs to */
|
||||||
|
|
||||||
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
|
||||||
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
SoundMacroState m_state; /**< State container for SoundMacro playback */
|
||||||
|
@ -164,8 +164,8 @@ class Voice : public Entity
|
||||||
void _notifyCtrlChange(uint8_t ctrl, int8_t val);
|
void _notifyCtrlChange(uint8_t ctrl, int8_t val);
|
||||||
public:
|
public:
|
||||||
~Voice();
|
~Voice();
|
||||||
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, Submix* smx);
|
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, std::weak_ptr<Studio> studio);
|
||||||
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter, Submix* smx);
|
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter, std::weak_ptr<Studio> studio);
|
||||||
|
|
||||||
/** Called before each supplyAudio invocation to prepare voice
|
/** Called before each supplyAudio invocation to prepare voice
|
||||||
* backend for possible parameter updates */
|
* backend for possible parameter updates */
|
||||||
|
@ -175,8 +175,8 @@ public:
|
||||||
* internally advancing the voice stream */
|
* internally advancing the voice stream */
|
||||||
size_t supplyAudio(size_t frames, int16_t* data);
|
size_t supplyAudio(size_t frames, int16_t* data);
|
||||||
|
|
||||||
/** Obtain pointer to Voice's Submix */
|
/** Obtain pointer to Voice's Studio */
|
||||||
Submix* getSubmix() {return m_submix;}
|
std::shared_ptr<Studio> getStudio() {return m_studio;}
|
||||||
|
|
||||||
/** Get current state of voice */
|
/** Get current state of voice */
|
||||||
VoiceState state() const {return m_voxState;}
|
VoiceState state() const {return m_voxState;}
|
||||||
|
|
|
@ -24,25 +24,20 @@ BooBackendVoice::BooBackendVoice(boo::IAudioVoiceEngine& engine, Voice& clientVo
|
||||||
m_booVoice(engine.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
|
m_booVoice(engine.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
BooBackendVoice::BooBackendVoice(boo::IAudioSubmix& submix, Voice& clientVox,
|
|
||||||
double sampleRate, bool dynamicPitch)
|
|
||||||
: m_clientVox(clientVox), m_cb(*this),
|
|
||||||
m_booVoice(submix.allocateNewMonoVoice(sampleRate, &m_cb, dynamicPitch))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void BooBackendVoice::resetSampleRate(double sampleRate)
|
void BooBackendVoice::resetSampleRate(double sampleRate)
|
||||||
{
|
{
|
||||||
m_booVoice->resetSampleRate(sampleRate);
|
m_booVoice->resetSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoice::setMatrixCoefficients(const float coefs[8], bool slew)
|
void BooBackendVoice::resetChannelLevels()
|
||||||
{
|
{
|
||||||
m_booVoice->setMonoMatrixCoefficients(coefs, slew);
|
m_booVoice->resetChannelLevels();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoice::setSubmixMatrixCoefficients(const float coefs[8], bool slew)
|
void BooBackendVoice::setChannelLevels(IBackendSubmix* submix, const float coefs[8], bool slew)
|
||||||
{
|
{
|
||||||
m_booVoice->setMonoSubmixMatrixCoefficients(coefs, slew);
|
BooBackendSubmix& smx = *reinterpret_cast<BooBackendSubmix*>(submix);
|
||||||
|
m_booVoice->setMonoChannelLevels(smx.m_booSubmix.get(), coefs, slew);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BooBackendVoice::setPitchRatio(double ratio, bool slew)
|
void BooBackendVoice::setPitchRatio(double ratio, bool slew)
|
||||||
|
@ -88,23 +83,14 @@ void BooBackendSubmix::SubmixCallback::resetOutputSampleRate(double sampleRate)
|
||||||
m_parent.m_clientSmx.resetOutputSampleRate(sampleRate);
|
m_parent.m_clientSmx.resetOutputSampleRate(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
BooBackendSubmix::BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx)
|
BooBackendSubmix::BooBackendSubmix(boo::IAudioVoiceEngine& engine, Submix& clientSmx, bool mainOut)
|
||||||
: m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(engine.allocateNewSubmix(&m_cb))
|
: m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(engine.allocateNewSubmix(mainOut, &m_cb))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
BooBackendSubmix::BooBackendSubmix(boo::IAudioSubmix& parent, Submix& clientSmx)
|
void BooBackendSubmix::setSendLevel(IBackendSubmix* submix, float level, bool slew)
|
||||||
: m_clientSmx(clientSmx), m_cb(*this), m_booSubmix(parent.allocateNewSubmix(&m_cb))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void BooBackendSubmix::setChannelGains(const float gains[8])
|
|
||||||
{
|
{
|
||||||
m_booSubmix->setChannelGains(gains);
|
BooBackendSubmix& smx = *reinterpret_cast<BooBackendSubmix*>(submix);
|
||||||
}
|
m_booSubmix->setSendLevel(smx.m_booSubmix.get(), level, slew);
|
||||||
|
|
||||||
std::unique_ptr<IBackendVoice>
|
|
||||||
BooBackendSubmix::allocateVoice(Voice& clientVox, double sampleRate, bool dynamicPitch)
|
|
||||||
{
|
|
||||||
return std::make_unique<BooBackendVoice>(*m_booSubmix, clientVox, sampleRate, dynamicPitch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double BooBackendSubmix::getSampleRate() const
|
double BooBackendSubmix::getSampleRate() const
|
||||||
|
@ -327,9 +313,9 @@ BooBackendVoiceAllocator::allocateVoice(Voice& clientVox, double sampleRate, boo
|
||||||
return std::make_unique<BooBackendVoice>(m_booEngine, clientVox, sampleRate, dynamicPitch);
|
return std::make_unique<BooBackendVoice>(m_booEngine, clientVox, sampleRate, dynamicPitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IBackendSubmix> BooBackendVoiceAllocator::allocateSubmix(Submix& clientSmx)
|
std::unique_ptr<IBackendSubmix> BooBackendVoiceAllocator::allocateSubmix(Submix& clientSmx, bool mainOut)
|
||||||
{
|
{
|
||||||
return std::make_unique<BooBackendSubmix>(m_booEngine, clientSmx);
|
return std::make_unique<BooBackendSubmix>(m_booEngine, clientSmx, mainOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enumerateMIDIDevices()
|
std::vector<std::pair<std::string, std::string>> BooBackendVoiceAllocator::enumerateMIDIDevices()
|
||||||
|
|
|
@ -16,8 +16,8 @@ Engine::~Engine()
|
||||||
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
|
||||||
if (!seq->m_destroyed)
|
if (!seq->m_destroyed)
|
||||||
seq->_destroy();
|
seq->_destroy();
|
||||||
while (m_activeSubmixes.size())
|
while (m_activeStudios.size())
|
||||||
removeSubmix(&m_activeSubmixes.front());
|
removeStudio(m_activeStudios.front());
|
||||||
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
|
for (std::shared_ptr<Emitter>& emitter : m_activeEmitters)
|
||||||
emitter->_destroy();
|
emitter->_destroy();
|
||||||
for (std::shared_ptr<Voice>& vox : m_activeVoices)
|
for (std::shared_ptr<Voice>& vox : m_activeVoices)
|
||||||
|
@ -25,7 +25,7 @@ Engine::~Engine()
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine::Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode)
|
Engine::Engine(IBackendVoiceAllocator& backend, AmplitudeMode ampMode)
|
||||||
: m_backend(backend), m_ampMode(ampMode)
|
: m_backend(backend), m_ampMode(ampMode), m_defaultStudio(std::make_shared<Studio>(*this, true))
|
||||||
{
|
{
|
||||||
backend.register5MsCallback(std::bind(&Engine::_5MsCallback, this, std::placeholders::_1));
|
backend.register5MsCallback(std::bind(&Engine::_5MsCallback, this, std::placeholders::_1));
|
||||||
m_midiReader = backend.allocateMIDIReader(*this);
|
m_midiReader = backend.allocateMIDIReader(*this);
|
||||||
|
@ -55,44 +55,41 @@ std::pair<AudioGroup*, const SFXGroupIndex*> Engine::_findSFXGroup(int groupId)
|
||||||
|
|
||||||
std::list<std::shared_ptr<Voice>>::iterator
|
std::list<std::shared_ptr<Voice>>::iterator
|
||||||
Engine::_allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
|
Engine::_allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
|
||||||
bool dynamicPitch, bool emitter, Submix* smx)
|
bool dynamicPitch, bool emitter, std::weak_ptr<Studio> studio)
|
||||||
{
|
{
|
||||||
auto it = m_activeVoices.emplace(m_activeVoices.end(),
|
auto it = m_activeVoices.emplace(m_activeVoices.end(),
|
||||||
new Voice(*this, group, groupId, m_nextVid++, emitter, smx));
|
new Voice(*this, group, groupId, m_nextVid++, emitter, studio));
|
||||||
if (smx)
|
m_activeVoices.back()->m_backendVoice =
|
||||||
m_activeVoices.back()->m_backendVoice =
|
m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
|
||||||
smx->m_backendSubmix->allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
|
|
||||||
else
|
|
||||||
m_activeVoices.back()->m_backendVoice =
|
|
||||||
m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
|
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::shared_ptr<Sequencer>>::iterator
|
std::list<std::shared_ptr<Sequencer>>::iterator
|
||||||
Engine::_allocateSequencer(const AudioGroup& group, int groupId,
|
Engine::_allocateSequencer(const AudioGroup& group, int groupId,
|
||||||
int setupId, Submix* smx)
|
int setupId, std::weak_ptr<Studio> studio)
|
||||||
{
|
{
|
||||||
const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId);
|
const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId);
|
||||||
if (songGroup)
|
if (songGroup)
|
||||||
{
|
{
|
||||||
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
||||||
new Sequencer(*this, group, groupId, songGroup, setupId, smx));
|
new Sequencer(*this, group, groupId, songGroup, setupId, studio));
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
const SFXGroupIndex* sfxGroup = group.getProj().getSFXGroupIndex(groupId);
|
const SFXGroupIndex* sfxGroup = group.getProj().getSFXGroupIndex(groupId);
|
||||||
if (sfxGroup)
|
if (sfxGroup)
|
||||||
{
|
{
|
||||||
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
|
||||||
new Sequencer(*this, group, groupId, sfxGroup, smx));
|
new Sequencer(*this, group, groupId, sfxGroup, studio));
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Submix>::iterator Engine::_allocateSubmix(Submix* smx)
|
std::list<std::shared_ptr<Studio>>::iterator Engine::_allocateStudio(bool mainOut)
|
||||||
{
|
{
|
||||||
auto it = m_activeSubmixes.emplace(m_activeSubmixes.end(), *this, smx);
|
auto it = m_activeStudios.emplace(m_activeStudios.end(), std::make_shared<Studio>(*this, mainOut));
|
||||||
m_activeSubmixes.back().m_backendSubmix = m_backend.allocateSubmix(m_activeSubmixes.back());
|
m_activeStudios.back()->m_auxA.m_backendSubmix = m_backend.allocateSubmix(m_activeStudios.back()->m_auxA, mainOut);
|
||||||
|
m_activeStudios.back()->m_auxB.m_backendSubmix = m_backend.allocateSubmix(m_activeStudios.back()->m_auxB, mainOut);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,15 +115,15 @@ std::list<std::shared_ptr<Sequencer>>::iterator Engine::_destroySequencer(std::l
|
||||||
return m_activeSequencers.erase(it);
|
return m_activeSequencers.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Submix>::iterator Engine::_destroySubmix(std::list<Submix>::iterator it)
|
std::list<std::shared_ptr<Studio>>::iterator Engine::_destroyStudio(std::list<std::shared_ptr<Studio>>::iterator it)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert(this == &it->getEngine());
|
assert(this == &(*it)->getEngine());
|
||||||
#endif
|
#endif
|
||||||
if (it->m_destroyed)
|
if ((*it)->m_destroyed)
|
||||||
return m_activeSubmixes.begin();
|
return m_activeStudios.begin();
|
||||||
it->_destroy();
|
(*it)->_destroy();
|
||||||
return m_activeSubmixes.erase(it);
|
return m_activeStudios.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::_bringOutYourDead()
|
void Engine::_bringOutYourDead()
|
||||||
|
@ -286,59 +283,47 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
|
||||||
m_audioGroups.erase(search);
|
m_audioGroups.erase(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create new Submix (a.k.a 'Studio') within root mix engine */
|
/** Create new Studio within engine */
|
||||||
Submix* Engine::addSubmix(Submix* smx)
|
std::shared_ptr<Studio> Engine::addStudio(bool mainOut)
|
||||||
{
|
{
|
||||||
return &*_allocateSubmix(smx);
|
return *_allocateStudio(mainOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Submix>::iterator Engine::_removeSubmix(std::list<Submix>::iterator smx)
|
std::list<std::shared_ptr<Studio>>::iterator Engine::_removeStudio(std::list<std::shared_ptr<Studio>>::iterator smx)
|
||||||
{
|
{
|
||||||
/* Delete all voices bound to submix */
|
/* Delete all voices bound to studio */
|
||||||
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ; ++it)
|
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ; ++it)
|
||||||
{
|
{
|
||||||
Voice* vox = it->get();
|
Voice* vox = it->get();
|
||||||
Submix* vsmx = vox->getSubmix();
|
std::shared_ptr<Studio> vsmx = vox->getStudio();
|
||||||
if (vsmx == &*smx)
|
if (vsmx == *smx)
|
||||||
vox->kill();
|
vox->kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete all sequencers bound to submix */
|
/* Delete all sequencers bound to studio */
|
||||||
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ; ++it)
|
for (auto it = m_activeSequencers.begin() ; it != m_activeSequencers.end() ; ++it)
|
||||||
{
|
{
|
||||||
Sequencer* seq = it->get();
|
Sequencer* seq = it->get();
|
||||||
Submix* ssmx = seq->getSubmix();
|
std::shared_ptr<Studio> ssmx = seq->getStudio();
|
||||||
if (ssmx == &*smx)
|
if (ssmx == *smx)
|
||||||
seq->kill();
|
seq->kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete all submixes bound to submix */
|
/* Delete studio */
|
||||||
for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
|
return _destroyStudio(smx);
|
||||||
{
|
|
||||||
Submix* ssmx = it->getParentSubmix();
|
|
||||||
if (ssmx == &*smx)
|
|
||||||
{
|
|
||||||
it = _removeSubmix(it);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete submix */
|
|
||||||
return _destroySubmix(smx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove Submix and deallocate */
|
/** Remove Submix and deallocate */
|
||||||
void Engine::removeSubmix(Submix* smx)
|
void Engine::removeStudio(std::weak_ptr<Studio> smx)
|
||||||
{
|
{
|
||||||
if (!smx)
|
std::shared_ptr<Studio> sm = smx.lock();
|
||||||
|
if (sm == m_defaultStudio)
|
||||||
return;
|
return;
|
||||||
|
for (auto it = m_activeStudios.begin() ; it != m_activeStudios.end() ;)
|
||||||
for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
|
|
||||||
{
|
{
|
||||||
if (&*it == &*smx)
|
if (*it == sm)
|
||||||
{
|
{
|
||||||
it = _removeSubmix(it);
|
it = _removeStudio(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
|
@ -346,7 +331,7 @@ void Engine::removeSubmix(Submix* smx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups */
|
/** Start soundFX playing from loaded audio groups */
|
||||||
std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix* smx)
|
std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, std::weak_ptr<Studio> smx)
|
||||||
{
|
{
|
||||||
auto search = m_sfxLookup.find(sfxId);
|
auto search = m_sfxLookup.find(sfxId);
|
||||||
if (search == m_sfxLookup.end())
|
if (search == m_sfxLookup.end())
|
||||||
|
@ -375,7 +360,8 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix*
|
||||||
|
|
||||||
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
/** Start soundFX playing from loaded audio groups, attach to positional emitter */
|
||||||
std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
|
std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f& dir, float maxDist,
|
||||||
float falloff, int sfxId, float minVol, float maxVol, Submix* smx)
|
float falloff, int sfxId, float minVol, float maxVol,
|
||||||
|
std::weak_ptr<Studio> smx)
|
||||||
{
|
{
|
||||||
auto search = m_sfxLookup.find(sfxId);
|
auto search = m_sfxLookup.find(sfxId);
|
||||||
if (search == m_sfxLookup.end())
|
if (search == m_sfxLookup.end())
|
||||||
|
@ -413,7 +399,7 @@ std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f&
|
||||||
|
|
||||||
/** Start song playing from loaded audio groups */
|
/** Start song playing from loaded audio groups */
|
||||||
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId,
|
std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId,
|
||||||
const unsigned char* arrData, Submix* smx)
|
const unsigned char* arrData, std::weak_ptr<Studio> smx)
|
||||||
{
|
{
|
||||||
std::pair<AudioGroup*, const SongGroupIndex*> songGrp = _findSongGroup(groupId);
|
std::pair<AudioGroup*, const SongGroupIndex*> songGrp = _findSongGroup(groupId);
|
||||||
if (songGrp.second)
|
if (songGrp.second)
|
||||||
|
|
|
@ -47,36 +47,40 @@ void Sequencer::_bringOutYourDead()
|
||||||
void Sequencer::_destroy()
|
void Sequencer::_destroy()
|
||||||
{
|
{
|
||||||
Entity::_destroy();
|
Entity::_destroy();
|
||||||
if (m_submix)
|
if (m_studio)
|
||||||
{
|
{
|
||||||
m_engine.removeSubmix(m_submix);
|
m_engine.removeStudio(m_studio);
|
||||||
m_submix = nullptr;
|
m_studio.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::~Sequencer()
|
Sequencer::~Sequencer()
|
||||||
{
|
{
|
||||||
if (m_submix)
|
if (m_studio)
|
||||||
{
|
{
|
||||||
m_engine.removeSubmix(m_submix);
|
m_engine.removeStudio(m_studio);
|
||||||
m_submix = nullptr;
|
m_studio.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
const SongGroupIndex* songGroup, int setupId, Submix* smx)
|
const SongGroupIndex* songGroup, int setupId, std::weak_ptr<Studio> studio)
|
||||||
: Entity(engine, group, groupId), m_songGroup(songGroup)
|
: Entity(engine, group, groupId), m_songGroup(songGroup)
|
||||||
{
|
{
|
||||||
auto it = m_songGroup->m_midiSetups.find(setupId);
|
auto it = m_songGroup->m_midiSetups.find(setupId);
|
||||||
if (it != m_songGroup->m_midiSetups.cend())
|
if (it != m_songGroup->m_midiSetups.cend())
|
||||||
m_midiSetup = it->second->data();
|
m_midiSetup = it->second->data();
|
||||||
|
|
||||||
m_submix = m_engine.addSubmix(smx);
|
std::shared_ptr<Studio> st = studio.lock();
|
||||||
m_submix->makeReverbHi(0.2f, 0.3f, 1.f, 0.5f, 0.f, 0.f);
|
m_studio = m_engine.addStudio(st ? false : true);
|
||||||
|
if (st)
|
||||||
|
m_studio->addStudioSend(studio, 1.f, 0.f, 0.f);
|
||||||
|
m_studio->getAuxA().makeReverbHi(0.2f, 0.3f, 1.f, 0.5f, 0.f, 0.f);
|
||||||
|
m_studio->getAuxB().makeChorus(10, 5, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
Sequencer::Sequencer(Engine& engine, const AudioGroup& group, int groupId,
|
||||||
const SFXGroupIndex* sfxGroup, Submix* smx)
|
const SFXGroupIndex* sfxGroup, std::weak_ptr<Studio> studio)
|
||||||
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup)
|
: Entity(engine, group, groupId), m_sfxGroup(sfxGroup)
|
||||||
{
|
{
|
||||||
//m_submix = m_engine.addSubmix(smx);
|
//m_submix = m_engine.addSubmix(smx);
|
||||||
|
@ -217,7 +221,7 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
|
||||||
std::list<std::shared_ptr<Voice>>::iterator ret =
|
std::list<std::shared_ptr<Voice>>::iterator ret =
|
||||||
m_parent.m_engine._allocateVoice(m_parent.m_audioGroup,
|
m_parent.m_engine._allocateVoice(m_parent.m_audioGroup,
|
||||||
m_parent.m_groupId, 32000.0,
|
m_parent.m_groupId, 32000.0,
|
||||||
true, false, m_parent.m_submix);
|
true, false, m_parent.m_studio);
|
||||||
if (*ret)
|
if (*ret)
|
||||||
{
|
{
|
||||||
m_chanVoxs[note] = *ret;
|
m_chanVoxs[note] = *ret;
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include "amuse/Studio.hpp"
|
||||||
|
#include "amuse/Engine.hpp"
|
||||||
|
|
||||||
|
namespace amuse
|
||||||
|
{
|
||||||
|
|
||||||
|
void Studio::_destroy()
|
||||||
|
{
|
||||||
|
m_destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Studio::_bringOutYourDead()
|
||||||
|
{
|
||||||
|
for (auto it = m_studiosOut.begin() ; it != m_studiosOut.end() ;)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Studio> studio = it->m_targetStudio.lock();
|
||||||
|
if (!studio)
|
||||||
|
it = m_studiosOut.erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool Studio::_cyclicCheck(Studio* leaf)
|
||||||
|
{
|
||||||
|
for (auto it = m_studiosOut.begin() ; it != m_studiosOut.end() ;)
|
||||||
|
{
|
||||||
|
if (std::shared_ptr<Studio> studio = it->m_targetStudio.lock())
|
||||||
|
{
|
||||||
|
if (leaf == studio.get() || studio->_cyclicCheck(leaf))
|
||||||
|
return true;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
it = m_studiosOut.erase(it);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Studio::Studio(Engine& engine, bool mainOut)
|
||||||
|
: m_engine(engine), m_auxA(engine), m_auxB(engine)
|
||||||
|
{
|
||||||
|
if (mainOut)
|
||||||
|
addStudioSend(engine.getDefaultStudio(), 1.f, 1.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Studio::addStudioSend(std::weak_ptr<Studio> studio, float dry, float auxA, float auxB)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
/* Cyclic check */
|
||||||
|
assert(!_cyclicCheck(this));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_studiosOut.emplace_back(studio, dry, auxA, auxB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Studio::resetOutputSampleRate(double sampleRate)
|
||||||
|
{
|
||||||
|
m_auxA.resetOutputSampleRate(sampleRate);
|
||||||
|
m_auxB.resetOutputSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,8 +8,8 @@ void Submix::_destroy()
|
||||||
m_destroyed = true;
|
m_destroyed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Submix::Submix(Engine& engine, Submix* smx)
|
Submix::Submix(Engine& engine)
|
||||||
: m_root(engine), m_submix(smx)
|
: m_root(engine)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period)
|
EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period)
|
||||||
|
|
|
@ -27,14 +27,14 @@ Voice::~Voice()
|
||||||
//fprintf(stderr, "DEALLOC %d\n", m_vid);
|
//fprintf(stderr, "DEALLOC %d\n", m_vid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, Submix* smx)
|
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, std::weak_ptr<Studio> studio)
|
||||||
: Entity(engine, group, groupId), m_vid(vid), m_emitter(emitter), m_submix(smx)
|
: Entity(engine, group, groupId), m_vid(vid), m_emitter(emitter), m_studio(studio)
|
||||||
{
|
{
|
||||||
//fprintf(stderr, "ALLOC %d\n", m_vid);
|
//fprintf(stderr, "ALLOC %d\n", m_vid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter, Submix* smx)
|
Voice::Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter, std::weak_ptr<Studio> studio)
|
||||||
: Entity(engine, group, groupId, oid), m_vid(vid), m_emitter(emitter), m_submix(smx)
|
: Entity(engine, group, groupId, oid), m_vid(vid), m_emitter(emitter), m_studio(studio)
|
||||||
{
|
{
|
||||||
//fprintf(stderr, "ALLOC %d\n", m_vid);
|
//fprintf(stderr, "ALLOC %d\n", m_vid);
|
||||||
}
|
}
|
||||||
|
@ -174,13 +174,9 @@ std::unique_ptr<int8_t[]>& Voice::_ensureCtrlVals()
|
||||||
std::list<std::shared_ptr<Voice>>::iterator Voice::_allocateVoice(double sampleRate, bool dynamicPitch)
|
std::list<std::shared_ptr<Voice>>::iterator Voice::_allocateVoice(double sampleRate, bool dynamicPitch)
|
||||||
{
|
{
|
||||||
auto it = m_childVoices.emplace(m_childVoices.end(), new Voice(m_engine, m_audioGroup,
|
auto it = m_childVoices.emplace(m_childVoices.end(), new Voice(m_engine, m_audioGroup,
|
||||||
m_groupId, m_engine.m_nextVid++, m_emitter, m_submix));
|
m_groupId, m_engine.m_nextVid++, m_emitter, m_studio));
|
||||||
if (m_submix)
|
m_childVoices.back()->m_backendVoice =
|
||||||
m_childVoices.back()->m_backendVoice =
|
m_engine.getBackend().allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch);
|
||||||
m_submix->m_backendSubmix->allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch);
|
|
||||||
else
|
|
||||||
m_childVoices.back()->m_backendVoice =
|
|
||||||
m_engine.getBackend().allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch);
|
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -897,11 +893,12 @@ void Voice::_setPan(float pan)
|
||||||
coefs[7] = (totalPan >= 0.f) ? 1.f : (1.f + totalPan);
|
coefs[7] = (totalPan >= 0.f) ? 1.f : (1.f + totalPan);
|
||||||
coefs[7] *= 1.f - std::fabs(totalSpan);
|
coefs[7] *= 1.f - std::fabs(totalSpan);
|
||||||
|
|
||||||
m_backendVoice->setMatrixCoefficients(coefs, true);
|
m_backendVoice->setChannelLevels(nullptr, coefs, true);
|
||||||
|
|
||||||
|
float revCoefs[8];
|
||||||
for (int i=0 ; i<8 ; ++i)
|
for (int i=0 ; i<8 ; ++i)
|
||||||
coefs[i] *= m_curReverbVol;
|
revCoefs[i] = coefs[i] * m_curReverbVol;
|
||||||
m_backendVoice->setSubmixMatrixCoefficients(coefs, true);
|
m_backendVoice->setChannelLevels(m_studio->getAuxA().m_backendSubmix.get(), revCoefs, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::setPan(float pan)
|
void Voice::setPan(float pan)
|
||||||
|
|
Loading…
Reference in New Issue