package ddf.minim.ugens;
import ddf.minim.Minim;
import ddf.minim.UGen;
/**
* BitCrush is an effect that reduces the fidelity of the incoming signal.
* This results in a sound that is "crunchier" sounding, or "distorted".
* <p>
* Audio is represented digitally (ultimately) as an integral value. If you
* have 16-bit audio, then you can represent a sample value with any number
* in the range -32,768 to +32,767. If you bit-crush this audio to be 8-bit,
* then you effectively reduce it representation to -128 to +127, even though
* you will still represent it with a 16-bit number. This reduction in the
* fidelity of the representation essentially squares off the waveform,
* which makes it sound "crunchy". Try bit crushing down to 1-bit and see
* what you get!
*
* @author Anderson Mills
*
* @example Synthesis/bitCrushExample
*
* @related UGen
*/
public class BitCrush extends UGen
{
// jam3: define the inputs to gain
/**
* The audio input is where audio that gets bit-crushed should be patched.
* However, you don't need to patch directly to this input, patching to
* the UGen itself will accomplish the same thing.
*
* @related BitCrush
*/
public UGenInput audio;
/**
* Control the bit resolution with another UGen by patching to bitRes. Values that
* make sense for this start at 1 and go up to whatever the actual resolution of
* the incoming audio is (typically 16).
*
* @example Synthesis/bitCrushExample
*
* @related setBitRes ( )
* @related BitCrush
*/
public UGenInput bitRes;
/**
* Control the bit rate with another UGen by patching to bitRate.
* Values that make sense for this start at 1 and go up to whatever the
* sample rate of your AudioOutput are (typically 44100)
*
* @example Synthesis/bitCrushExample
*
* @related BitCrush
*/
public UGenInput bitRate;
float[] sampledFrame;
int sampleCounter;
/**
* Construct a BitCrush with a bit resolution of 1 and a bit rate of 44100.
*
*/
public BitCrush()
{
this( 1.0f, 44100 );
}
/**
* Construct a BitCrush with the specified bit resolution and bit rate.
*
* @param localBitRes
* float: typically you'll want this in the range [1,16]
* @param localBitRate
* float: this must be in the range [1,outputSampleRate]
*/
public BitCrush( float localBitRes, float localBitRate )
{
super();
// jam3: These can't be instantiated until the uGenInputs ArrayList
// in the super UGen has been constructed
//audio = new UGenInput(InputType.AUDIO);
audio = new UGenInput(InputType.AUDIO);
bitRes = new UGenInput(InputType.CONTROL);
bitRes.setLastValue(localBitRes);
bitRate = new UGenInput(InputType.CONTROL);
bitRate.setLastValue( localBitRate );
sampledFrame = new float[ channelCount() ];
}
protected void channelCountChanged()
{
sampledFrame = new float[ channelCount() ];
sampleCounter = 0;
//System.out.println( "BitCrush now has " + getAudioChannelCount() + " channels." );
}
/**
* Set the bit resolution directly.
*
* @param localBitRes
* float: typically you'll want this in the range [1,16]
*
* @related bitRes
* @related BitCrush
*/
public void setBitRes(float localBitRes)
{
bitRes.setLastValue(localBitRes);
}
@Override
protected void uGenerate(float[] out)
{
if ( sampleCounter <= 0 )
{
if ( audio.getLastValues().length != channelCount() )
{
Minim.error( "BitCrush audio has " + audio.getLastValues().length + " channels and sampledFrame has " + channelCount() );
}
System.arraycopy( audio.getLastValues(), 0, sampledFrame, 0, channelCount() );
sampleCounter = (int)(sampleRate() / Math.max(bitRate.getLastValue(),1));
}
final int res = 1 << (int)bitRes.getLastValue();
for( int i = 0; i < out.length; ++i )
{
int samp = (int)(res * sampledFrame[i]);
out[i] = (float)samp/res;
}
--sampleCounter;
}
}