package micromod; import micromod.resamplers.Resampler; /** Mixer mixes the output of the individual channels together. */ public class Mixer { protected WaveShaper waveShaper; protected WaveScaler waveScaler; protected Synthesizer synthesizer; protected int[] leftMixBuffer, rightMixBuffer; protected int gain; /** Constructor. @param synth The Synthesizer object that maintains the Channels. @param shaper This may be null. It is the compressor/limiter/clipping algorithm to use. @param scaler This may be null. It is the decimation algorithm to use. Eg dithering. */ public Mixer( Synthesizer synth, WaveShaper shaper, WaveScaler scaler ) { setWaveShaper(shaper); setWaveScaler(scaler); synthesizer = synth; leftMixBuffer = new int[MicroMod.MAX_SAMPLES_PER_TICK]; rightMixBuffer = new int[MicroMod.MAX_SAMPLES_PER_TICK]; gain = 1 << 13; } public void setWaveShaper( WaveShaper shaper ) { if(shaper==null) shaper = new WaveShaper(); waveShaper = shaper; } public void setWaveScaler( WaveScaler scaler ) { if(scaler==null) scaler = new WaveScaler(); waveScaler = scaler; } /** @return the current gain value. 4096 represents a gain of 1.0 */ public int getGain() { return gain; } /** Set the current gain value. A parameter of 4096(1.0) guarantees the output never goes above the maximum. The maximum gain is 8.0 */ public void setGain( int value ) { if( value < 0 ) value = 0; if( value > (1<<15)-1 ) value = (1<<15)-1; gain = value; } /** Mix the specified number of samples from each of the channels into the specified buffers. @param leftBuffer The buffer containing the left channel's audio. @param length The number of samples to mix. Should be > 0. @param snapBack If true, the audio will be "rewound" after mixing, so a subsequent identical call to output() will yield the same output. Used for the volume ramping. */ public void output( short[] leftBuffer, short[] rightBuffer, int length, Resampler resampler, boolean snapBack ) { Channel channel; int sample, leftAmp, rightAmp; int numChan = synthesizer.getNumberOfChannels(); // 30 July 2003 (Jon Zeppieri) commented out the code below, // which forces the number of channels to be even // numChan = numChan + (numChan%2); // Do first channel seperately to clear out mix buffers channel = synthesizer.getChannel(0); if( channel.isSilent() ) { // Clear mix buffers for( int n=0; n<length; n++ ) { leftMixBuffer[n] = 0; rightMixBuffer[n] = 0; } } else { // Overwrite mix buffers with audio leftAmp = ( channel.getLeftAmplitude() * gain / numChan ) >> 15; rightAmp = ( channel.getRightAmplitude() * gain / numChan ) >> 15; channel.getAudio( leftBuffer, length, resampler, snapBack ); waveScaler.scaleWaves( leftBuffer, leftMixBuffer, length, leftAmp ); waveScaler.scaleWaves( leftBuffer, rightMixBuffer, length, rightAmp ); } // Accumulate other channels for( int n=1; n<numChan; n++ ) { channel = synthesizer.getChannel(n); if( !channel.isSilent() ) { leftAmp = ( channel.getLeftAmplitude() * gain / numChan ) >> 15; rightAmp = ( channel.getRightAmplitude() * gain / numChan ) >> 15; channel.getAudio( leftBuffer, length, resampler, snapBack ); waveScaler.scaleWavesAccumulate( leftBuffer, leftMixBuffer, length, leftAmp ); waveScaler.scaleWavesAccumulate( leftBuffer, rightMixBuffer, length, rightAmp ); } } // Clip or shape the final audio to 16 bit waveShaper.shapeWaves( leftMixBuffer, leftBuffer, length ); waveShaper.shapeWaves( rightMixBuffer, rightBuffer, length ); } }