FM synthesis on SND

  1. Description:

    Frequency Modulation (or FM) synthesis was discovered and introduced by John Chowning at Stanford around 1973. FM is one of the pillars of CCRMA and was the underlying technology for a very successful synthesizer manufactured by Yamaha and known as the DX-7 during the 1980's. Many of its trademark sounds are still a novel but in the past FM has been an efficient and simple method for generating and simulating complex textures as the vibrato of the singing voice. FM at its core is a simple and powerful method for creating and controlling complex spectra and is also categorized as a worshiping method of audio synthesis. In its simplest form it involves a sine wave carrier whose instantaneous frequency is modulated according to another waveform called the modulator. If the mean frequency of the modulator reaches as high as audio frequency range, sidebands appear as partials of the new modulated sound. This model then is often called simple FM or sine-wave FM. Other forms of FM are extensions of the basic model.

    The position of each sideband is a function of the carrier modulator ratio or C:M ratio, and its number and amplitude change as function of the amplitude of the modulator or depth of the modulation. While the precise relationship between the sidebands, the c:m ratio and the amplitude of the modulator (better known as modulation index) is determined by the use of Bessel functions, it is common practice to say that the number of sidebands produced on either side of the carrier equals to the modulation index plus 2.

  2. Implementation:

    FM synthesis is done by means of signal generators. In Snd oscil is Bill Shottstaedt's basic and outstanding signal generator among a very vast array of other generators. Bill's description of a signal generator is as follows:

    “A generator is a function that returns the next sample in an infinite stream of samples each time it is called. An oscillator, for example, returns an endless sine wave, one sample at a time”.

    For more on signal generators see Dick Moore's: Elements of Computer Music or Charles Dodge and T. Jerse's: Computer Music.

    “Furthermore each generator is made of a set of functions: Make-[gen] sets up the data structure associated with the generator at initialization time; [gen] produces a new sample; [gen?] checks whether a variable is that kind of generator”.

    [gen] is the name of a generator like oscil therefore make-oscil sets up a data structure (interpolation values) at initialization time. Then oscil produces a new sample in an stream of samples inside a loop which repeats itself the duration of the desired sound in seconds times the current sampling-rate.

    “The initialization function normally takes a number of optional arguments, setting whatever state the given generator needs to operate on. The run-time (loop) function's first argument is always its associated structure. Its second argument is nearly always something like an FM input, whatever run-time modulation might be desired; in other cases it can be a function to provide input data or editing operations. Amplitude envelopes are handled with a separate env generator. Frequency sweeps of all kinds (vibrato, glissando, breath noise, FM proper) are all forms of run-time frequency modulation”.

    In Snd's s7's scheme the initialization function might be something like:


    (sine-wave (make-oscil :frequency frequency))

    where frequency is in Hz or cycles per second (cps). There is an optional parameter to this function which is initial-phase or the initial angle of phase for the oscillator (oscil uses the Sine function for sine wave generation). The run-time (loop) function might look like:

    (oscil sine-wave )

    or using the optional parameters a more complex Oscil function call with vibrato, glissando and frequency modulation value looks like:

    (oscil sine-wave (+ vibrato glissando frequency-modulation))

    The Oscil signal generator definition in Snd is:

    “oscil produces a sine wave (using sin) with optional frequency change (i.e. fm). Its first argument is an oscil created by make-oscil. Oscil's second (optional) argument is the current (sample-wise) frequency change (it defaults to 0). The optional third argument is the (sample-wise) phase change (in addition to the carrier increment and so on). So the second argument can be viewed as FM, while the third is PM (phase modulation). The initial-phase argument to make-oscil is in radians. You can use degrees->radians to convert from degrees to radians. To get a cosine (as opposed to sin), set the initial-phase to (/ pi 2)”.

    As can be seen a simple signal generator like Oscil can be used for Frequency Modulation and its closely related cousin Phase Modulation.

    The terms Frequency Modulation (FM) and Phase Modulation (PM) are source of some confusion and ambiguities. The main source of the diverging paths taken by FM implementers can be traced to a discrepancy between the standard analytical FM formula cited above and “Music-V” implementation which have appeared in most texts on the subject. As to this issue Bill Schottstaedt points out: “The difference is that FM integrates, whereas PM does not. – this does not make up any difference in computational speed, or musical results”.

    A better explanation in FM.html should clear this confussion:

    “The terms "angle modulation", "phase modulation", and "frequency modulation" (not to mention "exponential modulation" and "angular modulation") are used almost interchangeably in the radio literature, but the textbooks on the subject normally distinguish between PM and FM as follows: if f(t) is directly proportional to the modulating signal then it's PM; if f(t) is directly proportional to the derivative of the modulating signal, then it's FM. Of course, you can't tell which is in use either from the waveform or the mathematical expression of the waveform – you have to know what the modulating signal was. That is a roundabout way of saying that in computer music applications there is no essential difference between frequency and phase modulation. However, the fact that phase and frequency modulation are just two ways of interpreting the same thing should not mislead us into thinking "phase doesn't matter" – the initial phases of the parts of the FM formula do make a difference, as we'll see below”.

    As a benefit for the reader, this tutorial shows “both” an instrument doing simple FM and another doing simple PM. The reader should listen for any audible or perceptual differences.

  3. Frequency Increment (Frequency change parameter)

    In order to understand some of the details in Frequency Modulation it is important to understand the notion of frequency increment. Frequency increment is expressed in terms of radians per second (RPS). In the case of vibrato, or FM or any time we need to specify values to the optional 2nd argument of some oscillator, it is necessary to deal explicitly in RPS. The Snd scheme function hz->radians converts converts frequencies expressed in cycles per second “Hz” to frequencies expressed in radians per second over the actual sampling rate.

    Since we know there are 2 pi radians in one cycle and if we know Snd's sampling rate is 22050 therefore, if we want to express this rate in terms of radians per second, the result should be also equal to 2 pi. To make sure this is true you can try typing the following command on Snd's listener window,

    (hz->radians 48000)

    and you should get,

    6.2831850751536

    which indeed is twopi. If you don't get twopi, you are working with other sampling frequency on Snd. You might find your sampling frequency by simply issuing,


    (seconds->samples 1)

    This also means that the radian frequency of half the sampling rate is pi, the radian frequency of 1/4 the sampling rate or quarter cycle is pi over two and so on.

    - Several years ago composer Nicky Hind wrote a series of tutorials for composers to get around CLM (Common Lisp Music) on NeXT machines at CCRMA. CLM is Snd predecessor and still being used by some composers because of Lisp code and perhaps some easiness in contrast with other languages. Among those tutorials is a two-part FM Synthesis tutorial here.Most of his examples can be translated into Snd with few differences, most notably CLM's “RUN” loop. Below we are borrowing his code and paraphrasing some of his indications.

  4. Frequency Increment Instrument

    A frequency increment instrument and other instruments illustrate this issue on Snd's s7's Scheme. (you can copy and paste them directly on Snd's listener window or better to Emacs or your favorite editor then save as “fm.cms”.

    
     		 
    (define (constant-freq-inc beg dur frequency amplitude freq-inc)
      (let* ((start (seconds->samples beg))	
    	 (len (seconds->samples (+ beg dur)))		
             (sine-wave (make-oscil :frequency frequency))
             (freq-inc-radians-per-sec (hz->radians freq-inc))
    	 )
        (do ((i start (1+ i)))
            ((= i len))
          (outa i (* amplitude (oscil sine-wave freq-inc-radians-per-sec ))
                           )) ))
    


  5. Sine-Wave Instrument with Enveloped Frequency-Increment

    
     		 
    (define* (enveloped-freq-inc beg dur frequency amplitude (freq-inc 0))
      (let* ((start (seconds->samples beg))	
    	 (len (seconds->samples (+ beg dur)))
             (freq-inc-func '(0 0  50 1  100 0))
             (sine-wave (make-oscil :frequency frequency))
             (freq-env (make-env :envelope freq-inc-func
                                 :scaler (hz->radians freq-inc)
                                   :duration dur)) )
        (do ((i start (1+ i)))
                   ((= i len))
                 (outa i (* amplitude (oscil sine-wave (env freq-env) ))
                           )) ))
    


    Following we have s7 Scheme code for a very simple FM instrument which can be used as a template for more complex instruments, and in fact more complex projects in Snd. Notice that make-oscil and make-env are the definitions for the the signal generators oscil and env respectively. Here we are creating two oscillators for the carrier and modulator plus one amplitude envelope and a modulation-index envelopes which changes as sound unfolds.


  6. Simple FM Instrument

    
     		 
    (define*  (simple-fm  start-time duration freq amp
    	       (ampenv '(0 0 25 1 75 1 100 0))
    	       (mratio 1) (index 1) (indenv '(0 1 100 1)))
      ;;
      (let* ((beg (seconds->samples start-time))
    	 (end (seconds->samples (+ start-time duration)))
    	 (car (make-oscil :frequency freq))
    	 (mod (make-oscil :frequency (* freq mratio)))
    	 (ampf (make-env :envelope ampenv :scaler amp 
    			 :duration duration))
    	 (devf (make-env :envelope indenv 
    			 :scaler (radians->hz (* freq mratio index)) 
    			 :duration duration)) )
        ;;
        
        (do ((i beg (1+ i)))
    	((= i end))
          (outa i (* (env ampf) 
    		 (oscil car (* (env devf) 
    			       (oscil mod))))) )
        ))
    

    The function calls for this instrument are as follows:

  7. Simple Phase Modulation Instrument

    As previously discussed if f(t) is directly proportional to the modulating signal then we have Phase Modulation. If f(t) is directly proportional to the derivative of the modulating signal, then we have Frequency Modulation or FM. This means that difference between PM and FM lies in that FM integrates, whereas PM does not. This does not mean that there is any difference in computational speed, musical or perceptual results. Snd provides tools to check this analytically with its spectrogram windows which can be dragged to change with time. Here we have a simple “Phase Modulation” instrument. Notice the modulating frequency at oscil's fourth parameter.

    
     		 
    (define* (simple-pm start-time duration freq amp 
                       (ampenv '(0 0 25 1 75 1 100 0))
                       (mratio 1) (index 1) (indenv '(0 1 100 1))
                       (fmp-inc 0.0)) ;; FM phase increment
      ;;
      (let* ((beg (seconds->samples start-time))
    	 (end (seconds->samples (+ start-time duration)))
             (freq-mod (hz->radians fmp-inc))
             (phase-mod 0.00)
             (car (make-oscil :frequency freq))
             (mod (make-oscil :frequency (* freq mratio)))
             (ampf (make-env :envelope ampenv
    			 :scaler amp 
    			 :end end))
             (devf (make-env :envelope indenv 
                             :scaler (radians->hz (* freq mratio index)) 
    			 :end end)) )
        ;;
        ;;   Notice below that the "phase-mod" part inside "oscil" is
        ;;   incremented on each pass. This means "oscil" is actually 
        ;;   doing "Phase Modulation".
        ;;
        
        (do ((i beg (1+ i)))
            ((= i end))
          (outa i (* (env ampf) 
                     (oscil car freq-mod (* (env devf)(oscil mod))))
    	    ))))
    

    Function calls for the Phase Modulation instrument are:

  8. Conclusion

    Synthesis of audio by means of Frequency Modulation and its relatives is still a powerful method for generating complex spectra. Many instruments using this principle as a basis have been developed and include violins, trumpets, plucked strings as well as bells, gongs, drums and more. As John Chowning points out, the richness of FM lies in the ability to manipulate on the time domain the spectrum of a sound. We have seen that this can be easily accomplished by using envelope generators which control the modulation-index over time.

  9. Further information:

© Copyright 2001-2022 CCRMA, Stanford University. All rights reserved.
Created and Mantained by Juan Reyes