- //FMSynthesis.c
- //gcc MKAiff.c FMSynthesis.c -o FMSynthesis
- #include "MKAiff.h"
- #include <math.h>
- #define SAMPLE_RATE 44100
- #define NUM_CHANNELS 1
- #define BITS_PER_SAMPLE 16
- #define NUM_SECONDS 3
- const int numSamples = NUM_SECONDS * NUM_CHANNELS * SAMPLE_RATE;
- #define PI 3.141592653589793
- const double TWO_PI_OVER_SAMPLE_RATE = 2*PI/SAMPLE_RATE;
- int main()
- {
- MKAiff* aiff = aiffWithDurationInSeconds(NUM_CHANNELS, SAMPLE_RATE, BITS_PER_SAMPLE, NUM_SECONDS);
- if(aiff == NULL) return 0;
- float audioBuffer[numSamples];
- double carrierFrequency = 440, carrierAngle = 0;
- double frequencyRatio = 2, modulationIndex = 2;
- double modulatorFrequency = carrierFrequency * frequencyRatio, modulatorAngle = 0;
- double modulatorAmplitude = carrierFrequency * modulationIndex;
- int i;
- for(i=0; i<numSamples; i+=NUM_CHANNELS)
- {
- audioBuffer[i] = sin(carrierAngle);
- carrierAngle += (carrierFrequency + sin(modulatorAngle) * modulatorAmplitude) * TWO_PI_OVER_SAMPLE_RATE;
- modulatorAngle += modulatorFrequency * TWO_PI_OVER_SAMPLE_RATE;
- }
- aiffAppendFloatingPointSamples(aiff, audioBuffer, numSamples, aiffFloatSampleType);
- aiffSaveWithFilename(aiff, "FMSynthesis.aif");
- aiffDestroy(aiff);
- return 0;
- }
Output:
Explanation of the Concepts
FM Synthesis is a way of using frequency modulation to create new timbres. In the chapter on vibrato we modulated the frequency of an audio-rate sine wave by a sub-audio-rate sine wave. FM Synthesis is very similar, except here we will modulate frequency of an audio-rate sine wave by another audio-rate sine wave. In other words we will be making a vibrato that is so fast that its individual ups and downs are longer heard as vibrato, but it is heard as an actual audio wave. Furthermore, the depth of the vibrato, or the amplitude of the vibrato's sine wave, will generally be much greater for FM synthesis than for vibrato.
Aside from that, the only other difference between vibrato and FM synthesis is just terminology. What, in the vibrato example, was the 'audio wave' will now be called the 'carrier wave', and what was the sub-audio vibrato producing wave will now be called the 'modulator wave'. For illustration, if a carrier wave that looks like this:
is frequency modulated by a modulator wave that looks like this:
The result will be a frequency modulated sine wave that may look something like this:
For clarity, the three waves have been superimposed here, although a careful observer will notice that the amplitudes are not strictly to scale.
Here it can be seen that the resultant wave's frequency (yellow) is, on average, equal to the carrier wave's frequency (white), but it gets gradually faster and then gradually slower alternately, at a rate determined by the the frequency of the modulator wave (red). Since the modulator wave is now audio-rate, the ratio of its frequency to the frequency of the carrier now plays an important role in the timbre of the resultant sound. This will be discussed in detail in the next chapter. For now, however, it will suffice to notice that in the above program the, ratio of the modulator frequency to the carrier frequency is 2, meaning that the carrier wave is oscillating twice as fast as the carrier frequency. Notice that such is not the case in the illustration above, which was made for visual clarity rather than accuracy to the code.
It again needs to be stated that how far the frequency of the resultant wave deviates from the frequency of the carrier wave is determined by the amplitude of the modulator wave. This is easy to understand if you think of vibrato, where a modulator wave with a great amplitude causes a wide vibrato and an modulator wave with a small amplitude causes a narrow vibrato. In this example, the vibrato is very wide indeed: the amplitude of the modulator is 880, meaning that the carrier wave, whose nominal frequency is 440 Hz, is actually swinging between -440 Hz and 1320 Hz. The negative frequency need not be a matter of concern, as a negative value just represents a positive value whose phase has been shifted by 180 degrees.
Again, it is important to remember that since frequency is logarithmic with respect to perceived pitch, the amplitude of the modulator should be specified as a percent of the carrier wave's frequency, rather than just as a numeric constant. This ratio between the the carrier's frequency and the modulator's amplitude is an important determinant of timbre for FM Synthesis, and is called the 'index of modulation'. The specific relationship between the index of modulation and timbre will be discussed in detail in the 'Mod Index Sweep' chapter.
Explanation of the Code
This example is virtually identical to the 'Vibrato' example, although some of the variables have been renamed to reflect the change in terminology. 'frequency', for instance is now called 'carrierFrequency', and 'VibratoFrequency', is now called 'modulatorFrequency'.
The only other difference is that the frequency and amplitude of the modulator are now specified in terms of the carrier frequency. Line 22 specifies that the modulator frequency will be twice the carrier frequency (frequencyRatio), and the amplitude of the modulator will be twice the frequency of the carrier (modulationIndex). These multiplications are actually carried out on lines 24 and 25. This extra layer o fabstraction can be conceptually difficult. Here, however, it is easy to understand since none of the values change. In fact, the values could have all been computed as numeric constants without the extra layer of abstraction, but the utility of the current arrangement will become apparent in subsequent chapters.