]> git.sesse.net Git - vlc/blob - modules/visualization/visual/effects.c
0ff178efc14d2b03f804f2a7c8ca0d9a161098b2
[vlc] / modules / visualization / visual / effects.c
1 /*****************************************************************************
2  * effects.c : Effects for the visualization system
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: effects.c,v 1.5 2003/09/03 10:00:23 zorglub Exp $
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "visual.h"
28 #include <math.h>
29
30 #include "fft.h"
31
32 #define PEAK_SPEED 1
33
34 /*****************************************************************************
35  * dummy_Run
36  *****************************************************************************/
37 int dummy_Run( visual_effect_t * p_effect, aout_instance_t *p_aout,
38                aout_buffer_t * p_buffer , picture_t * p_picture)
39 {
40     return 0;
41 }
42
43 /*****************************************************************************
44  * spectrum_Run: spectrum analyser
45  *****************************************************************************/
46 int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
47                  aout_buffer_t * p_buffer , picture_t * p_picture)
48 {
49     float p_output[FFT_BUFFER_SIZE];  /* Raw FFT Result  */
50     int *height;                      /* Bar heights */
51     int *peaks;                       /* Peaks */
52     int i_nb_bands;                   /* number of bands */
53     int i_band_width;                 /* width of bands */
54     int i_separ;                      /* Should we let blanks ? */
55     int i_amp;                        /* Vertical amplification */
56     int i_peak;                       /* Should we draw peaks ? */
57     char *psz_parse = NULL;           /* Args line */
58     
59     /* Horizontal scale for 20-band equalizer */
60     const int xscale1[]={0,1,2,3,4,5,6,7,8,11,15,20,27,
61                         36,47,62,82,107,141,184,255};
62                         
63     /* Horizontal scale for 80-band equalizer */
64     const int xscale2[] = 
65     {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
66      19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
67      35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
68      52,53,54,55,56,57,58,59,61,63,67,72,77,82,87,93,99,105,
69      110,115,121,130,141,152,163,174,185,200,255};
70     const int *xscale;
71     const double y_scale =  3.60673760222;  /* (log 256) */
72     
73     fft_state *p_state;                 /* internal FFT data */
74     
75     int i , j , y , k;
76     int i_line;
77     s16 p_dest[FFT_BUFFER_SIZE];          /* Adapted FFT result */
78     s16 p_buffer1[FFT_BUFFER_SIZE];       /* Buffer on which we perform
79                                              the FFT (first channel) */
80
81     float *p_buffl =                     /* Original buffer */
82             (float*)p_buffer->p_buffer;
83
84     s16  *p_buffs;                        /* s16 converted buffer */
85     s16  *p_s16_buff = NULL;                    /* s16 converted buffer */
86     
87     p_s16_buff = (s16*)malloc( 
88               p_buffer->i_nb_samples * p_effect->i_nb_chans * sizeof(s16));
89
90     if( !p_s16_buff )
91     {
92         msg_Err(p_aout,"Out of memory");
93         return -1;
94     }
95     
96     p_buffs = p_s16_buff;
97     i_nb_bands = config_GetInt ( p_aout, "visual-nbbands" );
98     i_separ    = config_GetInt( p_aout, "visual-separ" );
99     i_amp     = config_GetInt ( p_aout, "visual-amp" );
100     i_peak     = config_GetInt ( p_aout, "visual-peaks" );
101
102     if( i_nb_bands == 20)
103     {
104         xscale = xscale1;
105     }
106     else
107     {
108         i_nb_bands = 80;
109         xscale = xscale2;
110     }
111     
112     if( !p_effect->p_data )
113     {
114         p_effect->p_data=(void *)malloc(i_nb_bands * sizeof(int) );
115         if( !p_effect->p_data)
116         {
117             msg_Err(p_aout,"Out of memory");
118             return -1;
119         }
120         peaks = (int *)p_effect->p_data;
121         for( i = 0 ; i < i_nb_bands ; i++)
122         {
123            peaks[i] = 0;
124         }
125                       
126     }
127     else
128     {
129         peaks =(int *)p_effect->p_data;
130     }
131    
132     
133     height = (int *)malloc( i_nb_bands * sizeof(int) );
134     if( !height)
135     {
136         msg_Err(p_aout,"Out of memory");
137         return -1;
138     }
139     /* Convert the buffer to s16  */
140     /* Pasted from float32tos16.c */
141     for (i = p_buffer->i_nb_samples * p_effect->i_nb_chans; i--; )
142     {
143         float f_in = *p_buffl + 384.0;
144         s32 i_in;
145         i_in = *(s32 *)&f_in;
146         if(i_in >  0x43c07fff ) * p_buffs = 32767;
147         else if ( i_in < 0x43bf8000 ) *p_buffs = -32768;
148         else *p_buffs = i_in - 0x43c00000;
149       
150         p_buffl++ ; p_buffs++ ;
151     }
152     p_state  = fft_init();
153     if( !p_state)
154     {
155         msg_Err(p_aout,"Unable to initialize FFT transform");
156         return -1;
157     }
158     p_buffs = p_s16_buff;
159     for ( i = 0 ; i < FFT_BUFFER_SIZE ; i++)
160     {
161         p_output[i]    = 0;
162         p_buffer1[i] = *p_buffs;
163         p_buffs      = p_buffs + p_effect->i_nb_chans;
164     } 
165     fft_perform( p_buffer1, p_output, p_state);
166     for(i= 0; i< FFT_BUFFER_SIZE ; i++ )
167         p_dest[i] = ( (int) sqrt( p_output [ i + 1 ] ) ) >> 8;
168                 
169     for ( i = 0 ; i< i_nb_bands ;i++)
170     {
171         /* We search the maximum on one scale */
172         for( j = xscale[i] , y=0 ; j< xscale[ i + 1 ] ; j++ )
173         {
174             if ( p_dest[j] > y )
175                  y = p_dest[j];
176         }
177         /* Calculate the height of the bar */
178         y >>=5; /* remove some noise */
179         if( y != 0)
180         {
181             height[i] = (int)log(y)* y_scale;
182                if(height[i] > 150)
183                   height[i] = 150;
184         }
185         else
186         {
187             height[i] = 0 ;
188         }
189              
190         /* Draw the bar now */
191         i_band_width = floor( p_effect->i_width / i_nb_bands) ;
192
193         if( i_amp * height[i] > peaks[i])
194         {
195             peaks[i] = i_amp * height[i];
196         }
197         else if (peaks[i] > 0 )
198         {
199             peaks[i] -= PEAK_SPEED;
200             if( peaks[i] < i_amp * height[i] )
201             {
202                 peaks[i] = i_amp * height[i];
203             }
204             if( peaks[i] < 0 )
205             {
206                 peaks[i] = 0;
207             }
208         }
209
210         if( peaks[i] > 0 && i_peak )
211         {
212             if( peaks[i] >= p_effect->i_height ) 
213                 peaks[i] = p_effect->i_height - 2;
214             i_line = peaks[i];
215             
216             for( j = 0 ; j< i_band_width - i_separ; j++)
217             {
218                for( k = 0 ; k< 3 ; k ++)
219                {
220                    /* Draw the peak */
221                      *(p_picture->p[0].p_pixels + 
222                     (p_picture->p[0].i_lines - i_line -1 -k ) * 
223                      p_picture->p[0].i_pitch + (i_band_width*i +j) ) 
224                                     = 0xff;
225
226                     *(p_picture->p[1].p_pixels +
227                      (p_picture->p[1].i_lines - i_line /2 -1 -k/2 ) *
228                      p_picture->p[1].i_pitch + 
229                     ( ( i_band_width * i + j ) /2  ) )
230                                     = 0x00;
231   
232                    if( 0x04 * (i_line + k ) - 0x0f > 0 )
233                    {
234                        if ( 0x04 * (i_line + k ) -0x0f < 0xff)
235                            *(p_picture->p[2].p_pixels  +
236                             (p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
237                              p_picture->p[2].i_pitch + 
238                              ( ( i_band_width * i + j ) /2  ) ) 
239                                     = ( 0x04 * ( i_line + k ) ) -0x0f ;
240                        else
241                            *(p_picture->p[2].p_pixels  +
242                             (p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
243                              p_picture->p[2].i_pitch + 
244                              ( ( i_band_width * i + j ) /2  ) ) 
245                                     = 0xff; 
246                    }
247                    else
248                    {
249                         *(p_picture->p[2].p_pixels  +
250                          (p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
251                          p_picture->p[2].i_pitch + 
252                          ( ( i_band_width * i + j ) /2  ) ) 
253                                = 0x10 ;
254                    }
255                }
256             } 
257         }
258     
259         if(height[i] * i_amp > p_effect->i_height)
260             height[i] = floor(p_effect->i_height / i_amp );
261
262         for(i_line = 0 ; i_line < i_amp * height[i]; i_line ++ )
263         {
264             for( j = 0 ; j< i_band_width - i_separ ; j++)
265             {
266                *(p_picture->p[0].p_pixels + 
267                  (p_picture->p[0].i_lines - i_line -1) * 
268                   p_picture->p[0].i_pitch + (i_band_width*i +j) ) = 0xff;
269
270                 *(p_picture->p[1].p_pixels +
271                  (p_picture->p[1].i_lines - i_line /2 -1) *
272                  p_picture->p[1].i_pitch + 
273                  ( ( i_band_width * i + j ) /2  ) ) = 0x00;
274
275                
276                if( 0x04 * i_line - 0x0f > 0 )
277                {
278                     if( 0x04 * i_line - 0x0f < 0xff )
279                          *(p_picture->p[2].p_pixels  +
280                           (p_picture->p[2].i_lines - i_line /2 - 1) *
281                            p_picture->p[2].i_pitch + 
282                            ( ( i_band_width * i + j ) /2  ) ) = 
283                                ( 0x04 * i_line) -0x0f ;
284                     else
285                          *(p_picture->p[2].p_pixels  +
286                           (p_picture->p[2].i_lines - i_line /2 - 1) *
287                            p_picture->p[2].i_pitch + 
288                            ( ( i_band_width * i + j ) /2  ) ) = 
289                                        0xff;
290                }
291                else
292                {
293                     *(p_picture->p[2].p_pixels  +
294                      (p_picture->p[2].i_lines - i_line /2 - 1) *
295                      p_picture->p[2].i_pitch + 
296                      ( ( i_band_width * i + j ) /2  ) ) = 
297                             0x10 ;
298                }
299             }
300         }
301     }
302        
303     fft_close( p_state );
304    
305     if( p_s16_buff != NULL ) 
306     {
307         free( p_s16_buff );
308         p_s16_buff = NULL;
309     }
310    
311     if(height) free(height);
312    
313     if(psz_parse) free(psz_parse);
314     
315     return 0;
316 }
317
318         
319 /*****************************************************************************
320  * scope_Run: scope effect
321  *****************************************************************************/
322 int scope_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
323               aout_buffer_t * p_buffer , picture_t * p_picture)
324 {
325     int i_index;
326     float *p_sample ;
327     u8 *ppp_area[2][3];
328   
329     
330         for( i_index = 0 ; i_index < 2 ; i_index++ )
331         {
332             int j;
333             for( j = 0 ; j < 3 ; j++ )
334             {
335                 ppp_area[i_index][j] =
336                     p_picture->p[j].p_pixels + i_index * p_picture->p[j].i_lines
337                                 / 2 * p_picture->p[j].i_pitch;
338             }
339         }
340
341         for( i_index = 0, p_sample = (float *)p_buffer->p_buffer;
342              i_index < p_effect->i_width;
343              i_index++ )
344         {
345             u8 i_value;
346
347             /* Left channel */
348             i_value =  (*p_sample++ +1) * 127; 
349             *(ppp_area[0][0]
350                + p_picture->p[0].i_pitch * i_index / p_effect->i_width
351                + p_picture->p[0].i_lines * i_value / 512
352                    * p_picture->p[0].i_pitch) = 0xbf;
353             *(ppp_area[0][1]
354                 + p_picture->p[1].i_pitch * i_index / p_effect->i_width
355                 + p_picture->p[1].i_lines * i_value / 512
356                    * p_picture->p[1].i_pitch) = 0xff;
357
358                 
359            /* Right channel */
360            i_value = ( *p_sample++ +1 ) * 127;
361            *(ppp_area[1][0]
362               + p_picture->p[0].i_pitch * i_index / p_effect->i_width
363               + p_picture->p[0].i_lines * i_value / 512
364                  * p_picture->p[0].i_pitch) = 0x9f;
365            *(ppp_area[1][2]
366               + p_picture->p[2].i_pitch * i_index / p_effect->i_width
367               + p_picture->p[2].i_lines * i_value / 512
368                 * p_picture->p[2].i_pitch) = 0xdd;
369         }
370         return 0;
371 }
372
373
374 /*****************************************************************************
375  * random_Run:  random plots display effect
376  *****************************************************************************/
377 int random_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
378               aout_buffer_t * p_buffer , picture_t * p_picture)
379 {
380     int i_nb_plots;
381     char *psz_parse= NULL;
382     int i , i_y , i_u , i_v;
383     int i_position;
384     srand((unsigned int)mdate());
385
386     if( p_effect->psz_args )
387     {
388         psz_parse = strdup( p_effect->psz_args );
389         i_nb_plots = config_GetInt ( p_aout, "visual-stars" );
390     }
391     else
392     {
393         i_nb_plots = 200;
394     }
395
396     for( i = 0 ; i < i_nb_plots ; i++ )
397     {
398         i_position = rand() % (p_effect->i_width * p_effect->i_height );
399         i_y = rand() % 256;
400         i_u = rand() % 256;
401         i_v = rand() % 256;
402         *(p_picture->p[0].p_pixels + i_position )= i_u;
403         *(p_picture->p[1].p_pixels + i_position/4) = i_v;
404         *(p_picture->p[2].p_pixels + i_position/4) = i_y;
405     }
406     return 0;
407 }
408
409 /*****************************************************************************
410  * blur_Run:  blur effect
411  *****************************************************************************/
412 #if 0 
413   /* This code is totally crappy */
414 int blur_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
415               aout_buffer_t * p_buffer , picture_t * p_picture)
416 {
417     uint8_t * p_pictures;
418     int i,j; 
419     int i_size;   /* Total size of one image */
420     
421     i_size = (p_picture->p[0].i_pitch * p_picture->p[0].i_lines +
422               p_picture->p[1].i_pitch * p_picture->p[1].i_lines +
423               p_picture->p[2].i_pitch * p_picture->p[2].i_lines );
424     
425     if( !p_effect->p_data )
426     {
427         p_effect->p_data=(void *)malloc( 5 * i_size *sizeof(uint8_t));
428         
429         if( !p_effect->p_data)
430         {
431             msg_Err(p_aout,"Out of memory");
432             return -1;
433         }
434         p_pictures = (uint8_t *)p_effect->p_data;
435     }
436     else
437     {
438         p_pictures =(uint8_t *)p_effect->p_data;
439     }
440
441     for( i = 0 ; i < 5 ; i++)
442     {
443         for ( j = 0 ; j< p_picture->p[0].i_pitch * p_picture->p[0].i_lines; i++)
444             p_picture->p[0].p_pixels[j] = 
445                     p_pictures[i * i_size + j] * (100 - 20 * i) /100 ;
446         for ( j = 0 ; j< p_picture->p[1].i_pitch * p_picture->p[1].i_lines; i++)
447             p_picture->p[1].p_pixels[j] = 
448                     p_pictures[i * i_size +
449                     p_picture->p[0].i_pitch * p_picture->p[0].i_lines + j ];
450         for ( j = 0 ; j< p_picture->p[2].i_pitch * p_picture->p[2].i_lines; i++)
451             p_picture->p[2].p_pixels[j] = 
452                     p_pictures[i * i_size +
453                     p_picture->p[0].i_pitch * p_picture->p[0].i_lines +
454                     p_picture->p[1].i_pitch * p_picture->p[1].i_lines 
455                     + j ];
456     }
457
458     memcpy ( &p_pictures[ i_size ] , &p_pictures[0] , 4 * i_size * sizeof(uint8_t) );
459 }
460 #endif