这个简单的FM合成器devise有什么问题?

我试图用JavaScript实现雅马哈YM3812音效芯片(又名OPL2 http://en.wikipedia.org/wiki/YM3812 )的一些function,使用Audiolet(一个综合库, http: //oampo.github.io/ Audiolet / api.html )

Audiolet允许你创build一个合成器作为节点(振荡器,DSP,包络发生器等)的graphics。

OPL2有9个通道,每个通道有两个操作员(振荡器)。 通常,每个通道中的一个振荡器调制另一个振荡器的频率。 为了模拟这个,我为每个通道build立了一系列节点:

合成节点链(九个通道之一)

OPL2频道如实施

节点链创build和连接代码:

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仿真器几乎没有什么相似之处。 一些声音在球场上。 其他人相当不愉快。

我有一些关于如何进行的想法(我猜测在不同阶段绘制输出结果是一个很好的起点),但是我希望有经验的人能指点我的方向,或者指出一些明显的错误,在做什么 我没有信号处理或强大的math背景。 我对FM没有深入的了解。

我怀疑的一些问题是:

1)我的FM实现(如上所示)从根本上是错误的。 此外,播放音符的function可能存在问题(设置振荡器频率,并在触发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)调频合成器的输出可能对调制器ADSR包络形状的微小差异非常敏感(请告诉我这是真的!),而我的ADSR包络在实际的OPL2中是ADSR的粗略近似值。 我的实现也缺less一些看起来相对不重要的function(例如按键缩放),但这可能会显着影响FM合成器的声音(同样,我不太确定)。

大多数合成器都标有“FM”,实际上是相位调制(PM,见https://en.wikipedia.org/wiki/Phase_modulation )。 有一些好处(主要是在较大的色调范围内导致更稳定的声音)。 OPL2也可以使用这个,我没有find明确的证据,但维基百科的文章也使用了“相位调制”这个术语。

简而言之,许多标注为“FM”的音乐合成器实际上以“PM”为特色,所以您可以尝试一下,并检查它是否适合预期的OPL2声音。

从快速浏览到Audiolet源,我猜想Sine oscilator正在做真正的调频,所以你可能需要更换它,并添加一个相位input,以允许相位调制。

基本上,线路

 output.samples[0] = Math.sin(this.phase); 

使用载波振荡器的Sine将不得不读取类似的东西

 output.samples[0] = Math.sin(this.phase+phase_offset); 

其中phase_offset由mod phase_offset控制,而不是频率。