向 Miller Puckette 的无间断时域音高变换算法引入反馈

信息处理 沥青 音乐 延迟 C++ 回馈
2022-02-11 23:36:10

我已经在 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;
}
0个回答
没有发现任何回复~