Classic resonant filter

This tutorial will show you how to combine a low pass and band pass filter to create a 'resonant' low pass filter that is swept by an LFO. This is the most common subtractive filter type used in techno music.

Hear the result of this tutorial's music below.

ResonantLPF.mp3 [576 KB]

View / Download source - Instrument source code

View / Download source - Composition source code

Instrument

Here is the code:
import jm.audio.Instrument;
import jm.audio.io.*;
import jm.audio.synth.*;
import jm.music.data.Note;
import jm.audio.AudioObject;
 
/**
 * A  sawtooth waveform instrument implementation
 * which iincludes a low pass filter that is swept by
 * a three filters - two forming a band pass anf
 * one as the low pass.
 * @author Andrew Brown
 */
 
public final class ResSawInst extends Instrument{
	private int sampleRate;
        private int filterCutoff;
        private int channels;
 
	/**
	 * Basic default constructor to set an initial 
	 * sampling rate
	 * @param sampleRate 
	 */
	public ResSawInst (int sampleRate){
		this(sampleRate, 2500, 1);
	}
        
        /**
	 *  Constructor that sets sample rate and filter cutoff
         * @param sampleRate The number of samples per second (quality)
         * @param filterCutoff The frequency above which overtones are cut
         */
     public ResSawInst (int sampleRate, int filterCutoff){
		this(sampleRate, filterCutoff, 1);
	}
        
        /**
	 *  Constructor that sets sample rate cutoff and channels
         * @param sampleRate The number of samples per second (quality)
         * @param filterCutoff The frequency above which overtones are cut
         * @param channels 1 for Mono or 2 for Stereo
         */
        public ResSawInst (int sampleRate, int filterCutoff, int channels){
		this.sampleRate = sampleRate;
                this.filterCutoff = filterCutoff;
                this.channels = channels;
	}
 
	/**
	 * Initialisation method used to build the objects that
	 * this instrument will use and specify thier interconnections.
	 */
	public void createChain(){
		// filter mod source 1 
          Value modfreq = new Value(this, this.sampleRate, 1, (float)0.5);
          Oscillator sineMod = new Oscillator(modfreq, Oscillator.COSINE_WAVE, 
                    Oscillator.FREQUENCY);
          sineMod.setAmp((float) 2000.0);
          Oscillator wt = new Oscillator(this, Oscillator.SAWTOOTH_WAVE, 
                    this.sampleRate, this.channels);
          Filter filt = new Filter(new AudioObject[] {wt, sineMod}, 
                    this.filterCutoff, Filter.LOW_PASS);
          // filter mod source 2
          Value modfreq2 = new Value(this, this.sampleRate, 1, (float)0.5);
          Oscillator sineMod2 = new Oscillator(modfreq2, Oscillator.COSINE_WAVE, 
                    Oscillator.FREQUENCY);
          sineMod2.setAmp((float) 2000.0);
          Filter filt2 = new Filter(new AudioObject[] {filt, sineMod2}, 
                    this.filterCutoff, Filter.HIGH_PASS);
          Volume vol2 = new Volume(filt2, (float)10.0); // amount of resonance
          // filter mod source 3
          Value modfreq3 = new Value(this, this.sampleRate, 1, (float)0.5);
          Oscillator sineMod3 = new Oscillator(modfreq3, Oscillator.COSINE_WAVE, 
                    Oscillator.FREQUENCY);
          sineMod3.setAmp((float) 2000.0);
          Oscillator wt3 = new Oscillator(this, Oscillator.SAWTOOTH_WAVE, 
                    this.sampleRate, this.channels);
          Filter filt3 = new Filter(new AudioObject[] {wt3, sineMod3}, 
                    this.filterCutoff, Filter.LOW_PASS);
          Volume vol3 = new Volume(filt3);
          // add and pocess everythning
          Add add = new Add(new AudioObject[] {vol2, vol3}); 
          Envelope env = new Envelope(add, 
              new double[] {0.0, 0.0, 0.05, 1.0, 0.2, 0.4, 0.8, 0.3, 1.0, 0.0});
		StereoPan span = new StereoPan(env);
		SampleOut sout = new SampleOut(span);
	}	
}

More details to come.

 

Composition Example

More details to come.

import jm.music.data.*;
import jm.music.tools.*;
import jm.JMC;
import jm.audio.*;
import jm.util.*;
 
public class TextureLoops implements JMC {
	public static void main(String[] args) {
		new TextureLoops();
	}
	
	public TextureLoops() {
		Part part = new Part();
		Score score = new Score(part);
		
		// increase the texture over time
		for(int i = 0; i < 5; i++) {
			double currStageET = score.getEndTime();
			for (int j = 0; j < i+1; j++) {
				part.addPhrase(OnePhrase(currStageET, i));
			}
		} 
		
		// decrease the texture again
		for(int i = 4; i >= 0; i--) {
			double currStageET = score.getEndTime();
			for (int j = 0; j < i+1; j++) {
				part.addPhrase(OnePhrase(currStageET, i));
			}
		} 
		
		// add accents
		Mod.accents(score, 2.0, new double[] {0.0}, 40);
		
		// see the score
		View.show(score);
            
            // render as an audio file
		Instrument inst = new ResSawInst(11000);		
		Write.au(score, "TextureLoops.au", inst);
	}
	
	private Phrase OnePhrase(double startTime, int densityFactor) {
		double currentST = startTime - (int)(Math.random() * 12) * 0.25;
		if (currentST < 0.0) currentST = 0.0;
		Phrase phrase = new Phrase(currentST);
		double panPos = Math.random();
		// get a pitch
		int pitch = C4 + (int)(Math.random() * 12 * densityFactor - 6 *
			densityFactor);
		Note n = new Note(pitch, 1.0);
            while (!n.isScale(PENTATONIC_SCALE)) {
                  n = new Note(pitch, 1.0);
                  pitch = C2 + (int)(Math.random() * 36);
            }
		for(int i =0; i < 24 ; i++) {
            	Note note = new Note(pitch, 
                  			DEMI_SEMI_QUAVER * (int)(Math.random() * 
								(1.5 * densityFactor) + 1), 
                  			(int)(Math.random() * 80) + 47);
                 	note.setPan(panPos);
            	phrase.addNote(note);
		}
		return phrase;
	}
}


jMusic Tutorial Index

© 2001 Andrew Brown