]> git.sesse.net Git - vlc/commitdiff
* effects.c :
authorClément Stenac <zorglub@videolan.org>
Fri, 29 Aug 2003 16:56:43 +0000 (16:56 +0000)
committerClément Stenac <zorglub@videolan.org>
Fri, 29 Aug 2003 16:56:43 +0000 (16:56 +0000)
  - added a spectrum analyser
  options are:
-nb :  number of bands , 20 or 80 (80 is default)
-separ : how many blank pixels between bands (1 default)
-amp : vertical amplification ( 3 default)
-peaks: draw peaks ? (default 1)

  - improved options parsing

* fft.c, fft.h :
FFT code mainly taken from XMMS (adapted coding style)

* visual.c:
Sanity checks (users aren't stupid, are they ? )

* LIST: updated the list

modules/LIST
modules/visualization/visual/Modules.am
modules/visualization/visual/effects.c
modules/visualization/visual/fft.c [new file with mode: 0644]
modules/visualization/visual/fft.h [new file with mode: 0644]
modules/visualization/visual/visual.c
modules/visualization/visual/visual.h

index 537eece51e9a83cd31da3a392a1cde72164072f3..f65fef890884d8df564136fc1cb6f18bf08d1b2c 100644 (file)
@@ -1,5 +1,5 @@
 List of vlc plugins (221)
-$Id: LIST,v 1.10 2003/08/10 12:45:52 zorglub Exp $
+$Id: LIST,v 1.11 2003/08/29 16:56:43 zorglub Exp $
 
  * a52: A/52 basic parser
 
@@ -91,6 +91,8 @@ $Id: LIST,v 1.10 2003/08/10 12:45:52 zorglub Exp $
 
  * downmixsse: SSE accelerated version of downmix.
 
+ * dshow: DirectShow access plugin for encoding cards under Windows
+
  * dts: DTS basic parser
 
  * dtstospdif: Audio converter that encapsulates DTS into S/PDIF
@@ -157,6 +159,8 @@ $Id: LIST,v 1.10 2003/08/10 12:45:52 zorglub Exp $
  
  * gnome_main: Gtk+ wrapper for gtk_main
 
+ * goom: visualisation plugin based on goom
+
  * gtk2: interface using the Gtk2 widget set.
 
  * gtk2_main: Gtk+ wrapper for gtk_main
@@ -290,6 +294,8 @@ $Id: LIST,v 1.10 2003/08/10 12:45:52 zorglub Exp $
 
  * ncurses: interface module using the ncurses library.
 
+ * ntservice: run VLC as a NT service
+
  * ogg: input module for OGG decapsulation.
 
  * oss: audio output module using the OSS /dev/dsp interface.
@@ -413,6 +419,8 @@ $Id: LIST,v 1.10 2003/08/10 12:45:52 zorglub Exp $
 
  * vcd: input module for accessing Video CDs.
 
+ * visual: visualisation system
+
  * vorbis: a vorbis audio decoder using the libvorbis library.
 
  * vout_directx: video output module using the DirectX API.
@@ -433,8 +441,6 @@ $Id: LIST,v 1.10 2003/08/10 12:45:52 zorglub Exp $
 
  * x11: video output module using the X11 API.
 
- * xmga: X11 MGA video_output plugin
  * xosd: X On Screen Display interface
 
  * xvid: Decoder for the Xvid codec, using libxvidcore
index 87f6e8b014d4a92b7231ddbe23620df7760c2d18..10db6ab79f198e64826a9ace82ef3f49af69f8df 100644 (file)
@@ -1,2 +1,3 @@
 SOURCES_visual = visual.c \
-                effects.c
+                effects.c \
+                fft.c
index a6fda096325d9f5bcddfd344635a39b5a2e9b937..79ba73b1864a1ec26fc75c9d351dfde8cfcd39ca 100644 (file)
@@ -2,7 +2,7 @@
  * effects.c : Effects for the visualization system
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: effects.c,v 1.1 2003/08/19 21:20:00 zorglub Exp $
+ * $Id: effects.c,v 1.2 2003/08/29 16:56:43 zorglub Exp $
  *
  * Authors: Clément Stenac <zorglub@via.ecp.fr>
  *
@@ -27,7 +27,9 @@
 #include "visual.h"
 #include <math.h>
 
+#include "fft.h"
 
+#define PEAK_SPEED 1
 /*****************************************************************************
  * Argument list parsers                                                     *
  *****************************************************************************/
@@ -37,21 +39,28 @@ int args_getint(char *psz_parse, char * name,const int defaut)
     int i_value;
     if( psz_parse != NULL )
     {
-        if(!strncmp( psz_parse, name, strlen(name) ) )
+        while(1)
         {
-            psz_parse += strlen( name );
-            psz_eof = strchr( psz_parse , ',' );
-            if( !psz_eof)
-                psz_eof = psz_parse + strlen(psz_parse);
-            if( psz_eof )
+            if(!strncmp( psz_parse, name, strlen(name) ) )
             {
-                *psz_eof = '\0' ;
+                psz_parse += strlen( name );
+                psz_eof = strchr( psz_parse , ',' );
+                if( !psz_eof)
+                    psz_eof = psz_parse + strlen(psz_parse);
+                if( psz_eof )
+                {
+                    *psz_eof = '\0' ;
+                }
+                i_value = atoi(++psz_parse);
+                psz_parse= psz_eof;
+                psz_parse++;
+                return i_value;
             }
-            i_value = atoi(++psz_parse);
-            psz_parse= psz_eof;
-            psz_parse++;
-            return i_value;
-        }
+            if( *psz_parse )
+                psz_parse ++;
+            else
+                break;
+        } 
     }
     return defaut;
 }
