audio MIDI Music Algorithms Interfaces Programming Acoustics Context
> Audio > Synthesis > Overtones and Harmonics    
 
   

Overtones and Harmonics

All partials identified by Fourier analysis (a decomposition of sounds into thier sine wave components) are referred to as overtones.
The overtones that have a frequency at a simple multiple of the fundamental (2:1, 3:1, 6:1 etc.) are referred to as harmonics,
and create 'nice' musical sounds.
Inharmonic overtones (frequencies not at simple multiples) create more clangerous timbres, such as bells and other percussion sounds.
In this example, inharmonic overtones are used to create a timpani-like sound.

Heres the audio file:

TimpaniTest.au [1377k]

Heres the code:

View / Download source - Instrument source code

View / Download source - Composition source code

Instrument class overview
 

import jm.audio.io.*;
import jm.audio.synth.*;
import jm.music.data.Note;
import jm.audio.Instrument;

/**
* A basic additive synthesis instrument implementation
* which implements envelope and volume control
* @author Andrew Sorensen and Andrew R. Brown
*/
public final class TimpaniInst extends Instrument{ //----------------------------------------------
// Attributes
//----------------------------------------------
private int overtones = 5; /** the relative frequencies which make up this note */ private double[] freqVals = {1.0, 1.42, 1.53, 1.77, 1.94}; /** the volumes to use for each frequency */ private double[] volVals = {1.0, 0.8, 0.7, 0.6, 0.5}; /** The points to use in the construction of Envelopes */ private double[][] points = new double[overtones][8]; private double[] pointArray1 = {0.0, 0.0, 0.002, 1.0, 0.3, 0.3, 1.0, 0.0}; private double[] pointArray2 = {0.0, 0.0, 0.05, 1.0, 0.2, 0.4, 1.0, 0.0}; private double[] pointArray3 = {0.0, 0.0, 0.1, 1.0, 0.4, 0.3, 1.0, 0.0}; /** Pan */ private float pan; /** The sample Rate to use */ private int sampleRate; /** The Oscillators to use for each frequency specified */ private Oscillator[] osc; /** The envelope to apply to each Oscillator's output */ private Envelope[] env; /** The volume to apply to each envelopes output */ private Volume[] vol; //----------------------------------------------
// Constructor
//----------------------------------------------
public TimpaniInst(int sampleRate){ this.sampleRate = sampleRate; // set up envelope points points[0] = pointArray1; points[1] = pointArray2; points[2] = pointArray3; points[3] = pointArray2; points[4] = pointArray3; } //----------------------------------------------
// Methods
//----------------------------------------------
/**
* Initialisation method is used to build the objects that
* this instrument will use
*/
public void createChain(){ //define the audio chain(s) osc = new Oscillator[overtones]; env = new Envelope[overtones]; vol = new Volume[overtones]; for(int i=0;i&t;overtones; i++){ osc[i] = new Oscillator(this, Oscillator.SINE_WAVE, this.sampleRate, 2); osc[i].setFrqRatio((float)freqVals[i]); env[i] = new Envelope(osc[i], points[i]); vol[i] = new Volume(env[i], (float)volVals[i]); } //And now the add object brings us back to one path. Add add = new Add(vol); StereoPan span = new StereoPan(add); SampleOut sout = new SampleOut(span); } }


Importantly, the oscillators are set to frequency ratios of the fundamental that are not simple multiples.
The specific rations are speciefied in this line:

    private double[] freqVals = {1.0, 1.42, 1.53, 1.77, 1.94};

As well, each overtone can have a different amplitude envelope creating a dynamic timbre that changes over time.
For example, the envelope points of the fundamental is specified in this line:

    private double[] pointArray1 = {0.0, 0.0, 0.002, 1.0, 0.3, 0.3, 1.0, 0.0};

One convient coding 'trick' in the createChain() method is to use a for-loop to create the chain for each overtone, then add them together after that.
This saves some repetition of similar code. Here is the relevant for loop:

    for(int i=0;i<overtones;i++){
            osc[i] = new Oscillator(this, Oscillator.SINE_WAVE,
                            this.sampleRate, 2);
            osc[i].setFrqRatio((float)freqVals[i]);
            env[i] = new Envelope(osc[i], points[i]);
            vol[i] = new Volume(env[i], (float)volVals[i]);
        }


Musical Example

import jm.JMC;
import jm.music.data.*;
import jm.audio.*;
import jm.util.*;

public final class TimpaniTest implements JMC{
public static void main(String[] args){
Score score = new Score("JMDemo - Audio test");
Part part = new Part("wave", 0);
Phrase phr = new Phrase(0.0);
int sampleRate = 44100;
Instrument inst = new TimpaniInst(sampleRate);
for (int i=0; i<8; i++ ) {
Note note = new Note(C3 - i, 1.0);
phr.addNote(note);
}
part.addPhrase(phr);
score.addPart(part);
Write.au(score, "TimpaniTest.au", inst);
}
}


This test code creates a descending chromatic run of eight notes in a low register, as would be typical of a timpani pitch.


Easy variation of the Additive Synthesis instrument

The lines of code below can be substituted in the Timpani instrument to create a mellow bell-like tone, not unlike a vibraphone.

    private int overtones = 3;
    private double[] freqVals = {1.0, 2.7, 6.75};
    private double[] volVals = {1.0, 0.77, 0.7};

View / Download source - Instrument source code

This shows how simply a different timbre can be created with additive synthesis by changing overtone values.


 

 

jMusic Australia Council Queensland University of Technology Sitemap Contact Home Home http://www.qut.com http://explodingart.com/jmusic http://www.ozco.gov.au

Digital Instrument making Home