#include "amuse/EffectChorus.hpp" #include #include "amuse/Common.hpp" #include "amuse/IBackendVoice.hpp" namespace amuse { /* clang-format off */ constexpr std::array rsmpTab12khz{ 0.097504f, 0.802216f, 0.101593f, -0.000977f, 0.093506f, 0.802032f, 0.105804f, -0.001038f, 0.089600f, 0.801697f, 0.110107f, -0.001160f, 0.085785f, 0.801178f, 0.114471f, -0.001282f, 0.082031f, 0.800476f, 0.118927f, -0.001404f, 0.078369f, 0.799622f, 0.123474f, -0.001526f, 0.074799f, 0.798615f, 0.128143f, -0.001648f, 0.071350f, 0.797424f, 0.132874f, -0.001770f, 0.067963f, 0.796051f, 0.137695f, -0.001923f, 0.064697f, 0.794525f, 0.142609f, -0.002045f, 0.061493f, 0.792847f, 0.147614f, -0.002197f, 0.058350f, 0.790985f, 0.152710f, -0.002319f, 0.055328f, 0.788940f, 0.157898f, -0.002472f, 0.052368f, 0.786743f, 0.163177f, -0.002655f, 0.049500f, 0.784424f, 0.168518f, -0.002808f, 0.046722f, 0.781891f, 0.173981f, -0.002991f, 0.044006f, 0.779205f, 0.179504f, -0.003143f, 0.041412f, 0.776367f, 0.185120f, -0.003326f, 0.038879f, 0.773376f, 0.190826f, -0.003510f, 0.036407f, 0.770233f, 0.196594f, -0.003693f, 0.034027f, 0.766937f, 0.202484f, -0.003876f, 0.031738f, 0.763489f, 0.208435f, -0.004059f, 0.029510f, 0.759857f, 0.214447f, -0.004272f, 0.027374f, 0.756104f, 0.220551f, -0.004456f, 0.025299f, 0.752197f, 0.226746f, -0.004669f, 0.023315f, 0.748169f, 0.233002f, -0.004852f, 0.021393f, 0.743988f, 0.239319f, -0.005066f, 0.019562f, 0.739655f, 0.245728f, -0.005310f, 0.017792f, 0.735199f, 0.252197f, -0.005524f, 0.016052f, 0.730591f, 0.258728f, -0.005707f, 0.014404f, 0.725861f, 0.265350f, -0.005920f, 0.012817f, 0.721008f, 0.272034f, -0.006165f, 0.011322f, 0.716003f, 0.278778f, -0.006378f, 0.009888f, 0.710907f, 0.285583f, -0.006561f, 0.008514f, 0.705658f, 0.292450f, -0.006775f, 0.007202f, 0.700317f, 0.299347f, -0.007019f, 0.005920f, 0.694855f, 0.306335f, -0.007233f, 0.004700f, 0.689270f, 0.313385f, -0.007416f, 0.003571f, 0.683563f, 0.320465f, -0.007629f, 0.002472f, 0.677734f, 0.327606f, -0.007874f, 0.001434f, 0.671844f, 0.334778f, -0.008087f, 0.000458f, 0.665833f, 0.341980f, -0.008270f, -0.000488f, 0.659729f, 0.349243f, -0.008453f, -0.001343f, 0.653534f, 0.356567f, -0.008636f, -0.002167f, 0.647217f, 0.363892f, -0.008850f, -0.002960f, 0.640839f, 0.371277f, -0.009033f, -0.003693f, 0.634338f, 0.378693f, -0.009216f, -0.004364f, 0.627777f, 0.386139f, -0.009338f, -0.004974f, 0.621155f, 0.393616f, -0.009491f, -0.005585f, 0.614441f, 0.401093f, -0.009644f, -0.006134f, 0.607635f, 0.408600f, -0.009796f, -0.006653f, 0.600769f, 0.416107f, -0.009918f, -0.007141f, 0.593842f, 0.423645f, -0.010010f, -0.007568f, 0.586853f, 0.431213f, -0.010132f, -0.007965f, 0.579773f, 0.438751f, -0.010223f, -0.008331f, 0.572662f, 0.446320f, -0.010284f, -0.008667f, 0.565521f, 0.453888f, -0.010345f, -0.008972f, 0.558319f, 0.461456f, -0.010406f, -0.009216f, 0.551056f, 0.469025f, -0.010406f, -0.009460f, 0.543732f, 0.476593f, -0.010406f, -0.009674f, 0.536407f, 0.484131f, -0.010376f, -0.009857f, 0.529022f, 0.491669f, -0.010376f, -0.010010f, 0.521606f, 0.499176f, -0.010315f, -0.010132f, 0.514160f, 0.506683f, -0.010254f, -0.010254f, 0.506683f, 0.514160f, -0.010132f, -0.010315f, 0.499176f, 0.521606f, -0.010010f, -0.010376f, 0.491669f, 0.529022f, -0.009857f, -0.010376f, 0.484131f, 0.536407f, -0.009674f, -0.010406f, 0.476593f, 0.543732f, -0.009460f, -0.010406f, 0.469025f, 0.551056f, -0.009216f, -0.010406f, 0.461456f, 0.558319f, -0.008972f, -0.010345f, 0.453888f, 0.565521f, -0.008667f, -0.010284f, 0.446320f, 0.572662f, -0.008331f, -0.010223f, 0.438751f, 0.579773f, -0.007965f, -0.010132f, 0.431213f, 0.586853f, -0.007568f, -0.010010f, 0.423645f, 0.593842f, -0.007141f, -0.009918f, 0.416107f, 0.600769f, -0.006653f, -0.009796f, 0.408600f, 0.607635f, -0.006134f, -0.009644f, 0.401093f, 0.614441f, -0.005585f, -0.009491f, 0.393616f, 0.621155f, -0.004974f, -0.009338f, 0.386139f, 0.627777f, -0.004364f, -0.009216f, 0.378693f, 0.634338f, -0.003693f, -0.009033f, 0.371277f, 0.640839f, -0.002960f, -0.008850f, 0.363892f, 0.647217f, -0.002167f, -0.008636f, 0.356567f, 0.653534f, -0.001343f, -0.008453f, 0.349243f, 0.659729f, -0.000488f, -0.008270f, 0.341980f, 0.665833f, 0.000458f, -0.008087f, 0.334778f, 0.671844f, 0.001434f, -0.007874f, 0.327606f, 0.677734f, 0.002472f, -0.007629f, 0.320465f, 0.683563f, 0.003571f, -0.007416f, 0.313385f, 0.689270f, 0.004700f, -0.007233f, 0.306335f, 0.694855f, 0.005920f, -0.007019f, 0.299347f, 0.700317f, 0.007202f, -0.006775f, 0.292450f, 0.705658f, 0.008514f, -0.006561f, 0.285583f, 0.710907f, 0.009888f, -0.006378f, 0.278778f, 0.716003f, 0.011322f, -0.006165f, 0.272034f, 0.721008f, 0.012817f, -0.005920f, 0.265350f, 0.725861f, 0.014404f, -0.005707f, 0.258728f, 0.730591f, 0.016052f, -0.005524f, 0.252197f, 0.735199f, 0.017792f, -0.005310f, 0.245728f, 0.739655f, 0.019562f, -0.005066f, 0.239319f, 0.743988f, 0.021393f, -0.004852f, 0.233002f, 0.748169f, 0.023315f, -0.004669f, 0.226746f, 0.752197f, 0.025299f, -0.004456f, 0.220551f, 0.756104f, 0.027374f, -0.004272f, 0.214447f, 0.759857f, 0.029510f, -0.004059f, 0.208435f, 0.763489f, 0.031738f, -0.003876f, 0.202484f, 0.766937f, 0.034027f, -0.003693f, 0.196594f, 0.770233f, 0.036407f, -0.003510f, 0.190826f, 0.773376f, 0.038879f, -0.003326f, 0.185120f, 0.776367f, 0.041412f, -0.003143f, 0.179504f, 0.779205f, 0.044006f, -0.002991f, 0.173981f, 0.781891f, 0.046722f, -0.002808f, 0.168518f, 0.784424f, 0.049500f, -0.002655f, 0.163177f, 0.786743f, 0.052368f, -0.002472f, 0.157898f, 0.788940f, 0.055328f, -0.002319f, 0.152710f, 0.790985f, 0.058350f, -0.002197f, 0.147614f, 0.792847f, 0.061493f, -0.002045f, 0.142609f, 0.794525f, 0.064697f, -0.001923f, 0.137695f, 0.796051f, 0.067963f, -0.001770f, 0.132874f, 0.797424f, 0.071350f, -0.001648f, 0.128143f, 0.798615f, 0.074799f, -0.001526f, 0.123474f, 0.799622f, 0.078369f, -0.001404f, 0.118927f, 0.800476f, 0.082031f, -0.001282f, 0.114471f, 0.801178f, 0.085785f, -0.001160f, 0.110107f, 0.801697f, 0.089600f, -0.001038f, 0.105804f, 0.802032f, 0.093506f, -0.000977f, 0.101593f, 0.802216f, 0.097504f, }; /* clang-format on */ EffectChorus::EffectChorus(uint32_t baseDelay, uint32_t variation, uint32_t period) : x90_baseDelay(std::clamp(baseDelay, 5u, 15u)) , x94_variation(std::clamp(variation, 0u, 5u)) , x98_period(std::clamp(period, 500u, 10000u)) {} EffectChorusImp::EffectChorusImp(uint32_t baseDelay, uint32_t variation, uint32_t period, double sampleRate) : EffectChorus(baseDelay, variation, period) { _setup(sampleRate); } void EffectChorusImp::_setup(double sampleRate) { m_sampsPerMs = std::ceil(sampleRate / 1000.0); m_blockSamples = m_sampsPerMs * 5; delete[] x0_lastChans[0][0]; const size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS; auto* buf = new float[chanPitch * NumChannels](); for (size_t c = 0; c < NumChannels; ++c) { for (size_t i = 0; i < AMUSE_CHORUS_NUM_BLOCKS; ++i) { x0_lastChans[c][i] = buf + chanPitch * c + m_blockSamples * i; } } x6c_src.x88_trigger = chanPitch; m_dirty = true; } void EffectChorusImp::_update() { size_t chanPitch = m_blockSamples * AMUSE_CHORUS_NUM_BLOCKS; size_t fifteenSamps = 15 * m_sampsPerMs; x5c_currentPosHi = m_blockSamples * 2 - (x90_baseDelay - 5) * m_sampsPerMs; x58_currentPosLo = 0; uint32_t temp = (x5c_currentPosHi + (x24_currentLast - 1) * m_blockSamples); x5c_currentPosHi = temp % (chanPitch / fifteenSamps * fifteenSamps); x68_pitchOffsetPeriod = (x98_period / 5 + 1) & ~1; x64_pitchOffsetPeriodCount = x68_pitchOffsetPeriod / 2; x60_pitchOffset = x94_variation * 2048 / x68_pitchOffsetPeriod; m_dirty = false; } EffectChorusImp::~EffectChorusImp() { delete[] x0_lastChans[0][0]; } void EffectChorusImp::SrcInfo::doSrc1(size_t blockSamples, size_t chanCount) { float old1 = x74_old[0]; float old2 = x74_old[1]; float old3 = x74_old[2]; float cur = x70_smpBase[x7c_posHi]; auto* dest = x6c_dest; for (size_t i = 0; i < blockSamples; ++i) { const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc]; uint64_t ovrTest = uint64_t(x78_posLo) + uint64_t(x80_pitchLo); if (ovrTest > UINT32_MAX) { /* overflow */ x78_posLo = ovrTest & 0xffffffff; ++x7c_posHi; if (x7c_posHi == x88_trigger) x7c_posHi = x8c_target; *dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur; dest += chanCount; old1 = old2; old2 = old3; old3 = cur; cur = x70_smpBase[x7c_posHi]; } else { x78_posLo = ovrTest; *dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur; dest += chanCount; } } x74_old[0] = old1; x74_old[1] = old2; x74_old[2] = old3; } void EffectChorusImp::SrcInfo::doSrc2(size_t blockSamples, size_t chanCount) { float old1 = x74_old[0]; float old2 = x74_old[1]; float old3 = x74_old[2]; float cur = x70_smpBase[x7c_posHi]; auto* dest = x6c_dest; for (size_t i = 0; i < blockSamples; ++i) { const float* selTab = &rsmpTab12khz[x78_posLo >> 23 & 0x1fc]; ++x7c_posHi; uint64_t ovrTest = uint64_t(x78_posLo) + uint64_t(x80_pitchLo); if (ovrTest > UINT32_MAX) { /* overflow */ x78_posLo = ovrTest & 0xffffffff; if (x7c_posHi == x88_trigger) x7c_posHi = x8c_target; old1 = old3; old2 = cur; old3 = x70_smpBase[x7c_posHi]; ++x7c_posHi; if (x7c_posHi == x88_trigger) x7c_posHi = x8c_target; *dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur; dest += chanCount; cur = x70_smpBase[x7c_posHi]; } else { x78_posLo = ovrTest; *dest = selTab[0] * old1 + selTab[1] * old2 + selTab[2] * old3 + selTab[3] * cur; dest += chanCount; old1 = old2; old2 = old3; old3 = cur; if (x7c_posHi == x88_trigger) x7c_posHi = x8c_target; cur = x70_smpBase[x7c_posHi]; } } x74_old[0] = old1; x74_old[1] = old2; x74_old[2] = old3; } void EffectChorusImp::applyEffect(float* audio, size_t frameCount, const ChannelMap& chanMap) { if (m_dirty) _update(); size_t remFrames = frameCount; for (size_t f = 0; f < frameCount;) { uint8_t next = x24_currentLast + 1; uint8_t buf = next % 3; std::array bufs{ x0_lastChans[0][buf], x0_lastChans[1][buf], x0_lastChans[2][buf], x0_lastChans[3][buf], x0_lastChans[4][buf], x0_lastChans[5][buf], x0_lastChans[6][buf], x0_lastChans[7][buf], }; auto* inBuf = audio; for (size_t s = 0; f < frameCount && s < m_blockSamples; ++s, ++f) { for (size_t c = 0; c < chanMap.m_channelCount && c < NumChannels; ++c) { *bufs[c]++ = *inBuf++; } } 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; } auto* outBuf = audio; size_t bs = std::min(remFrames, size_t(m_blockSamples)); for (size_t c = 0; c < chanMap.m_channelCount && c < NumChannels; ++c) { x6c_src.x7c_posHi = x5c_currentPosHi; x6c_src.x78_posLo = x58_currentPosLo; x6c_src.x6c_dest = outBuf++; x6c_src.x70_smpBase = x0_lastChans[c][0]; x6c_src.x74_old = x28_oldChans[c].data(); switch (x6c_src.x84_pitchHi) { case 0: x6c_src.doSrc1(bs, chanMap.m_channelCount); break; case 1: x6c_src.doSrc2(bs, chanMap.m_channelCount); break; default: break; } } audio += bs * chanMap.m_channelCount; 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; } } } // namespace amuse