Skip to content

Commit

Permalink
Add info structures for holding effect parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
jackoalan committed Jan 23, 2017
1 parent ecd990e commit 2e7345f
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/amuse/BooBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class BooBackendVoiceAllocator : public IBackendVoiceAllocator
std::vector<std::pair<std::string, std::string>> enumerateMIDIDevices();
std::unique_ptr<IMIDIReader> allocateMIDIReader(Engine& engine, const char* name = nullptr);
void register5MsCallback(std::function<void(double)>&& callback);
void unregister5MsCallback();
AudioChannelSet getAvailableSet();
void pumpAndMixVoices();
void setVolume(float vol);
Expand Down
22 changes: 22 additions & 0 deletions include/amuse/EffectChorus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ class EffectChorusImp;

#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 */
class EffectChorus
{
Expand Down Expand Up @@ -48,6 +60,13 @@ class EffectChorus
x98_period = period;
m_dirty = true;
}

void updateParams(const EffectChorusInfo& info)
{
setBaseDelay(info.baseDelay);
setVariation(info.variation);
setPeriod(info.period);
}
};

/** Type-specific implementation of chorus effect */
Expand Down Expand Up @@ -91,6 +110,9 @@ class EffectChorusImp : public EffectBase<T>, public EffectChorus
public:
~EffectChorusImp();
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 resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
Expand Down
47 changes: 47 additions & 0 deletions include/amuse/EffectDelay.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define __AMUSE_EFFECTDELAY_HPP__

#include "EffectBase.hpp"
#include "IBackendVoice.hpp"
#include "Common.hpp"
#include <stdint.h>
#include <memory>
Expand All @@ -11,6 +12,38 @@ namespace amuse
template <typename T>
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 */
class EffectDelay
{
Expand Down Expand Up @@ -59,12 +92,24 @@ class EffectDelay
x54_output[i] = output;
m_dirty = true;
}

void setChanOutput(int chanIdx, uint32_t output)
{
output = clamp(0u, output, 100u);
x54_output[chanIdx] = output;
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 */
Expand All @@ -85,6 +130,8 @@ class EffectDelayImp : public EffectBase<T>, public EffectDelay

public:
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 resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
Expand Down
54 changes: 54 additions & 0 deletions include/amuse/EffectReverb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,35 @@
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 */
struct ReverbDelayLine
{
Expand Down Expand Up @@ -78,6 +107,15 @@ class EffectReverbStd
x150_x1d8_preDelay = clamp(0.f, preDelay, 0.1f);
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 */
Expand All @@ -98,6 +136,16 @@ class EffectReverbHi : public EffectReverbStd
x1dc_crosstalk = clamp(0.f, crosstalk, 1.f);
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 */
Expand All @@ -121,6 +169,9 @@ class EffectReverbStdImp : public EffectBase<T>, public EffectReverbStd

public:
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 resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
Expand Down Expand Up @@ -151,6 +202,9 @@ class EffectReverbHiImp : public EffectBase<T>, public EffectReverbHi
public:
EffectReverbHiImp(float coloration, float mix, float time, float damping, float preDelay, float crosstalk,
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 resetOutputSampleRate(double sampleRate) { _setup(sampleRate); }
};
Expand Down
3 changes: 3 additions & 0 deletions include/amuse/IBackendVoiceAllocator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class IBackendVoiceAllocator

/** Amuse may request callbacks 200-updates-per-second virtually */
virtual void register5MsCallback(std::function<void(double dt)>&& callback) = 0;

/** This is important to ensure orderly cleanup */
virtual void unregister5MsCallback() = 0;
};
}

Expand Down
12 changes: 12 additions & 0 deletions include/amuse/Submix.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,28 @@ class Submix
/** Add new chorus effect to effect stack and assume ownership */
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 */
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 */
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 */
EffectReverbHi& makeReverbHi(float coloration, float mix, float time, float damping, float preDelay,
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 */
void clearEffects() { m_effectStack.clear(); }

Expand Down
5 changes: 5 additions & 0 deletions lib/BooBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ void BooBackendVoiceAllocator::register5MsCallback(std::function<void(double)>&&
m_booEngine.register5MsCallback(std::move(callback));
}

void BooBackendVoiceAllocator::unregister5MsCallback()
{
m_booEngine.unregister5MsCallback();
}

AudioChannelSet BooBackendVoiceAllocator::getAvailableSet() { return AudioChannelSet(m_booEngine.getAvailableSet()); }

void BooBackendVoiceAllocator::pumpAndMixVoices() { m_booEngine.pumpAndMixVoices(); }
Expand Down
13 changes: 13 additions & 0 deletions lib/EffectDelay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ EffectDelayImp<T>::EffectDelayImp(uint32_t initDelay, uint32_t initFeedback, uin
_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>
void EffectDelayImp<T>::_setup(double sampleRate)
{
Expand Down
1 change: 1 addition & 0 deletions lib/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
m_backend.unregister5MsCallback();
for (std::shared_ptr<Sequencer>& seq : m_activeSequencers)
if (!seq->m_destroyed)
seq->_destroy();
Expand Down
20 changes: 20 additions & 0 deletions lib/Submix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,42 @@ EffectChorus& Submix::makeChorus(uint32_t baseDelay, uint32_t variation, uint32_
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)
{
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)
{
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,
float 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
{
for (const std::unique_ptr<EffectBaseTypeless>& effect : m_effectStack)
Expand Down

0 comments on commit 2e7345f

Please sign in to comment.