Implement EffectDelay

This commit is contained in:
Jack Andersen 2016-05-08 16:36:07 -10:00
parent 02d6478ce3
commit 4353113649
5 changed files with 193 additions and 115 deletions

View File

@ -12,8 +12,7 @@ template <typename T>
class EffectBase class EffectBase
{ {
public: public:
virtual void applyEffect(T* audio, size_t frameCount, virtual void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap)=0;
const ChannelMap& chanMap, double sampleRate)=0;
}; };
} }

View File

@ -59,7 +59,7 @@ class EffectChorus : public EffectBase<T>
uint32_t x94_variation; /**< [0, 5] time error (in ms) to set delay within */ 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 */ uint32_t x98_period; /**< [500, 10000] time (in ms) of one delay-shift cycle */
double m_sampsPerMs; uint32_t m_sampsPerMs;
uint32_t m_blockSamples; uint32_t m_blockSamples;
bool m_dirty = true; bool m_dirty = true;
@ -68,8 +68,7 @@ class EffectChorus : public EffectBase<T>
public: public:
~EffectChorus(); ~EffectChorus();
EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate); EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate);
void applyEffect(T* audio, size_t frameCount, void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
const ChannelMap& chanMap, double sampleRate);
}; };
} }

View File

@ -3,24 +3,33 @@
#include "EffectBase.hpp" #include "EffectBase.hpp"
#include <stdint.h> #include <stdint.h>
#include <memory>
namespace amuse namespace amuse
{ {
/** Mixes the audio back into itself after specified delay */ /** Mixes the audio back into itself after specified delay */
class EffectDelay : public EffectBase template <typename T>
class EffectDelay : public EffectBase<T>
{ {
uint32_t m_delay[8]; /**< [10, 5000] time in ms of each channel's delay */ uint32_t x0_currentSize[8];
uint32_t m_feedback[8]; /**< [0, 100] percent to mix delayed signal with input signal */ uint32_t xc_currentPos[8];
uint32_t m_output[8]; /**< [0, 100] total output percent */ uint32_t x18_currentFeedback[8];
uint32_t x24_currentOutput[8];
std::unique_ptr<T[]> x30_chanLines[8];
uint32_t x3c_delay[8]; /**< [10, 5000] time in ms of each channel's delay */
uint32_t x48_feedback[8]; /**< [0, 100] percent to mix delayed signal with input signal */
uint32_t x54_output[8]; /**< [0, 100] total output percent */
uint32_t m_sampsPerMs;
uint32_t m_blockSamples;
bool m_dirty = true;
void _update();
public: public:
EffectDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput); EffectDelay(uint32_t initDelay, uint32_t initFeedback, uint32_t initOutput, double sampleRate);
void applyEffect(int16_t* audio, size_t frameCount, void applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap);
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

@ -145,7 +145,7 @@ EffectChorus<T>::EffectChorus(uint32_t baseDelay, uint32_t variation,
x94_variation(clamp(0u, variation, 5u)), x94_variation(clamp(0u, variation, 5u)),
x98_period(clamp(500u, period, 10000u)), x98_period(clamp(500u, period, 10000u)),
m_sampsPerMs(sampleRate / 1000.0), m_sampsPerMs(sampleRate / 1000.0),
m_blockSamples(sampleRate * 160.0 / 32000.0) m_blockSamples(m_sampsPerMs * 160 / 32)
{ {
T* buf = new T[m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8]; T* buf = new T[m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8];
memset(buf, 0, m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8 * sizeof(T)); memset(buf, 0, m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS * 8 * sizeof(T));
@ -303,12 +303,14 @@ void EffectChorus<T>::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount)
} }
template <typename T> template <typename T>
void EffectChorus<T>::applyEffect(T* audio, size_t frameCount, void EffectChorus<T>::applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap)
const ChannelMap& chanMap, double sampleRate)
{ {
if (m_dirty) if (m_dirty)
_update(); _update();
size_t remFrames = frameCount;
for (size_t f=0 ; f<frameCount ;)
{
uint8_t next = x24_currentLast + 1; uint8_t next = x24_currentLast + 1;
uint8_t buf = next % 3; uint8_t buf = next % 3;
T* leftBuf = x0_lastLeft[buf]; T* leftBuf = x0_lastLeft[buf];
@ -321,7 +323,7 @@ void EffectChorus<T>::applyEffect(T* audio, size_t frameCount,
T* sideRightBuf = x18_lastSideRight[buf]; T* sideRightBuf = x18_lastSideRight[buf];
T* inBuf = audio; T* inBuf = audio;
for (size_t f=0 ; f<frameCount && f<m_blockSamples ; ++f) for (size_t s=0 ; f<frameCount && s<m_blockSamples ; ++s, ++f)
{ {
for (size_t c=0 ; c<chanMap.m_channelCount ; ++c) for (size_t c=0 ; c<chanMap.m_channelCount ; ++c)
{ {
@ -369,6 +371,7 @@ void EffectChorus<T>::applyEffect(T* audio, size_t frameCount,
} }
T* outBuf = audio; T* outBuf = audio;
size_t bs = std::min(remFrames, size_t(m_blockSamples));
for (size_t c=0 ; c<chanMap.m_channelCount ; ++c) for (size_t c=0 ; c<chanMap.m_channelCount ; ++c)
{ {
x6c_src.x7c_posHi = x5c_currentPosHi; x6c_src.x7c_posHi = x5c_currentPosHi;
@ -415,21 +418,25 @@ void EffectChorus<T>::applyEffect(T* audio, size_t frameCount,
switch (x6c_src.x84_pitchHi) switch (x6c_src.x84_pitchHi)
{ {
case 0: case 0:
x6c_src.doSrc1(m_blockSamples, chanMap.m_channelCount); x6c_src.doSrc1(bs, chanMap.m_channelCount);
break; break;
case 1: case 1:
x6c_src.doSrc2(m_blockSamples, chanMap.m_channelCount); x6c_src.doSrc2(bs, chanMap.m_channelCount);
break; break;
default: break; default: break;
} }
} }
audio = outBuf;
remFrames -= bs;
size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS; size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
size_t fifteenSamps = 15 * m_sampsPerMs; size_t fifteenSamps = 15 * m_sampsPerMs;
x5c_currentPosHi = x6c_src.x7c_posHi % (chanPitch / fifteenSamps * fifteenSamps); x5c_currentPosHi = x6c_src.x7c_posHi % (chanPitch / fifteenSamps * fifteenSamps);
x58_currentPosLo = x6c_src.x78_posLo; x58_currentPosLo = x6c_src.x78_posLo;
x24_currentLast = buf; x24_currentLast = buf;
}
} }
template class EffectChorus<int16_t>; template class EffectChorus<int16_t>;

View File

@ -0,0 +1,64 @@
#include "amuse/EffectDelay.hpp"
#include "amuse/Common.hpp"
#include "amuse/IBackendVoice.hpp"
#include <string.h>
namespace amuse
{
template <typename T>
EffectDelay<T>::EffectDelay(uint32_t initDelay, uint32_t initFeedback,
uint32_t initOutput, double sampleRate)
: m_sampsPerMs(sampleRate / 1000.0),
m_blockSamples(m_sampsPerMs * 160 / 32)
{
initDelay = clamp(10u, initDelay, 5000u);
initFeedback = clamp(0u, initFeedback, 100u);
initOutput = clamp(0u, initOutput, 100u);
for (int i=0 ; i<8 ; ++i)
{
x3c_delay[i] = initDelay;
x48_feedback[i] = initFeedback;
x54_output[i] = initOutput;
}
_update();
}
template <typename T>
void EffectDelay<T>::_update()
{
for (int i=0 ; i<8 ; ++i)
{
x0_currentSize[i] = ((x3c_delay[i] - 5) * m_sampsPerMs + 159) / 160;
xc_currentPos[i] = 0;
x18_currentFeedback[i] = x48_feedback[i] * 128 / 100;
x24_currentOutput[i] = x54_output[i] * 128 / 100;
x30_chanLines[i].reset(new T[m_blockSamples * x0_currentSize[i]]);
memset(x30_chanLines[i], 0, m_blockSamples * x0_currentSize[i] * sizeof(T));
}
m_dirty = false;
}
template <typename T>
void EffectDelay<T>::applyEffect(T* audio, size_t frameCount, const ChannelMap& chanMap)
{
for (size_t f=0 ; f<frameCount ;)
{
for (int c=0 ; c<chanMap.m_channelCount ; ++c)
{
for (int i=0 ; i<m_blockSamples && f<frameCount ; ++i, ++f)
{
T& samp = x30_chanLines[c][xc_currentPos[c] * m_blockSamples + i];
samp = samp * x18_currentFeedback[c] / 128 + *audio;
*audio++ = samp * x24_currentOutput[c] / 128;
}
xc_currentPos = (xc_currentPos[c] + 1) % x0_currentSize[c];
}
}
}
}