1 /*****************************************************************************
2 * projectm.cpp: visualization module based on libprojectM
3 *****************************************************************************
4 * Copyright © 2009-2011 VLC authors and VideoLAN
7 * Authors: Rémi Duraffort <ivoire@videolan.org>
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.
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.
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 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
32 #include <vlc_vout_window.h>
33 #include <vlc_opengl.h>
34 #include <vlc_filter.h>
37 #include <libprojectM/projectM.hpp>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int Open ( vlc_object_t
* );
43 static void Close ( vlc_object_t
* );
45 #define CONFIG_TEXT N_("projectM configuration file")
46 #define CONFIG_LONGTEXT N_("File that will be used to configure the projectM " \
49 #define PRESET_PATH_TXT N_("projectM preset path")
50 #define PRESET_PATH_LONGTXT N_("Path to the projectM preset directory")
52 #define TITLE_FONT_TXT N_("Title font")
53 #define TITLE_FONT_LONGTXT N_("Font used for the titles")
55 #define MENU_FONT_TXT N_("Font menu")
56 #define MENU_FONT_LONGTXT N_("Font used for the menus")
58 #define WIDTH_TEXT N_("Video width")
59 #define WIDTH_LONGTEXT N_("The width of the video window, in pixels.")
61 #define HEIGHT_TEXT N_("Video height")
62 #define HEIGHT_LONGTEXT N_("The height of the video window, in pixels.")
64 #define MESHX_TEXT N_("Mesh width")
65 #define MESHX_LONGTEXT N_("The width of the mesh, in pixels.")
67 #define MESHY_TEXT N_("Mesh height")
68 #define MESHY_LONGTEXT N_("The height of the mesh, in pixels.")
70 #define TEXTURE_TEXT N_("Texture size")
71 #define TEXTURE_LONGTEXT N_("The size of the texture, in pixels.")
74 # define FONT_PATH "C:\\WINDOWS\\Fonts\\arial.ttf"
75 # define FONT_PATH_MENU "C:\\WINDOWS\\Fonts\\arial.ttf"
76 # define PRESET_PATH NULL
78 # define FONT_PATH "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"
79 # define FONT_PATH_MENU "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf"
80 # define PRESET_PATH "/usr/share/projectM/presets"
83 #ifdef DEFAULT_FONT_FILE
85 #define FONT_PATH DEFAULT_FONT_FILE
88 #ifdef DEFAULT_MONOSPACE_FONT_FILE
90 #define FONT_PATH_MENU DEFAULT_MONOSPACE_FONT_FILE
94 set_shortname( N_("projectM"))
95 set_description( N_("libprojectM effect") )
96 set_capability( "visualization", 0 )
97 set_category( CAT_AUDIO
)
98 set_subcategory( SUBCAT_AUDIO_VISUAL
)
99 #ifndef HAVE_PROJECTM2
100 add_loadfile( "projectm-config", "/usr/share/projectM/config.inp",
101 CONFIG_TEXT
, CONFIG_LONGTEXT
, true )
103 add_directory( "projectm-preset-path", PRESET_PATH
,
104 PRESET_PATH_TXT
, PRESET_PATH_LONGTXT
, true )
105 add_loadfile( "projectm-title-font", FONT_PATH
,
106 TITLE_FONT_TXT
, TITLE_FONT_LONGTXT
, true )
107 add_loadfile( "projectm-menu-font", FONT_PATH_MENU
,
108 MENU_FONT_TXT
, MENU_FONT_LONGTXT
, true )
110 add_integer( "projectm-width", 800, WIDTH_TEXT
, WIDTH_LONGTEXT
,
112 add_integer( "projectm-height", 500, HEIGHT_TEXT
, HEIGHT_LONGTEXT
,
114 add_integer( "projectm-meshx", 32, MESHX_TEXT
, MESHX_LONGTEXT
,
116 add_integer( "projectm-meshy", 24, MESHY_TEXT
, MESHY_LONGTEXT
,
118 add_integer( "projectm-texture-size", 1024, TEXTURE_TEXT
, TEXTURE_LONGTEXT
,
120 add_shortcut( "projectm" )
121 set_callbacks( Open
, Close
)
125 /*****************************************************************************
127 *****************************************************************************/
143 unsigned i_buffer_size
;
144 unsigned i_nb_samples
;
148 static block_t
*DoWork( filter_t
*, block_t
* );
149 static void *Thread( void * );
153 * @param p_this: the filter object
154 * @return VLC_SUCCESS or vlc error codes
156 static int Open( vlc_object_t
* p_this
)
158 filter_t
*p_filter
= (filter_t
*)p_this
;
161 p_sys
= p_filter
->p_sys
= (filter_sys_t
*)malloc( sizeof( *p_sys
) );
165 /* Create the object for the thread */
166 p_sys
->b_quit
= false;
167 p_sys
->i_channels
= aout_FormatNbChannels( &p_filter
->fmt_in
.audio
);
168 vlc_mutex_init( &p_sys
->lock
);
169 p_sys
->p_buffer
= NULL
;
170 p_sys
->i_buffer_size
= 0;
171 p_sys
->i_nb_samples
= 0;
173 /* Create the OpenGL context */
174 vout_window_cfg_t cfg
;
176 memset(&cfg
, 0, sizeof (cfg
));
177 cfg
.width
= var_CreateGetInteger( p_filter
, "projectm-width" );
178 cfg
.height
= var_CreateGetInteger( p_filter
, "projectm-height" );
180 p_sys
->gl
= vlc_gl_surface_Create( VLC_OBJECT(p_filter
), &cfg
, NULL
);
181 if( p_sys
->gl
== NULL
)
184 /* Create the thread */
185 if( vlc_clone( &p_sys
->thread
, Thread
, p_filter
,
186 VLC_THREAD_PRIORITY_LOW
) )
188 vlc_gl_surface_Destroy( p_sys
->gl
);
192 p_filter
->fmt_in
.audio
.i_format
= VLC_CODEC_FL32
;
193 p_filter
->fmt_out
.audio
= p_filter
->fmt_in
.audio
;
194 p_filter
->pf_audio_filter
= DoWork
;
198 vlc_mutex_destroy( &p_sys
->lock
);
206 * @param p_this: the filter object
208 static void Close( vlc_object_t
*p_this
)
210 filter_t
*p_filter
= (filter_t
*)p_this
;
211 filter_sys_t
*p_sys
= p_filter
->p_sys
;
214 * XXX vlc_cleanup_push does not seems to work with C++ so no
216 vlc_mutex_lock( &p_sys
->lock
);
217 p_sys
->b_quit
= true;
218 vlc_mutex_unlock( &p_sys
->lock
);
220 vlc_join( p_sys
->thread
, NULL
);
222 /* Free the ressources */
223 vlc_gl_surface_Destroy( p_sys
->gl
);
224 vlc_mutex_destroy( &p_sys
->lock
);
225 free( p_sys
->p_buffer
);
231 * Do the actual work with the new sample
232 * @param p_aout: audio output object
233 * @param p_filter: filter object
234 * @param p_in_buf: input buffer
235 * @param p_out_buf: output buffer
237 static block_t
*DoWork( filter_t
*p_filter
, block_t
*p_in_buf
)
239 filter_sys_t
*p_sys
= p_filter
->p_sys
;
241 vlc_mutex_lock( &p_sys
->lock
);
242 if( p_sys
->i_buffer_size
> 0 )
244 p_sys
->i_nb_samples
= __MIN( p_sys
->i_buffer_size
,
245 p_in_buf
->i_nb_samples
);
247 const float *p_src
= (float*)p_in_buf
->p_buffer
;
248 for( unsigned i
= 0; i
< p_sys
->i_nb_samples
; i
++ )
251 for( int j
= 0; j
< p_sys
->i_channels
; j
++ )
252 v
+= p_src
[p_sys
->i_channels
* i
+ j
];
253 p_sys
->p_buffer
[i
] = v
/ p_sys
->i_channels
;
256 vlc_mutex_unlock( &p_sys
->lock
);
262 * ProjectM update thread which do the rendering
263 * @param p_this: the p_thread object
265 static void *Thread( void *p_data
)
267 filter_t
*p_filter
= (filter_t
*)p_data
;
268 filter_sys_t
*p_sys
= p_filter
->p_sys
;
269 vlc_gl_t
*gl
= p_sys
->gl
;
273 projectM
*p_projectm
;
274 #ifndef HAVE_PROJECTM2
277 char *psz_preset_path
;
278 char *psz_title_font
;
280 projectM::Settings settings
;
283 if( vlc_gl_MakeCurrent( gl
) != VLC_SUCCESS
)
285 msg_Err( p_filter
, "Can't attach gl context" );
289 /* Work-around the projectM locale bug */
290 loc
= newlocale (LC_NUMERIC_MASK
, "C", NULL
);
291 oldloc
= uselocale (loc
);
293 /* Create the projectM object */
294 #ifndef HAVE_PROJECTM2
295 psz_config
= var_InheritString( p_filter
, "projectm-config" );
296 p_projectm
= new projectM( psz_config
);
299 psz_preset_path
= var_InheritString( p_filter
, "projectm-preset-path" );
301 if ( psz_preset_path
== NULL
)
303 char *psz_data_path
= config_GetDataDir();
304 asprintf( &psz_preset_path
, "%s" DIR_SEP
"visualization", psz_data_path
);
305 free( psz_data_path
);
309 psz_title_font
= var_InheritString( p_filter
, "projectm-title-font" );
310 psz_menu_font
= var_InheritString( p_filter
, "projectm-menu-font" );
312 settings
.meshX
= var_InheritInteger( p_filter
, "projectm-meshx" );
313 settings
.meshY
= var_InheritInteger( p_filter
, "projectm-meshy" );
315 settings
.textureSize
= var_InheritInteger( p_filter
, "projectm-texture-size" );
316 settings
.windowWidth
= var_InheritInteger( p_filter
, "projectm-width" );
317 settings
.windowHeight
= var_CreateGetInteger( p_filter
, "projectm-height" );
318 settings
.presetURL
= psz_preset_path
;
319 settings
.titleFontURL
= psz_title_font
;
320 settings
.menuFontURL
= psz_menu_font
;
321 settings
.smoothPresetDuration
= 5;
322 settings
.presetDuration
= 30;
323 settings
.beatSensitivity
= 10;
324 settings
.aspectCorrection
= 1;
325 settings
.easterEgg
= 1;
326 settings
.shuffleEnabled
= 1;
327 settings
.softCutRatingsEnabled
= false;
329 p_projectm
= new projectM( settings
);
331 free( psz_menu_font
);
332 free( psz_title_font
);
333 free( psz_preset_path
);
334 #endif /* HAVE_PROJECTM2 */
336 p_sys
->i_buffer_size
= p_projectm
->pcm()->maxsamples
;
337 p_sys
->p_buffer
= (float*)calloc( p_sys
->i_buffer_size
,
340 /* Choose a preset randomly or projectM will always show the first one */
341 if ( p_projectm
->getPlaylistSize() > 0 )
342 p_projectm
->selectPreset( (unsigned)vlc_mrand48() % p_projectm
->getPlaylistSize() );
347 const mtime_t i_deadline
= mdate() + CLOCK_FREQ
/ 50; /* 50 fps max */
349 /* Manage the events */
350 unsigned width
, height
;
353 if( vlc_gl_surface_CheckSize( gl
, &width
, &height
) )
354 p_projectm
->projectM_resetGL( width
, height
);
356 /* Render the image and swap the buffers */
357 vlc_mutex_lock( &p_sys
->lock
);
358 if( p_sys
->i_nb_samples
> 0 )
360 p_projectm
->pcm()->addPCMfloat( p_sys
->p_buffer
,
361 p_sys
->i_nb_samples
);
362 p_sys
->i_nb_samples
= 0;
364 quit
= p_sys
->b_quit
;
365 vlc_mutex_unlock( &p_sys
->lock
);
370 p_projectm
->renderFrame();
380 if (loc
!= (locale_t
)0)
386 vlc_gl_ReleaseCurrent( gl
);