@@ -63,23 +72,30 @@ char * args_getpsz(char *psz_parse, char * name,const char * defaut)
     char *psz_value;
     if( psz_parse != NULL )
     {
-        if(!strncmp( psz_parse, name, strlen(name) ) )                            
+        while(1)
         {
-            psz_parse += strlen( name );
-            psz_eof = strchr( psz_parse , ',' );
-            if( !psz_eof)
-                psz_eof = psz_parse + strlen(psz_parse);
-            if( psz_eof )
+            if(!strncmp( psz_parse, name, strlen(name) ) )                            
             {
-                *psz_eof = '\0' ;
+                psz_parse += strlen( name );
+                psz_eof = strchr( psz_parse , ',' );
+                if( !psz_eof)
+                    psz_eof = psz_parse + strlen(psz_parse);
+                if( psz_eof )
+                {
+                    *psz_eof = '\0' ;
+                }
+                psz_value = strdup(++psz_parse);
+                psz_parse= psz_eof;
+                psz_parse++;
+                return psz_value;
             }
-            psz_value = strdup(++psz_parse);
-            psz_parse= psz_eof;
-            psz_parse++;
-            return psz_value;
+            if( *psz_parse )
+                psz_parse ++;
+            else
+                break;
         }
     }
-        return strdup(defaut);
+    return strdup(defaut);
 }
 
 
