plectrum

Plectrum: instrument tuner for Android
Log | Files | Refs | README | LICENSE

FlangerEffect.java (6493B)


      1 /*
      2 *      _______                       _____   _____ _____  
      3 *     |__   __|                     |  __ \ / ____|  __ \ 
      4 *        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
      5 *        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
      6 *        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
      7 *        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
      8 *                                                         
      9 * -------------------------------------------------------------
     10 *
     11 * TarsosDSP is developed by Joren Six at IPEM, University Ghent
     12 *  
     13 * -------------------------------------------------------------
     14 *
     15 *  Info: http://0110.be/tag/TarsosDSP
     16 *  Github: https://github.com/JorenSix/TarsosDSP
     17 *  Releases: http://0110.be/releases/TarsosDSP/
     18 *  
     19 *  TarsosDSP includes modified source code by various authors,
     20 *  for credits and info, see README.
     21 * 
     22 */
     23 
     24 /*
     25  *      _______                       _____   _____ _____  
     26  *     |__   __|                     |  __ \ / ____|  __ \ 
     27  *        | | __ _ _ __ ___  ___  ___| |  | | (___ | |__) |
     28  *        | |/ _` | '__/ __|/ _ \/ __| |  | |\___ \|  ___/ 
     29  *        | | (_| | |  \__ \ (_) \__ \ |__| |____) | |     
     30  *        |_|\__,_|_|  |___/\___/|___/_____/|_____/|_|     
     31  *                                                         
     32  * -----------------------------------------------------------
     33  *
     34  *  TarsosDSP is developed by Joren Six at 
     35  *  The School of Arts,
     36  *  University College Ghent,
     37  *  Hoogpoort 64, 9000 Ghent - Belgium
     38  *  
     39  * -----------------------------------------------------------
     40  *
     41  *  Info: http://tarsos.0110.be/tag/TarsosDSP
     42  *  Github: https://github.com/JorenSix/TarsosDSP
     43  *  Releases: http://tarsos.0110.be/releases/TarsosDSP/
     44  *  
     45  *  TarsosDSP includes modified source code by various authors,
     46  *  for credits and info, see README.
     47  * 
     48  */
     49 
     50 package be.tarsos.dsp.effects;
     51 
     52 import be.tarsos.dsp.AudioEvent;
     53 import be.tarsos.dsp.AudioProcessor;
     54 
     55 /**
     56  * <p>
     57  * Adds a flanger effect to a signal. The implementation is done with a delay
     58  * buffer and an LFO in the form of a sine wave. It is probably the most
     59  * straightforward flanger implementation possible.
     60  * </p>
     61  * 
     62  * @author Joren Six
     63  */
     64 public class FlangerEffect implements AudioProcessor {
     65 
     66 	/**
     67 	 * A simple delay buffer, it holds a number of samples determined by the
     68 	 * maxFlangerLength and the sample rate.
     69 	 */
     70 	private float[] flangerBuffer;
     71 
     72 	/**
     73 	 * The position in the delay buffer to store the current sample.
     74 	 */
     75 	private int writePosition;
     76 
     77 	/**
     78 	 * Determines the factor of original signal that remains in the final mix.
     79 	 * Dry should always equal 1-wet).
     80 	 */
     81 	private float dry;
     82 	/**
     83 	 * Determines the factor of flanged signal that is mixed in the final mix.
     84 	 * Wet should always equal 1-dry.
     85 	 */
     86 	private float wet;
     87 	/**
     88 	 * The frequency for the LFO (sine).
     89 	 */
     90 	private double lfoFrequency;
     91 
     92 	/**
     93 	 * The sample rate is neede to calculate the length of the delay buffer.
     94 	 */
     95 	private double sampleRate;
     96 
     97 	/**
     98 	 * @param maxFlangerLength
     99 	 *            in seconds
    100 	 * @param wet
    101 	 *            The 'wetness' of the flanging effect. A value between 0 and 1.
    102 	 *            Zero meaning no flanging effect in the resulting signal, one
    103 	 *            means total flanging effect and no original signal left. The
    104 	 *            dryness of the signal is determined by dry = "1-wet".
    105 	 * @param sampleRate
    106 	 *            the sample rate in Hz.
    107 	 * @param lfoFrequency
    108 	 *            in Hertz
    109 	 */
    110 	public FlangerEffect(double maxFlangerLength, double wet,
    111 			double sampleRate, double lfoFrequency) {
    112 		flangerBuffer = new float[(int) (sampleRate * maxFlangerLength)];
    113 		this.sampleRate = sampleRate;
    114 		this.lfoFrequency = lfoFrequency;
    115 		this.wet = (float) wet;
    116 		this.dry = (float) (1 - wet);
    117 	}
    118 
    119 	@Override
    120 	public boolean process(AudioEvent audioEvent) {
    121 		float[] audioFloatBuffer = audioEvent.getFloatBuffer();
    122 		int overlap = audioEvent.getOverlap();
    123 
    124 		// Divide f by two, to counter rectifier below, which effectively
    125 		// doubles the frequency
    126 		double twoPIf = 2 * Math.PI * lfoFrequency / 2.0;
    127 		double time = audioEvent.getTimeStamp();
    128 		double timeStep = 1.0 / sampleRate;
    129 
    130 		for (int i = overlap; i < audioFloatBuffer.length; i++) {
    131 
    132 			// Calculate the LFO delay value with a sine wave:
    133 			//fix by hans bickel
    134 			double lfoValue = (flangerBuffer.length - 1) * Math.sin(twoPIf * time);
    135 			// add a time step, each iteration
    136 			time += timeStep;
    137 
    138 			// Make the delay a positive integer
    139 			int delay = (int) (Math.round(Math.abs(lfoValue)));
    140 			
    141 			// store the current sample in the delay buffer;
    142 			if (writePosition >= flangerBuffer.length) {
    143 				writePosition = 0;
    144 			}
    145 			flangerBuffer[writePosition] = audioFloatBuffer[i];
    146 
    147 			// find out the position to read the delayed sample:
    148 			int readPosition = writePosition - delay;
    149 			if (readPosition < 0) {
    150 				readPosition += flangerBuffer.length;
    151 			}
    152 
    153 			//increment the write position
    154 			writePosition++;
    155 
    156 			// Output is the input summed with the value at the delayed flanger
    157 			// buffer
    158 			audioFloatBuffer[i] = dry * audioFloatBuffer[i] + wet * flangerBuffer[readPosition];
    159 		}
    160 		return true;
    161 	}
    162 
    163 	@Override
    164 	public void processingFinished() {
    165 	}
    166 
    167 	/**
    168 	 * Set the new length of the delay LineWavelet.
    169 	 * 
    170 	 * @param flangerLength
    171 	 *            The new length of the delay LineWavelet, in seconds.
    172 	 */
    173 	public void setFlangerLength(double flangerLength) {
    174 		flangerBuffer = new float[(int) (sampleRate * flangerLength)];
    175 	}
    176 
    177 	/**
    178 	 * Sets the frequency of the LFO (sine wave), in Hertz.
    179 	 * 
    180 	 * @param lfoFrequency
    181 	 *            The new LFO frequency in Hertz.
    182 	 */
    183 	public void setLFOFrequency(double lfoFrequency) {
    184 		this.lfoFrequency = lfoFrequency;
    185 	}
    186 
    187 	/**
    188 	 * Sets the wetness and dryness of the effect. Should be a value between
    189 	 * zero and one (inclusive), the dryness is determined by 1-wet.
    190 	 * 
    191 	 * @param wet
    192 	 *            A value between zero and one (inclusive) that determines the
    193 	 *            wet and dryness of the resulting mix.
    194 	 */
    195 	public void setWet(double wet) {
    196 		this.wet = (float) wet;
    197 		this.dry = (float) (1 - wet);
    198 	}
    199 
    200 	/**
    201 	 * Sets the wetness and wetness of the effect. Should be a value between
    202 	 * zero and one (inclusive), the wetness is determined by 1-dry.
    203 	 * 
    204 	 * @param dry
    205 	 *            A value between zero and one (inclusive) that determines the
    206 	 *            wet and dryness of the resulting mix.
    207 	 */
    208 	public void setDry(double dry) {
    209 		this.dry = (float) dry;
    210 		this.wet = (float) (1 - dry);
    211 	}
    212 }