Skip to content

Instantly share code, notes, and snippets.

@jrmoserbaltimore
Last active April 20, 2024 02:42
Show Gist options
  • Save jrmoserbaltimore/68049858f0ab5fee9eddcb6de663ddf2 to your computer and use it in GitHub Desktop.
Save jrmoserbaltimore/68049858f0ab5fee9eddcb6de663ddf2 to your computer and use it in GitHub Desktop.
Step-by-step FM synthesis explanation

An attempt to explain step-by-step how FM synthesis calculation works.

OPL3

Using the OPL3 as an example, there are several components:

  • Vibrato feeds into the phase generator (PG) to modulate its frequency
  • Tremolo feeds into the envelope generator (EG) to modulate its amplitude
  • PG and EG feed into the operator
  • Operator outputs to the next operator

Within the operator, the input—either nothing or the prior FM operator's output—is combined with the PG signal and any feedback. The result goes into a sine function and is multiplied by the EG's amplitude.

This is very confusing.

Yamaha writes this as A×sin(ωc[t]+B×sin(ωm[t])), with A being the carrier amplitude, ωc being the angular frequency of the carrier (phase generator), B being the modulator amplitude, and ωm being the angular frequency of the modulator. The modulator is the first operator, which feeds into the carrier: the carrier produces a signal (carrier signal), modulating it by the signal provided by the modulator.

…This is very confusing.

To understand FM synthesis, we'll just carry it out step by step for the OPL3.

logsin and exponent tables

The OPL3 uses two look-up tables, each containing 256 entries.

The exponent table exp[] is calculated by f(x)=round((power(2, x/256)-1)×1024) for x from 0 to 255. Given a value, the significand is calculated by exp[8 LSB] + 1024, and the exponent is the remaining MSBs, producing a floating-point value. Ten bits of exponent are required to represent all values in the table, the largest being 1,018.

The logsin table logsin[] is calculated by f(x)=round(-log(sin((x+0.5)*pi/512))/log(2)*256) for x from 0 to 255. It requires 12 bits to represent all values (largest is 2,137) and represents the first rising quarter of a sine wave.

Waveforms

The OPL3 provides 8 waveforms for the phase generator:

  • Sine: Sine[0:255] traversed forward/backward and inverted
  • Half-sine: Sine[0:255], Sine[255:0], toggle output to be table or 0 each time index=0
  • Abs-sine: Sine[0:255] is traversed forward/backward but not inverted
  • Pulse-sine: lookup table is Sine[0:255], toggle between table and 0 at overflow
  • Even-Sine: Sine[], toggle between table and 0 each full period
  • Even-abs-sine: Even-sine without inversion
  • Square: Literally just the sign of the sine wave.
  • Derived square: ?

Output

The OPL3 decapsulation project says output is generated as exp[logsin[phase2 + exp[logsin[phase1] + gain1]] + gain2] which is mysterious and terrifying. This is the equation exp[logsin[ωc + exp[logsin[ωm] + B]] + A].

How does that even work?

https://github.com/gtaylormb/opl3_fpga/blob/master/docs/opl3math/opl3math.pdf

A×sin(x) is equivalent to e(ln(a) + ln(sin(x))), hence the entry in exp[] is the addition of an entry in logsin[] and some figure by which the logsin[] entry is multiplied.

This implies B and A must be log of the envelope.

So how do we pass from one operator to the next?

Op1out = exp[logsin[phase1 + Op1in] + gain1]

Op2out = exp[logsin[phase2 + Op2in] + gain2]

Op1in is silence or feedback; Op2in is silence or Op1out. That makes the general formula exp[logsin[ω + Input] + EG]], where EG is the log of the envelope (log(A), note logsin[A] is log(sin(A)) and is different).

Envelope generator

I have no idea? Need to know exactly how the EG, PG, and vibrato come up with their exact values to get the inputs to the equations above.

https://ayce.dev/emptyx16.html

https://github.com/gtaylormb/opl3_fpga/blob/master/docs/opl3math/opl3math.pdf

http://map.grauw.nl/resources/sound/yamaha_opl4.pdf

@jrmoserbaltimore
Copy link
Author

It's simple enough. A and B are the gain values (loudness), omega is the angular frequency (Hz), and c[t] and m[t] are the phase of the oscillator at the given time (as a function of time). The big part is the adding of the modulator's amplified output to the phase of the carrier. This is only FM when the modulator is a sine wave itself; this is technically phase modulation.

Look up the datasheet for the OPL3 and OPL4, they have a diagram of the FM carrier-operator relationship in there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment