I've played with some simple FM synthesis, and reworked the PlaySynthMusic example to use it,
as well as trying to declutter all the toplevel boilerplate so it can be parameterized by a number of voices.
The way I've addressed this is to bundle all the apparatus for a voice into a class, 3 oscillators and an
envelope, like this:
The whole reworked example is attached as a zip - I'd recommend finding something less annoying as the example
data than the William Tell overture (I found a midi file of Bach's Tocatta / Fugue in D-minor, which can be listened too
repeatedly without going crazy! - and put it through miditones, but it was copyright so didn't include it here alas).
The FM parameters I found after a little tinkering sound fairly organ-like and are pretty funky on the 'scope!

Comments welcome - the topic of how to structure audio components hierarchically is relevant, found a few comments
about this in a search on teensy FM synthesis.
BTW this is on Teensy 4.0 with 150MHz clock, about 22% audio CPU for 16 voices which is pretty reasonable...
It was quite fun to play with FM synthesis for the first time
[ I was partly inspired by reading this https://cs.gmu.edu/~sean/book/synthesis/Synthesis.pdf ]
as well as trying to declutter all the toplevel boilerplate so it can be parameterized by a number of voices.
The way I've addressed this is to bundle all the apparatus for a voice into a class, 3 oscillators and an
envelope, like this:
Code:
// Implement an FM voice, 3 stages in the algorithm in sequence, plus the envelope
class FMVoice
{
public:
FMVoice ()
{
new AudioConnection (modulator, 0, middle, 0) ; // on heap so destructors not called when this
new AudioConnection (middle, 0, finalosc, 0) ; // constructor exits!
new AudioConnection (finalosc, 0, env, 0) ;
}
AudioEffectEnvelope & output (void) // need this to connect up and to set envelope parameters
{
return env ;
}
// depth1 is modulation depth applied to middle,
// depth2 is modulation depth applied to final
// f2 and f3 are multipliers for fundamental used in middle and modulator respectively, small integers
void noteOn (float amp, float freq, float depth1, float depth2, int f2, int f3)
{
AudioNoInterrupts() ;
modulator.frequency (f3 * freq) ; // modulator is lowly sine wave generator, no begin method...
modulator.amplitude (depth1) ;
middle.phaseModulation (180) ; // mid range so no discontinuities
middle.begin (depth2, f2 * freq, WAVEFORM_SINE) ;
finalosc.phaseModulation (180) ; // mid range so no discontinuities
finalosc.begin (amp, freq, WAVEFORM_SINE) ;
env.noteOn () ;
AudioInterrupts () ;
}
void noteOff (void)
{
env.noteOff() ;
}
bool isActive (void)
{
return env.isActive() ;
}
void silence () // save cycles when the envelope has finished releasing
{
finalosc.amplitude (0) ;
middle.amplitude (0) ;
modulator.amplitude (0) ;
}
protected:
AudioSynthWaveformSine modulator ;
AudioSynthWaveformModulated middle ;
AudioSynthWaveformModulated finalosc ;
AudioEffectEnvelope env ;
};
The whole reworked example is attached as a zip - I'd recommend finding something less annoying as the example
data than the William Tell overture (I found a midi file of Bach's Tocatta / Fugue in D-minor, which can be listened too
repeatedly without going crazy! - and put it through miditones, but it was copyright so didn't include it here alas).
The FM parameters I found after a little tinkering sound fairly organ-like and are pretty funky on the 'scope!

Comments welcome - the topic of how to structure audio components hierarchically is relevant, found a few comments
about this in a search on teensy FM synthesis.
BTW this is on Teensy 4.0 with 150MHz clock, about 22% audio CPU for 16 voices which is pretty reasonable...
It was quite fun to play with FM synthesis for the first time
[ I was partly inspired by reading this https://cs.gmu.edu/~sean/book/synthesis/Synthesis.pdf ]