Work on Chorus effect

This commit is contained in:
Jack Andersen 2016-05-07 19:19:27 -10:00
parent 3cce975977
commit 7aad87ea8c
9 changed files with 193 additions and 12 deletions

View File

@ -42,9 +42,12 @@ class BooBackendSubmix : public IBackendSubmix
{ {
BooBackendSubmix& m_parent; BooBackendSubmix& m_parent;
bool canApplyEffect() const; bool canApplyEffect() const;
void applyEffect(int16_t* audio, const boo::ChannelMap& chanMap, double sampleRate) const; void applyEffect(int16_t* audio, size_t frameCount,
void applyEffect(int32_t* audio, const boo::ChannelMap& chanMap, double sampleRate) const; const boo::ChannelMap& chanMap, double sampleRate) const;
void applyEffect(float* audio, const boo::ChannelMap& chanMap, double sampleRate) const; void applyEffect(int32_t* audio, size_t frameCount,
const boo::ChannelMap& chanMap, double sampleRate) const;
void applyEffect(float* audio, size_t frameCount,
const boo::ChannelMap& chanMap, double sampleRate) const;
SubmixCallback(BooBackendSubmix& parent) : m_parent(parent) {} SubmixCallback(BooBackendSubmix& parent) : m_parent(parent) {}
} m_cb; } m_cb;
std::unique_ptr<boo::IAudioSubmix> m_booSubmix; std::unique_ptr<boo::IAudioSubmix> m_booSubmix;

View File

@ -1,9 +1,14 @@
#ifndef __AMUSE_COMMON_HPP__ #ifndef __AMUSE_COMMON_HPP__
#define __AMUSE_COMMON_HPP__ #define __AMUSE_COMMON_HPP__
#include <algorithm>
namespace amuse namespace amuse
{ {
template <typename T>
static inline T clamp(T a, T val, T b) {return std::max<T>(a, std::min<T>(b, val));}
#ifndef M_PIF #ifndef M_PIF
#define M_PIF 3.14159265358979323846f /* pi */ #define M_PIF 3.14159265358979323846f /* pi */
#endif #endif

View File

@ -1,11 +1,22 @@
#ifndef __AMUSE_EFFECTBASE_HPP__ #ifndef __AMUSE_EFFECTBASE_HPP__
#define __AMUSE_EFFECTBASE_HPP__ #define __AMUSE_EFFECTBASE_HPP__
#include <stdint.h>
#include <stdlib.h>
namespace amuse namespace amuse
{ {
class ChannelMap;
class EffectBase class EffectBase
{ {
public:
virtual void applyEffect(int16_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate)=0;
virtual void applyEffect(int32_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate)=0;
virtual void applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate)=0;
}; };
} }

View File

@ -7,12 +7,66 @@
namespace amuse namespace amuse
{ {
#define AMUSE_CHORUS_NUM_BLOCKS 3
/** Mixes the audio back into itself after continuously-varying delay */ /** Mixes the audio back into itself after continuously-varying delay */
class EffectChorus : public EffectBase class EffectChorus : public EffectBase
{ {
uint32_t m_baseDelay; /**< [5, 15] minimum value (in ms) for computed delay */ int32_t* x0_lastLeft[AMUSE_CHORUS_NUM_BLOCKS];
uint32_t m_variation; /**< [0, 5] time error (in ms) to set delay within */ int32_t* xc_lastRight[AMUSE_CHORUS_NUM_BLOCKS];
uint32_t m_period; /**< [500, 10000] time (in ms) of one delay-shift cycle */ int32_t* x18_lastRearLeft[AMUSE_CHORUS_NUM_BLOCKS];
int32_t* x18_lastRearRight[AMUSE_CHORUS_NUM_BLOCKS];
int32_t* x18_lastCenter[AMUSE_CHORUS_NUM_BLOCKS];
int32_t* x18_lastLFE[AMUSE_CHORUS_NUM_BLOCKS];
int32_t* x18_lastSideLeft[AMUSE_CHORUS_NUM_BLOCKS];
int32_t* x18_lastSideRight[AMUSE_CHORUS_NUM_BLOCKS];
uint8_t x24_currentLast = 1;
int32_t x28_oldLeft[4] = {};
int32_t x38_oldRight[4] = {};
int32_t x48_oldRearLeft[4] = {};
int32_t x48_oldRearRight[4] = {};
int32_t x48_oldCenter[4] = {};
int32_t x48_oldLFE[4] = {};
int32_t x48_oldSideLeft[4] = {};
int32_t x48_oldSideRight[4] = {};
uint32_t x58_currentPosLo = 0;
uint32_t x5c_currentPosHi = 0;
int32_t x60_pitchOffset;
uint32_t x64_pitchOffsetPeriodCount;
uint32_t x68_pitchOffsetPeriod;
struct SrcInfo
{
int32_t* x6c_dest;
int32_t* x70_smpBase;
int32_t* x74_old;
uint32_t x78_posLo;
uint32_t x7c_posHi;
uint32_t x80_pitchLo;
uint32_t x84_pitchHi;
uint32_t x88_trigger;
uint32_t x8c_target = 0;
} x6c_src;
uint32_t x90_baseDelay; /**< [5, 15] minimum value (in ms) for computed delay */
uint32_t x94_variation; /**< [0, 5] time error (in ms) to set delay within */
uint32_t x98_period; /**< [500, 10000] time (in ms) of one delay-shift cycle */
double m_sampleRate;
uint32_t m_blockSamples;
public:
~EffectChorus();
EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate);
void applyEffect(int16_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(int32_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
}; };
} }

View File

@ -13,6 +13,14 @@ class EffectDelay : public EffectBase
uint32_t m_delay[8]; /**< [10, 5000] time in ms of each channel's delay */ uint32_t m_delay[8]; /**< [10, 5000] time in ms of each channel's delay */
uint32_t m_feedback[8]; /**< [0, 100] percent to mix delayed signal with input signal */ uint32_t m_feedback[8]; /**< [0, 100] percent to mix delayed signal with input signal */
uint32_t m_output[8]; /**< [0, 100] total output percent */ uint32_t m_output[8]; /**< [0, 100] total output percent */
public:
EffectDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput);
void applyEffect(int16_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(int32_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
}; };
} }

