next up previous contents
Next: A simple tutorial of Up: SND Previous: Additive Synthesis on SND

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'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 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''.

    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 22050)        
    
    and you should get,

    
     		   6.2831850751536       
    
    which indeed is two pi.

    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.

  4. Frequency Increment Instrument

    A frequency increment instrument and other instruments inspired on Nicky Hind's tutorials will illustrate this issue on Snd's Scheme (you can copy and paste them directly on Snd's listener window):

    
     		 
    (define constant-freq-inc
           (lambda (beg dur frequency amplitude freq-inc)
             (let* ((start (floor (* beg (srate))))
                    (len (floor (* dur (srate))))
                    (sine-wave (make-oscil :frequency frequency))
                    (freq-inc-radians-per-sec (hz->radians freq-inc))
                    (output (make-vct len)))
               (do ((i 0 (1+ i)))
                   ((= i len))
                 (vct-set! output i (* amplitude (oscil sine-wave freq-inc-radians-per-sec ))
                           ))
               (vct->channel output start len ))))
    
    • First start by opening a new sound window on Snd:

      
       		 (new-sound "/zap/test.snd")        
      
    • Now you can try the following function calls on the constant-freq-inc instrument:

      • 
         		  (constant-freq-inc 0 1 440 0.3 0)       
        
        Will produce a single one second 440Hz sound.

      • 
         		  (constant-freq-inc 0 1 440 0.3 440)       
        
        Notice a frequency change of 440 which synthesizes a tone one octave higher than 440Hz at 880Hz.

      • 
         		  (constant-freq-inc 0 1 440 0.3 220)       
        
        Will produce a tone a fifth higher than 440Hz at 660Hz.

      • 
         		  (constant-freq-inc 0 1 440 0.3 -220)       
        
        A frequency change of -220 will produce a tone an octave lower than 440Hz at 220Hz.

  5. Sine-Wave Instrument with Enveloped Frequency-Increment

    
     		 
    (define enveloped-freq-inc
           (lambda* (beg dur frequency amplitude #:key (freq-inc 0))
             (let* ((start (floor (* beg (srate))))
                    (len (floor (* dur (srate))))
                    (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)
                                  :start beg
                                  :duration dur))
                    (output (make-vct len)))
               (do ((i 0 (1+ i)))
                   ((= i len))
                 (vct-set! output i (* amplitude (oscil sine-wave (env freq-env) ))
                           ))
               (vct->channel output start len ))))
    
    • Start by opening a new sound window on Snd if you don't already have one.

      
       		  (new-sound "/zap/test.snd")       
      
    • Now try the following function calls on the enveloped-freq-inc instrument:

      • 
         		  (enveloped-freq-inc 0 1 440 0.3)       
        
        Will produce a one second sound at 440Hz with no frequency increment.

      • 
         		 (enveloped-freq-inc 0 1 440 0.3 :freq-inc 440)        
        
        This call produces a glissando up to one octave higher and back again.

      • 
         		 (enveloped-freq-inc 0 1 440 0.3 :freq-inc -220)        
        
        This call produces a glissando down to one octave below and back again. Notice -220 frequency change.

    Following we have 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
           (lambda* (start dur freq amp #:key
                           (ampenv '(0 0 25 1 75 1 100 0))
                           (mratio 1) (index 1) (indenv '(0 1 100 1)))
                    ;;
                    (let* ((beg (floor (* start (srate))))
                           (end (floor (* dur (srate))))
                           (car (make-oscil :frequency freq))
                           (mod (make-oscil :frequency (* freq mratio)))
                           (ampf (make-env :envelope ampenv :scaler amp 
                                           :start start :end end))
                           (devf (make-env :envelope indenv 
                                           :scaler (in-hz (* freq mratio index)) 
                                           :start start :end end))
                           ;;
                           ;; Here we create a vector data structure to store
                           ;; the processed audio data
                           ;;
                           (out-data (make-vct end)))
                      ;;
                      ;; The part that follows is  like the Run loop in CLM
                      ;; or where the actual sound data is assigned to the
                      ;; out-data vector
                      ;;
                      (vct-map! out-data (lambda () 
                                           (* (env ampf) 
                                              (oscil car (* (env devf) 
                                                            (oscil mod))))
                                           ))
                      ;;
                      ;; This function outputs samples to the actice soundfile
                      ;; window in SND
                      ;;
                      (vct->channel out-data beg end ))
                    ))
    
    The function calls for this instrument are as follows:

    • Open a new sound:

      
       		 (new-sound "/zap/test.snd")        
      
    • A simple function call to the instrument with it default values:

      
       		 (simple-fm 0 3 400 0.5)        
      
      There is a carrier frequency of 400Hz and a sideband of 800Hz with 0.65 the value of the amplitude of the carrier. You can activate the FFT or (f) view of your Snd sound file to make sure these are the values of this spectra.

    • Changing the modulation-index to 0.75
      
       		 (simple-fm 0 3 400 0.5 :index 0.75)        
      
      Here we get a different spectrum with a carrier frequency at its maximum amplitude and a second sideband frequency which decreases 40% the value of the peak amplitude.

    • In the next function call we are manipulating the modulation index as well as C:M ratio. In this case we are using a C:M ratio of 4:1
      
       		 (simple-fm 0 3 400 0.5 :index 0.75 :mratio 4)        
      
      then we obtain sidebands on 100Hz with 0.95 amplitude and at 690Hz and the same 0.95 amplitude.

    • Now if we change both the modulation-index to 1.75 and the C:M ratio also to 4,

      
       		  (simple-fm 0 3 400 0.5 :index 1.75 :mratio 4)       
      
      here we get a fundamental frequency around 200Hz at the peak amplitude and average sidebands at 200Hz and 975Hz each one with an average amplitude of 0.925 the peak amplitude.

    • In this last example of function call we change the default modulation-index envelope to '(0 0.25 100 1.75) meaning that the value of the modulation index increases from 0.25 to 1.75 along the duration of the sound. Make sure to open the frequencies view or F-view on Snd's graphic interface to get a good look at the spectra of the sound. Move the sliders to see how the sound evolves.

      
       		  (simple-fm 0 3 400 0.5 :index 0.75 :mratio 4 :indenv '(0 0.25 100 1.75))         
      
      Notice that we get a changing spectra with an average carrier frequency of 400Hz.

    • You can always play an active sound window in Snd by using the (play) function call (you can always type ' C-x u ' to undo or erase the active sound you just created on Snd's editing window):

      
       		  (play)       
      

  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
           (lambda* (start dur freq amp #:key
                           (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 (floor (* start (srate))))
                           (end (floor (* dur (srate))))
                           (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 
                                           :start start :end end))
                           (devf (make-env :envelope indenv 
                                           :scaler (in-hz (* freq mratio index)) 
                                           :start start :end end))
                           (out-data (make-vct end)))
                      ;;
                      ;; Here we generate an out-data vector. 
                      ;; Notice the phase-mod part inside "oscil" which is
                      ;; incremented on each pass.This instrument is actually 
                      ;; doing Phase Modulation
                      ;;
                      (do ((i 0 (1+ i)))
                          ((= i end))
                        (vct-set! out-data i (* (env ampf) 
                                                (oscil car freq-mod (* (env devf)(oscil mod))))) )
                      ;;
                      ;; Output samples to the active soundfile window in SND
                      ;;
                      (vct->channel out-data beg end ))
                    ))
    
    The same function calls for the Phase Modulation instrument are:

    • Open a new sound:

      
       		 (new-sound "/zap/test.snd")        
      
    • A simple function call to the instrument with it default values:

      
       		 (simple-pm 0 3 400 0.5)        
      
      Notice the carrier frequency of 400Hz and a sideband of 800Hz with 0.65 the value of the amplitude of the carrier. You can activate the FFT or (f) view of your Snd sound file to make sure these are the values of this spectra.

      The other function calls which should match the FM instrument calls are as follows:

    • Changing the modulation-index to 0.75
      
       		 (simple-pm 0 3 400 0.5 :index 0.75)        
      
    • Manipulating the modulation index as well as C:M ratio.

      
       		 (simple-pm 0 3 400 0.5 :index 0.75 :mratio 4)        
      
    • Now if we change both the modulation-index to 1.75 and the C:M ratio also to 4,

      
       		  (simple-pm 0 3 400 0.5 :index 1.75 :mratio 4)       
      
    • In this last example of function call we change the default modulation-index envelope to '(0 0.25 100 1.75) meaning that the value of the modulation index increases from 0.25 to 1.75 along the duration of the sound.

      
       		  (simple-pm 0 3 400 0.5 :index 0.75 :mratio 4 :indenv '(0 0.25 100 1.75))         
      
      We should get a changing spectra with an average carrier frequency of 400Hz similar to the FM instrument. The reader is encouraged to check this out and compare spectra given by botd the FM PM instruments in addition to tweaking more of this parameters.

  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:

    • John Chowning. The synthesis of complex audio spectra by means of frequency modulation. Journal of the Audio Engineering Society, 7:pp:526-534, 1973.

    • William Schottstaedt. The simulation of natural instrument tones using frequency modulation with a complex modulating wave. Computer Music Journal, 1(4), 1977.

    • Barry Truax. Organizational techniques for c:m ratios in frequency modulation. Computer Music Journal, pages 39-45, 1978. Reprinted in Foundations of Computer Music, C. Roads and J. Strawn (eds.). MIT Press, 1985.

    • Dexter Morril. Trumpet algorithms for computer composition. Computer Music Journal, 1(1):46-52, 1977. Reprinted in Foundations of Computer Music, C. Roads and J. Strawn (eds.). MIT Press, 1985.

    • James Beauchamp. Letters to the editor: Will the real fm equation please stand up ? Computer Music Journal, 16(4), 1992.


next up previous contents
Next: A simple tutorial of Up: SND Previous: Additive Synthesis on SND

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