38

I'm trying to implement some features of a Yamaha YM3812 sound chip (aka OPL2 http://en.wikipedia.org/wiki/YM3812) in JavaScript using Audiolet (a synthesis library, http://oampo.github.io/Audiolet/api.html)

Audiolet allows you to build a synthesizer as a graph of nodes (oscillators, DSPs, envelope generators etc).

The OPL2 has nine channels with two operators (oscillators) each. Usually, one oscillator in each channel modulates the frequency of the other. To simulate this, I've built up a chain of nodes for each channel:

Synth node chain (one of nine channels)

OPL2 channel as implemented

Node chain creation and connection code:

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
};

However, when I set the parameters of the modulator and carrier nodes (oscillator waveforms, relative frequencies, attenuation, ADSR parameters) and trigger notes, the output bears very little resemblance to a decent OPL2 emulator with approximately the same parameters. Some sounds are in the ballpark. Others are fairly unpleasant.

I have some ideas on how to proceed (I guess plotting the output at different stages would be a good starting point), but I'm hoping someone experienced can point me in the right direction, or point out something obviously wrong with what I'm doing. I don't have a signal-processing or strong mathematical background. I don't have a deep intuitive understanding of FM.

Some issues I suspect are:

1) My FM implementation (as shown above) is fundamentally wrong. Also, there may be an issue in the function where play a note (set the oscillator frequencies, and scale and offset the modulator before triggering the ADSR envelopes):

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) Output of FM synths may be highly sensitive to small differences in the shape of the modulator ADSR envelope (please tell me if this is true!), and my ADSR envelopes are crude approximations at best of the ADSRs in a real OPL2. My implementation is also missing some features which seem relatively unimportant (eg key scaling), but which may affect the sound of an FM synth significantly (again, I'm not sure).

bsa
  • 2,301
  • 17
  • 29
  • 4
    Looking your image, the modulator should be linked to carrier frequency and not gain (like this: https://en.wikipedia.org/wiki/Frequency_modulation#/media/File:Amfm3-en-de.gif ). – eri0o Sep 27 '15 at 18:10
  • Usually, you would want to be careful with the gain stage of the modulator and not apply too much gain and hence modulation. If the modulation is too large you get "unpleasant sounds" with the modulation dominating over the carrier. I am not sure this is what you describe. – noumenal Jan 13 '16 at 10:14
  • Elric, based on the diagram it certainly does look like the modulator is linked to gain. It's been so long since I worked on this or looked at Audiolet that I'm really not sure now if that's what's happening! I'll have a dig into it. – bsa Jan 15 '16 at 12:09
  • noumenal, I think you might be on the right path there. I'll see if I can resurrect it and see what happens with less gain on the modulator. – bsa Jan 15 '16 at 12:10

1 Answers1

1

Most synthesizers labled 'FM' in fact do phase modulation (PM, see https://en.wikipedia.org/wiki/Phase_modulation ). There are some benefits (mostly leading to more stable sound over a large tonal range). The OPL2 may use this too, I found no clear evidence, but the Wikipedia article also uses the term 'phase modulation'.

For short, many musical synthesizers labeled 'FM' in fact featured 'PM', so you might try go with that, and check if it better fits the expected OPL2 sounds.

From a quick glance to the Audiolet source, I would guess the Sine oscilator is doing true FM, so you may need to replace it and add a phase input to allow phase modulation.

Basically, the line

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

used by Sine of the carrier oscilator would have to read something like

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

with phase_offset controlled by the mod oscilator instead of the frequency.

dronus
  • 9,208
  • 8
  • 45
  • 72
  • The famous Yamaha DX7 keyboard, around at the same time by the same manufacturer as the OPL2, was labeled 'FM synthesis' despite using phase modulation too. – dronus Jan 13 '16 at 12:52
  • Thanks for the answer. You're right, the OPL does use phase modulation, and I thought that my implementation was doing "real" FM, but it's been so long since I looked at it I really can't say now :). My understanding was that for sine waves, phase modulation and frequency modulation are equivalent, so I though I could achieve a similar sound that way. – bsa Jan 15 '16 at 12:02
  • No, FM and PM are quite different beside sharing many properties. However, temporary frequency changes integrate over time for FM to add an permanent phase shift. On PM, a temporary modulation adds a temporary phase shift. – dronus Jan 15 '16 at 12:58
  • On a higher level, changing the modulation frequency in respect to the carrier frequency on FM changes the power distribution between the carrier and the side band frequencys, which make FM sounds change vastly over the tone range, eg. the instruments change their sound more perceivable depending on the pitch of the notes. The same effect is much softer for PM sounds, which makes the design process more controllable. – dronus Jan 15 '16 at 13:09