@@ -98,7 +114,287 @@ int dummy_Run( visual_effect_t * p_effect, aout_instance_t *p_aout,
 int spectrum_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
                  aout_buffer_t * p_buffer , picture_t * p_picture)
 {
-        return 0;
+    float p_output[FFT_BUFFER_SIZE];  /* Raw FFT Result  */
+    int *height;                      /* Bar heights */
+    int *peaks;                       /* Peaks */
+    int i_nb_bands;                   /* number of bands */
+    int i_band_width;                 /* width of bands */
+    int i_separ;                      /* Should we let blanks ? */
+    int i_amp;                        /* Vertical amplification */
+    int i_peak;                       /* Should we draw peaks ? */
+    char *psz_parse = NULL;           /* Args line */
+    
+    /* Horizontal scale for 20-band equalizer */
+    const int xscale1[]={0,1,2,3,4,5,6,7,8,11,15,20,27,
+                        36,47,62,82,107,141,184,255};
+                        
+    /* Horizontal scale for 80-band equalizer */
+    const int xscale2[] = 
+    {0,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,
+     35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
+     52,53,54,55,56,57,58,59,61,63,67,72,77,82,87,93,99,105,
+     110,115,121,130,141,152,163,174,185,255};
+    const int *xscale;
+    const double y_scale =  3.60673760222;  /* (log 256) */
+    
+    fft_state *p_state;                 /* internal FFT data */
+    
+    int i , j , y , k;
+    int i_line;
+    s16 p_dest[FFT_BUFFER_SIZE];          /* Adapted FFT result */
+    s16 p_buffer1[FFT_BUFFER_SIZE];       /* Buffer on which we perform
+                                             the FFT (first channel) */
+
+    float *p_buffl =                     /* Original buffer */
+            (float*)p_buffer->p_buffer;
+
+    s16  *p_buffs;                        /* s16 converted buffer */
+    s16  *p_s16_buff = NULL;                    /* s16 converted buffer */
+    
+    p_s16_buff = (s16*)malloc( 
+              p_buffer->i_nb_samples * p_effect->i_nb_chans * sizeof(s16));
+
+    if( !p_s16_buff )
+    {
+        msg_Err(p_aout,"Out of memory");
+        return -1;
+    }
+    
+    p_buffs = p_s16_buff;
+    if( p_effect->psz_args )
+    {
+        psz_parse  = strdup( p_effect->psz_args );
+        i_nb_bands = args_getint ( psz_parse , "nb" , 80 );
+        psz_parse  = strdup( p_effect->psz_args );
+        i_separ    = args_getint ( psz_parse , "separ", 1 );
+        psz_parse  = strdup( p_effect->psz_args );
+        i_amp     = args_getint ( psz_parse , "amp", 3 );
+        psz_parse  = strdup( p_effect->psz_args );
+        i_peak     = args_getint ( psz_parse , "peaks", 1 );
+    }
+    else
+    {
+       i_nb_bands = 80;
+       i_separ = 1;
+       i_amp = 3;
+       i_peak = 1;
+    }
+
+    if( i_nb_bands == 20)
+    {
+        xscale = xscale1;
+    }
+    else
+    {
+        i_nb_bands = 80;
+        xscale = xscale2;
+    }
+    
+    if( !p_effect->p_data )
+    {
+        p_effect->p_data=(void *)malloc(i_nb_bands * sizeof(int) );
+        if( !p_effect->p_data)
+        {
+            msg_Err(p_aout,"Out of memory");
+            return -1;
+        }
+        peaks = (int *)p_effect->p_data;
+        for( i = 0 ; i < i_nb_bands ; i++)
+        {
+           peaks[i] = 0;
+        }
+                      
+    }
+    else
+    {
+        peaks =(int *)p_effect->p_data;
+    }
+   
+    
+    height = (int *)malloc( i_nb_bands * sizeof(int) );
+    if( !height)
+    {
+        msg_Err(p_aout,"Out of memory");
+        return -1;
+    }
+    /* Convert the buffer to s16  */
+    /* Pasted from float32tos16.c */
+    for (i = p_buffer->i_nb_samples * p_effect->i_nb_chans; i--; )
+    {
+        float f_in = *p_buffl + 384.0;
+        s32 i_in;
+        i_in = *(s32 *)&f_in;
+        if(i_in >  0x43c07fff ) * p_buffs = 32767;
+        else if ( i_in < 0x43bf8000 ) *p_buffs = -32768;
+        else *p_buffs = i_in - 0x43c00000;
+      
+        p_buffl++ ; p_buffs++ ;
+    }
+    p_state  = fft_init();
+    if( !p_state)
+    {
+        msg_Err(p_aout,"Unable to initialize FFT transform");
+        return -1;
+    }
+    p_buffs = p_s16_buff;
+    for ( i = 0 ; i < FFT_BUFFER_SIZE ; i++)
+    {
+        p_output[i]    = 0;
+        p_buffer1[i] = *p_buffs;
+        p_buffs      = p_buffs + p_effect->i_nb_chans;
+    } 
+    fft_perform( p_buffer1, p_output, p_state);
+    for(i= 0; i< FFT_BUFFER_SIZE ; i++ )
+        p_dest[i] = ( (int) sqrt( p_output [ i + 1 ] ) ) >> 8;
+                
+    for ( i = 0 ; i< i_nb_bands ;i++)
+    {
+        /* We search the maximum on one scale */
+        for( j = xscale[i] , y=0 ; j< xscale[ i + 1 ] ; j++ )
+        {
+            if ( p_dest[j] > y )
+                 y = p_dest[j];
+        }
+        /* Calculate the height of the bar */
+        y >>=5; /* remove some noise */
+        if( y != 0)
+        {
+            height[i] = (int)log(y)* y_scale;
+               if(height[i] > 150)
+                  height[i] = 150;
+        }
+        else
+        {
+            height[i] = 0 ;
+        }
+             
+        /* Draw the bar now */
+        i_band_width = floor( p_effect->i_width / i_nb_bands) ;
+
+        if( i_amp * height[i] > peaks[i])
+        {
+            peaks[i] = i_amp * height[i];
+        }
+        else if (peaks[i] > 0 )
+        {
+            peaks[i] -= PEAK_SPEED;
+            if( peaks[i] < i_amp * height[i] )
+            {
+                peaks[i] = i_amp * height[i];
+            }
+            if( peaks[i] < 0 )
+            {
+                peaks[i] = 0;
+            }
+        }
+
+        if( peaks[i] > 0 && i_peak )
+        {
+            if( peaks[i] >= p_effect->i_height ) 
+                peaks[i] = p_effect->i_height - 2;
+            i_line = peaks[i];
+            
+            for( j = 0 ; j< i_band_width - i_separ; j++)
+            {
+               for( k = 0 ; k< 3 ; k ++)
+               {
+                   /* Draw the peak */
+                     *(p_picture->p[0].p_pixels + 
+                    (p_picture->p[0].i_lines - i_line -1 -k ) * 
+                     p_picture->p[0].i_pitch + (i_band_width*i +j) ) 
+                                    = 0xff;
+
+                    *(p_picture->p[1].p_pixels +
+                     (p_picture->p[1].i_lines - i_line /2 -1 -k/2 ) *
+                     p_picture->p[1].i_pitch + 
+                    ( ( i_band_width * i + j ) /2  ) )
+                                    = 0x00;
+  
+                   if( 0x04 * (i_line + k ) - 0x0f > 0 )
+                   {
+                       if ( 0x04 * (i_line + k ) -0x0f < 0xff)
+                           *(p_picture->p[2].p_pixels  +
+                            (p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
+                             p_picture->p[2].i_pitch + 
+                             ( ( i_band_width * i + j ) /2  ) ) 
+                                    = ( 0x04 * ( i_line + k ) ) -0x0f ;
+                       else
+                           *(p_picture->p[2].p_pixels  +
+                            (p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
+                             p_picture->p[2].i_pitch + 
+                             ( ( i_band_width * i + j ) /2  ) ) 
+                                    = 0xff; 
+                   }
+                   else
+                   {
+                        *(p_picture->p[2].p_pixels  +
+                         (p_picture->p[2].i_lines - i_line /2 - 1 -k/2 ) *
+                         p_picture->p[2].i_pitch + 
+                         ( ( i_band_width * i + j ) /2  ) ) 
+                               = 0x10 ;
+                   }
+               }
+            } 
+        }
+    
+        if(height[i] * i_amp > p_effect->i_height)
+            height[i] = floor(p_effect->i_height / i_amp );
+
+        for(i_line = 0 ; i_line < i_amp * height[i]; i_line ++ )
+        {
+            for( j = 0 ; j< i_band_width - i_separ ; j++)
+            {
+               *(p_picture->p[0].p_pixels + 
+                 (p_picture->p[0].i_lines - i_line -1) * 
+                  p_picture->p[0].i_pitch + (i_band_width*i +j) ) = 0xff;
+
+                *(p_picture->p[1].p_pixels +
+                 (p_picture->p[1].i_lines - i_line /2 -1) *
+                 p_picture->p[1].i_pitch + 
+                 ( ( i_band_width * i + j ) /2  ) ) = 0x00;
+
+               
+               if( 0x04 * i_line - 0x0f > 0 )
+               {
+                    if( 0x04 * i_line - 0x0f < 0xff )
+                         *(p_picture->p[2].p_pixels  +
+                          (p_picture->p[2].i_lines - i_line /2 - 1) *
+                           p_picture->p[2].i_pitch + 
+                           ( ( i_band_width * i + j ) /2  ) ) = 
+                               ( 0x04 * i_line) -0x0f ;
+                    else
+                         *(p_picture->p[2].p_pixels  +
+                          (p_picture->p[2].i_lines - i_line /2 - 1) *
+                           p_picture->p[2].i_pitch + 
+                           ( ( i_band_width * i + j ) /2  ) ) = 
+                                       0xff;
+               }
+               else
+               {
+                    *(p_picture->p[2].p_pixels  +
+                     (p_picture->p[2].i_lines - i_line /2 - 1) *
+                     p_picture->p[2].i_pitch + 
+                     ( ( i_band_width * i + j ) /2  ) ) = 
+                            0x10 ;
+               }
+            }
+        }
+    }
+       
+    fft_close( p_state );
+   
+    if( p_s16_buff != NULL ) 
+    {
+        free( p_s16_buff );
+        p_s16_buff = NULL;
+    }
+   
+    if(height) free(height);
+   
+    if(psz_parse) free(psz_parse);
+    
+    return 0;
 }
 
         
@@ -172,15 +468,7 @@ int random_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
     if( p_effect->psz_args )
     {
         psz_parse = strdup( p_effect->psz_args );
-        while(1)
-        {
-            i_nb_plots = args_getint ( psz_parse , "nb" , 200 );
-            if(i_nb_plots) break;
-            if( *psz_parse )
-                 psz_parse ++;
-            else
-                break;
-        }
+        i_nb_plots = args_getint ( psz_parse , "nb" , 200 );
     }
     else
     {
@@ -194,6 +482,61 @@ int random_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
         i_u = rand() % 256;
         i_v = rand() % 256;
         *(p_picture->p[0].p_pixels + i_position )= i_u;
+        *(p_picture->p[1].p_pixels + i_position/4) = i_v;
+        *(p_picture->p[2].p_pixels + i_position/4) = i_y;
     }
     return 0;
 }
+
+/*****************************************************************************
+ * blur_Run:  blur effect
+ *****************************************************************************/
+#if 0 
+  /* This code is totally crappy */
+int blur_Run(visual_effect_t * p_effect, aout_instance_t *p_aout,
+              aout_buffer_t * p_buffer , picture_t * p_picture)
+{
+    uint8_t * p_pictures;
+    int i,j; 
+    int i_size;   /* Total size of one image */
+    
+    i_size = (p_picture->p[0].i_pitch * p_picture->p[0].i_lines +
+              p_picture->p[1].i_pitch * p_picture->p[1].i_lines +
+              p_picture->p[2].i_pitch * p_picture->p[2].i_lines );
+    
+    if( !p_effect->p_data )
+    {
+        p_effect->p_data=(void *)malloc( 5 * i_size *sizeof(uint8_t));
+        
+        if( !p_effect->p_data)
+        {
+            msg_Err(p_aout,"Out of memory");
+            return -1;
+        }
+        p_pictures = (uint8_t *)p_effect->p_data;
+    }
+    else
+    {
+        p_pictures =(uint8_t *)p_effect->p_data;
+    }
+
+    for( i = 0 ; i < 5 ; i++)
+    {
+        for ( j = 0 ; j< p_picture->p[0].i_pitch * p_picture->p[0].i_lines; i++)
+            p_picture->p[0].p_pixels[j] = 
+                    p_pictures[i * i_size + j] * (100 - 20 * i) /100 ;
+        for ( j = 0 ; j< p_picture->p[1].i_pitch * p_picture->p[1].i_lines; i++)
+            p_picture->p[1].p_pixels[j] = 
+                    p_pictures[i * i_size +
+                    p_picture->p[0].i_pitch * p_picture->p[0].i_lines + j ];
+        for ( j = 0 ; j< p_picture->p[2].i_pitch * p_picture->p[2].i_lines; i++)
+            p_picture->p[2].p_pixels[j] = 
+                    p_pictures[i * i_size +
+                    p_picture->p[0].i_pitch * p_picture->p[0].i_lines +
+                    p_picture->p[1].i_pitch * p_picture->p[1].i_lines 
+                    + j ];
+    }
+
+    memcpy ( &p_pictures[ i_size ] , &p_pictures[0] , 4 * i_size * sizeof(uint8_t) );
+}
+#endif
diff --git a/modules/visualization/visual/fft.c b/modules/visualization/visual/fft.c
new file mode 100644 (file)
index 0000000..0ddc3ed
--- /dev/null
@@ -0,0 +1,213 @@
+/*****************************************************************************
+ * fft.c: Iterative implementation of a FFT
+ *****************************************************************************
+ * $Id: fft.c,v 1.1 2003/08/29 16:56:43 zorglub Exp $
+ *
+ * Mainly taken from XMMS's code
+ * 
+ * Authors: Richard Boulton <richard@tartarus.org>
+ *          Ralph Loader <suckfish@ihug.co.nz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include "fft.h"
+
+#include <stdlib.h>
+#include <math.h>
+#ifndef PI
+ #ifdef M_PI
+  #define PI M_PI
+ #else
+  #define PI            3.14159265358979323846  /* pi */
+ #endif
+#endif
+
+/******************************************************************************
+ * Local prototypes 
+ *****************************************************************************/
+static void fft_prepare(const sound_sample *input, float * re, float * im);
+static void fft_calculate(float * re, float * im);
+static void fft_output(const float *re, const float *im, float *output);
+static int reverseBits(unsigned int initial);
+
+
+/* Table to speed up bit reverse copy */
+static unsigned int bitReverse[FFT_BUFFER_SIZE];
+
+/* The next two tables could be made to use less space in memory, since they
+ * overlap hugely, but hey. */
+static float sintable[FFT_BUFFER_SIZE / 2];
+static float costable[FFT_BUFFER_SIZE / 2];
+
+/*****************************************************************************
+ * These functions are the ones called externally
+ *****************************************************************************/
+
+/*
+ * Initialisation routine - sets up tables and space to work in.
+ * Returns a pointer to internal state, to be used when performing calls.
+ * On error, returns NULL.
+ * The pointer should be freed when it is finished with, by fft_close().
+ */
+fft_state *fft_init(void) 
+{
+    fft_state *p_state;
+    unsigned int i;
+
+    p_state = (fft_state *) malloc (sizeof(fft_state));
+    if(! p_state ) 
+        return NULL;
+
+    for(i = 0; i < FFT_BUFFER_SIZE; i++) 
+    {
+       bitReverse[i] = reverseBits(i);
+    }
+    for(i = 0; i < FFT_BUFFER_SIZE / 2; i++) 
+    {
+       float j = 2 * PI * i / FFT_BUFFER_SIZE;
+       costable[i] = cos(j);
+       sintable[i] = sin(j);
+    }
+
+    return p_state;
+}
+
+/*
+ * Do all the steps of the FFT, taking as input sound data (as described in
+ * sound.h) and returning the intensities of each frequency as floats in the
+ * range 0 to ((FFT_BUFFER_SIZE / 2) * 32768) ^ 2
+ *
+ * The input array is assumed to have FFT_BUFFER_SIZE elements,
+ * and the output array is assumed to have (FFT_BUFFER_SIZE / 2 + 1) elements.
+ * state is a (non-NULL) pointer returned by fft_init.
+ */
+void fft_perform(const sound_sample *input, float *output, fft_state *state) {
+    /* Convert data from sound format to be ready for FFT */
+    fft_prepare(input, state->real, state->imag);
+
+    /* Do the actual FFT */
+    fft_calculate(state->real, state->imag);
+
+    /* Convert the FFT output into intensities */
+    fft_output(state->real, state->imag, output);
+}
+
+/*
+ * Free the state.
+ */
+void fft_close(fft_state *state) {
+    if(state) free(state);
+}
+
+/*****************************************************************************
+ * These functions are called from the other ones
+ *****************************************************************************/
+
+/*
+ * Prepare data to perform an FFT on
+ */
+static void fft_prepare(const sound_sample *input, float * re, float * im) {
+    unsigned int i;
+    float *p_real = re;
+    float *p_imag = im;
+    
+    /* Get input, in reverse bit order */
+    for(i = 0; i < FFT_BUFFER_SIZE; i++) 
+    {
+       *p_real++ = input[bitReverse[i]];
+       *p_imag++ = 0;
+    }
+}
+
+/*
+ * Take result of an FFT and calculate the intensities of each frequency
+ * Note: only produces half as many data points as the input had.
+ */
+static void fft_output(const float * re, const float * im, float *output)
+{
+    float *p_output = output;
+    const float *p_real   = re;
+    const float *p_imag   = im;
+    float *p_end    = output + FFT_BUFFER_SIZE / 2;
+    while(p_output <= p_end) 
+    {
+       *p_output = (*p_real * *p_real) + (*p_imag * *p_imag);
+       p_output++; p_real++; p_imag++;
+    }
+    /* Do divisions to keep the constant and highest frequency terms in scale
+     * with the other terms. */
+    *output /= 4;
+    *p_end /= 4;
+}
+
+
+/*
+ * Actually perform the FFT
+ */
+static void fft_calculate(float * re, float * im) 
+{
+    unsigned int i, j, k;
+    unsigned int exchanges;
+    float fact_real, fact_imag;
+    float tmp_real, tmp_imag;
+    unsigned int factfact;
+    
+    /* Set up some variables to reduce calculation in the loops */
+    exchanges = 1;
+    factfact = FFT_BUFFER_SIZE / 2;
+
+    /* Loop through the divide and conquer steps */
+    for(i = FFT_BUFFER_SIZE_LOG; i != 0; i--) {
+       /* In this step, we have 2 ^ (i - 1) exchange groups, each with
+        * 2 ^ (FFT_BUFFER_SIZE_LOG - i) exchanges
+        */
+       /* Loop through the exchanges in a group */
+       for(j = 0; j != exchanges; j++) {
+           /* Work out factor for this exchange
+            * factor ^ (exchanges) = -1
+            * So, real = cos(j * PI / exchanges),
+            *     imag = sin(j * PI / exchanges)
+            */
+           fact_real = costable[j * factfact];
+           fact_imag = sintable[j * factfact];
+           
+           /* Loop through all the exchange groups */
+           for(k = j; k < FFT_BUFFER_SIZE; k += exchanges << 1) {
+               int k1 = k + exchanges;
+               tmp_real = fact_real * re[k1] - fact_imag * im[k1];
+               tmp_imag = fact_real * im[k1] + fact_imag * re[k1];
+               re[k1] = re[k] - tmp_real;
+               im[k1] = im[k] - tmp_imag;
+               re[k]  += tmp_real;
+               im[k]  += tmp_imag;
+           }
+       }
+       exchanges <<= 1;
+       factfact >>= 1;
+    }
+}
+
+static int reverseBits(unsigned int initial) 
+{
+    unsigned int reversed = 0, loop;
+    for(loop = 0; loop < FFT_BUFFER_SIZE_LOG; loop++) {
+       reversed <<= 1;
+       reversed += (initial & 1);
+       initial >>= 1;
+    }
+    return reversed;
+}
diff --git a/modules/visualization/visual/fft.h b/modules/visualization/visual/fft.h
new file mode 100644 (file)
index 0000000..bf11dcc
--- /dev/null
@@ -0,0 +1,48 @@
+/*****************************************************************************
+ * fft.h: Headers for iterative implementation of a FFT
+ *****************************************************************************
+ * $Id: fft.h,v 1.1 2003/08/29 16:56:43 zorglub Exp $
+ *
+ * Mainly taken from XMMS's code
+ * 
+ * Authors: Richard Boulton <richard@tartarus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef _FFT_H_
+#define _FFT_H_
+
+#define FFT_BUFFER_SIZE_LOG 9
+
+#define FFT_BUFFER_SIZE (1 << FFT_BUFFER_SIZE_LOG)
+
+/* sound sample - should be an signed 16 bit value */
+typedef short int sound_sample;
+
+struct _struct_fft_state {
+     /* Temporary data stores to perform FFT in. */
+     float real[FFT_BUFFER_SIZE];
+     float imag[FFT_BUFFER_SIZE];
+};
+
+/* FFT prototypes */
+typedef struct _struct_fft_state fft_state;
+fft_state *fft_init (void);
+void fft_perform (const sound_sample *input, float *output, fft_state *state);
+void fft_close (fft_state *state);
+
+
+#endif /* _FFT_H_ */
index 120bb9e97557dfebea3f10b0e5620fa2c7078fbb..00998d18e9e2013357b6f2992c99b7a16379560c 100644 (file)
@@ -2,7 +2,7 @@
  * visual.c : Visualisation system
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: visual.c,v 1.1 2003/08/19 21:20:00 zorglub Exp $
+ * $Id: visual.c,v 1.2 2003/08/29 16:56:43 zorglub Exp $
  *
  * Authors: Clément Stenac <zorglub@via.ecp.fr>
  *
@@ -97,7 +97,18 @@ static int Open( vlc_object_t *p_this )
     }
 
     p_filter->p_sys->i_height = config_GetInt( p_filter , "effect-height");
