package ddf.minim.ugens;
import java.util.ArrayList;
import java.util.Arrays;
import ddf.minim.AudioSignal;
import ddf.minim.Minim;
import ddf.minim.UGen;
/**
* A Summer allows you to sum the outputs of multiple UGens to be sent further
* down the chain. Unlike most UGen effects, you can patch more than one UGen to
* a Summer.
*
* @example Synthesis/summerExample
*
* @author Damien Di Fede
*
*/
public class Summer extends UGen implements AudioSignal
{
private ArrayList<UGen> m_ugens;
private float[] m_tickBuffer;
/**
* Constructs a Summer that you can patch multiple UGens to.
*
*/
public Summer()
{
m_ugens = new ArrayList<UGen>();
}
// ddf: override because everything that patches to us
// goes into our list. then when we generate a sample
// we'll sum the audio generated by all of the ugens patched to us.
@Override
protected void addInput(UGen input)
{
// Minim.debug( "Bus::addInput - Adding " + input + " to the m_ugens list of " + this );
// it needs to know how many channels of audio we expect
// we set the channel count before adding because concurrency means
// that we might try to tick input between the add finishing and
// setAudioChannelCount completing.
input.setChannelCount( channelCount() );
synchronized( m_ugens )
{
m_ugens.add( input );
}
}
@Override
protected void removeInput(UGen input)
{
Minim.debug( "Bus::removeInput - Removing " + input + " to the m_ugens list of " + this );
synchronized( m_ugens )
{
for ( int i = 0; i < m_ugens.size(); ++i )
{
if ( m_ugens.get( i ) == input )
{
m_ugens.set( i, null );
}
}
}
}
protected void sampleRateChanged()
{
// ddf: need to let all of the UGens in our list know about the sample rate change
synchronized( m_ugens )
{
for ( int i = 0; i < m_ugens.size(); i++ )
{
UGen u = m_ugens.get( i );
if ( u != null )
{
u.setSampleRate( sampleRate() );
}
}
}
}
protected void channelCountChanged()
{
synchronized( m_ugens )
{
for( int i = 0; i < m_ugens.size(); ++i )
{
UGen u = m_ugens.get( i );
if ( u != null )
{
u.setChannelCount( channelCount() );
}
}
}
m_tickBuffer = new float[ channelCount() ];
}
@Override
protected void uGenerate(float[] channels)
{
// make sure we are generating the correct number of channels
if ( m_tickBuffer == null || m_tickBuffer.length != channels.length )
{
m_tickBuffer = new float[channels.length];
// and propagate that to our list
synchronized( m_ugens )
{
for ( int i = 0; i < m_ugens.size(); ++i )
{
UGen u = m_ugens.get( i );
if ( u != null )
{
u.setChannelCount( channels.length );
}
else
// a null entry means it was unpatched, so go ahead and cull now
{
m_ugens.remove( i );
--i;
}
}
}
}
// start with silence
Arrays.fill( channels, 0 );
synchronized( m_ugens )
{
for ( int i = 0; i < m_ugens.size(); ++i )
{
// m_tickBuffer should be filled with the correct audio
// even if this ugen has generated audio already
UGen u = m_ugens.get( i );
if ( u != null )
{
u.tick( m_tickBuffer );
processSampleFrame( m_tickBuffer, channels );
}
else
// a null entry means this ugen was unpatched, so we remove the
// entry
{
m_ugens.remove( i );
--i;
}
}
}
}
// ddf: I broke this out into its own method so that Sink could extend Summer.
// Doing this means not having to rewrite all of the UGen list handling
// that Summer already does. The only difference between Summer and Sink
// is that Sink produces silence.
protected void processSampleFrame(float[] in, float[] out)
{
for ( int i = 0; i < out.length; ++i )
{
out[i] += in[i];
}
}
/**
* Generates a buffer of samples by ticking this UGen mono.length times.
* Like the tick method, this will result in all of the
*/
public void generate(float[] mono)
{
float[] sample = new float[1];
for ( int i = 0; i < mono.length; i++ )
{
tick( sample );
mono[i] = sample[0];
}
}
public void generate(float[] left, float[] right)
{
float[] sample = new float[2];
for ( int i = 0; i < left.length; i++ )
{
tick( sample );
left[i] = sample[0];
right[i] = sample[1];
}
}
}