我正在尝试使用Audiolet(一种合成库,http://oampo.github.io/Audiolet/api.html)在JavaScript中实现Yamaha YM3812声音芯片的一些功能(又称为OPL2,详情请参阅 http://en.wikipedia.org/wiki/YM3812)。
Audiolet允许您将合成器构建为节点图(振荡器、数字信号处理器、包络发生器等)。
OPL2有九个通道,每个通道都有两个运算器(振荡器)。通常情况下,每个通道中的一个振荡器调制另一个振荡器的频率。为了模拟这一点,我为每个通道构建了一系列节点:
合成器节点链(其中之一的九个通道)
节点链创建和连接代码:
var FmChannel = function(audiolet) {
this.car = new ModifiedSine(audiolet);
this.carMult = 1;
this.setCarrierWaveform(this.SIN);
this.mod = new ModifiedSine(audiolet);
this.modMult = 1;
this.setModulatorWaveform(this.SIN);
this.modMulAdd = new MulAdd(audiolet);
this.carGain = new Gain(audiolet);
this.carEnv = new ADSREnvelope(audiolet, 0, 0.1, 0.1, 0.1, 0.1,
function() {
this.carEnv.reset();
}.bind(this)
);
this.carAtten = new Multiply(audiolet);
this.modGain = new Gain(audiolet);
this.modEnv = new ADSREnvelope(audiolet, 0, 0.1, 0.1, 0.1, 0.1,
function() {
this.modEnv.reset();
}.bind(this)
);
this.modAtten = new Multiply(audiolet);
this.modEnv.connect(this.modGain, 0, 1);
this.mod.connect(this.modGain);
this.modGain.connect(this.modAtten);
this.modAtten.connect(this.modMulAdd);
this.modMulAdd.connect(this.car);
this.carEnv.connect(this.carGain, 0, 1);
this.car.connect(this.carGain);
this.carGain.connect(this.carAtten);
// connect carAtten to the mixer from outside
};
然而,当我设置调制器和载波节点的参数(振荡器波形、相对频率、衰减、ADSR参数)并触发音符时,输出与具有相同参数的良好OPL2仿真器几乎没有什么相似之处。一些声音大致相符,另一些则相当不愉快。
我有一些想法可以继续进行(我猜在不同阶段绘制输出可能是一个很好的起点),但我希望有经验的人能指点我方向,或者指出我所做的事情明显错误的地方。我没有信号处理或强大的数学背景。我对FM没有深刻的直观理解。
我怀疑存在以下问题:
1)我的FM实现(如上所示)基本上是错误的。此外,在播放音符的函数中可能存在问题(设置振荡器频率,并在触发ADSR包络之前缩放和偏移调制器):
FmChannel.prototype.noteOn = function (frq) {
var Fc = frq*this.carMult;
this.car.reset(Fc);
this.mod.reset(frq*this.modMult);
// scale and offset modulator from range (-1, 1) to (0, 2*Fc)
// (scale and offset is after ADSR gain and fixed attenuation is applied)
this.modMulAdd.mul.setValue(Fc);
this.modMulAdd.add.setValue(Fc);
this.carEnv.reset();
this.modEnv.reset();
this.carEnv.gate.setValue(1);
Thethis.modEnv.gate.setValue(1);
};
2)FM合成器的输出可能对调制器ADSR包络形状的微小差异非常敏感(如果这是正确的,请告诉我!),而我的ADSR包络充其量只是真正OPL2中的ADSR的粗略近似。我的实现还缺少一些看起来相对不重要的功能(例如键盘缩放),但这可能会显着影响FM合成器的声音(同样,我不确定)。