View File

@ -15,6 +15,15 @@ class EffectReverbHi : public EffectBase
float m_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */ float m_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
float m_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */ float m_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */
float m_crosstalk; /**< [0.0, 100.0] factor defining how much reflections are allowed to bleed to other channels */ float m_crosstalk; /**< [0.0, 100.0] factor defining how much reflections are allowed to bleed to other channels */
public:
EffectReverbHi(float coloration, float mix, float time,
float damping, float preDelay, float crosstalk);
void applyEffect(int16_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(int32_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
}; };
} }

View File

@ -14,6 +14,15 @@ class EffectReverbStd : public EffectBase
float m_time; /**< [0.01, 10.0] time in seconds for reflection decay */ float m_time; /**< [0.01, 10.0] time in seconds for reflection decay */
float m_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */ float m_damping; /**< [0.0, 1.0] damping factor influencing low-pass filter of reflections */
float m_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */ float m_preDelay; /**< [0.0, 0.1] time in seconds before initial reflection heard */
public:
EffectReverbStd(float coloration, float mix, float time,
float damping, float preDelay);
void applyEffect(int16_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(int32_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
void applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate);
}; };
} }

View File

@ -48,20 +48,20 @@ bool BooBackendSubmix::SubmixCallback::canApplyEffect() const
return m_parent.m_clientSmx.canApplyEffect(); return m_parent.m_clientSmx.canApplyEffect();
} }
void BooBackendSubmix::SubmixCallback::applyEffect(int16_t* audio, const boo::ChannelMap& chanMap, void BooBackendSubmix::SubmixCallback::applyEffect(int16_t* audio, size_t frameCount,
double sampleRate) const const boo::ChannelMap& chanMap, double sampleRate) const
{ {
return m_parent.m_clientSmx.applyEffect(audio, reinterpret_cast<const ChannelMap&>(chanMap), sampleRate); return m_parent.m_clientSmx.applyEffect(audio, reinterpret_cast<const ChannelMap&>(chanMap), sampleRate);
} }
void BooBackendSubmix::SubmixCallback::applyEffect(int32_t* audio, const boo::ChannelMap& chanMap, void BooBackendSubmix::SubmixCallback::applyEffect(int32_t* audio, size_t frameCount,
double sampleRate) const const boo::ChannelMap& chanMap, double sampleRate) const
{ {
return m_parent.m_clientSmx.applyEffect(audio, reinterpret_cast<const ChannelMap&>(chanMap), sampleRate); return m_parent.m_clientSmx.applyEffect(audio, reinterpret_cast<const ChannelMap&>(chanMap), sampleRate);
} }
void BooBackendSubmix::SubmixCallback::applyEffect(float* audio, const boo::ChannelMap& chanMap, void BooBackendSubmix::SubmixCallback::applyEffect(float* audio, size_t frameCount,
double sampleRate) const const boo::ChannelMap& chanMap, double sampleRate) const
{ {
return m_parent.m_clientSmx.applyEffect(audio, reinterpret_cast<const ChannelMap&>(chanMap), sampleRate); return m_parent.m_clientSmx.applyEffect(audio, reinterpret_cast<const ChannelMap&>(chanMap), sampleRate);
} }

