Minim
core | ugens | analysis
 

WaveShaper

Fields

Methods

A UGen which provides waveshaping distortion. The incoming "audio" signal is used as an index to a Waveform containing a "mapping" function and the output of the waveshaper is the value in the Waveform given by the index. The incoming wave is expected to have values between -1 and 1 although exceeding this range can be used expressively. The input signal is then normalized so that -1 to 1 becomes 0 and 1 to provide the index value. The output waveshape is then multiplied by an output amplitude. A library of shapes is defined, that the user can call. The shapes are Wavetables, which can be used in a creative way (using waveforms from the Waves library for example).

Constructors

Constructor for WaveShaper. 
 
 mapWrap, a boolean flag to wrap the map
 around the ends instead of hitting the edge, defaults to false.
WaveShaper(float outAmp, float mapAmp, Waveform mapShape)
Constructor for WaveShaper.
WaveShaper(float outAmp, float mapAmp, Waveform mapShape, boolean wrapMap)

Parameters

outAmp — float: the output amplitude multiplier of the shaped wave
mapAmp — float: amplitude over which to map the incoming signal
mapShape — Waveform: waveshape over which to map the incoming signal
wrapMap — boolean: flag to wrap the map instead of hit the edge and stick

Related

Waves
Wavetable
UGen

Example

/* waveShaperExample<br/>
   is an example of using the WaveShaper UGen inside an instrument.
   <p>
   For more information about Minim and additional features, 
   visit http://code.compartmental.net/minim/
   <p>   
   author: Damien Di Fede, Anderson Mills<br/>
   Anderson Mills's work was supported by numediart (www.numediart.org).
*/

import ddf.minim.*;
import ddf.minim.ugens.*;
import ddf.minim.effects.*; // for BandPass

Minim minim;
AudioOutput out;

// setup is run once at the beginning
void setup()
{
  // initialize the drawing window
  size( 512, 200, P2D );
  
  // initialize the minim and out objects
  minim = new Minim( this );
  out = minim.getLineOut( Minim.MONO, 2048 );
  
  // pause time when adding a bunch of notes at once
  out.pauseNotes();

  // one can set the tempo of the piece in beats per minute, too
  out.setTempo( 120f );
  
  // our chik sounds won't overlap, so we can reuse the same instance
  ChikInstrument chik = new ChikInstrument( out );
  float chikDur = 0.1f;
  
  float shaperAmp = 0.5f;
  // let's do a few repeats of this pattern
  for(int i = 0; i < 4; i++)
  {
    // first set the note offset so we put notes in the right measure
    out.setNoteOffset( i * 8 );
    
    // and now notes!
    out.playNote( 0.f, chikDur, chik );
    out.playNote( 0.f, 1.0f, new WaveShaperInstrument( Frequency.ofPitch("C2").asHz(), shaperAmp, out ) );
    out.playNote( 1.f, chikDur, chik );
    out.playNote( 2.f, chikDur, chik );
    out.playNote( 3.f, chikDur, chik );
    
    out.playNote( 4.f, 1.0f, new WaveShaperInstrument( Frequency.ofPitch("C2").asHz(), shaperAmp, out ) );
    out.playNote( 4.f, chikDur, chik );
    out.playNote( 5.f, chikDur, chik );
    out.playNote( 5.5f, 1.0f, new WaveShaperInstrument( Frequency.ofPitch("Eb2").asHz(), shaperAmp, out ) );
    out.playNote( 6.f, chikDur, chik );
    out.playNote( 7.f, chikDur, chik );
    out.playNote( 7.f, 1.0f, new WaveShaperInstrument( Frequency.ofPitch("Eb2").asHz(), shaperAmp, out ) );
  }
  // one last hit!
  out.playNote( 8.f, chikDur, chik );
  out.playNote( 8.f, 8.0f, new WaveShaperInstrument( Frequency.ofPitch("C1").asHz(), shaperAmp, out ) );
  
  // resume notes after you enter a bunch
  out.resumeNotes();
  
}