-    p_filter->p_sys->i_width = config_GetInt( p_filter , "effect-width");
+    p_filter->p_sys->i_width  = config_GetInt( p_filter , "effect-width");
+
+    if ( p_filter->p_sys->i_height < 20 ) 
+        p_filter->p_sys->i_height =  20;
+    if ( p_filter->p_sys->i_width < 20 ) 
+        p_filter->p_sys->i_width =  20;
+    
+    if( (p_filter->p_sys->i_height % 2 ) != 0 )
+        p_filter->p_sys->i_height --;
+   
+    if( (p_filter->p_sys->i_width % 2 ) != 0 )
+        p_filter->p_sys->i_width --;
     
     /* Parse the effect list */
     psz_effects = config_GetPsz( p_filter, "effect-list" );
@@ -113,40 +124,6 @@ static int Open( vlc_object_t *p_this )
 
     p_current_effect = p_filter->p_sys->p_first_effect;
     p_current_effect->p_next = NULL;
-    
-#define SEARCH(name , function )                                              \
-    if(!strncmp( psz_effects , name, strlen(name) ) )                         \
-    {                                                                         \
-        p_current_effect->p_next =                                            \
-                (visual_effect_t *)malloc( sizeof( visual_effect_t ) );       \
-        if( !p_current_effect )                                               \
-        {                                                                     \
-            msg_Err( p_filter, "Out of memory" );                             \
-        }                                                                     \
-        p_current_effect = p_current_effect -> p_next;                        \
-        p_current_effect->pf_run = NULL;                                      \
-        p_current_effect->p_next = NULL;                                      \
-        p_current_effect->i_width = p_filter->p_sys->i_width;                 \
-        p_current_effect->i_height = p_filter->p_sys->i_height;               \
-        p_current_effect->pf_run = function ;                                 \
-        p_current_effect->psz_args  = NULL;                                   \
-        psz_boa = strchr( psz_effects, '{' );                                 \
-        if( psz_boa )                                                         \
-        {                                                                     \
-            psz_eoa = strchr( psz_effects, '}');                              \
-            if( ! psz_eoa )                                                   \
-            {                                                                 \
-               msg_Err( p_filter, "Unable to parse effect list. Aborting");   \
-               return -1;                                                     \
-            }                                                                 \
-            *psz_eoa = '\0';                                                  \
-            p_current_effect->psz_args = strdup(++psz_boa);                   \
-            psz_effects = psz_eoa;                                            \
-        }                                                                     \
-        msg_Dbg(p_filter, "Adding filter: %s ( %s )",name,                    \
-                        p_current_effect->psz_args);                          \
-    }
-    
     while(1)
     {
         psz_eof = strchr( psz_effects , ';'  );
@@ -159,26 +136,62 @@ static int Open( vlc_object_t *p_this )
         {
             *psz_eof = '\0';
         }
-    
 
-        SEARCH("dummy",dummy_Run);
-        SEARCH("scope",scope_Run);
-        SEARCH("random",random_Run);
-        SEARCH("spectrum",spectrum_Run);
-        
+        p_current_effect->p_next =
+                (visual_effect_t *)malloc( sizeof( visual_effect_t ) );
+        if( !p_current_effect )
+        {
+            msg_Err( p_filter, "Out of memory" );
+        }
+        p_current_effect = p_current_effect -> p_next;
+        p_current_effect->pf_run = NULL;
+        p_current_effect->p_next = NULL;
+        p_current_effect->i_width = p_filter->p_sys->i_width;
+        p_current_effect->i_height = p_filter->p_sys->i_height;
+        p_current_effect->p_data = NULL;
+
+        if(! strncasecmp(psz_effects,"dummy",5))
+            p_current_effect->pf_run = dummy_Run;
+        else if(! strncasecmp(psz_effects,"scope",5) )
+            p_current_effect->pf_run = scope_Run;
+        else if(! strncasecmp(psz_effects,"spectrum",8) )
+            p_current_effect->pf_run = spectrum_Run;
+        else if(! strncasecmp(psz_effects,"random",6) )
+            p_current_effect->pf_run = random_Run;
+#if 0
+        else if(! strncasecmp(psz_effects,"blur",4) )
+            p_current_effect->pf_run = blur_Run;
+#endif
+        p_current_effect->psz_args  = NULL;
+        p_current_effect->i_nb_chans =
+                aout_FormatNbChannels( &p_filter->input);
+        psz_boa = strchr( psz_effects, '{' );
+        if( psz_boa )
+        {
+            psz_eoa = strchr( psz_effects, '}');
+            if( ! psz_eoa )
+            {
+               msg_Err( p_filter, "Unable to parse effect list. Aborting");
+               return -1;
+            }
+            *psz_eoa = '\0';
+            p_current_effect->psz_args = strdup(++psz_boa);
+            psz_effects = psz_eoa;
+        }
         psz_effects =  psz_eof;
         psz_effects ++;
 
-        if( !* psz_effects || b_end == VLC_TRUE )
+        if( b_end == VLC_TRUE )
             break;
     }
                 
     p_filter->pf_do_work = DoWork;
