Подтвердить что ты не робот

Что не так с этим простым FM-синтезатором?

Я пытаюсь реализовать некоторые особенности звукового чипа Yamaha YM3812 (иначе OPL2 http://en.wikipedia.org/wiki/YM3812) в JavaScript с использованием Audiolet (синтез библиотека, http://oampo.github.io/Audiolet/ api.html)

Аудиопетлет позволяет создавать синтезатор в виде графика узлов (осцилляторов, DSP, генераторов огибающей и т.д.).

OPL2 имеет девять каналов с двумя операторами (осцилляторами) каждый. Обычно один генератор в каждом канале модулирует частоту другого. Чтобы имитировать это, я создал цепочку узлов для каждого канала:

Синтетическая цепочка node (один из девяти каналов)

OPL2 channel as implemented

Node создание цепочки и код подключения:

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 (опять же, я не уверен).

4b9b3361

Ответ 1

Большинство синтезаторов, занесенных в "FM", фактически выполняют фазовую модуляцию (PM, см. https://en.wikipedia.org/wiki/Phase_modulation). Имеются некоторые преимущества (в основном приводящие к более стабильному звучанию в большом тональном диапазоне). OPL2 также может использовать это, я не нашел четких доказательств, но статья Википедии также использует термин "фазовая модуляция".

Короче говоря, многие музыкальные синтезаторы с надписью "FM" на самом деле представлены "PM", поэтому вы можете попробовать пойти с этим и проверить, лучше ли это соответствует ожидаемым звукам OPL2.

С быстрым взглядом на источник Audiolet я бы предположил, что occilator Sine выполняет истинное значение FM, поэтому вам может потребоваться его заменить и добавить фазовый вход для обеспечения фазовой модуляции.

В принципе, строка

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

используемый Sine носителя-носителя, должен был бы прочитать что-то вроде

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

с phase_offset, управляемым модулем oscilator вместо частоты.