public void Init() { chInfo = new ChInfo[maxCh]; for (int i = 0; i < chInfo.Length; i++) { chInfo[i] = new ChInfo(); // 内部変数 // 高音域のみ通す(低音域をカットする)フィルタ設定(左右分) // カットする周波数の目安は20Hz~300Hz程度 // 増幅量が大きくなれば、カットオフ周波数も大きくするとよい chInfo[i].hFreq = 1000f; chInfo[i].hQ = (float)(1.0f / Math.Sqrt(2.0f)); chInfo[i].lFreq = 300f; chInfo[i].lQ = (float)(1.0f / Math.Sqrt(2.0f)); chInfo[i].hsw = false; chInfo[i].highpassL = new CMyFilter(); chInfo[i].highpassR = new CMyFilter(); chInfo[i].lsw = false; chInfo[i].lowpassL = new CMyFilter(); chInfo[i].lowpassR = new CMyFilter(); updateParam(i); } }
public void Init() { chInfo = new ChInfo[maxCh]; for (int i = 0; i < chInfo.Length; i++) { chInfo[i] = new ChInfo((int)clock); } }
public void SetReg(bool isSysIns, uint adr, byte data) { if (!isSysIns && adr == 0) { currentCh = Math.Max(Math.Min(data & 0x3f, 38), 0); if ((data & 0x80) != 0) { Init(); } return; } ChInfo info = sysInfo; if (!isSysIns) { info = chInfo[currentCh]; } if (adr == 1) { info.sw = ((data & 0x80) != 0); info.volume = (data & 0x7f) / (127.0f / 4.0f); } else if (adr == 2) { info.threshold = Math.Max(data / 255.0f, 0.1f); } else if (adr == 3) { info.ratio = Math.Max(data / (255.0f / 10.0f), 1.0f); } else if (adr == 4) { info.envFreq = data / (255.0f / 80.0f); info.envfilterL.LowPass(info.envFreq, info.envQ, samplerate); info.envfilterR.LowPass(info.envFreq, info.envQ, samplerate); } else if (adr == 5) { info.envQ = CMyFilter.QTable[data]; info.envfilterL.LowPass(info.envFreq, info.envQ, samplerate); info.envfilterR.LowPass(info.envFreq, info.envQ, samplerate); } else if (adr == 6) { info.gainFreq = data / (255.0f / 80.0f); info.gainfilterL.LowPass(info.gainFreq, info.gainQ, samplerate); info.gainfilterR.LowPass(info.gainFreq, info.gainQ, samplerate); } else if (adr == 7) { info.gainQ = CMyFilter.QTable[data]; info.gainfilterL.LowPass(info.gainFreq, info.gainQ, samplerate); info.gainfilterR.LowPass(info.gainFreq, info.gainQ, samplerate); } }
public void Init() { chInfo = new ChInfo[maxCh]; for (int i = 0; i < chInfo.Length; i++) { chInfo[i] = new ChInfo(); chInfo[i].sw = false; // 内部変数 // 高音域のみ通す(低音域をカットする)フィルタ設定(左右分) // カットする周波数の目安は20Hz~300Hz程度 // 増幅量が大きくなれば、カットオフ周波数も大きくするとよい chInfo[i].highpassL = new CMyFilter(); chInfo[i].highpassL.HighPass(200.0f, (float)(1.0f / Math.Sqrt(2.0f)), clock); chInfo[i].highpassR = new CMyFilter(); chInfo[i].highpassR.HighPass(200.0f, (float)(1.0f / Math.Sqrt(2.0f)), clock); chInfo[i].gain = 300.0f; chInfo[i].volume = 0.1f; } }
public void Init() { currentCh = 0; chInfo = new ChInfo[maxCh]; for (int i = 0; i < chInfo.Length; i++) { chInfo[i] = new ChInfo(); chInfo[i].sw = false; chInfo[i].threshold = 0.3f; chInfo[i].ratio = 2.0f; chInfo[i].volume = 2.0f; chInfo[i].envFreq = 30.0f; chInfo[i].envQ = 1.0f; chInfo[i].gainFreq = 5.0f; chInfo[i].gainQ = 1.0f; chInfo[i].envfilterL = new CMyFilter(); chInfo[i].envfilterR = new CMyFilter(); // 音圧を検知するために使うローパスフィルタ chInfo[i].gainfilterL = new CMyFilter(); chInfo[i].gainfilterR = new CMyFilter(); // 急激な音量変化を避けるためのローパスフィルタ SetLowPass(i, 30.0f, 1.0f, 5.0f, 1.0f); } sysInfo = new ChInfo(); sysInfo.sw = false; sysInfo.threshold = 0.3f; sysInfo.ratio = 2.0f; sysInfo.volume = 2.0f; sysInfo.envFreq = 30.0f; sysInfo.envQ = 1.0f; sysInfo.gainFreq = 5.0f; sysInfo.gainQ = 1.0f; sysInfo.envfilterL = new CMyFilter(); sysInfo.envfilterR = new CMyFilter(); // 音圧を検知するために使うローパスフィルタ sysInfo.gainfilterL = new CMyFilter(); sysInfo.gainfilterR = new CMyFilter(); // 急激な音量変化を避けるためのローパスフィルタ SetLowPass(-1, 30.0f, 1.0f, 5.0f, 1.0f); }
public void Mix(int ch, ref int inL, ref int inR) { if (ch < 0) { return; } if (ch >= maxCh) { return; } if (chInfo == null) { return; } if (chInfo[ch] == null) { return; } if (!chInfo[ch].sw) { return; } ChInfo ci = chInfo[ch]; float finL = inL / 21474.83647f; float finR = inR / 21474.83647f; float speed = (2.0f * 3.14159265f * ci.rate) / clock; // 揺らぎのスピード。角速度ωと同じ。 // inL[]、inR[]、outL[]、outR[]はそれぞれ入力信号と出力信号のバッファ(左右) // wavelenghtはバッファのサイズ、サンプリング周波数は44100Hzとする // 入力信号にコーラスかける // 角度θに角速度を加える ci.theta += speed; // 読み込み位置を揺らす量を計算 // sin()関数の結果にdepthを掛ける float a = (float)(Math.Sin(ci.theta) * ci.depth); // 読み込み位置を揺らした際の前後の整数値を取得(あとで線形補間するため) int p1 = (int)a; int p2 = (int)(a + 1); // 前後の整数値から読み込み位置の値を線形補間で割り出す float lerpL1 = lerp(ci.ringbufL.Read(p1), ci.ringbufL.Read(p2), a - (float)p1); float lerpR1 = lerp(ci.ringbufR.Read(p1), ci.ringbufR.Read(p2), a - (float)p1); // 入力信号にディレイ信号を混ぜる float tmpL = (1.0f - ci.mix) * finL + ci.mix * lerpL1; float tmpR = (1.0f - ci.mix) * finR + ci.mix * lerpR1; // ディレイ信号として入力信号とフィードバック信号をリングバッファに書き込み ci.ringbufL.Write((1.0f - ci.feedback) * finL + ci.feedback * tmpL); ci.ringbufR.Write((1.0f - ci.feedback) * finR + ci.feedback * tmpR); // リングバッファの状態を更新する ci.ringbufL.Update(); ci.ringbufR.Update(); // 出力信号に書き込む finL = tmpL; finR = tmpR; inL = (int)(finL * 21474.83647f); inR = (int)(finR * 21474.83647f); }
public void Mix(int ch, ref int inL, ref int inR, int wavelength = 1) { if (ch < 0) { return; } if (ch >= maxCh) { return; } if (chInfo == null) { return; } if (chInfo[ch] == null) { return; } if (!chInfo[ch].sw) { return; } ChInfo info = chInfo[ch]; fbuf[0] = inL / 21474.83647f; fbuf[1] = inR / 21474.83647f; // inL[]、inR[]、outL[]、outR[]はそれぞれ入力信号と出力信号のバッファ(左右) // wavelenghtはバッファのサイズ、サンプリング周波数は44100Hzとする // 入力信号にエフェクトをかける // 入力信号の絶対値をとったものをローパスフィルタにかけて音圧を検知する float tmpL = info.envfilterL.Process(Math.Abs(fbuf[0])); float tmpR = info.envfilterR.Process(Math.Abs(fbuf[1])); // 音圧をもとに音量(ゲイン)を調整(左) float gainL = 1.0f; if (tmpL > info.threshold) { // スレッショルドを超えたので音量(ゲイン)を調節(圧縮) gainL = info.threshold + (tmpL - info.threshold) / info.ratio; } // 音量(ゲイン)が急激に変化しないようローパスフィルタを通す gainL = info.gainfilterL.Process(gainL); // 左と同様に右も音圧をもとに音量(ゲイン)を調整 float gainR = 1.0f; if (tmpR > info.threshold) { gainR = info.threshold + (tmpR - info.threshold) / info.ratio; } gainR = info.gainfilterR.Process(gainR); // 入力信号に音量(ゲイン)をかけ、さらに最終的な音量を調整し出力する fbuf[0] = info.volume * gainL * fbuf[0]; fbuf[1] = info.volume * gainR * fbuf[1]; inL = (int)(fbuf[0] * 21474.83647f); inR = (int)(fbuf[1] * 21474.83647f); }