gpt4 book ai didi

javascript - 这个简单的 FM 合成器设计有什么问题?

转载 作者:IT王子 更新时间:2023-10-29 03:10:37 25 4
gpt4 key购买 nike

我正在尝试使用 Audiolet(合成库,http://en.wikipedia.org/wiki/YM3812)在 JavaScript 中实现 Yamaha YM3812 声音芯片(又名 OPL2 http://oampo.github.io/Audiolet/api.html)的一些功能

Audiolet 允许您将合成器构建为节点图(振荡器、DSP、包络发生器等)。

OPL2 有九个 channel ,每个 channel 有两个运算符(振荡器)。通常,每个 channel 中的一个振荡器调制另一个的频率。为了模拟这一点,我为每个 channel 建立了一个节点链:

Synth 节点链(九个 channel 之一)

OPL2 channel as implemented

节点链创建和连接代码:

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 包络充其量是实际 ADSR 的粗略近似值OPL2。我的实现还缺少一些看起来相对不重要的功能(例如键缩放),但可能会显着影响 FM 合成器的声音(同样,我不确定)。

最佳答案

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

简而言之,许多标记为“FM”的音乐合成器实际上具有“PM”功能,因此您可以尝试使用它,并检查它是否更适合预期的 OPL2 声音。

通过快速浏览 Audiolet 源,我猜想 Sine 振荡器正在执行真正的 FM,因此您可能需要更换它并添加相位输入以允许相位调制。

基本上,这条线

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

由载波振荡器的 Sine 使用必须读取类似的内容

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

phase_offset 由 mod 振荡器而不是频率控制。

关于javascript - 这个简单的 FM 合成器设计有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16923288/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com