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 }