1 /*****************************************************************************
2 * projectm: visualization module based on libprojectM
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
7 * Authors: RĂ©mi Duraffort <ivoire@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, write to the Free Software Foundation, Inc., 51
21 * Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
27 #ifndef __STDC_CONSTANT_MACROS
28 # define __STDC_CONSTANT_MACROS
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
35 #include <vlc_vout_wrapper.h>
36 #include <vlc_filter.h>
38 #include <libprojectM/projectM.hpp>
41 /*****************************************************************************
43 *****************************************************************************/
44 static int Open ( vlc_object_t
* );
45 static void Close ( vlc_object_t
* );
47 #define CONFIG_TEXT N_("projectM configuration file")
48 #define CONFIG_LONGTEXT N_("File that will be used to configure the projectM " \
51 #define PRESET_PATH_TXT N_("projectM preset path")
52 #define PRESET_PATH_LONGTXT N_("Path to the projectM preset directory")
54 #define TITLE_FONT_TXT N_("Title font")
55 #define TITLE_FONT_LONGTXT N_("Font used for the titles")
57 #define MENU_FONT_TXT N_("Font menu")
58 #define MENU_FONT_LONGTXT N_("Font used for the menus")
60 #define WIDTH_TEXT N_("Video width")
61 #define WIDTH_LONGTEXT N_("The width of the video window, in pixels.")
63 #define HEIGHT_TEXT N_("Video height")
64 #define HEIGHT_LONGTEXT N_("The height of the video window, in pixels.")
67 set_shortname( N_("projectM"))
68 set_description( N_("libprojectM effect") )
69 set_capability( "visualization2", 0 )
70 set_category( CAT_AUDIO
)
71 set_subcategory( SUBCAT_AUDIO_VISUAL
)
72 #ifndef HAVE_PROJECTM2
73 add_file( "projectm-config", "/usr/share/projectM/config.inp", NULL
,
74 CONFIG_TEXT
, CONFIG_LONGTEXT
, true )
76 add_file( "projectm-preset-path", "/usr/share/projectM/presets", NULL
,
77 PRESET_PATH_TXT
, PRESET_PATH_LONGTXT
, true )
78 add_file( "projectm-title-font", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", NULL
,
79 TITLE_FONT_TXT
, TITLE_FONT_LONGTXT
, true )
80 add_file( "projectm-menu-font", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", NULL
,
81 MENU_FONT_TXT
, MENU_FONT_LONGTXT
, true )
83 add_integer( "projectm-width", 800, NULL
, WIDTH_TEXT
, WIDTH_LONGTEXT
,
85 add_integer( "projectm-height", 640, NULL
, HEIGHT_TEXT
, HEIGHT_LONGTEXT
,
87 add_shortcut( "projectm" )
88 set_callbacks( Open
, Close
)
92 /*****************************************************************************
94 *****************************************************************************/
103 vout_thread_t
*p_vout
;
104 vout_display_t
*p_vd
;
106 /* libprojectM objects */
107 projectM
*p_projectm
;
108 #ifndef HAVE_PROJECTM2
111 char *psz_preset_path
;
112 char *psz_title_font
;
132 static block_t
*DoWork( filter_t
*, block_t
* );
133 static void *Thread( void * );
137 * @param p_this: the filter object
138 * @return VLC_SUCCESS or vlc error codes
140 static int Open( vlc_object_t
* p_this
)
142 filter_t
*p_filter
= (filter_t
*)p_this
;
145 /* Test the audio format */
146 if( p_filter
->fmt_in
.audio
.i_format
!= VLC_CODEC_FL32
||
147 p_filter
->fmt_out
.audio
.i_format
!= VLC_CODEC_FL32
)
149 msg_Warn( p_filter
, "bad input or output format" );
152 if( !AOUT_FMTS_SIMILAR( &p_filter
->fmt_in
.audio
, &p_filter
->fmt_out
.audio
) )
154 msg_Warn( p_filter
, "input and outut are not similar" );
158 p_filter
->pf_audio_filter
= DoWork
;
160 p_sys
= p_filter
->p_sys
= (filter_sys_t
*)malloc( sizeof( *p_sys
) );
164 /* Create the object for the thread */
165 vlc_sem_init( &p_sys
->ready
, 0 );
166 p_sys
->b_error
= false;
167 p_sys
->b_quit
= false;
168 p_sys
->i_width
= var_InheritInteger( p_filter
, "projectm-width" );
169 p_sys
->i_height
= var_InheritInteger( p_filter
, "projectm-height" );
170 p_sys
->i_channels
= aout_FormatNbChannels( &p_filter
->fmt_in
.audio
);
171 #ifndef HAVE_PROJECTM2
172 p_sys
->psz_config
= var_InheritString( p_filter
, "projectm-config" );
174 p_sys
->psz_preset_path
= var_InheritString( p_filter
, "projectm-preset-path" );
175 p_sys
->psz_preset_path
= var_InheritString( p_filter
, "projectm-title-font" );
176 p_sys
->psz_preset_path
= var_InheritString( p_filter
, "projectm-menu-font" );
178 vlc_mutex_init( &p_sys
->lock
);
179 p_sys
->p_buffer
= NULL
;
180 p_sys
->i_buffer_size
= 0;
181 p_sys
->i_nb_samples
= 0;
183 /* Create the thread */
184 if( vlc_clone( &p_sys
->thread
, Thread
, p_filter
, VLC_THREAD_PRIORITY_LOW
) )
187 vlc_sem_wait( &p_sys
->ready
);
190 vlc_join( p_sys
->thread
, NULL
);
197 vlc_sem_destroy( &p_sys
->ready
);
205 * @param p_this: the filter object
207 static void Close( vlc_object_t
*p_this
)
209 filter_t
*p_filter
= (filter_t
*)p_this
;
210 filter_sys_t
*p_sys
= p_filter
->p_sys
;
213 * XXX vlc_cleanup_push does not seems to work with C++ so no
215 vlc_mutex_lock( &p_sys
->lock
);
216 p_sys
->b_quit
= true;
217 vlc_mutex_unlock( &p_sys
->lock
);
219 vlc_join( p_sys
->thread
, NULL
);
221 /* Free the ressources */
222 vlc_sem_destroy( &p_sys
->ready
);
223 vlc_mutex_destroy( &p_sys
->lock
);
224 free( p_sys
->p_buffer
);
225 #ifndef HAVE_PROJECTM2
226 free( p_sys
->psz_config
);
228 free( p_sys
->psz_preset_path
);
229 free( p_sys
->psz_title_font
);
230 free( p_sys
->psz_menu_font
);
237 * Do the actual work with the new sample
238 * @param p_aout: audio output object
239 * @param p_filter: filter object
240 * @param p_in_buf: input buffer
241 * @param p_out_buf: output buffer
243 static block_t
*DoWork( filter_t
*p_filter
, block_t
*p_in_buf
)
245 filter_sys_t
*p_sys
= p_filter
->p_sys
;
247 vlc_mutex_lock( &p_sys
->lock
);
248 if( p_sys
->i_buffer_size
> 0 )
250 p_sys
->i_nb_samples
= __MIN( p_sys
->i_buffer_size
,
251 p_in_buf
->i_nb_samples
);
253 const float *p_src
= (float*)p_in_buf
->p_buffer
;
254 for( int i
= 0; i
< p_sys
->i_nb_samples
; i
++ )
257 for( int j
= 0; j
< p_sys
->i_channels
; j
++ )
258 v
+= p_src
[p_sys
->i_channels
* i
+ j
];
259 p_sys
->p_buffer
[i
] = v
/ p_sys
->i_channels
;
262 vlc_mutex_unlock( &p_sys
->lock
);
268 * Variable callback for the dummy vout
270 static int VoutCallback( vlc_object_t
*p_vout
, char const *psz_name
,
271 vlc_value_t oldv
, vlc_value_t newv
, void *p_data
)
273 vout_display_t
*p_vd
= (vout_display_t
*)p_data
;
275 if( !strcmp(psz_name
, "fullscreen") )
277 vout_SetDisplayFullscreen( p_vd
, newv
.b_bool
);
283 * ProjectM update thread which do the rendering
284 * @param p_this: the p_thread object
286 static void *Thread( void *p_data
)
288 filter_t
*p_filter
= (filter_t
*)p_data
;
289 filter_sys_t
*p_sys
= p_filter
->p_sys
;
290 int cancel
= vlc_savecancel();
293 int i_last_width
= 0;
294 int i_last_height
= 0;
295 #ifdef HAVE_PROJECTM2
296 projectM::Settings settings
;
299 /* Create the openGL provider */
301 (vout_thread_t
*)vlc_object_create( p_filter
, sizeof(vout_thread_t
) );
306 video_format_Init( &fmt
, 0 );
307 video_format_Setup( &fmt
, VLC_CODEC_RGB32
,
308 p_sys
->i_width
, p_sys
->i_height
, 0, 1 );
312 vout_display_state_t state
;
313 memset( &state
, 0, sizeof(state
) );
314 state
.cfg
.display
.sar
.num
= 1;
315 state
.cfg
.display
.sar
.den
= 1;
316 state
.cfg
.is_display_filled
= true;
317 state
.cfg
.zoom
.num
= 1;
318 state
.cfg
.zoom
.den
= 1;
322 p_sys
->p_vd
= vout_NewDisplay( p_sys
->p_vout
, &fmt
, &state
, "opengl",
326 vlc_object_release( p_sys
->p_vout
);
329 var_Create( p_sys
->p_vout
, "fullscreen", VLC_VAR_BOOL
);
330 var_AddCallback( p_sys
->p_vout
, "fullscreen", VoutCallback
, p_sys
->p_vd
);
332 gl
= vout_GetDisplayOpengl( p_sys
->p_vd
);
335 vout_DeleteDisplay( p_sys
->p_vd
, NULL
);
336 vlc_object_release( p_sys
->p_vout
);
340 /* Create the projectM object */
341 #ifndef HAVE_PROJECTM2
342 p_sys
->p_projectm
= new projectM( p_sys
->psz_config
);
347 settings
.textureSize
= 1024;
348 settings
.windowWidth
= p_sys
->i_width
;
349 settings
.windowHeight
= p_sys
->i_height
;
350 settings
.presetURL
= p_sys
->psz_preset_path
;
351 settings
.titleFontURL
= p_sys
->psz_title_font
;
352 settings
.menuFontURL
= p_sys
->psz_menu_font
;
353 settings
.smoothPresetDuration
= 5;
354 settings
.presetDuration
= 30;
355 settings
.beatSensitivity
= 10;
356 settings
.aspectCorrection
= 1;
357 settings
.easterEgg
= 1;
358 settings
.shuffleEnabled
= 1;
359 p_sys
->p_projectm
= new projectM( settings
);
361 p_sys
->i_buffer_size
= p_sys
->p_projectm
->pcm()->maxsamples
;
362 p_sys
->p_buffer
= (float*)calloc( p_sys
->i_buffer_size
,
365 vlc_sem_post( &p_sys
->ready
);
367 /* TODO: Give to projectm the name of the input
368 p_sys->p_projectm->projectM_setTitle( "" ); */
373 const mtime_t i_deadline
= mdate() + CLOCK_FREQ
/ 50; /* 50 fps max */
374 /* Manage the events */
375 vout_ManageDisplay( p_sys
->p_vd
, true );
376 if( p_sys
->p_vd
->cfg
->display
.width
!= i_last_width
||
377 p_sys
->p_vd
->cfg
->display
.height
!= i_last_height
)
379 /* FIXME it is not perfect as we will have black bands */
380 vout_display_place_t place
;
381 vout_display_PlacePicture( &place
, &p_sys
->p_vd
->source
, p_sys
->p_vd
->cfg
, false );
382 p_sys
->p_projectm
->projectM_resetGL( place
.width
, place
.height
);
384 i_last_width
= p_sys
->p_vd
->cfg
->display
.width
;
385 i_last_height
= p_sys
->p_vd
->cfg
->display
.height
;
388 /* Render the image and swap the buffers */
389 vlc_mutex_lock( &p_sys
->lock
);
390 if( p_sys
->i_nb_samples
> 0 )
392 p_sys
->p_projectm
->pcm()->addPCMfloat( p_sys
->p_buffer
,
393 p_sys
->i_nb_samples
);
394 p_sys
->i_nb_samples
= 0;
398 vlc_mutex_unlock( &p_sys
->lock
);
400 delete p_sys
->p_projectm
;
401 vout_DeleteDisplay( p_sys
->p_vd
, NULL
);
402 vlc_object_release( p_sys
->p_vout
);
405 vlc_mutex_unlock( &p_sys
->lock
);
407 p_sys
->p_projectm
->renderFrame();
412 if( !vout_opengl_Lock(gl
) )
414 vout_opengl_Swap( gl
);
415 vout_opengl_Unlock( gl
);
421 p_sys
->b_error
= true;
422 vlc_sem_post( &p_sys
->ready
);