1 /* 2 * Copyright (c) 2002-2021, City of Paris 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice 10 * and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice 13 * and the following disclaimer in the documentation and/or other materials 14 * provided with the distribution. 15 * 16 * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 * License 1.0 33 */ 34 package fr.paris.lutece.plugins.captcha.modules.jcaptcha.service.sound.filter; 35 36 import fr.paris.lutece.plugins.captcha.modules.jcaptcha.service.sound.LuteceWordToSound; 37 38 /** 39 * 40 */ 41 public class EchoFilter extends SoundFilter 42 { 43 private short [ ] _delayBuffer; 44 private int _delayBufferPos; 45 private float _decay; 46 47 /** 48 * Creates an EchoFilter with the specified number of delay samples and the specified decay rate. 49 * <p> 50 * The number of delay samples specifies how long before the echo is initially heard. For a 1 second echo with mono, 44100Hz sound, use 44100 delay samples. 51 * <p> 52 * The decay value is how much the echo has decayed from the source. A decay value of .5 means the echo heard is half as loud as the source. 53 * 54 * @param echoDelay 55 * the echoDelay 56 * @param decay 57 * the decay 58 */ 59 public EchoFilter( float echoDelay, float decay ) 60 { 61 int numSampleDelay = ( Math.round( LuteceWordToSound.getSoundsSampleRate( ) * ( echoDelay / 1000 ) ) + 1 ); 62 _delayBuffer = new short [ numSampleDelay]; 63 _decay = decay / 100; 64 } 65 66 /** 67 * Gets the remaining size, in bytes, of samples that this filter can echo after the sound is done playing. Ensures that the sound will have decayed to 68 * below 1% of maximum volume (amplitude). 69 * 70 * @return the Remaining Size 71 */ 72 public int getRemainingSize( ) 73 { 74 float finalDecay = 0.01f; 75 76 // derived from Math.pow(decay,x) <= finalDecay 77 int numRemainingBuffers = (int) Math.ceil( Math.log( finalDecay ) / Math.log( _decay ) ); 78 int bufferSize = _delayBuffer.length; 79 80 return bufferSize * numRemainingBuffers; 81 } 82 83 /** 84 * Clears this EchoFilter's internal delay buffer. 85 */ 86 public void reset( ) 87 { 88 for ( int i = 0; i < _delayBuffer.length; i++ ) 89 { 90 _delayBuffer [i] = 0; 91 } 92 93 _delayBufferPos = 0; 94 } 95 96 /** 97 * Filters the sound samples to add an echo. The samples played are added to the sound in the delay buffer multipied by the decay rate. The result is then 98 * stored in the delay buffer, so multiple echoes are heard. 99 * 100 * @param samples 101 * the samples 102 * @param offset 103 * the offset 104 * @param length 105 * the length 106 * @param sampleSizeInBits 107 * the sample size in bits 108 */ 109 public void filter( byte [ ] samples, int offset, int length, int sampleSizeInBits ) 110 { 111 if ( sampleSizeInBits == SAMPLE_SIZE_8_BIT ) 112 { 113 for ( int i = offset; i < ( offset + length ); i++ ) 114 { 115 // update the sample 116 short oldSample = get8bitSample( samples, i ); 117 short newSample = (short) ( oldSample + ( _decay * _delayBuffer [_delayBufferPos] ) ); 118 set8bitSample( samples, i, newSample ); 119 // update the delay buffer 120 _delayBuffer [_delayBufferPos] = newSample; 121 _delayBufferPos++; 122 123 if ( _delayBufferPos == _delayBuffer.length ) 124 { 125 _delayBufferPos = 0; 126 } 127 } 128 } 129 else 130 if ( sampleSizeInBits == SAMPLE_SIZE_16_BIT ) 131 { 132 for ( int i = offset; i < ( offset + length ); i += 2 ) 133 { 134 // update the sample 135 short oldSample = get16bitSample( samples, i ); 136 short newSample = (short) ( oldSample + ( _decay * _delayBuffer [_delayBufferPos] ) ); 137 set16bitSample( samples, i, newSample ); 138 // update the delay buffer 139 _delayBuffer [_delayBufferPos] = newSample; 140 _delayBufferPos++; 141 142 if ( _delayBufferPos == _delayBuffer.length ) 143 { 144 _delayBufferPos = 0; 145 } 146 } 147 } 148 } 149 }