mirror of https://github.com/AxioDL/amuse.git
Implement EffectDelay
This commit is contained in:
parent
02d6478ce3
commit
4353113649
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,133 +303,140 @@ 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();
|
||||||
|
|
||||||
uint8_t next = x24_currentLast + 1;
|
size_t remFrames = frameCount;
|
||||||
uint8_t buf = next % 3;
|
for (size_t f=0 ; f<frameCount ;)
|
||||||
T* leftBuf = x0_lastLeft[buf];
|
|
||||||
T* rightBuf = xc_lastRight[buf];
|
|
||||||
T* rearLeftBuf = x18_lastRearLeft[buf];
|
|
||||||
T* rearRightBuf = x18_lastRearRight[buf];
|
|
||||||
T* centerBuf = x18_lastCenter[buf];
|
|
||||||
T* lfeBuf = x18_lastLFE[buf];
|
|
||||||
T* sideLeftBuf = x18_lastSideLeft[buf];
|
|
||||||
T* sideRightBuf = x18_lastSideRight[buf];
|
|
||||||
|
|
||||||
T* inBuf = audio;
|
|
||||||
for (size_t f=0 ; f<frameCount && f<m_blockSamples ; ++f)
|
|
||||||
{
|
{
|
||||||
|
uint8_t next = x24_currentLast + 1;
|
||||||
|
uint8_t buf = next % 3;
|
||||||
|
T* leftBuf = x0_lastLeft[buf];
|
||||||
|
T* rightBuf = xc_lastRight[buf];
|
||||||
|
T* rearLeftBuf = x18_lastRearLeft[buf];
|
||||||
|
T* rearRightBuf = x18_lastRearRight[buf];
|
||||||
|
T* centerBuf = x18_lastCenter[buf];
|
||||||
|
T* lfeBuf = x18_lastLFE[buf];
|
||||||
|
T* sideLeftBuf = x18_lastSideLeft[buf];
|
||||||
|
T* sideRightBuf = x18_lastSideRight[buf];
|
||||||
|
|
||||||
|
T* inBuf = audio;
|
||||||
|
for (size_t s=0 ; f<frameCount && s<m_blockSamples ; ++s, ++f)
|
||||||
|
{
|
||||||
|
for (size_t c=0 ; c<chanMap.m_channelCount ; ++c)
|
||||||
|
{
|
||||||
|
switch (chanMap.m_channels[c])
|
||||||
|
{
|
||||||
|
case AudioChannel::FrontLeft:
|
||||||
|
*leftBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::FrontRight:
|
||||||
|
*rightBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::RearLeft:
|
||||||
|
*rearLeftBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::RearRight:
|
||||||
|
*rearRightBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::FrontCenter:
|
||||||
|
*centerBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::LFE:
|
||||||
|
*lfeBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::SideLeft:
|
||||||
|
*sideLeftBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
case AudioChannel::SideRight:
|
||||||
|
*sideRightBuf++ = *inBuf++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
inBuf++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x6c_src.x84_pitchHi = (x60_pitchOffset >> 16) + 1;
|
||||||
|
x6c_src.x80_pitchLo = (x60_pitchOffset << 16);
|
||||||
|
|
||||||
|
--x64_pitchOffsetPeriodCount;
|
||||||
|
if (x64_pitchOffsetPeriodCount == 0)
|
||||||
|
{
|
||||||
|
x64_pitchOffsetPeriodCount = x68_pitchOffsetPeriod;
|
||||||
|
x60_pitchOffset = -x60_pitchOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.x78_posLo = x58_currentPosLo;
|
||||||
|
|
||||||
|
x6c_src.x6c_dest = outBuf++;
|
||||||
switch (chanMap.m_channels[c])
|
switch (chanMap.m_channels[c])
|
||||||
{
|
{
|
||||||
case AudioChannel::FrontLeft:
|
case AudioChannel::FrontLeft:
|
||||||
*leftBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x0_lastLeft[0];
|
||||||
|
x6c_src.x74_old = x28_oldLeft;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::FrontRight:
|
case AudioChannel::FrontRight:
|
||||||
*rightBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = xc_lastRight[0];
|
||||||
|
x6c_src.x74_old = x38_oldRight;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::RearLeft:
|
case AudioChannel::RearLeft:
|
||||||
*rearLeftBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x18_lastRearLeft[0];
|
||||||
|
x6c_src.x74_old = x48_oldRearLeft;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::RearRight:
|
case AudioChannel::RearRight:
|
||||||
*rearRightBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x18_lastRearRight[0];
|
||||||
|
x6c_src.x74_old = x48_oldRearRight;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::FrontCenter:
|
case AudioChannel::FrontCenter:
|
||||||
*centerBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x18_lastCenter[0];
|
||||||
|
x6c_src.x74_old = x48_oldCenter;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::LFE:
|
case AudioChannel::LFE:
|
||||||
*lfeBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x18_lastLFE[0];
|
||||||
|
x6c_src.x74_old = x48_oldLFE;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::SideLeft:
|
case AudioChannel::SideLeft:
|
||||||
*sideLeftBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x18_lastSideLeft[0];
|
||||||
|
x6c_src.x74_old = x48_oldSideLeft;
|
||||||
break;
|
break;
|
||||||
case AudioChannel::SideRight:
|
case AudioChannel::SideRight:
|
||||||
*sideRightBuf++ = *inBuf++;
|
x6c_src.x70_smpBase = x18_lastSideRight[0];
|
||||||
|
x6c_src.x74_old = x48_oldSideRight;
|
||||||
break;
|
break;
|
||||||
default:
|
default: break;
|
||||||
inBuf++;
|
}
|
||||||
|
|
||||||
|
switch (x6c_src.x84_pitchHi)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x6c_src.doSrc1(bs, chanMap.m_channelCount);
|
||||||
break;
|
break;
|
||||||
|
case 1:
|
||||||
|
x6c_src.doSrc2(bs, chanMap.m_channelCount);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audio = outBuf;
|
||||||
|
remFrames -= bs;
|
||||||
|
|
||||||
|
size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
|
||||||
|
size_t fifteenSamps = 15 * m_sampsPerMs;
|
||||||
|
|
||||||
|
x5c_currentPosHi = x6c_src.x7c_posHi % (chanPitch / fifteenSamps * fifteenSamps);
|
||||||
|
x58_currentPosLo = x6c_src.x78_posLo;
|
||||||
|
x24_currentLast = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
x6c_src.x84_pitchHi = (x60_pitchOffset >> 16) + 1;
|
|
||||||
x6c_src.x80_pitchLo = (x60_pitchOffset << 16);
|
|
||||||
|
|
||||||
--x64_pitchOffsetPeriodCount;
|
|
||||||
if (x64_pitchOffsetPeriodCount == 0)
|
|
||||||
{
|
|
||||||
x64_pitchOffsetPeriodCount = x68_pitchOffsetPeriod;
|
|
||||||
x60_pitchOffset = -x60_pitchOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* outBuf = audio;
|
|
||||||
for (size_t c=0 ; c<chanMap.m_channelCount ; ++c)
|
|
||||||
{
|
|
||||||
x6c_src.x7c_posHi = x5c_currentPosHi;
|
|
||||||
x6c_src.x78_posLo = x58_currentPosLo;
|
|
||||||
|
|
||||||
x6c_src.x6c_dest = outBuf++;
|
|
||||||
switch (chanMap.m_channels[c])
|
|
||||||
{
|
|
||||||
case AudioChannel::FrontLeft:
|
|
||||||
x6c_src.x70_smpBase = x0_lastLeft[0];
|
|
||||||
x6c_src.x74_old = x28_oldLeft;
|
|
||||||
break;
|
|
||||||
case AudioChannel::FrontRight:
|
|
||||||
x6c_src.x70_smpBase = xc_lastRight[0];
|
|
||||||
x6c_src.x74_old = x38_oldRight;
|
|
||||||
break;
|
|
||||||
case AudioChannel::RearLeft:
|
|
||||||
x6c_src.x70_smpBase = x18_lastRearLeft[0];
|
|
||||||
x6c_src.x74_old = x48_oldRearLeft;
|
|
||||||
break;
|
|
||||||
case AudioChannel::RearRight:
|
|
||||||
x6c_src.x70_smpBase = x18_lastRearRight[0];
|
|
||||||
x6c_src.x74_old = x48_oldRearRight;
|
|
||||||
break;
|
|
||||||
case AudioChannel::FrontCenter:
|
|
||||||
x6c_src.x70_smpBase = x18_lastCenter[0];
|
|
||||||
x6c_src.x74_old = x48_oldCenter;
|
|
||||||
break;
|
|
||||||
case AudioChannel::LFE:
|
|
||||||
x6c_src.x70_smpBase = x18_lastLFE[0];
|
|
||||||
x6c_src.x74_old = x48_oldLFE;
|
|
||||||
break;
|
|
||||||
case AudioChannel::SideLeft:
|
|
||||||
x6c_src.x70_smpBase = x18_lastSideLeft[0];
|
|
||||||
x6c_src.x74_old = x48_oldSideLeft;
|
|
||||||
break;
|
|
||||||
case AudioChannel::SideRight:
|
|
||||||
x6c_src.x70_smpBase = x18_lastSideRight[0];
|
|
||||||
x6c_src.x74_old = x48_oldSideRight;
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (x6c_src.x84_pitchHi)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x6c_src.doSrc1(m_blockSamples, chanMap.m_channelCount);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
x6c_src.doSrc2(m_blockSamples, chanMap.m_channelCount);
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS;
|
|
||||||
size_t fifteenSamps = 15 * m_sampsPerMs;
|
|
||||||
|
|
||||||
x5c_currentPosHi = x6c_src.x7c_posHi % (chanPitch / fifteenSamps * fifteenSamps);
|
|
||||||
x58_currentPosLo = x6c_src.x78_posLo;
|
|
||||||
x24_currentLast = buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template class EffectChorus<int16_t>;
|
template class EffectChorus<int16_t>;
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue