]> git.sesse.net Git - vlc/blob - modules/visualization/visual/effects.c
visual: don't crash on empty buffers
[vlc] / modules / visualization / visual / effects.c
1 /*****************************************************************************
2  * effects.c : Effects for the visualization system
3  *****************************************************************************
4  * Copyright (C) 2002-2009 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@via.ecp.fr>
8  *          Adrien Maglo <magsoft@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_vout.h>
34 #include <vlc_aout.h>
35
36 #include "visual.h"
37 #include <math.h>
38
39 #include "fft.h"
40 #include "window.h"
41
42 #define PEAK_SPEED 1
43 #define BAR_DECREASE_SPEED 5
44
45 #define GRAD_ANGLE_MIN 0.2
46 #define GRAD_ANGLE_MAX 0.5
47 #define GRAD_INCR 0.01
48
49 /*****************************************************************************
50  * dummy_Run
51  *****************************************************************************/
52 static int dummy_Run( visual_effect_t * p_effect, vlc_object_t *p_aout,
53                       const block_t * p_buffer , picture_t * p_picture)
54 {
55     VLC_UNUSED(p_effect); VLC_UNUSED(p_aout); VLC_UNUSED(p_buffer);
56     VLC_UNUSED(p_picture);
57     return 0;
58 }
59
60 static void dummy_Free( void *data )
61 {
62     VLC_UNUSED(data);
63 }
64
65
66 /*****************************************************************************
67  * spectrum_Run: spectrum analyser
68  *****************************************************************************/
69 typedef struct spectrum_data
70 {
71     int *peaks;
72     int *prev_heights;
73
74     unsigned i_prev_nb_samples;
75     int16_t *p_prev_s16_buff;
76
77     window_param wind_param;
78 } spectrum_data;
79
80 static int spectrum_Run(visual_effect_t * p_effect, vlc_object_t *p_aout,
81                         const block_t * p_buffer , picture_t * p_picture)
82 {
83     spectrum_data *p_data = p_effect->p_data;
84     float p_output[FFT_BUFFER_SIZE];  /* Raw FFT Result  */
85     int *height;                      /* Bar heights */
86     int *peaks;                       /* Peaks */
87     int *prev_heights;                /* Previous bar heights */
88     int i_80_bands;                   /* number of bands : 80 if true else 20 */
89     int i_nb_bands;                   /* number of bands : 80 or 20 */
90     int i_band_width;                 /* width of bands */
91     int i_start;                      /* first band horizontal position */
92     int i_peak;                       /* Should we draw peaks ? */
93
94     /* Horizontal scale for 20-band equalizer */
95     const int xscale1[]={0,1,2,3,4,5,6,7,8,11,15,20,27,
96                         36,47,62,82,107,141,184,255};
97
98     /* Horizontal scale for 80-band equalizer */
99     const int xscale2[] =
100     {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
101      19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
102      35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
103      52,53,54,55,56,57,58,59,61,63,67,72,77,82,87,93,99,105,
104      110,115,121,130,141,152,163,174,185,200,255};
105     const int *xscale;
106
107     fft_state *p_state;                 /* internal FFT data */
108     DEFINE_WIND_CONTEXT( wind_ctx );    /* internal window data */
109
110     int i , j , y , k;
111     int i_line;
112     int16_t p_dest[FFT_BUFFER_SIZE];      /* Adapted FFT result */
113     int16_t p_buffer1[FFT_BUFFER_SIZE];   /* Buffer on which we perform
114                                              the FFT (first channel) */
115
116     float *p_buffl =                     /* Original buffer */
117             (float*)p_buffer->p_buffer;
118
119     int16_t  *p_buffs;                    /* int16_t converted buffer */
120     int16_t  *p_s16_buff;                 /* int16_t converted buffer */
121
122     if (!p_buffer->i_nb_samples) {
123         msg_Err(p_aout, "no samples yet");
124         return -1;
125     }
126
127     /* Create p_data if needed */
128     if( !p_data )
129     {
130         p_effect->p_data = p_data = malloc( sizeof( spectrum_data ) );
131         if( !p_data )
132             return -1;
133
134         p_data->peaks = calloc( 80, sizeof(int) );
135         p_data->prev_heights = calloc( 80, sizeof(int) );
136
137         p_data->i_prev_nb_samples = 0;
138         p_data->p_prev_s16_buff = NULL;
139
140         window_get_param( p_aout, &p_data->wind_param );
141     }
142     peaks = (int *)p_data->peaks;
143     prev_heights = (int *)p_data->prev_heights;
144
145     /* Allocate the buffer only if the number of samples change */
146     if( p_buffer->i_nb_samples != p_data->i_prev_nb_samples )
147     {
148         free( p_data->p_prev_s16_buff );
149         p_data->p_prev_s16_buff = malloc( p_buffer->i_nb_samples *
150                                           p_effect->i_nb_chans *
151                                           sizeof(int16_t));
152         p_data->i_prev_nb_samples = p_buffer->i_nb_samples;
153         if( !p_data->p_prev_s16_buff )
154             return -1;
155     }
156     p_buffs = p_s16_buff = p_data->p_prev_s16_buff;
157
158     i_80_bands = var_InheritInteger( p_aout, "visual-80-bands" );
159     i_peak     = var_InheritInteger( p_aout, "visual-peaks" );
160
161     if( i_80_bands != 0)
162     {
163         xscale = xscale2;
164         i_nb_bands = 80;
165     }
166     else
167     {
168         xscale = xscale1;
169         i_nb_bands = 20;
170     }
171
172     height = malloc( i_nb_bands * sizeof(int) );
173     if( !height )
174     {
175         return -1;
176     }
177     /* Convert the buffer to int16_t  */
178     /* Pasted from float32tos16.c */
179     for (i = p_buffer->i_nb_samples * p_effect->i_nb_chans; i--; )
180     {
181         union { float f; int32_t i; } u;
182         u.f = *p_buffl + 384.0;
183         if(u.i >  0x43c07fff ) * p_buffs = 32767;
184         else if ( u.i < 0x43bf8000 ) *p_buffs = -32768;
185         else *p_buffs = u.i - 0x43c00000;
186
187         p_buffl++ ; p_buffs++ ;
188     }
189     p_state  = visual_fft_init();
190     if( !p_state)
191     {
192         free( height );
193         msg_Err(p_aout,"unable to initialize FFT transform");
194         return -1;
195     }
196     if( !window_init( FFT_BUFFER_SIZE, &p_data->wind_param, &wind_ctx ) )
197     {
198         fft_close( p_state );
199         free( height );
200         msg_Err(p_aout,"unable to initialize FFT window");
201         return -1;
202     }
203     p_buffs = p_s16_buff;
204     for ( i = 0 ; i < FFT_BUFFER_SIZE ; i++)
205     {
206         p_output[i]  = 0;
207         p_buffer1[i] = *p_buffs;
208
209         p_buffs += p_effect->i_nb_chans;
210         if( p_buffs >= &p_s16_buff[p_buffer->i_nb_samples * p_effect->i_nb_chans] )
211             p_buffs = p_s16_buff;
212
213     }
214     window_scale_in_place( p_buffer1, &wind_ctx );
215     fft_perform( p_buffer1, p_output, p_state);
216     for( i = 0; i< FFT_BUFFER_SIZE ; i++ )
217         p_dest[i] = p_output[i] *  ( 2 ^ 16 ) / ( ( FFT_BUFFER_SIZE / 2 * 32768 ) ^ 2 );
218
219     /* Compute the horizontal position of the first band */
220     i_band_width = floor( p_effect->i_width / i_nb_bands);
221     i_start = ( p_effect->i_width - i_band_width * i_nb_bands ) / 2;
222
223     for ( i = 0 ; i < i_nb_bands ;i++)
224     {
225         /* We search the maximum on one scale */
226         for( j = xscale[i], y = 0; j< xscale[ i + 1 ]; j++ )
227         {
228             if ( p_dest[j] > y )
229                  y = p_dest[j];
230         }
231         /* Calculate the height of the bar */
232         if( y != 0 )
233         {
234             height[i] = log( y ) * 30;
235             if( height[i] > 380 )
236                 height[i] = 380;
237         }
238         else
239             height[ i ] = 0;
240
241         /* Draw the bar now */
242
243         if( height[i] > peaks[i] )
244         {
245             peaks[i] = height[i];
246         }
247         else if( peaks[i] > 0 )
248         {
249             peaks[i] -= PEAK_SPEED;
250             if( peaks[i] < height[i] )
251             {
252                 peaks[i] = height[i];
253             }
254             if( peaks[i] < 0 )
255             {
256                 peaks[i] = 0;
257             }
258         }
259
260         /* Decrease the bars if needed */
261         if( height[i] <= prev_heights[i] - BAR_DECREASE_SPEED )
262         {
263             height[i] = prev_heights[i];
264             height[i] -= BAR_DECREASE_SPEED;
265         }
266         prev_heights[i] = height[i];
267
268         if( peaks[i] > 0 && i_peak )
269         {
270             if( peaks[i] >= p_effect->i_height )
271                 peaks[i] = p_effect->i_height - 2;
272             i_line = peaks[i];
273
274             for( j = 0; j < i_band_width - 1; j++ )
275             {
276                for( k = 0; k < 3; k ++ )
277                {
278                    /* Draw the peak */
279                    *(p_picture->p[0].p_pixels +
280                     ( p_effect->i_height - i_line -1 -k ) *
281                      p_picture->p[0].i_pitch +
282                      ( i_start + i_band_width*i + j ) )
283                                     = 0xff;
284
285                    *(p_picture->p[1].p_pixels +
286                     ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
287                      p_picture->p[1].i_pitch +
288                      ( ( i_start + i_band_width * i + j ) /2  ) )
289                                     = 0x00;
290
291                    if( i_line + k - 0x0f > 0 )
292                    {
293                        if ( i_line + k - 0x0f < 0xff )
294                            *(p_picture->p[2].p_pixels  +
295                             ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
296                              p_picture->p[2].i_pitch +
297                              ( ( i_start + i_band_width * i + j ) /2  ) )
298                                     = ( i_line + k ) - 0x0f;
299                        else
300                            *(p_picture->p[2].p_pixels  +
301                             ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
302                              p_picture->p[2].i_pitch +
303                              ( ( i_start + i_band_width * i + j ) /2  ) )
304                                     = 0xff;
305                    }
306                    else
307                    {
308                         *(p_picture->p[2].p_pixels  +
309                          ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
310                          p_picture->p[2].i_pitch +
311                          ( ( i_start + i_band_width * i + j ) /2  ) )
312                                = 0x10 ;
313                    }
314                }
315             }
316         }
317
318         if(height[i] > p_effect->i_height)
319             height[i] = floor(p_effect->i_height );
320
321         for( i_line = 0; i_line < height[i]; i_line++ )
322         {
323             for( j = 0 ; j < i_band_width - 1; j++)
324             {
325                *(p_picture->p[0].p_pixels +
326                  (p_effect->i_height - i_line - 1) *
327                   p_picture->p[0].i_pitch +
328                   ( i_start + i_band_width*i + j ) ) = 0xff;
329
330                *(p_picture->p[1].p_pixels +
331                  ( ( p_effect->i_height - i_line ) / 2 - 1) *
332                  p_picture->p[1].i_pitch +
333                  ( ( i_start + i_band_width * i + j ) /2  ) ) = 0x00;
334
335                if( i_line - 0x0f > 0 )
336                {
337                     if( i_line - 0x0f < 0xff )
338                          *(p_picture->p[2].p_pixels  +
339                            ( ( p_effect->i_height - i_line ) / 2 - 1) *
340                            p_picture->p[2].i_pitch +
341                            ( ( i_start + i_band_width * i + j ) /2  ) ) =
342                                i_line - 0x0f;
343                     else
344                          *(p_picture->p[2].p_pixels  +
345                            ( ( p_effect->i_height - i_line ) / 2  - 1) *
346                            p_picture->p[2].i_pitch +
347                            ( ( i_start + i_band_width * i + j ) /2  ) ) =
348                                        0xff;
349                }
350                else
351                {
352                     *(p_picture->p[2].p_pixels  +
353                       ( ( p_effect->i_height - i_line ) / 2  - 1) *
354                       p_picture->p[2].i_pitch +
355                       ( ( i_start + i_band_width * i + j ) /2  ) ) =
356                             0x10;
357                }
358             }
359         }
360     }
361
362     window_close( &wind_ctx );
363
364     fft_close( p_state );
365
366     free( height );
367
368     return 0;
369 }
370
371 static void spectrum_Free( void *data )
372 {
373     spectrum_data *p_data = data;
374
375     if( p_data != NULL )
376     {
377         free( p_data->peaks );
378         free( p_data->prev_heights );
379         free( p_data->p_prev_s16_buff );
380         free( p_data );
381     }
382 }
383
384
385 /*****************************************************************************
386  * spectrometer_Run: derivative spectrum analysis
387  *****************************************************************************/
388 typedef struct
389 {
390     int *peaks;
391
392     unsigned i_prev_nb_samples;
393     int16_t *p_prev_s16_buff;
394
395     window_param wind_param;
396 } spectrometer_data;
397
398 static int spectrometer_Run(visual_effect_t * p_effect, vlc_object_t *p_aout,
399                             const block_t * p_buffer , picture_t * p_picture)
400 {
401 #define Y(R,G,B) ((uint8_t)( (R * .299) + (G * .587) + (B * .114) ))
402 #define U(R,G,B) ((uint8_t)( (R * -.169) + (G * -.332) + (B * .500) + 128 ))
403 #define V(R,G,B) ((uint8_t)( (R * .500) + (G * -.419) + (B * -.0813) + 128 ))
404     float p_output[FFT_BUFFER_SIZE];  /* Raw FFT Result  */
405     int *height;                      /* Bar heights */
406     int *peaks;                       /* Peaks */
407     int i_80_bands;                   /* number of bands : 80 if true else 20 */
408     int i_nb_bands;                   /* number of bands : 80 or 20 */
409     int i_band_width;                 /* width of bands */
410     int i_separ;                      /* Should we let blanks ? */
411     int i_amp;                        /* Vertical amplification */
412     int i_peak;                       /* Should we draw peaks ? */
413
414     int i_original;          /* original spectrum graphic routine */
415     int i_rad;               /* radius of circle of base of bands */
416     int i_sections;          /* sections of spectranalysis */
417     int i_extra_width;       /* extra width on peak */
418     int i_peak_height;       /* height of peak */
419     int c;                   /* sentinel container of total spectral sections */
420     double band_sep_angle;   /* angled separation between beginning of each band */
421     double section_sep_angle;/* "   "    '     "    '    "     "    spectrum section */
422     int max_band_length;     /* try not to go out of screen */
423     int i_show_base;         /* Should we draw base of circle ? */
424     int i_show_bands;        /* Should we draw bands ? */
425     //int i_invert_bands;      /* do the bands point inward ? */
426     double a;                /* for various misc angle situations in radians */
427     int x,y,xx,yy;           /* various misc x/y */
428     char color1;             /* V slide on a YUV color cube */
429     //char color2;             /* U slide.. ?  color2 fade color ? */
430
431     /* Horizontal scale for 20-band equalizer */
432     const int xscale1[]={0,1,2,3,4,5,6,7,8,11,15,20,27,
433                         36,47,62,82,107,141,184,255};
434
435     /* Horizontal scale for 80-band equalizer */
436     const int xscale2[] =
437     {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
438      19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,
439      35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
440      52,53,54,55,56,57,58,59,61,63,67,72,77,82,87,93,99,105,
441      110,115,121,130,141,152,163,174,185,200,255};
442     const int *xscale;
443     const double y_scale =  3.60673760222;  /* (log 256) */
444
445     fft_state *p_state;                 /* internal FFT data */
446     DEFINE_WIND_CONTEXT( wind_ctx );    /* internal window data */
447
448     int i , j , k;
449     int i_line = 0;
450     int16_t p_dest[FFT_BUFFER_SIZE];      /* Adapted FFT result */
451     int16_t p_buffer1[FFT_BUFFER_SIZE];   /* Buffer on which we perform
452                                              the FFT (first channel) */
453     float *p_buffl =                     /* Original buffer */
454             (float*)p_buffer->p_buffer;
455
456     int16_t  *p_buffs;                    /* int16_t converted buffer */
457     int16_t  *p_s16_buff;                /* int16_t converted buffer */
458
459     if (!p_buffer->i_nb_samples) {
460         msg_Err(p_aout, "no samples yet");
461         return -1;
462     }
463
464     /* Create the data struct if needed */
465     spectrometer_data *p_data = p_effect->p_data;
466     if( !p_data )
467     {
468         p_data = malloc( sizeof(spectrometer_data) );
469         if( !p_data )
470             return -1;
471         p_data->peaks = calloc( 80, sizeof(int) );
472         if( !p_data->peaks )
473         {
474             free( p_data );
475             return -1;
476         }
477         p_data->i_prev_nb_samples = 0;
478         p_data->p_prev_s16_buff = NULL;
479         window_get_param( p_aout, &p_data->wind_param );
480         p_effect->p_data = (void*)p_data;
481     }
482     peaks = p_data->peaks;
483
484     /* Allocate the buffer only if the number of samples change */
485     if( p_buffer->i_nb_samples != p_data->i_prev_nb_samples )
486     {
487         free( p_data->p_prev_s16_buff );
488         p_data->p_prev_s16_buff = malloc( p_buffer->i_nb_samples *
489                                           p_effect->i_nb_chans *
490                                           sizeof(int16_t));
491         p_data->i_prev_nb_samples = p_buffer->i_nb_samples;
492         if( !p_data->p_prev_s16_buff )
493             return -1;
494     }
495     p_buffs = p_s16_buff = p_data->p_prev_s16_buff;
496
497     i_original     = var_InheritInteger( p_aout, "spect-show-original" );
498     i_80_bands     = var_InheritInteger( p_aout, "spect-80-bands" );
499     i_separ        = var_InheritInteger( p_aout, "spect-separ" );
500     i_amp          = var_InheritInteger( p_aout, "spect-amp" );
501     i_peak         = var_InheritInteger( p_aout, "spect-show-peaks" );
502     i_show_base    = var_InheritInteger( p_aout, "spect-show-base" );
503     i_show_bands   = var_InheritInteger( p_aout, "spect-show-bands" );
504     i_rad          = var_InheritInteger( p_aout, "spect-radius" );
505     i_sections     = var_InheritInteger( p_aout, "spect-sections" );
506     i_extra_width  = var_InheritInteger( p_aout, "spect-peak-width" );
507     i_peak_height  = var_InheritInteger( p_aout, "spect-peak-height" );
508     color1         = var_InheritInteger( p_aout, "spect-color" );
509
510     if( i_80_bands != 0)
511     {
512         xscale = xscale2;
513         i_nb_bands = 80;
514     }
515     else
516     {
517         xscale = xscale1;
518         i_nb_bands = 20;
519     }
520
521     height = malloc( i_nb_bands * sizeof(int) );
522     if( !height)
523         return -1;
524
525     /* Convert the buffer to int16_t  */
526     /* Pasted from float32tos16.c */
527     for (i = p_buffer->i_nb_samples * p_effect->i_nb_chans; i--; )
528     {
529         union { float f; int32_t i; } u;
530         u.f = *p_buffl + 384.0;
531         if(u.i >  0x43c07fff ) * p_buffs = 32767;
532         else if ( u.i < 0x43bf8000 ) *p_buffs = -32768;
533         else *p_buffs = u.i - 0x43c00000;
534
535         p_buffl++ ; p_buffs++ ;
536     }
537     p_state  = visual_fft_init();
538     if( !p_state)
539     {
540         msg_Err(p_aout,"unable to initialize FFT transform");
541         free( height );
542         return -1;
543     }
544     if( !window_init( FFT_BUFFER_SIZE, &p_data->wind_param, &wind_ctx ) )
545     {
546         fft_close( p_state );
547         free( height );
548         msg_Err(p_aout,"unable to initialize FFT window");
549         return -1;
550     }
551     p_buffs = p_s16_buff;
552     for ( i = 0 ; i < FFT_BUFFER_SIZE; i++)
553     {
554         p_output[i]    = 0;
555         p_buffer1[i] = *p_buffs;
556
557         p_buffs += p_effect->i_nb_chans;
558         if( p_buffs >= &p_s16_buff[p_buffer->i_nb_samples * p_effect->i_nb_chans] )
559             p_buffs = p_s16_buff;
560     }
561     window_scale_in_place( p_buffer1, &wind_ctx );
562     fft_perform( p_buffer1, p_output, p_state);
563     for(i = 0; i < FFT_BUFFER_SIZE; i++)
564     {
565         int sqrti = sqrt(p_output[i]);
566         p_dest[i] = sqrti >> 8;
567     }
568
569     i_nb_bands *= i_sections;
570
571     for ( i = 0 ; i< i_nb_bands/i_sections ;i++)
572     {
573         /* We search the maximum on one scale */
574         for( j = xscale[i] , y=0 ; j< xscale[ i + 1 ] ; j++ )
575         {
576             if ( p_dest[j] > y )
577                  y = p_dest[j];
578         }
579         /* Calculate the height of the bar */
580         y >>=7;/* remove some noise */
581         if( y != 0)
582         {
583             int logy = log(y);
584             height[i] = logy * y_scale;
585             if(height[i] > 150)
586                 height[i] = 150;
587         }
588         else
589         {
590             height[i] = 0 ;
591         }
592
593         /* Draw the bar now */
594         i_band_width = floor( p_effect->i_width / (i_nb_bands/i_sections)) ;
595
596         if( i_amp * height[i] > peaks[i])
597         {
598             peaks[i] = i_amp * height[i];
599         }
600         else if (peaks[i] > 0 )
601         {
602             peaks[i] -= PEAK_SPEED;
603             if( peaks[i] < i_amp * height[i] )
604             {
605                 peaks[i] = i_amp * height[i];
606             }
607             if( peaks[i] < 0 )
608             {
609                 peaks[i] = 0;
610             }
611         }
612
613         if( i_original != 0 )
614         {
615         if( peaks[i] > 0 && i_peak )
616         {
617             if( peaks[i] >= p_effect->i_height )
618                 peaks[i] = p_effect->i_height - 2;
619             i_line = peaks[i];
620
621             for( j = 0 ; j< i_band_width - i_separ; j++)
622             {
623                for( k = 0 ; k< 3 ; k ++)
624                {
625                    //* Draw the peak
626                      *(p_picture->p[0].p_pixels +
627                     (p_effect->i_height - i_line -1 -k ) *
628                      p_picture->p[0].i_pitch + (i_band_width*i +j) )
629                                     = 0xff;
630
631                     *(p_picture->p[1].p_pixels +
632                      ( ( p_effect->i_height - i_line ) / 2 -1 -k/2 ) *
633                      p_picture->p[1].i_pitch +
634                     ( ( i_band_width * i + j ) /2  ) )
635                                     = 0x00;
636
637                    if( 0x04 * (i_line + k ) - 0x0f > 0 )
638                    {
639                        if ( 0x04 * (i_line + k ) -0x0f < 0xff)
640                            *(p_picture->p[2].p_pixels  +
641                             ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
642                              p_picture->p[2].i_pitch +
643                              ( ( i_band_width * i + j ) /2  ) )
644                                     = ( 0x04 * ( i_line + k ) ) -0x0f ;
645                        else
646                            *(p_picture->p[2].p_pixels  +
647                             ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
648                              p_picture->p[2].i_pitch +
649                              ( ( i_band_width * i + j ) /2  ) )
650                                     = 0xff;
651                    }
652                    else
653                    {
654                         *(p_picture->p[2].p_pixels  +
655                          ( ( p_effect->i_height - i_line ) / 2 - 1 -k/2 ) *
656                          p_picture->p[2].i_pitch +
657                          ( ( i_band_width * i + j ) /2  ) )
658                                = 0x10 ;
659                    }
660                }
661             }
662         }
663         if(height[i] * i_amp > p_effect->i_height)
664             height[i] = floor(p_effect->i_height / i_amp );
665
666         for(i_line = 0 ; i_line < i_amp * height[i]; i_line ++ )
667         {
668             for( j = 0 ; j< i_band_width - i_separ ; j++)
669             {
670                *(p_picture->p[0].p_pixels +
671                  (p_effect->i_height - i_line -1) *
672                   p_picture->p[0].i_pitch + (i_band_width*i +j) ) = 0xff;
673
674                 *(p_picture->p[1].p_pixels +
675                  ( ( p_effect->i_height - i_line ) / 2 -1) *
676                  p_picture->p[1].i_pitch +
677                  ( ( i_band_width * i + j ) /2  ) ) = 0x00;
678
679                if( 0x04 * i_line - 0x0f > 0 )
680                {
681                     if( 0x04 * i_line - 0x0f < 0xff )
682                          *(p_picture->p[2].p_pixels  +
683                           ( ( p_effect->i_height - i_line ) / 2 - 1) *
684                            p_picture->p[2].i_pitch +
685                            ( ( i_band_width * i + j ) /2  ) ) =
686                                ( 0x04 * i_line) -0x0f ;
687                     else
688                          *(p_picture->p[2].p_pixels  +
689                           ( ( p_effect->i_height - i_line ) / 2 - 1) *
690                            p_picture->p[2].i_pitch +
691                            ( ( i_band_width * i + j ) /2  ) ) =
692                                        0xff;
693                }
694                else
695                {
696                     *(p_picture->p[2].p_pixels  +
697                      ( ( p_effect->i_height - i_line ) / 2 - 1) *
698                      p_picture->p[2].i_pitch +
699                      ( ( i_band_width * i + j ) /2  ) ) =
700                             0x10 ;
701                }
702             }
703         }
704         }
705     }
706
707     band_sep_angle = 360.0 / i_nb_bands;
708     section_sep_angle = 360.0 / i_sections;
709     if( i_peak_height < 1 )
710         i_peak_height = 1;
711     max_band_length = p_effect->i_height / 2 - ( i_rad + i_peak_height + 1 );
712
713     i_band_width = floor( 360 / i_nb_bands - i_separ );
714     if( i_band_width < 1 )
715         i_band_width = 1;
716
717     for( c = 0 ; c < i_sections ; c++ )
718     for( i = 0 ; i < (i_nb_bands / i_sections) ; i++ )
719     {
720         /* DO A PEAK */
721         if( peaks[i] > 0 && i_peak )
722         {
723             if( peaks[i] >= p_effect->i_height )
724                 peaks[i] = p_effect->i_height - 2;
725             i_line = peaks[i];
726
727             /* circular line pattern(so color blend is more visible) */
728             for( j = 0 ; j < i_peak_height ; j++ )
729             {
730                 //x = p_picture->p[0].i_pitch / 2;
731                 x = p_effect->i_width / 2;
732                 y = p_effect->i_height / 2;
733                 xx = x;
734                 yy = y;
735                 for( k = 0 ; k < (i_band_width + i_extra_width) ; k++ )
736                 {
737                     x = xx;
738                     y = yy;
739                     a = ( (i+1) * band_sep_angle + section_sep_angle * (c+1) + k )
740                         * 3.141592 / 180.0;
741                     x += (double)( cos(a) * (double)( i_line + j + i_rad ) );
742                     y += (double)( -sin(a) * (double)( i_line + j + i_rad ) );
743
744                     *(p_picture->p[0].p_pixels + x + y * p_picture->p[0].i_pitch
745                     ) = 255;/* Y(R,G,B); */
746
747                     x /= 2;
748                     y /= 2;
749
750                     *(p_picture->p[1].p_pixels + x + y * p_picture->p[1].i_pitch
751                     ) = 0;/* U(R,G,B); */
752
753                     if( 0x04 * (i_line + k ) - 0x0f > 0 )
754                     {
755                         if ( 0x04 * (i_line + k ) -0x0f < 0xff)
756                             *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
757                             ) = ( 0x04 * ( i_line + k ) ) -(color1-1);/* -V(R,G,B); */
758                         else
759                             *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
760                             ) = 255;/* V(R,G,B); */
761                     }
762                     else
763                     {
764                         *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
765                         ) = color1;/* V(R,G,B); */
766                     }
767                 }
768             }
769         }
770
771         if( (height[i] * i_amp) > p_effect->i_height )
772             height[i] = floor( p_effect->i_height / i_amp );
773
774         /* DO BASE OF BAND (mostly makes a circle) */
775         if( i_show_base != 0 )
776         {
777             //x = p_picture->p[0].i_pitch / 2;
778             x = p_effect->i_width / 2;
779             y = p_effect->i_height / 2;
780
781             a =  ( (i+1) * band_sep_angle + section_sep_angle * (c+1) )
782                 * 3.141592 / 180.0;
783             x += (double)( cos(a) * (double)i_rad );/* newb-forceful casting */
784             y += (double)( -sin(a) * (double)i_rad );
785
786             *(p_picture->p[0].p_pixels + x + y * p_picture->p[0].i_pitch
787             ) = 255;/* Y(R,G,B); */
788
789             x /= 2;
790             y /= 2;
791
792             *(p_picture->p[1].p_pixels + x + y * p_picture->p[1].i_pitch
793             ) = 0;/* U(R,G,B); */
794
795             if( 0x04 * i_line - 0x0f > 0 )
796             {
797                 if( 0x04 * i_line -0x0f < 0xff)
798                     *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
799                     ) = ( 0x04 * i_line) -(color1-1);/* -V(R,G,B); */
800                 else
801                     *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
802                     ) = 255;/* V(R,G,B); */
803             }
804             else
805             {
806                 *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
807                 ) = color1;/* V(R,G,B); */
808             }
809         }
810
811         /* DO A BAND */
812         if( i_show_bands != 0 )
813         for( j = 0 ; j < i_band_width ; j++ )
814         {
815             x = p_effect->i_width / 2;
816             y = p_effect->i_height / 2;
817             xx = x;
818             yy = y;
819             a = ( (i+1) * band_sep_angle + section_sep_angle * (c+1) + j )
820                 * 3.141592/180.0;
821
822             for( k = (i_rad+1) ; k < max_band_length ; k++ )
823             {
824                 if( (k-i_rad) > height[i] )
825                     break;/* uhh.. */
826
827                 x = xx;
828                 y = yy;
829                 x += (double)( cos(a) * (double)k );/* newbed! */
830                 y += (double)( -sin(a) * (double)k );
831
832                 *(p_picture->p[0].p_pixels + x + y * p_picture->p[0].i_pitch
833                 ) = 255;
834
835                 x /= 2;
836                 y /= 2;
837
838                 *(p_picture->p[1].p_pixels + x + y * p_picture->p[1].i_pitch
839                 ) = 0;
840
841                 if( 0x04 * i_line - 0x0f > 0 )
842                 {
843                     if ( 0x04 * i_line -0x0f < 0xff)
844                         *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
845                         ) = ( 0x04 * i_line) -(color1-1);
846                     else
847                         *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
848                         ) = 255;
849                 }
850                 else
851                 {
852                     *(p_picture->p[2].p_pixels + x + y * p_picture->p[2].i_pitch
853                     ) = color1;
854                 }
855             }
856         }
857     }
858
859     window_close( &wind_ctx );
860
861     fft_close( p_state );
862
863     free( height );
864
865     return 0;
866 }
867
868 static void spectrometer_Free( void *data )
869 {
870     spectrometer_data *p_data = data;
871
872     if( p_data != NULL )
873     {
874         free( p_data->peaks );
875         free( p_data->p_prev_s16_buff );
876         free( p_data );
877     }
878 }
879
880
881 /*****************************************************************************
882  * scope_Run: scope effect
883  *****************************************************************************/
884 static int scope_Run(visual_effect_t * p_effect, vlc_object_t *p_aout,
885                      const block_t * p_buffer , picture_t * p_picture)
886 {
887     VLC_UNUSED(p_aout);
888
889     int i_index;
890     float *p_sample ;
891     uint8_t *ppp_area[2][3];
892
893     for( i_index = 0 ; i_index < 2 ; i_index++ )
894     {
895         for( int j = 0 ; j < 3 ; j++ )
896         {
897             ppp_area[i_index][j] =
898                 p_picture->p[j].p_pixels + (i_index * 2 + 1) * p_picture->p[j].i_lines
899                 / 4 * p_picture->p[j].i_pitch;
900         }
901     }
902
903     for( i_index = 0, p_sample = (float *)p_buffer->p_buffer;
904             i_index < __MIN( p_effect->i_width, (int)p_buffer->i_nb_samples );
905             i_index++ )
906     {
907         int8_t i_value;
908
909         /* Left channel */
910         i_value =  p_sample[p_effect->i_idx_left] * 127;
911         *(ppp_area[0][0]
912                 + p_picture->p[0].i_pitch * i_index / p_effect->i_width
913                 + p_picture->p[0].i_lines * i_value / 512
914                 * p_picture->p[0].i_pitch) = 0xbf;
915         *(ppp_area[0][1]
916                 + p_picture->p[1].i_pitch * i_index / p_effect->i_width
917                 + p_picture->p[1].i_lines * i_value / 512
918                 * p_picture->p[1].i_pitch) = 0xff;
919
920
921         /* Right channel */
922         i_value = p_sample[p_effect->i_idx_right] * 127;
923         *(ppp_area[1][0]
924                 + p_picture->p[0].i_pitch * i_index / p_effect->i_width
925                 + p_picture->p[0].i_lines * i_value / 512
926                 * p_picture->p[0].i_pitch) = 0x9f;
927         *(ppp_area[1][2]
928                 + p_picture->p[2].i_pitch * i_index / p_effect->i_width
929                 + p_picture->p[2].i_lines * i_value / 512
930                 * p_picture->p[2].i_pitch) = 0xdd;
931
932         p_sample += p_effect->i_nb_chans;
933     }
934     return 0;
935 }
936
937
938 /*****************************************************************************
939  * vuMeter_Run: vu meter effect
940  *****************************************************************************/
941 static int vuMeter_Run(visual_effect_t * p_effect, vlc_object_t *p_aout,
942                        const block_t * p_buffer , picture_t * p_picture)
943 {
944     VLC_UNUSED(p_aout);
945     float i_value_l = 0;
946     float i_value_r = 0;
947
948     /* Compute the peack values */
949     for ( unsigned i = 0 ; i < p_buffer->i_nb_samples; i++ )
950     {
951         const float *p_sample = (float *)p_buffer->p_buffer;
952         float ch;
953
954         ch = p_sample[p_effect->i_idx_left] * 256;
955         if (ch > i_value_l)
956             i_value_l = ch;
957
958         ch = p_sample[p_effect->i_idx_right] * 256;
959         if (ch > i_value_r)
960             i_value_r = ch;
961
962         p_sample += p_effect->i_nb_chans;
963     }
964
965     i_value_l = abs(i_value_l);
966     i_value_r = abs(i_value_r);
967
968     /* Stay under maximum value admited */
969     if ( i_value_l > 200 * M_PI_2 )
970         i_value_l = 200 * M_PI_2;
971     if ( i_value_r > 200 * M_PI_2 )
972         i_value_r = 200 * M_PI_2;
973
974     float *i_value;
975
976     if( !p_effect->p_data )
977     {
978         /* Allocate memory to save hand positions */
979         p_effect->p_data = malloc( 2 * sizeof(float) );
980         i_value = p_effect->p_data;
981         i_value[0] = i_value_l;
982         i_value[1] = i_value_r;
983     }
984     else
985     {
986         /* Make the hands go down slowly if the current values are slower
987            than the previous */
988         i_value = p_effect->p_data;
989
990         if ( i_value_l > i_value[0] - 6 )
991             i_value[0] = i_value_l;
992         else
993             i_value[0] = i_value[0] - 6;
994
995         if ( i_value_r > i_value[1] - 6 )
996             i_value[1] = i_value_r;
997         else
998             i_value[1] = i_value[1] - 6;
999     }
1000
1001     int x, y;
1002     float teta;
1003     float teta_grad;
1004
1005     int start_x = p_effect->i_width / 2 - 120; /* i_width.min = 532 (visual.c) */
1006
1007     for ( int j = 0; j < 2; j++ )
1008     {
1009         /* Draw the two scales */
1010         int k = 0;
1011         teta_grad = GRAD_ANGLE_MIN;
1012         for ( teta = -M_PI_4; teta <= M_PI_4; teta = teta + 0.003 )
1013         {
1014             for ( unsigned i = 140; i <= 150; i++ )
1015             {
1016                 y = i * cos(teta) + 20;
1017                 x = i * sin(teta) + start_x + 240 * j;
1018                 /* Compute the last color for the gradation */
1019                 if (teta >= teta_grad + GRAD_INCR && teta_grad <= GRAD_ANGLE_MAX)
1020                 {
1021                     teta_grad = teta_grad + GRAD_INCR;
1022                     k = k + 5;
1023                 }
1024                 *(p_picture->p[0].p_pixels +
1025                         (p_picture->p[0].i_lines - y - 1 ) * p_picture->p[0].i_pitch
1026                         + x ) = 0x45;
1027                 *(p_picture->p[1].p_pixels +
1028                         (p_picture->p[1].i_lines - y / 2 - 1 ) * p_picture->p[1].i_pitch
1029                         + x / 2 ) = 0x0;
1030                 *(p_picture->p[2].p_pixels +
1031                         (p_picture->p[2].i_lines - y / 2 - 1 ) * p_picture->p[2].i_pitch
1032                         + x / 2 ) = 0x4D + k;
1033             }
1034         }
1035
1036         /* Draw the two hands */
1037         teta = (float)i_value[j] / 200 - M_PI_4;
1038         for ( int i = 0; i <= 150; i++ )
1039         {
1040             y = i * cos(teta) + 20;
1041             x = i * sin(teta) + start_x + 240 * j;
1042             *(p_picture->p[0].p_pixels +
1043                     (p_picture->p[0].i_lines - y - 1 ) * p_picture->p[0].i_pitch
1044                     + x ) = 0xAD;
1045             *(p_picture->p[1].p_pixels +
1046                     (p_picture->p[1].i_lines - y / 2 - 1 ) * p_picture->p[1].i_pitch
1047                     + x / 2 ) = 0xFC;
1048             *(p_picture->p[2].p_pixels +
1049                     (p_picture->p[2].i_lines - y / 2 - 1 ) * p_picture->p[2].i_pitch
1050                     + x / 2 ) = 0xAC;
1051         }
1052
1053         /* Draw the hand bases */
1054         for ( teta = -M_PI_2; teta <= M_PI_2 + 0.01; teta = teta + 0.003 )
1055         {
1056             for ( int i = 0; i < 10; i++ )
1057             {
1058                 y = i * cos(teta) + 20;
1059                 x = i * sin(teta) + start_x + 240 * j;
1060                 *(p_picture->p[0].p_pixels +
1061                         (p_picture->p[0].i_lines - y - 1 ) * p_picture->p[0].i_pitch
1062                         + x ) = 0xFF;
1063                 *(p_picture->p[1].p_pixels +
1064                         (p_picture->p[1].i_lines - y / 2 - 1 ) * p_picture->p[1].i_pitch
1065                         + x / 2 ) = 0x80;
1066                 *(p_picture->p[2].p_pixels +
1067                         (p_picture->p[2].i_lines - y / 2 - 1 ) * p_picture->p[2].i_pitch
1068                         + x / 2 ) = 0x80;
1069             }
1070         }
1071
1072     }
1073
1074     return 0;
1075 }
1076
1077 /* Table of effects */
1078 const struct visual_cb_t effectv[] = {
1079     { "scope",        scope_Run,        dummy_Free        },
1080     { "vuMeter",      vuMeter_Run,      dummy_Free        },
1081     { "spectrum",     spectrum_Run,     spectrum_Free     },
1082     { "spectrometer", spectrometer_Run, spectrometer_Free },
1083     { "dummy",        dummy_Run,        dummy_Free        },
1084 };
1085 const unsigned effectc = sizeof (effectv) / sizeof (effectv[0]);