我已经在 PureData 的 C++ 帮助文件中实现了 Miller Puckette 的时域音高变换算法( http://msp.ucsd.edu/techniques/v0.11/book-html/node125.html )(我的代码在这里: https: //github.com/aparks5/synthcastle/blob/main/src/pitchshift_timedomain.cpp )
我一直在玩它,并注意到将反馈引入延迟线会产生一些有趣的效果。我可以将它描述为“绽放”,但它可能更清楚地描述为一个音高移位器,随着时间的推移(以指数方式?)进一步增加音高。
然而,由于对包络相位和调制延迟时间的单极锯齿相位的假设,当引入反馈时,允许这种拼接干净地发生而没有间断的关于相位的假设不再成立。
如何在不引入更多咔嗒声的情况下将反馈引入音高变换延迟线?
我不希望在没有相位语音编码的情况下听起来“干净”,我只是想更好地了解如何修改包络以补偿反馈路径。
有趣的是,我认为这种效果一定是可能的,因为它是在 Boss RPS-10 Pitch-Shifter Delay 上实现的,我不得不想象这种效果在时域中起作用。
这是我粘贴在下面的代码
#include "pitchshift_timedomain.h"
#include "gain.h"
PitchShift::PitchShift(size_t fs)
: Module(fs)
, m_delay(fs, 1.0f)
, m_delayInv(fs, 1.f)
, m_saw(fs)
, m_shiftSemitones(7)
{
m_delay.update(0.f, 0.0f);
m_delayInv.update(0.f, 0.0f);
// http://msp.ucsd.edu/techniques/v0.11/book-html/node125.html
float semi = m_shiftSemitones;
float temp = expf(semi * 0.05776f) - 1;
temp = temp / 0.08; // window
m_saw.freq(temp);
}
float PitchShift::operator()(float in) {
// http://msp.ucsd.edu/techniques/v0.11/book-html/node125.html
float delay1Modulation = m_saw();
// make saw unipolar
delay1Modulation = (delay1Modulation * 0.5f) + 0.5f;
// add 90 degree offset, wrap around 1
float delay2Modulation = 0.5f + delay1Modulation;
if (delay2Modulation > 1) {
delay2Modulation -= 1;
}
m_delay.update((delay1Modulation * 80) + 67, 0.0f);
m_delayInv.update((delay2Modulation * 80) + 67, 0.0f);
float temp = m_delay();
// restrict cosine from -.25 to .25
float env = cosf(2*M_PI * ((delay1Modulation - 0.5f) * 0.5f));
temp *= env;
float tempInv = m_delayInv();
float envInv = cosf(2*M_PI * ((delay2Modulation - 0.5f) * 0.5f));
tempInv *= envInv;
m_delay.write(in);
m_delayInv.write(in);
return (temp + tempInv) * 0.707;
}