-    p_filter->b_in_place= 0;
+    p_filter->b_in_place= 1;
 
     /* Open the video output */
     p_filter->p_sys->p_vout =
-         vout_Create( p_filter, p_filter->p_sys->i_width, 
+         vout_Request( p_filter, NULL,
+                         p_filter->p_sys->i_width, 
                          p_filter->p_sys->i_height,
                   VLC_FOURCC('I','4','2','0'), 
                   VOUT_ASPECT_FACTOR * p_filter->p_sys->i_width/
@@ -315,6 +328,8 @@ static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
 
     while( p_current_effect )  
     {
+
+#if 1
         /* FIXME: Find why it segfaults when we directly call
          * p_current_effect->pf_run(....)
          *  (segfault in errno()  ) */
@@ -334,7 +349,15 @@ static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
         {
             spectrum_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
         }
-            
+#if 0
+        else if (p_current_effect->pf_run == blur_Run )
+        {
+            blur_Run(p_current_effect, p_aout, p_out_buf , p_outpic );
+        }
+#endif
+#else
+        p_current_effect->pf_run(p_current_effect, p_aout, p_out_buf , p_outpic );
+#endif
         p_current_effect = p_current_effect->p_next;
     }
    
@@ -343,7 +366,6 @@ static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
     
     vout_DisplayPicture ( p_filter->p_sys->p_vout, p_outpic );
 
-    
 }
 
 /*****************************************************************************
@@ -353,12 +375,23 @@ static void Close( vlc_object_t *p_this )
 {
     aout_filter_t * p_filter = (aout_filter_t *)p_this;
 
+    visual_effect_t *p_old;
+    visual_effect_t *p_cur = p_filter->p_sys->p_first_effect;
+    
     if( p_filter->p_sys->p_vout ) 
     {
         vlc_object_detach( p_filter->p_sys->p_vout) ;
         vout_Destroy( p_filter->p_sys->p_vout );
     }
-    
+   
+    /* Free the list */ 
+    while( p_cur )
+    {
+        p_old = p_cur;
+        p_cur = p_cur->p_next;
+        if( p_old ) free( p_old );
+    }
+                    
     if( p_filter->p_sys != NULL )
         free( p_filter->p_sys);
 }
index f145121f9f30b210729afe544898132df4499060..807e84a6e424b2af39df2f688eee36277139cbbd 100644 (file)
@@ -2,7 +2,7 @@
  * visual.h : Header for the visualisation system
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: visual.h,v 1.1 2003/08/19 21:20:00 zorglub Exp $
+ * $Id: visual.h,v 1.2 2003/08/29 16:56:43 zorglub Exp $
  *
  * Authors: Clément Stenac <zorglub@via.ecp.fr>
  *
@@ -51,6 +51,7 @@ typedef struct visual_effect_t
     int        i_width;
     int        i_height;
     char *     psz_args; 
+    int        i_nb_chans;
 } visual_effect_t ;
 
 
@@ -71,7 +72,10 @@ int random_Run
         (visual_effect_t * , aout_instance_t *, aout_buffer_t *, picture_t *);
 int spectrum_Run
         (visual_effect_t * , aout_instance_t *, aout_buffer_t *, picture_t *);
-
+#if 0
+int blur_Run
+        (visual_effect_t * , aout_instance_t *, aout_buffer_t *, picture_t *);
+#endif
 
 /* Default vout size */       
 #define VOUT_WIDTH 320