1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 public class LuteceWordToSound extends AbstractWordToSound
58 {
59 private static final String BLANK_SOUND_FILE_NAME = "white_sound";
60 private static final String WAV_EXTENSION = ".wav";
61 private static final String JCAPTCHA_SOUND_DIRECTORY = "jcaptcha.sound.directory";
62 private static final float DEFAULT_SOUND_SAMPLE_RATE = 22050;
63 private int _minAcceptedWordLength;
64 private int _maxAcceptedWordLength;
65 private int _minWhiteSoundNumber;
66 private int _maxWhiteSoundNumber;
67 private LuteceBackgroundSoundMixerConfigurator _backgroundSoundMixerConfigurator;
68 private SoundFilter [ ] _filters;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 public LuteceWordToSound( SoundConfigurator configurator, int minAcceptedWordLength, int maxAcceptedWordLength, int minWhiteSoundNumber,
88 int maxWhiteSoundNumber, LuteceBackgroundSoundMixerConfigurator mixerConfigurator, SoundFilter... filters )
89 {
90 super( configurator, minAcceptedWordLength, maxAcceptedWordLength );
91 _minAcceptedWordLength = minAcceptedWordLength;
92 _maxAcceptedWordLength = maxAcceptedWordLength;
93 _minWhiteSoundNumber = minWhiteSoundNumber;
94 _maxWhiteSoundNumber = maxWhiteSoundNumber;
95 _backgroundSoundMixerConfigurator = mixerConfigurator;
96 _filters = filters;
97 }
98
99
100
101
102
103
104 public AudioInputStream getSound( String word )
105 {
106 return getSound( word, Locale.getDefault( ) );
107 }
108
109
110
111
112
113
114
115
116 public AudioInputStream getSound( String word, Locale locale )
117 {
118 try
119 {
120 String soundFolder = AppPathService.getPath( JCAPTCHA_SOUND_DIRECTORY );
121 File emptySound = new File( soundFolder + BLANK_SOUND_FILE_NAME + WAV_EXTENSION );
122 int random;
123 int whiteSoundCount = 0;
124 int [ ] randomArray = new int [ word.length( )];
125
126 for ( int i = 0; i < word.length( ); i++ )
127 {
128 if ( i != ( word.length( ) - 1 ) )
129 {
130 random = (int) ( Math.random( ) * ( ( _maxWhiteSoundNumber + 1 ) - _minWhiteSoundNumber ) ) + _minWhiteSoundNumber;
131 }
132 else
133 {
134 random = 1;
135 }
136
137 randomArray [i] = random;
138 whiteSoundCount += random;
139 }
140
141 File [ ] finalFileArray = new File [ word.length( ) + whiteSoundCount];
142 File soundFile;
143 int finalArraySent = 0;
144
145 for ( int i = 0; i < word.length( ); i++ )
146 {
147 soundFile = new File( soundFolder + word.charAt( i ) + WAV_EXTENSION );
148
149 if ( soundFile.exists( ) )
150 {
151 finalFileArray [finalArraySent++] = soundFile;
152 }
153
154 for ( int j = 0; j < randomArray [i]; j++ )
155 {
156 finalFileArray [finalArraySent++] = emptySound;
157 }
158 }
159
160 AudioInputStream result = AudioSystem.getAudioInputStream( new ByteArrayInputStream( AudioConcat.concat( finalFileArray ).toByteArray( ) ) );
161
162 return addEffects( result );
163 }
164 catch( Exception e )
165 {
166 AppLogService.error( "Problem during sound generation", e );
167 }
168
169 return null;
170 }
171
172
173
174
175 public int getMaxAcceptedWordLenght( )
176 {
177 return _maxAcceptedWordLength;
178 }
179
180
181
182
183 public int getMaxAcceptedWordLength( )
184 {
185 return _maxAcceptedWordLength;
186 }
187
188
189
190
191 public int getMinAcceptedWordLenght( )
192 {
193 return _minAcceptedWordLength;
194 }
195
196
197
198
199 public int getMinAcceptedWordLength( )
200 {
201 return _minAcceptedWordLength;
202 }
203
204
205
206
207
208
209 protected AudioInputStream addEffects( AudioInputStream inputStream )
210 {
211 try
212 {
213 AudioInputStream is = inputStream;
214 AudioFormat originalFormat = inputStream.getFormat( );
215
216 for ( SoundFilter filter : _filters )
217 {
218 filter.reset( );
219 is = new AudioInputStream( new FilteredSoundStream( is, filter ), filter.getAudioFormat( is ), is.available( ) );
220 }
221
222 if ( null != _backgroundSoundMixerConfigurator )
223 {
224 File backSound = _backgroundSoundMixerConfigurator.getRandomBackgroundFile( );
225 AudioInputStream backStream = AudioSystem.getAudioInputStream( backSound );
226 List<AudioInputStream> streamList;
227
228 while ( backStream.available( ) < is.available( ) )
229 {
230 streamList = new ArrayList<AudioInputStream>( );
231 streamList.add( backStream );
232 streamList.add( AudioSystem.getAudioInputStream( backSound ) );
233 backStream = AudioSystem.getAudioInputStream( new ByteArrayInputStream( AudioConcat.concat( streamList, originalFormat ).toByteArray( ) ) );
234 }
235
236 is = new MixingFloatAudioInputStream( is.getFormat( ), is, backStream, _backgroundSoundMixerConfigurator.getAttenuationValue( ) );
237 }
238
239
240 return is;
241 }
242 catch( Exception e )
243 {
244 AppLogService.error( "Problem during add effects", e );
245 }
246
247
248 return inputStream;
249 }
250
251
252
253
254
255
256 public static float getSoundsSampleRate( )
257 {
258 File emptySound = new File( AppPathService.getPath( JCAPTCHA_SOUND_DIRECTORY ) + BLANK_SOUND_FILE_NAME + WAV_EXTENSION );
259
260 try
261 {
262 return AudioSystem.getAudioInputStream( emptySound ).getFormat( ).getSampleRate( );
263 }
264 catch( Exception e )
265 {
266 AppLogService.error( e.getMessage( ), e );
267 }
268
269 return DEFAULT_SOUND_SAMPLE_RATE;
270 }
271 }