View File

@ -0,0 +1,82 @@
#include "amuse/EffectChorus.hpp"
#include "amuse/Common.hpp"
#include <string.h>
namespace amuse
{
EffectChorus::EffectChorus(uint32_t baseDelay, uint32_t variation,
uint32_t period, double sampleRate)
: x90_baseDelay(clamp(5u, baseDelay, 15u)),
x94_variation(clamp(0u, variation, 5u)),
x98_period(clamp(500u, period, 10000u)),
m_sampleRate(sampleRate),
m_blockSamples(sampleRate * 160.0 / 32000.0)
{
int32_t* buf = new int32_t[m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8];
memset(buf, 0, m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8 * sizeof(int32_t));
size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
x0_lastLeft[0] = buf;
x0_lastLeft[1] = x0_lastLeft[0] + m_blockSamples;
x0_lastLeft[2] = x0_lastLeft[0] + m_blockSamples * 2;
xc_lastRight[0] = buf + chanPitch;
xc_lastRight[1] = xc_lastRight[0] + m_blockSamples;
xc_lastRight[2] = xc_lastRight[0] + m_blockSamples * 2;
x18_lastRearLeft[0] = buf + chanPitch * 2;
x18_lastRearLeft[1] = x18_lastRearLeft[0] + m_blockSamples;
x18_lastRearLeft[2] = x18_lastRearLeft[0] + m_blockSamples * 2;
x18_lastRearRight[0] = buf + chanPitch * 3;
x18_lastRearRight[1] = x18_lastRearRight[0] + m_blockSamples;
x18_lastRearRight[2] = x18_lastRearRight[0] + m_blockSamples * 2;
x18_lastCenter[0] = buf + chanPitch * 4;
x18_lastCenter[1] = x18_lastCenter[0] + m_blockSamples;
x18_lastCenter[2] = x18_lastCenter[0] + m_blockSamples * 2;
x18_lastLFE[0] = buf + chanPitch * 5;
x18_lastLFE[1] = x18_lastLFE[0] + m_blockSamples;
x18_lastLFE[2] = x18_lastLFE[0] + m_blockSamples * 2;
x18_lastSideLeft[0] = buf + chanPitch * 6;
x18_lastSideLeft[1] = x18_lastSideLeft[0] + m_blockSamples;
x18_lastSideLeft[2] = x18_lastSideLeft[0] + m_blockSamples * 2;
x18_lastSideRight[0] = buf + chanPitch * 7;
x18_lastSideRight[1] = x18_lastSideRight[0] + m_blockSamples;
x18_lastSideRight[2] = x18_lastSideRight[0] + m_blockSamples * 2;
x6c_src.x88_trigger = chanPitch;
x5c_currentPosHi = m_blockSamples * 2 - ((x90_baseDelay - 5) * m_sampleRate / 1000.f);
uint32_t temp = (x5c_currentPosHi + (x24_currentLast - 1) * m_blockSamples);
x5c_currentPosHi = temp - ((temp * 8 / 15) >> 8) * chanPitch;
x68_pitchOffsetPeriod = (x98_period * 2 / 10 + 1) & ~1;
x60_pitchOffset = x94_variation * 2048 / x68_pitchOffsetPeriod;
}
EffectChorus::~EffectChorus()
{
delete[] x0_lastLeft[0];
}
void EffectChorus::applyEffect(int16_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate)
{
}
void EffectChorus::applyEffect(int32_t* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate)
{
}
void EffectChorus::applyEffect(float* audio, size_t frameCount,
const ChannelMap& chanMap, double sampleRate)
{
}
}