In the book “the computer music tutorial” by Curtis Roads, there is the formula for the modulation index:

I = D / M

with D being the amount of frequency deviation from the carrier frequency, and M being the modulator frequency. So I understand this as in the following example:

the deviation from the carrier frequency is 100 Hz, resulting in a modulation index of 200.
The book states that as a rule of thumb the number of significant sideband pairs is I + 1.

In the above example however, I can’t hear or see (FreqScope) any sidebands at all, there is only the carrier frequency vibrating 100 Hz above and below it’s center frequency (and I was not expecting any thing else!). According to Curtis Roads’ formula (page 229), there should exist 101 sidebands?

I have the book, but it’s an ebook, so my page numbers don’t line up, but you can’t hear sidebands because your modulator isn’t audio rate. It’s an ‘ar’ ugen, but by audio rate I mean a signal within 20-20K hz sounds. What you have is just a very long, dramatic pitch shift.

Your modulator frequency is only 1 hz, which produces the slow vibrato that you hear. In order to get side bands, you need a modulator frequency greater than 20 hz or so. Here’s an alteration to your code to demonstrate the effect:

Ok, let’s start with a case of f_c = 100, f_m = 100, modulation width = 100. Then the index = 1 and you’d expect 2 sidebands.

Drop f_m to 50 Hz, keeping the same width. Now index = 2 and you’d expect 3 sidebands.

Now drop f_m to 0 Hz. Now the modulator is not moving at all, so you will get a fixed frequency (though possibly not f_c). The index is 100/0 = infinity. So… infinite sidebands? But clearly that’s not happening with the 0 Hz modulator. (I guess one could say that all energy has been transferred away from the carrier frequency and this is an infinite ratio of some kind, but the result will decidedly not contain an infinite number of sidebands.)

So, somewhere between f_m = 100 and f_m = 0, the sidebands break down and change into simple vibrato (and even that slows to a standstill.)

The question seems to assume that the effect of FM, on the spectrum and on our perception of the timbre, is the same with all possible inputs. But this thought experiment shows that this can’t be true.

Another fun way to look at it – in the original example, the ratio between the modulator frequency and the carrier frequency is 0.01.

Since the modulation index decreases inversely relative to the modulator frequency, then increasing the carrier and modulator frequencies proportionally would lower the modulation index. So we can raise the modulator width proportionally and keep the same modulation index.

(
f = { |f_car = 100, dur = 1|
{
var modRatio = 0.01;
var modWidth = f_car; // index always = 1/modRatio
var f_mod = f_car * modRatio;
SinOsc.ar(
f_car + (modWidth * SinOsc.ar(f_mod))
)
}.plot(duration: dur);
};
)
// Original example
f.(100, 1);
// Original example, 50 times faster
f.(5000, 1/50);

In both cases, the modulation yields the same wave shape, just on a different timescale. But the perceptual effect of 50 Hz modulation versus 1 Hz modulation will be totally different.

I don’t have the math to develop it, but I suspect, if you have a lot of closely-spaced sidebands (100 Hz, 100+/-1, 100+/-2 etc.) that they would reinforce and cancel out in a way that produces the effect of a slowly changing frequency. Compare to Auditory illusion with exponentially-spaced frequencies where a sum of closely-spaced, fixed-frequency sine waves sounds entirely convincingly like downward frequency sweeps. At higher modulator and carrier frequencies, the sidebands are not so tightly spaced and the spectral effect is very different.

When you follow the literature the deviation for FM is defined as dev = modFreq * index and not as dev = carFreq * index.

this looks like this for FM:

( /// FM
{
var carFreq = 100;
var fmRatio = 2;
var modFreq = carFreq * fmRatio;
var fmIndex = 2;
var fmod = SinOsc.ar(modFreq);
SinOsc.ar(carFreq + (modFreq * fmod * fmIndex));
}.plot(0.01);
)

and for PM like this:

( // PM
{
var carFreq = 100;
var pmRatio = 2;
var modFreq = carFreq * pmRatio;
var pmIndex = 2;
var phi = ((1 - SinOsc.ar(modFreq, 0.5pi)) * pmIndex).mod(2pi);
SinOsc.ar(carFreq, phi);
}.plot(0.01);
)

But if you look at this video where the difference between FM and PM is explained its also stated that dev = carFreq * index is true to make FM behave like PM instead of dev = modFreq * index, which is really confusing me.

I also think there is a difference between waveforms and the spectrum, even if the waveforms look different they might create the same spectrum.