Coverage Report - fr.paris.lutece.plugins.captcha.modules.jcaptcha.service.sound.LuteceWordToSound
 
Classes in this File Line Coverage Branch Coverage Complexity
LuteceWordToSound
0 %
0/63
0 %
0/16
2,556
 
 1  
 /*
 2  
  * Copyright (c) 2002-2014, Mairie de 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;
 35  
 
 36  
 import fr.paris.lutece.plugins.captcha.modules.jcaptcha.service.sound.filter.FilteredSoundStream;
 37  
 import fr.paris.lutece.plugins.captcha.modules.jcaptcha.service.sound.filter.SoundFilter;
 38  
 import fr.paris.lutece.portal.service.util.AppLogService;
 39  
 import fr.paris.lutece.portal.service.util.AppPathService;
 40  
 
 41  
 import java.io.ByteArrayInputStream;
 42  
 import java.io.File;
 43  
 import java.util.ArrayList;
 44  
 import java.util.List;
 45  
 import java.util.Locale;
 46  
 
 47  
 import javax.sound.sampled.AudioFormat;
 48  
 import javax.sound.sampled.AudioInputStream;
 49  
 import javax.sound.sampled.AudioSystem;
 50  
 
 51  
 import com.octo.captcha.component.sound.soundconfigurator.SoundConfigurator;
 52  
 import com.octo.captcha.component.sound.wordtosound.AbstractWordToSound;
 53  
 
 54  
 
 55  
 /**
 56  
  *
 57  
  */
 58  
 public class LuteceWordToSound extends AbstractWordToSound
 59  
 {
 60  
     private static final String BLANK_SOUND_FILE_NAME = "white_sound";
 61  
     private static final String WAV_EXTENSION = ".wav";
 62  
     private static final String JCAPTCHA_SOUND_DIRECTORY = "jcaptcha.sound.directory";
 63  
     private static final float DEFAULT_SOUND_SAMPLE_RATE = 22050;
 64  
     private int _minAcceptedWordLength;
 65  
     private int _maxAcceptedWordLength;
 66  
     private int _minWhiteSoundNumber;
 67  
     private int _maxWhiteSoundNumber;
 68  
     private LuteceBackgroundSoundMixerConfigurator _backgroundSoundMixerConfigurator;
 69  
     private SoundFilter[] _filters;
 70  
 
 71  
     /**
 72  
      * 
 73  
      * @param configurator the configurator
 74  
      * @param minAcceptedWordLength the min Accepted Word Length
 75  
      * @param maxAcceptedWordLength the max Accepted Word Length
 76  
      * @param minWhiteSoundNumber the min White Sound Number
 77  
      * @param maxWhiteSoundNumber the max White Sound Number
 78  
      * @param mixerConfigurator the mixer Configurator
 79  
      * @param filters the filters
 80  
      */
 81  
     public LuteceWordToSound( SoundConfigurator configurator, int minAcceptedWordLength, int maxAcceptedWordLength,
 82  
             int minWhiteSoundNumber, int maxWhiteSoundNumber, LuteceBackgroundSoundMixerConfigurator mixerConfigurator,
 83  
             SoundFilter... filters )
 84  
     {
 85  0
         super( configurator, minAcceptedWordLength, maxAcceptedWordLength );
 86  0
         _minAcceptedWordLength = minAcceptedWordLength;
 87  0
         _maxAcceptedWordLength = maxAcceptedWordLength;
 88  0
         _minWhiteSoundNumber = minWhiteSoundNumber;
 89  0
         _maxWhiteSoundNumber = maxWhiteSoundNumber;
 90  0
         _backgroundSoundMixerConfigurator = mixerConfigurator;
 91  0
         _filters = filters;
 92  0
     }
 93  
 
 94  
     /**
 95  
      * @param word the word
 96  
      * @return the audio input stream
 97  
      */
 98  
     public AudioInputStream getSound( String word )
 99  
     {
 100  0
         return getSound( word, Locale.getDefault( ) );
 101  
     }
 102  
 
 103  
     /**
 104  
      * @param word the word
 105  
      * @param locale the locale
 106  
      * @return the audio input stream
 107  
      */
 108  
     public AudioInputStream getSound( String word, Locale locale )
 109  
     {
 110  
         try
 111  
         {
 112  0
             String soundFolder = AppPathService.getPath( JCAPTCHA_SOUND_DIRECTORY );
 113  0
             File emptySound = new File( soundFolder + BLANK_SOUND_FILE_NAME + WAV_EXTENSION );
 114  
             int random;
 115  0
             int whiteSoundCount = 0;
 116  0
             int[] randomArray = new int[word.length( )];
 117  
 
 118  0
             for ( int i = 0; i < word.length( ); i++ )
 119  
             {
 120  0
                 if ( i != ( word.length( ) - 1 ) )
 121  
                 {
 122  0
                     random = (int) ( Math.random( ) * ( ( _maxWhiteSoundNumber + 1 ) - _minWhiteSoundNumber ) )
 123  
                             + _minWhiteSoundNumber;
 124  
                 }
 125  
                 else
 126  
                 {
 127  0
                     random = 1;
 128  
                 }
 129  
 
 130  0
                 randomArray[i] = random;
 131  0
                 whiteSoundCount += random;
 132  
             }
 133  
 
 134  0
             File[] finalFileArray = new File[word.length( ) + whiteSoundCount];
 135  
             File soundFile;
 136  0
             int finalArraySent = 0;
 137  
 
 138  0
             for ( int i = 0; i < word.length( ); i++ )
 139  
             {
 140  0
                 soundFile = new File( soundFolder + word.charAt( i ) + WAV_EXTENSION );
 141  
 
 142  0
                 if ( soundFile.exists( ) )
 143  
                 {
 144  0
                     finalFileArray[finalArraySent++] = soundFile;
 145  
                 }
 146  
 
 147  0
                 for ( int j = 0; j < randomArray[i]; j++ )
 148  
                 {
 149  0
                     finalFileArray[finalArraySent++] = emptySound;
 150  
                 }
 151  
             }
 152  
 
 153  0
             AudioInputStream result = AudioSystem.getAudioInputStream( new ByteArrayInputStream( AudioConcat.concat(
 154  0
                     finalFileArray ).toByteArray( ) ) );
 155  
 
 156  0
             return addEffects( result );
 157  
         }
 158  0
         catch ( Exception e )
 159  
         {
 160  0
             AppLogService.error( "Problem during sound generation", e );
 161  
         }
 162  
 
 163  0
         return null;
 164  
     }
 165  
 
 166  
     /**
 167  
      * @return the Max Accepted Word Lenght
 168  
      */
 169  
     public int getMaxAcceptedWordLenght( )
 170  
     {
 171  0
         return _maxAcceptedWordLength;
 172  
     }
 173  
 
 174  
     /**
 175  
      * @return the Max Accepted Word Length
 176  
      */
 177  
     public int getMaxAcceptedWordLength( )
 178  
     {
 179  0
         return _maxAcceptedWordLength;
 180  
     }
 181  
 
 182  
     /**
 183  
      * @return the Min Accepted Word Lenght
 184  
      */
 185  
     public int getMinAcceptedWordLenght( )
 186  
     {
 187  0
         return _minAcceptedWordLength;
 188  
     }
 189  
 
 190  
     /**
 191  
      * @return the Min Accepted Word Length
 192  
      */
 193  
     public int getMinAcceptedWordLength( )
 194  
     {
 195  0
         return _minAcceptedWordLength;
 196  
     }
 197  
 
 198  
     /**
 199  
      * @param inputStream the input Stream
 200  
      * @return audio input stream
 201  
      */
 202  
     protected AudioInputStream addEffects( AudioInputStream inputStream )
 203  
     {
 204  
         try
 205  
         {
 206  0
             AudioInputStream is = inputStream;
 207  0
             AudioFormat originalFormat = inputStream.getFormat( );
 208  
 
 209  0
             for ( SoundFilter filter : _filters )
 210  
             {
 211  0
                 filter.reset( );
 212  0
                 is = new AudioInputStream( new FilteredSoundStream( is, filter ), filter.getAudioFormat( is ),
 213  0
                         is.available( ) );
 214  
             }
 215  
 
 216  0
             if ( null != _backgroundSoundMixerConfigurator )
 217  
             {
 218  0
                 File backSound = _backgroundSoundMixerConfigurator.getRandomBackgroundFile( );
 219  0
                 AudioInputStream backStream = AudioSystem.getAudioInputStream( backSound );
 220  
                 List<AudioInputStream> streamList;
 221  
 
 222  0
                 while ( backStream.available( ) < is.available( ) )
 223  
                 {
 224  0
                     streamList = new ArrayList<AudioInputStream>( );
 225  0
                     streamList.add( backStream );
 226  0
                     streamList.add( AudioSystem.getAudioInputStream( backSound ) );
 227  0
                     backStream = AudioSystem.getAudioInputStream( new ByteArrayInputStream( AudioConcat.concat(
 228  0
                             streamList, originalFormat ).toByteArray( ) ) );
 229  
                 }
 230  
 
 231  0
                 is = new MixingFloatAudioInputStream( is.getFormat( ), is, backStream,
 232  0
                         _backgroundSoundMixerConfigurator.getAttenuationValue( ) );
 233  
             }
 234  
 
 235  
             // return filtered sound stream
 236  0
             return is;
 237  
         }
 238  0
         catch ( Exception e )
 239  
         {
 240  0
             AppLogService.error( "Problem during add effects", e );
 241  
         }
 242  
 
 243  
         // if failed return natural generated sound
 244  0
         return inputStream;
 245  
     }
 246  
 
 247  
     /**
 248  
      * Static method to get used sounds sample rate
 249  
      * @return used sounds sample rate or default value (22050 Hz) if there is
 250  
      *         problem during analysis
 251  
      */
 252  
     public static float getSoundsSampleRate( )
 253  
     {
 254  0
         File emptySound = new File( AppPathService.getPath( JCAPTCHA_SOUND_DIRECTORY ) + BLANK_SOUND_FILE_NAME
 255  
                 + WAV_EXTENSION );
 256  
 
 257  
         try
 258  
         {
 259  0
             return AudioSystem.getAudioInputStream( emptySound ).getFormat( ).getSampleRate( );
 260  
         }
 261  0
         catch ( Exception e )
 262  
         {
 263  0
             AppLogService.error( e.getMessage( ), e );
 264  
         }
 265  
 
 266  0
         return DEFAULT_SOUND_SAMPLE_RATE;
 267  
     }
 268  
 }