Add info structures for holding effect parameters

This commit is contained in:
Jack Andersen 2017-01-22 21:21:50 -10:00
parent ecd990e94e
commit 2e7345f11d
10 changed files with 178 additions and 0 deletions

View File

@ -128,6 +128,7 @@ public:
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);
void unregister5MsCallback();
AudioChannelSet getAvailableSet(); AudioChannelSet getAvailableSet();
void pumpAndMixVoices(); void pumpAndMixVoices();
void setVolume(float vol); void setVolume(float vol);

View File

@ -12,6 +12,18 @@ class EffectChorusImp;
#define AMUSE_CHORUS_NUM_BLOCKS 3 #define AMUSE_CHORUS_NUM_BLOCKS 3
/** Parameters needed to create EffectChorus */
struct EffectChorusInfo
{
uint32_t baseDelay = 5; /**< [5, 15] minimum value (in ms) for computed delay */
uint32_t variation = 0; /**< [0, 5] time error (in ms) to set delay within */
uint32_t period = 500; /**< [500, 10000] time (in ms) of one delay-shift cycle */
EffectChorusInfo() = default;
EffectChorusInfo(uint32_t baseDelay, uint32_t variation, uint32_t period)
: baseDelay(baseDelay), variation(variation), period(period) {}
};
/** Mixes the audio back into itself after continuously-varying delay */ /** Mixes the audio back into itself after continuously-varying delay */
class EffectChorus class EffectChorus
{ {
@ -48,6 +60,13 @@ public:
x98_period = period; x98_period = period;
m_dirty = true; m_dirty = true;
} }
void updateParams(const EffectChorusInfo& info)
{
setBaseDelay(info.baseDelay);
setVariation(info.variation);
setPeriod(info.period);
}
}; };
/** Type-specific implementation of chorus effect */ /** Type-specific implementation of chorus effect */
@ -91,6 +110,9 @@ class EffectChorusImp : public EffectBase<T>, public EffectChorus
public: public:
~EffectChorusImp(); ~EffectChorusImp();
EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate); EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate);
EffectChorusImp(const EffectChorusInfo& info, double sampleRate)
: EffectChorusImp(info.baseDelay, info.variation, info.period, sampleRate) {}
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
}; };

View File

@ -2,6 +2,7 @@
#define __AMUSE_EFFECTDELAY_HPP__ #define __AMUSE_EFFECTDELAY_HPP__
#include "EffectBase.hpp" #include "EffectBase.hpp"
#include "IBackendVoice.hpp"
#include "Common.hpp" #include "Common.hpp"
#include <stdint.h> #include <stdint.h>
#include <memory> #include <memory>
@ -11,6 +12,38 @@ namespace amuse
template <typename T> template <typename T>
class EffectDelayImp; class EffectDelayImp;
/** Parameters needed to create EffectDelay */
struct EffectDelayInfo
{
uint32_t delay[8]; /**< [10, 5000] time in ms of each channel's delay */
uint32_t feedback[8] = {}; /**< [0, 100] percent to mix delayed signal with input signal */
uint32_t output[8] = {}; /**< [0, 100] total output percent */
static uint32_t lerp(uint32_t v0, uint32_t v1, float t) { return (1.f - t) * v0 + t * v1; }
static void Interp3To8(uint32_t arr[8], uint32_t L, uint32_t R, uint32_t S)
{
arr[int(AudioChannel::FrontLeft)] = L;
arr[int(AudioChannel::FrontRight)] = R;
arr[int(AudioChannel::RearLeft)] = lerp(L, S, 0.75f);
arr[int(AudioChannel::RearRight)] = lerp(R, S, 0.75f);
arr[int(AudioChannel::FrontCenter)] = lerp(L, R, 0.5f);
arr[int(AudioChannel::LFE)] = arr[int(AudioChannel::FrontCenter)];
arr[int(AudioChannel::SideLeft)] = lerp(L, S, 0.5f);
arr[int(AudioChannel::SideRight)] = lerp(R, S, 0.5f);
}
EffectDelayInfo() { std::fill_n(delay, 8, 10); }
EffectDelayInfo(uint32_t delayL, uint32_t delayR, uint32_t delayS,
uint32_t feedbackL, uint32_t feedbackR, uint32_t feedbackS,
uint32_t outputL, uint32_t outputR, uint32_t outputS)
{
Interp3To8(delay, delayL, delayR, delayS);
Interp3To8(feedback, feedbackL, feedbackR, feedbackS);
Interp3To8(output, outputL, outputR, outputS);
}
};
/** Mixes the audio back into itself after specified delay */ /** Mixes the audio back into itself after specified delay */
class EffectDelay class EffectDelay
{ {
@ -59,12 +92,24 @@ public:
x54_output[i] = output; x54_output[i] = output;
m_dirty = true; m_dirty = true;
} }
void setChanOutput(int chanIdx, uint32_t output) void setChanOutput(int chanIdx, uint32_t output)
{ {
output = clamp(0u, output, 100u); output = clamp(0u, output, 100u);
x54_output[chanIdx] = output; x54_output[chanIdx] = output;
m_dirty = true; m_dirty = true;
} }
void setParams(const EffectDelayInfo& info)
{
for (int i = 0; i < 8; ++i)
{
x3c_delay[i] = clamp(10u, info.delay[i], 5000u);
x48_feedback[i] = clamp(0u, info.feedback[i], 100u);
x54_output[i] = clamp(0u, info.output[i], 100u);
}
m_dirty = true;
}
}; };
/** Type-specific implementation of delay effect */ /** Type-specific implementation of delay effect */
@ -85,6 +130,8 @@ class EffectDelayImp : public EffectBase<T>, public EffectDelay
public: public:
EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate); EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate);
EffectDelayImp(const EffectDelayInfo& info, double sampleRate);
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
}; };

