package ddf.minim.ugens;
import ddf.minim.UGen;
/**
* A UGen which provides <a href="http://en.wikipedia.org/wiki/Waveshaper">waveshaping distortion</a>.
* 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).
*
* @example Synthesis/waveShaperExample
*
* @related Waves
* @related Wavetable
* @related UGen
*
* @author Nicolas Brix, Anderson Mills
*/
public class WaveShaper extends UGen
{
/**
* The default input is "audio."
*
* @related WaveShaper
*/
public UGenInput audio;
/**
* The output amplitude
*
* @related WaveShaper
*/
public UGenInput outAmplitude;
/**
* The mapping amplitude of the input signal
*
* @related WaveShaper
*/
public UGenInput mapAmplitude;
// flag to wrap the map around the ends instead of hitting the edge
private boolean wrapMap;
// the current waveshape for mapping
private Waveform mapShape;
/**
* Constructor for WaveShaper.
*
* mapWrap, a boolean flag to wrap the map
* around the ends instead of hitting the edge, defaults to false.
*
* @shortdesc Constructor for WaveShaper.
*
* @param outAmp
* float: the output amplitude multiplier of the shaped wave
* @param mapAmp
* float: amplitude over which to map the incoming signal
* @param mapShape
* Waveform: waveshape over which to map the incoming signal
*
* @related WaveShaper
*/
public WaveShaper(float outAmp, float mapAmp, Waveform mapShape)
{
this( outAmp, mapAmp, mapShape, false );
}
/**
* Constructor for WaveShaper.
*
* @param outAmp
* float: the output amplitude multiplier of the shaped wave
* @param mapAmp
* float: amplitude over which to map the incoming signal
* @param mapShape
* Waveform: waveshape over which to map the incoming signal
* @param wrapMap
* boolean: flag to wrap the map instead of hit the edge and stick
*
* @related WaveShaper
*/
public WaveShaper(float outAmp, float mapAmp, Waveform mapShape, boolean wrapMap)
{
super();
audio = new UGenInput( InputType.AUDIO );
mapAmplitude = new UGenInput( InputType.CONTROL );
mapAmplitude.setLastValue( mapAmp );
outAmplitude = new UGenInput( InputType.CONTROL );
outAmplitude.setLastValue( outAmp );
this.mapShape = mapShape;
this.wrapMap = wrapMap;
}
// the input signal is supposed to be less than 1 in amplitude
// as Wavetable is basically an array of floats accessed via a 0 to 1.0
// index,
// some shifting+scaling has to be done
// the shape is supposed to be -1 at [0] and +1 at [length].
@Override
protected void uGenerate(float[] channels)
{
// run over the length of the channel array
for ( int i = 0; i < channels.length; i++ )
{
// bring in the audio as index, scale by the map amplitude, and
// normalize
float tmpIndex = ( mapAmplitude.getLastValue() * audio
.getLastValues()[i] ) / 2.0f + 0.5f;
// handle the cases where it goes out of bouds
if ( wrapMap ) // wrap oround
{
// what's left after dividing by 1?
tmpIndex %= 1.0f;
// I don't like that remaider gives the same sign as the first
// argument
if ( tmpIndex < 0.0f )
{
tmpIndex += 1.0f;
}
}
else if ( tmpIndex > 1.0f ) // otherwise cap at 1
{
tmpIndex = 1.0f;
}
else if ( tmpIndex < 0.0f ) // and cap on the bottom at 0
{
tmpIndex = 0.0f;
}
// now that tmpIndex is good, look up the wavetable value and
// multiply by outAmp
channels[i] = outAmplitude.getLastValue() * mapShape.value( tmpIndex );
}
}
}