javascript - tag - title html w3schools
¿Qué pasa con este simple diseño de sintetizador de FM? (1)
La mayoría de los sintetizadores etiquetados ''FM'' en efecto modulan la fase (PM, consulte https://en.wikipedia.org/wiki/Phase_modulation ). Hay algunos beneficios (que en su mayoría conducen a un sonido más estable en un amplio rango tonal). El OPL2 puede usar esto también, no encontré evidencia clara, pero el artículo de Wikipedia también usa el término ''modulación de fase''.
Para abreviar, muchos sintetizadores musicales etiquetados ''FM'' de hecho presentaban ''PM'', por lo que podría intentar ir con eso, y verificar si se ajusta mejor a los sonidos esperados de OPL2.
Desde un vistazo rápido a la fuente Audiolet, supongo que el oscilador Sine
está haciendo verdadero FM, por lo que es posible que deba reemplazarlo y agregar una entrada de fase para permitir la modulación de fase.
Básicamente, la línea
output.samples[0] = Math.sin(this.phase);
utilizado por Sine
del transportador oscilator tendría que leer algo así como
output.samples[0] = Math.sin(this.phase+phase_offset);
con phase_offset
controlado por el mod oscilador en lugar de la frecuencia.
Estoy intentando implementar algunas características de un chip de sonido Yamaha YM3812 (también conocido como OPL2 http://en.wikipedia.org/wiki/YM3812 ) en JavaScript utilizando Audiolet (una biblioteca de síntesis, http://oampo.github.io/Audiolet/api.html )
Audiolet le permite construir un sintetizador como un gráfico de nodos (osciladores, DSP, generadores de envolvente, etc.).
El OPL2 tiene nueve canales con dos operadores (osciladores) cada uno. Usualmente, un oscilador en cada canal modula la frecuencia del otro. Para simular esto, he creado una cadena de nodos para cada canal:
Cadena de nodo Synth (uno de nueve canales)
Código de creación y conexión de cadena de nodo:
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
};
Sin embargo, cuando establezco los parámetros del modulador y los nodos de portadora (formas de onda del oscilador, frecuencias relativas, atenuación, parámetros ADSR) y notas de activación, la salida tiene muy poco parecido con un emulador decente OPL2 con aproximadamente los mismos parámetros. Algunos sonidos están en el estadio. Otros son bastante desagradables.
Tengo algunas ideas sobre cómo proceder (supongo que trazar la salida en diferentes etapas sería un buen punto de partida), pero espero que alguien con experiencia pueda señalarme en la dirección correcta o señalar algo obviamente incorrecto con lo que hago. Estoy haciendo. No tengo un procesamiento de señal o una sólida formación matemática. No tengo una comprensión intuitiva profunda de FM.
Algunos problemas que sospecho son:
1) Mi implementación FM (como se muestra arriba) es fundamentalmente incorrecta. Además, puede haber un problema en la función donde reproducir una nota (establecer las frecuencias del oscilador, y escalar y compensar el modulador antes de activar las envolventes 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) La salida de los sintetizadores FM puede ser muy sensible a las pequeñas diferencias en la forma del sobre ADSR del modulador (¡dime si esto es cierto!), Y mis sobres ADSR son crudas aproximaciones en el mejor de los ADSR en un OPL2 real. A mi implementación también le faltan algunas características que parecen relativamente sin importancia (por ejemplo, escala de teclas), pero que pueden afectar significativamente el sonido de un sintetizador FM (de nuevo, no estoy seguro).