View File

@ -8,6 +8,35 @@
namespace amuse namespace amuse
{ {
/** Parameters needed to create EffectReverbStd */
struct EffectReverbStdInfo
{
float coloration = 0.f; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */
float mix = 0.f; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */
float time = 0.01f; /**< [0.01, 10.0] time in seconds for reflection decay */
float damping = 0.f; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
float preDelay = 0.f; /**< [0.0, 0.1] time in seconds before initial reflection heard */
EffectReverbStdInfo() = default;
EffectReverbStdInfo(float coloration, float mix, float time, float damping, float preDelay)
: coloration(coloration), mix(mix), time(time), damping(damping), preDelay(preDelay) {}
};
/** Parameters needed to create EffectReverbHi */
struct EffectReverbHiInfo
{
float coloration = 0.f; /**< [0.0, 1.0] influences filter coefficients to define surface characteristics of a room */
float mix = 0.f; /**< [0.0, 1.0] dry/wet mix factor of reverb effect */
float time = 0.01f; /**< [0.01, 10.0] time in seconds for reflection decay */
float damping = 0.f; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
float preDelay = 0.f; /**< [0.0, 0.1] time in seconds before initial reflection heard */
float crosstalk = 0.f; /**< [0.0, 1.0] factor defining how much reflections are allowed to bleed to other channels */
EffectReverbHiInfo() = default;
EffectReverbHiInfo(float coloration, float mix, float time, float damping, float preDelay, float crosstalk)
: coloration(coloration), mix(mix), time(time), damping(damping), preDelay(preDelay), crosstalk(crosstalk) {}
};
/** Delay state for one 'tap' of the reverb effect */ /** Delay state for one 'tap' of the reverb effect */
struct ReverbDelayLine struct ReverbDelayLine
{ {
@ -78,6 +107,15 @@ public:
x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f); x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f);
m_dirty = true; m_dirty = true;
} }
void setParams(const EffectReverbStdInfo& info)
{
setColoration(info.coloration);
setMix(info.mix);
setTime(info.time);
setDamping(info.damping);
setPreDelay(info.preDelay);
}
}; };
/** Reverb effect with configurable reflection filtering, adds per-channel low-pass and crosstalk */ /** Reverb effect with configurable reflection filtering, adds per-channel low-pass and crosstalk */
@ -98,6 +136,16 @@ public:
x1dc_crosstalk = clamp(0.f, crosstalk, 1.f); x1dc_crosstalk = clamp(0.f, crosstalk, 1.f);
m_dirty = true; m_dirty = true;
} }
void setParams(const EffectReverbHiInfo& info)
{
setColoration(info.coloration);
setMix(info.mix);
setTime(info.time);
setDamping(info.damping);
setPreDelay(info.preDelay);
setCrosstalk(info.crosstalk);
}
}; };
/** Standard-quality 2-stage reverb */ /** Standard-quality 2-stage reverb */
@ -121,6 +169,9 @@ class EffectReverbStdImp : public EffectBase<T>, public EffectReverbStd
public: public:
EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay, double sampleRate); EffectReverbStdImp(float coloration, float mix, float time, float damping, float preDelay, double sampleRate);
EffectReverbStdImp(const EffectReverbStdInfo& info, double sampleRate)
: EffectReverbStdImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, sampleRate) {}
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
}; };
@ -151,6 +202,9 @@ class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi
public: public:
EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk, EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk,
double sampleRate); double sampleRate);
EffectReverbHiImp(const EffectReverbHiInfo& info, double sampleRate)
: EffectReverbHiImp(info.coloration, info.mix, info.time, info.damping, info.preDelay, info.crosstalk, sampleRate) {}
void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap); void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); } void resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
}; };

View File

@ -61,6 +61,9 @@ public:
/** Amuse may request callbacks 200-updates-per-second virtually */ /** Amuse may request callbacks 200-updates-per-second virtually */
virtual void register5MsCallback(std::function<void(double dt)>&& callback) = 0; virtual void register5MsCallback(std::function<void(double dt)>&& callback) = 0;
/** This is important to ensure orderly cleanup */
virtual void unregister5MsCallback() = 0;
}; };
} }

View File