// draw is run many times
void draw()
{
  // erase the window to black
  background( 0 );
  // draw using a white stroke
  stroke( 255 );
  // draw the waveforms
  for( int i = 0; i < out.bufferSize() - 1; i++ )
  {
    // find the x position of each buffer value
    float x1  =  map( i, 0, out.bufferSize(), 0, width );
    float x2  =  map( i+1, 0, out.bufferSize(), 0, width );
    // draw a line from one buffer position to the next for both channels
    line( x1, 50  - out.left.get(i)*50,  x2, 50  - out.left.get(i+1)*50);
    line( x1, 150 - out.right.get(i)*50, x2, 150 - out.right.get(i+1)*50);
  }  
}

// this ChikInstrument will make a "chik" sound
class ChikInstrument implements Instrument
{
  // to make a chik sound we'll just filter some noise
  Noise noize;
  BandPass bpFilt;
  AudioOutput out;
  
  ChikInstrument( AudioOutput output )
  {
    out = output;
    
    // amplitude and noise tint
    noize = new Noise( 1.f, Noise.Tint.WHITE);
    
    // make a bandpass with center frequency of 400Hz, bandwidth of 20Hz and sample rate of 44100.
    bpFilt = new BandPass( 1000.f, 200.f, 44100.f );
    
    // patch the noise through the filter
    noize.patch( bpFilt );
  }
  
  // called by the note manager when this instrument should play
  void noteOn(float dur)
  {
    bpFilt.patch(out);
  }
  
  // called by the note manager when this instrument should stop playing
  void noteOff()
  {
    bpFilt.unpatch(out);
  }
}

// this instrument uses a WaveShaper to shape an Oscil
// over time.
class WaveShaperInstrument implements Instrument
{
  // our tone
  Oscil sineOsc;
  // what we'll shape our oscil with
  WaveShaper shaper;
  // a line to change the amount of shaping over time
  Line shaperAmountLine;
  // and a reciprocal to change the output amplitude over time
  Reciprocal reciprocal;
  
  AudioOutput out;

  WaveShaperInstrument(float frequency, float amplitude, AudioOutput output)
  {
    out = output;
    sineOsc = new Oscil(frequency, amplitude, Waves.SINE);
    // We've created three different waves to shape the sine with.  Just uncomment
    // one of the "shaper =" lines to hear the different waves.
    // The first is a modified saw wave.  We made this while we were experimenting
    // with the WaveShaper and liked it, so it remains.
    Wavetable shapeA = new Wavetable( Waves.SAW );
    shapeA.set(0, -1.0);
    shapeA.set(shapeA.size()-1, 1.0);
    // The second argument in WaveShaper
    // is the amount of shaping to be applied, which in our case doesn't 
    // really matter because we are going to drive that with a Line.
    shaper = new WaveShaper(amplitude, 5, shapeA);
    
    // If we want to shape the sine with a saw wave... 
    //shaper = new WaveShaper( amplitude, 5, Waves.SAW );
    
    // We can choose to wrap around the ends of the waveshaping map for interesting
    // effects, and one does this by setting the fourth argument to true.
    //shaper = new WaveShaper( amplitude, 5, Waves.SAW, true );
    
    shaperAmountLine = new Line(5.f, 1.f, 25.f);
    reciprocal = new Reciprocal();
   
    // patch the line into the mapAmplitude of the WaveShaper
    shaperAmountLine.patch( shaper.mapAmplitude );
    // Patch the reciprocal of the line into the outAmplitude.
    // Since the line goes from 1 to 25, the reciprocal goes from 1/1 to 1/25.
    // This creates a pretty good approximation of a drum envelope.
    shaperAmountLine.patch( reciprocal ).patch( shaper.outAmplitude );
    sineOsc.patch( shaper );
  }
 
  void noteOn(float dur)
  {
    // set our line time based on duration
    shaperAmountLine.setLineTime( dur );
    shaperAmountLine.activate();
    shaper.patch( out );
  }
  
  void noteOff()
  {
    shaper.unpatch( out );
  }
}

Usage

Web & Application