void pitchshifter(float inL[], float inR[], float outL[], float outR[], int wavelength)
{
// エフェクターのパラメーター
static float mix = 1.0f; // ピッチシフターの効き具合。0.0~1.0の間
static float pitch = 12.0f; // どれだけ音を高く(低く)するか。-12~12程度
// 内部変数
static CRingBuffur ringbufL, ringbufR; // リングバッファ(https://www.utsbox.com/?p=1505 より)
// リングバッファのinteravalを設定する
// とりあえず1000サンプル程度とする
// (intervalはリングバッファ(https://www.utsbox.com/?p=1505 より)
int delaysample = 1000;
ringbufL.SetInterval(delaysample);
ringbufR.SetInterval(delaysample);
// 読み込み速度を速めた後の読み込み位置
static float pos = 0.0f;
// ピッチから読み込み速度を計算
// -12半音(1オクターブ下)で-0.5、12半音(1オクターブ上)で1となるようにする
static float speed = pow(2.0f, pitch / 12.0f) - 1.0f ;
// 入力信号をピッチシフトする
for (int i = 0; i < wavelength; i++)
{
// 読み込み位置を移動した際の前後の整数値を取得(あとで線形補間するため)
int p1 = (int)pos;
int p2 = pos + 1;
// 前後の整数値から読み込み位置の値を線形補間で割り出す
// 線形補間で割り出した結果はピッチシフト後の信号となる
float lerpL1 = lerp(ringbufL.Read(p1), ringbufL.Read(p2), pos - (float)p1);
float lerpR1 = lerp(ringbufR.Read(p1), ringbufR.Read(p2), pos - (float)p1);
// 読み込み位置を更新する
// posが大きく(小さく)なりすぎないように定期的に 0 に戻す
// 大きくなった時にリングバッファのintervalを超えてはいけないので、
// とりあえずdelaysample* 0.9とする。
pos += speed;
if (abs(pos) >= (float)delaysample * 0.9f) { pos = 0.0f; }
// ディレイ信号として入力信号をリングバッファに書き込み
ringbufL.Write(inL[i]);
ringbufR.Write(inR[i]);
// リングバッファの状態を更新する
ringbufL.Update();
ringbufR.Update();
// 入力信号にピッチシフト信号を混ぜて出力する
outL[i] = (1.0f - mix)*inL[i] + mix * lerpL1;
outR[i] = (1.0f - mix)*inR[i] + mix * lerpR1;
}