@ -60,16 +60,28 @@ public:
/** Add new chorus effect to effect stack and assume ownership */ /** Add new chorus effect to effect stack and assume ownership */
EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period); EffectChorus& makeChorus(uint32_t baseDelay, uint32_t variation, uint32_t period);
/** Add new chorus effect to effect stack and assume ownership */
EffectChorus& makeChorus(const EffectChorusInfo& info);
/** Add new delay effect to effect stack and assume ownership */ /** Add new delay effect to effect stack and assume ownership */
EffectDelay& makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput); EffectDelay& makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput);
/** Add new delay effect to effect stack and assume ownership */
EffectDelay& makeDelay(const EffectDelayInfo& info);
/** Add new standard-quality reverb effect to effect stack and assume ownership */ /** Add new standard-quality reverb effect to effect stack and assume ownership */
EffectReverbStd& makeReverbStd(float coloration, float mix, float time, float damping, float preDelay); EffectReverbStd& makeReverbStd(float coloration, float mix, float time, float damping, float preDelay);
/** Add new standard-quality reverb effect to effect stack and assume ownership */
EffectReverbStd& makeReverbStd(const EffectReverbStdInfo& info);
/** Add new high-quality reverb effect to effect stack and assume ownership */ /** Add new high-quality reverb effect to effect stack and assume ownership */
EffectReverbHi& makeReverbHi(float coloration, float mix, float time, float damping, float preDelay, EffectReverbHi& makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
float crosstalk); float crosstalk);
/** Add new high-quality reverb effect to effect stack and assume ownership */
EffectReverbHi& makeReverbHi(const EffectReverbHiInfo& info);
/** Remove and deallocate all effects from effect stack */ /** Remove and deallocate all effects from effect stack */
void clearEffects() { m_effectStack.clear(); } void clearEffects() { m_effectStack.clear(); }

View File

@ -285,6 +285,11 @@ void BooBackendVoiceAllocator::register5MsCallback(std::function<void(double)>&&
m_booEngine.register5MsCallback(std::move(callback)); m_booEngine.register5MsCallback(std::move(callback));
} }
void BooBackendVoiceAllocator::unregister5MsCallback()
{
m_booEngine.unregister5MsCallback();
}
AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); } AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); }
void BooBackendVoiceAllocator::pumpAndMixVoices() { m_booEngine.pumpAndMixVoices(); } void BooBackendVoiceAllocator::pumpAndMixVoices() { m_booEngine.pumpAndMixVoices(); }

View File

@ -24,6 +24,19 @@ EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uin
_setup(sampleRate); _setup(sampleRate);
} }
template <typename T>
EffectDelayImp<T>::EffectDelayImp(const EffectDelayInfo& info, double sampleRate)
{
for (int i = 0; i < 8; ++i)
{
x3c_delay[i] = clamp(10u, info.delay[i], 5000u);
x48_feedback[i] = clamp(0u, info.feedback[i], 100u);
x54_output[i] = clamp(0u, info.output[i], 100u);
}
_setup(sampleRate);
}
template <typename T> template <typename T>
void EffectDelayImp<T>::_setup(double sampleRate) void EffectDelayImp<T>::_setup(double sampleRate)
{ {

View File

@ -15,6 +15,7 @@ static const float FullLevels[8] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
Engine::~Engine() Engine::~Engine()
{ {
m_backend.unregister5MsCallback();
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();

View File

@ -10,22 +10,42 @@ EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_
return makeEffect<EffectChorus>(baseDelay, variation, period); return makeEffect<EffectChorus>(baseDelay, variation, period);
} }
EffectChorus& Submix::makeChorus(const EffectChorusInfo& info)
{
return makeEffect<EffectChorus>(info);
}
EffectDelay& Submix::makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput) EffectDelay& Submix::makeDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput)
{ {
return makeEffect<EffectDelay>(initDelay, initFeedback, initOutput); return makeEffect<EffectDelay>(initDelay, initFeedback, initOutput);
} }
EffectDelay& Submix::makeDelay(const EffectDelayInfo& info)
{
return makeEffect<EffectDelay>(info);
}
EffectReverbStd& Submix::makeReverbStd(float coloration, float mix, float time, float damping, float preDelay) EffectReverbStd& Submix::makeReverbStd(float coloration, float mix, float time, float damping, float preDelay)
{ {
return makeEffect<EffectReverbStd>(coloration, mix, time, damping, preDelay); return makeEffect<EffectReverbStd>(coloration, mix, time, damping, preDelay);
} }
EffectReverbStd& Submix::makeReverbStd(const EffectReverbStdInfo& info)
{
return makeEffect<EffectReverbStd>(info);
}
EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, float damping, float preDelay, EffectReverbHi& Submix::makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
float crosstalk) float crosstalk)
{ {
return makeEffect<EffectReverbHi>(coloration, mix, time, damping, preDelay, crosstalk); return makeEffect<EffectReverbHi>(coloration, mix, time, damping, preDelay, crosstalk);
} }
EffectReverbHi& Submix::makeReverbHi(const EffectReverbHiInfo& info)
{
return makeEffect<EffectReverbHi>(info);
}
void Submix::applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const void Submix::applyEffect(int16_t* audio, size_t frameCount, const ChannelMap& chanMap) const
{ {
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack) for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)