Mercurial > audlegacy-plugins
comparison src/projectm-1.0/main.cxx @ 3040:f13b61c91ada
go back to the SDL version
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Tue, 14 Apr 2009 14:47:25 -0500 |
parents | |
children | c733dd93af62 |
comparison
equal
deleted
inserted
replaced
3039:f856ff6a0055 | 3040:f13b61c91ada |
---|---|
1 /* | |
2 projectM v1.01 - xmms-projectm.sourceforge.net | |
3 -------------------------------------------------- | |
4 | |
5 Lead Developers: Carmelo Piccione (carmelo.piccione@gmail.com) & | |
6 Peter Sperl (peter@sperl.com) | |
7 | |
8 We have also been advised by some professors at CMU, namely Roger B. Dannenberg. | |
9 http://www-2.cs.cmu.edu/~rbd/ | |
10 | |
11 The inspiration for this program was Milkdrop by Ryan Geiss. Obviously. | |
12 | |
13 This code is distributed under the GPL. | |
14 | |
15 | |
16 THANKS FOR THE CODE!!! | |
17 ------------------------------------------------- | |
18 The base for this program was andy@nobugs.org's XMMS plugin tutorial | |
19 http://www.xmms.org/docs/vis-plugin.html | |
20 | |
21 We used some FFT code by Takuya OOURA instead of XMMS' built-in fft code | |
22 fftsg.c - http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html | |
23 | |
24 and some beat detection code was inspired by Frederic Patin @ | |
25 www.gamedev.net/reference/programming/features/beatdetection/ | |
26 | |
27 */ | |
28 | |
29 #include <stdio.h> | |
30 #include <string.h> | |
31 #include <string> | |
32 #include <stdlib.h> | |
33 #include <unistd.h> | |
34 #include <fcntl.h> | |
35 #include <SDL/SDL.h> | |
36 #include <SDL/SDL_thread.h> | |
37 | |
38 extern "C" { | |
39 #include <audacious/util.h> | |
40 #include <audacious/plugin.h> | |
41 #include <audacious/auddrct.h> | |
42 } | |
43 | |
44 #include <math.h> | |
45 #include "ConfigFile.h" | |
46 | |
47 #include <libprojectM/projectM.hpp> | |
48 | |
49 #include "sdltoprojectM.h" | |
50 #include "video_init.h" | |
51 | |
52 #include <GL/gl.h> | |
53 #define CONFIG_FILE "/share/projectM/config.inp" | |
54 | |
55 // Forward declarations | |
56 extern "C" void projectM_xmms_init(void); | |
57 extern "C" void projectM_cleanup(void); | |
58 extern "C" void projectM_about(void); | |
59 extern "C" void projectM_configure(void); | |
60 extern "C" void projectM_playback_start(void); | |
61 extern "C" void projectM_playback_stop(void); | |
62 extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]); | |
63 extern "C" void projectM_render_freq(gint16 pcm_data[2][256]); | |
64 extern "C" int worker_func(void*); | |
65 std::string read_config(); | |
66 void saveSnapshotToFile(); | |
67 | |
68 extern "C" VisPlugin projectM_vtable; | |
69 | |
70 //extern preset_t * active_preset; | |
71 | |
72 //FILE * debugFile = fopen("./dwrite-dump", "wb"); | |
73 | |
74 // Our worker thread | |
75 SDL_Thread *worker_thread = NULL; | |
76 SDL_sem *sem = NULL; | |
77 SDL_Event event; | |
78 | |
79 SDL_Surface *screen; | |
80 | |
81 | |
82 projectM * globalPM = NULL; | |
83 | |
84 int maxsamples=512; | |
85 | |
86 int texsize=512; | |
87 int gx=32,gy=24; | |
88 int wvw=400,wvh=400; | |
89 int fvw=1024,fvh=768; | |
90 int fps=35, fullscreen=0; | |
91 | |
92 // char *title; | |
93 | |
94 gint disable_projectm(void *something) { | |
95 projectM_vtable.disable_plugin(&projectM_vtable); | |
96 return 0; | |
97 } | |
98 | |
99 Uint32 get_xmms_title(Uint32 something, void *somethingelse) { | |
100 static char check_title = 1; | |
101 static int last_pos; | |
102 static char *last_title = NULL; | |
103 int pos; | |
104 char *title = NULL; | |
105 | |
106 //Nice optimization, but we want the title no matter what so I can display it when the song changes | |
107 #if 0 | |
108 if(!(globalPM->showtitle%2)) { | |
109 /* Repeat less often when not showing title */ | |
110 return 1000; | |
111 } | |
112 #endif | |
113 | |
114 pos = audacious_drct_pl_get_pos(); | |
115 /* Only check every 1 second for title change, otherwise check pos */ | |
116 if(check_title || pos != last_pos) { | |
117 title = audacious_drct_pl_get_title(pos); | |
118 if(title && (!last_title || strcmp(last_title,title))) { | |
119 //globalPM->renderer->title = title; | |
120 //globalPM->renderer->drawtitle = 1; | |
121 | |
122 std::string titlepp(title); | |
123 globalPM->projectM_setTitle(titlepp); | |
124 g_free(last_title); | |
125 last_title = title; | |
126 } else if(title && last_title != title) { | |
127 /* New copy of last title */ | |
128 g_free(title); | |
129 } | |
130 check_title = !check_title; | |
131 } | |
132 last_pos = pos; | |
133 /* Repeat every 500ms */ | |
134 return 500; | |
135 } | |
136 | |
137 int capture = 0; | |
138 | |
139 int worker_func(void*) | |
140 { | |
141 // char projectM_data[1024]; | |
142 SDL_TimerID title_timer = NULL; | |
143 std::string config_file; | |
144 config_file = read_config(); | |
145 ConfigFile config(config_file); | |
146 | |
147 int wvw = config.read<int>( "Window Width", 512 ); | |
148 int wvh = config.read<int>( "Window Height", 512 ); | |
149 | |
150 int fullscreen = 0; | |
151 if (config.read("Fullscreen", true)) fullscreen = 1; | |
152 else fullscreen = 0; | |
153 | |
154 init_display(wvw,wvh,&fvw,&fvh,fullscreen); | |
155 SDL_WM_SetCaption("projectM v1.00", "projectM v1.00"); | |
156 | |
157 /** Initialise projectM */ | |
158 | |
159 globalPM = new projectM(config_file); | |
160 SDL_SemPost(sem); | |
161 title_timer = SDL_AddTimer(500, get_xmms_title, NULL); | |
162 /** Initialise the thread */ | |
163 // SDL_SemTryWait(sem); | |
164 while ( SDL_SemValue(sem)==1 ) { | |
165 projectMEvent evt; | |
166 projectMKeycode key; | |
167 projectMModifier mod; | |
168 | |
169 /** Process SDL events */ | |
170 SDL_Event event; | |
171 while ( SDL_PollEvent( &event ) ) { | |
172 /** Translate into projectM codes and process */ | |
173 evt = sdl2pmEvent( event ); | |
174 | |
175 key = sdl2pmKeycode( event.key.keysym.sym ); | |
176 mod = sdl2pmModifier( event.key.keysym.mod ); | |
177 | |
178 if ( evt == PROJECTM_KEYDOWN ) { | |
179 | |
180 if(key == PROJECTM_K_c) | |
181 { | |
182 //SDL_SaveBMP(screen, "/home/pete/1.bmp"); | |
183 saveSnapshotToFile(); | |
184 } | |
185 if(key == PROJECTM_K_v) | |
186 { | |
187 // capture++; | |
188 } | |
189 if(key == PROJECTM_K_f) | |
190 { | |
191 | |
192 | |
193 int w, h; | |
194 if (fullscreen == 0) { | |
195 w = fvw; | |
196 h = fvh; | |
197 fullscreen = 1; | |
198 } else { | |
199 w = wvw; | |
200 h = wvh; | |
201 fullscreen = 0; | |
202 } | |
203 | |
204 resize_display(w, h, fullscreen); | |
205 globalPM->projectM_resetGL( w, h ); | |
206 } | |
207 else globalPM->key_handler(evt,key,mod); | |
208 | |
209 } | |
210 else if ( evt == PROJECTM_VIDEORESIZE ) | |
211 { | |
212 | |
213 | |
214 | |
215 wvw=event.resize.w; | |
216 wvh=event.resize.h; | |
217 | |
218 | |
219 resize_display(wvw,wvh,fullscreen); | |
220 globalPM->projectM_resetGL( wvw, wvh ); | |
221 | |
222 } | |
223 else if ( evt == PROJECTM_VIDEOQUIT ) { | |
224 | |
225 (void) g_idle_add ((GSourceFunc) disable_projectm, NULL); | |
226 } | |
227 } | |
228 | |
229 /** Add the waveform data */ | |
230 | |
231 | |
232 /** Render the new frame */ | |
233 // strcpy(title,xmms_remote_get_playlist_title(projectM_vtable.xmms_session, xmms_remote_get_playlist_pos(projectM_vtable.xmms_session))); | |
234 | |
235 //printf("%s\n",title); | |
236 // strcpy(globalPM->title,title); | |
237 | |
238 globalPM->renderFrame(); | |
239 | |
240 | |
241 | |
242 SDL_GL_SwapBuffers(); | |
243 | |
244 if (capture % 2 == 1) saveSnapshotToFile(); | |
245 // SDL_SemPost(sem); | |
246 } | |
247 | |
248 if(title_timer) | |
249 SDL_RemoveTimer(title_timer); | |
250 delete globalPM; | |
251 | |
252 | |
253 return 0; | |
254 } | |
255 | |
256 extern "C" void projectM_xmms_init(void) | |
257 { | |
258 | |
259 /* First, initialize SDL's video subsystem. */ | |
260 // std::cerr << "sdl init begin" << std::endl; | |
261 if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 ) { | |
262 /* Failed, exit. */ | |
263 fprintf( stderr, "Video initialization failed: %s\n", | |
264 SDL_GetError( ) ); | |
265 //projectM_vtable.disable_plugin (&projectM_vtable); | |
266 return; | |
267 | |
268 } | |
269 sem = SDL_CreateSemaphore(0); | |
270 // printf("projectM plugin: Initializing\n"); | |
271 | |
272 SDL_EnableUNICODE(1); | |
273 | |
274 worker_thread = SDL_CreateThread ( *worker_func, NULL); | |
275 | |
276 } | |
277 | |
278 | |
279 | |
280 extern "C" void projectM_cleanup(void) | |
281 { | |
282 | |
283 if(!sem) return; | |
284 SDL_SemWait(sem); | |
285 if(worker_thread) SDL_WaitThread(worker_thread, NULL); | |
286 // SDL_KillThread(worker_thread); | |
287 //printf("killed thread\n"); | |
288 | |
289 SDL_DestroySemaphore(sem); | |
290 //printf("Destroy Mutex\n"); | |
291 SDL_Quit(); | |
292 | |
293 sem = NULL; | |
294 worker_thread = NULL; | |
295 | |
296 // printf("projectM plugin: Cleanup completed\n"); | |
297 } | |
298 extern "C" void projectM_about(void) | |
299 { | |
300 printf("projectM plugin: About\n"); | |
301 } | |
302 extern "C" void projectM_configure(void) | |
303 { | |
304 printf("projectM plugin: Configure\n"); | |
305 } | |
306 extern "C" void projectM_playback_start(void) | |
307 {//thread_control = GO; | |
308 printf("projectM plugin: Playback starting\n"); | |
309 } | |
310 extern "C" void projectM_playback_stop(void) | |
311 {//thread_control = STOP; | |
312 printf("projectM plugin: Playback stopping\n"); | |
313 } | |
314 extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]) | |
315 { | |
316 //SDL_mutexP(mutex); while ( SDL_SemValue(sem)==1 ) | |
317 if ( SDL_SemValue(sem)==1 ) | |
318 globalPM->pcm()->addPCM16(pcm_data); | |
319 | |
320 //SDL_mutexV(mutex); | |
321 | |
322 } | |
323 | |
324 extern "C" void projectM_render_freq(gint16 freq_data[2][256]) | |
325 { | |
326 printf("NO GOOD\n"); | |
327 } | |
328 | |
329 std::string read_config() | |
330 { | |
331 | |
332 // int n; | |
333 | |
334 char num[512]; | |
335 FILE *in; | |
336 FILE *out; | |
337 | |
338 char* home; | |
339 char projectM_home[1024]; | |
340 char projectM_config[1024]; | |
341 | |
342 strcpy(projectM_config, PROJECTM_PREFIX); | |
343 strcpy(projectM_config+strlen(PROJECTM_PREFIX), CONFIG_FILE); | |
344 projectM_config[strlen(PROJECTM_PREFIX)+strlen(CONFIG_FILE)]='\0'; | |
345 //printf("dir:%s \n",projectM_config); | |
346 home=getenv("HOME"); | |
347 strcpy(projectM_home, home); | |
348 strcpy(projectM_home+strlen(home), "/.projectM/config.inp"); | |
349 projectM_home[strlen(home)+strlen("/.projectM/config.inp")]='\0'; | |
350 | |
351 | |
352 if ((in = fopen(projectM_home, "r")) != 0) | |
353 { | |
354 //printf("reading ~/.projectM/config.inp \n"); | |
355 fclose(in); | |
356 return std::string(projectM_home); | |
357 } | |
358 else | |
359 { | |
360 printf("trying to create ~/.projectM/config.inp \n"); | |
361 | |
362 strcpy(projectM_home, home); | |
363 strcpy(projectM_home+strlen(home), "/.projectM"); | |
364 projectM_home[strlen(home)+strlen("/.projectM")]='\0'; | |
365 mkdir(projectM_home,0755); | |
366 | |
367 strcpy(projectM_home, home); | |
368 strcpy(projectM_home+strlen(home), "/.projectM/config.inp"); | |
369 projectM_home[strlen(home)+strlen("/.projectM/config.inp")]='\0'; | |
370 | |
371 if((out = fopen(projectM_home,"w"))!=0) | |
372 { | |
373 | |
374 if ((in = fopen(projectM_config, "r")) != 0) | |
375 { | |
376 | |
377 while(fgets(num,80,in)!=NULL) | |
378 { | |
379 fputs(num,out); | |
380 } | |
381 fclose(in); | |
382 fclose(out); | |
383 | |
384 | |
385 if ((in = fopen(projectM_home, "r")) != 0) | |
386 { | |
387 printf("created ~/.projectM/config.inp successfully\n"); | |
388 fclose(in); | |
389 return std::string(projectM_home); | |
390 } | |
391 else{printf("This shouldn't happen, using implementation defualts\n");abort();} | |
392 } | |
393 else{printf("Cannot find projectM default config, using implementation defaults\n");abort();} | |
394 } | |
395 else | |
396 { | |
397 printf("Cannot create ~/.projectM/config.inp, using default config file\n"); | |
398 if ((in = fopen(projectM_config, "r")) != 0) | |
399 { printf("Successfully opened default config file\n"); | |
400 fclose(in); | |
401 return std::string(projectM_config);} | |
402 else{ printf("Using implementation defaults, your system is really messed up, I'm suprised we even got this far\n"); abort();} | |
403 } | |
404 | |
405 } | |
406 | |
407 abort(); | |
408 } | |
409 | |
410 int frame = 1; | |
411 | |
412 | |
413 void saveSnapshotToFile() | |
414 { | |
415 char dumpPath[512]; | |
416 char Home[512]; | |
417 //char *home; | |
418 | |
419 SDL_Surface * bitmap; | |
420 | |
421 GLint viewport[4]; | |
422 long bytewidth; | |
423 GLint width, height; | |
424 long bytes; | |
425 | |
426 glReadBuffer(GL_FRONT); | |
427 glGetIntegerv(GL_VIEWPORT, viewport); | |
428 | |
429 width = viewport[2]; | |
430 height = viewport[3]; | |
431 | |
432 bytewidth = width * 4; | |
433 bytewidth = (bytewidth + 3) & ~3; | |
434 bytes = bytewidth * height; | |
435 | |
436 /* | |
437 glFinish(); | |
438 glPixelStorei(GL_PACK_ALIGNMENT, 4); | |
439 glPixelStorei(GL_PACK_ROW_LENGTH, 0); | |
440 glPixelStorei(GL_PACK_SKIP_ROWS, 0); | |
441 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); | |
442 */ | |
443 | |
444 | |
445 bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,0,0,0,0); | |
446 glReadPixels(0, 0, width, height, | |
447 GL_BGRA, | |
448 GL_UNSIGNED_INT_8_8_8_8_REV, | |
449 bitmap->pixels); | |
450 | |
451 sprintf(dumpPath, "/.projectM/%.8d.bmp", frame++); | |
452 // home=getenv("HOME"); | |
453 strcpy(Home, getenv("HOME")); | |
454 strcpy(Home+strlen(Home), dumpPath); | |
455 Home[strlen(Home)]='\0'; | |
456 SDL_SaveBMP(bitmap, Home); | |
457 | |
458 SDL_FreeSurface(bitmap); | |
459 | |
460 | |
461 } | |
462 |