Mercurial > audlegacy-plugins
view src/projectm-1.0/main.cxx @ 1936:a55b1c903628
branch merge
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Mon, 01 Oct 2007 15:35:02 -0500 |
parents | a6d84a2cfaa7 |
children | 47a4e93ed7ce |
line wrap: on
line source
/* projectM v1.01 - xmms-projectm.sourceforge.net -------------------------------------------------- Lead Developers: Carmelo Piccione (carmelo.piccione@gmail.com) & Peter Sperl (peter@sperl.com) We have also been advised by some professors at CMU, namely Roger B. Dannenberg. http://www-2.cs.cmu.edu/~rbd/ The inspiration for this program was Milkdrop by Ryan Geiss. Obviously. This code is distributed under the GPL. THANKS FOR THE CODE!!! ------------------------------------------------- The base for this program was andy@nobugs.org's XMMS plugin tutorial http://www.xmms.org/docs/vis-plugin.html We used some FFT code by Takuya OOURA instead of XMMS' built-in fft code fftsg.c - http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html and some beat detection code was inspired by Frederic Patin @ www.gamedev.net/reference/programming/features/beatdetection/ */ #include <stdio.h> #include <string.h> #include <string> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <SDL/SDL.h> #include <SDL/SDL_thread.h> #include <GL/gl.h> #include <GL/glu.h> extern "C" { #include <audacious/util.h> #include <audacious/plugin.h> #include <audacious/auddrct.h> } #include <math.h> #include "ConfigFile.h" #include <libprojectM/BeatDetect.hpp> #include <libprojectM/PCM.hpp> #include <libprojectM/projectM.hpp> #include <libprojectM/KeyHandler.hpp> #include "sdltoprojectM.h" #include "video_init.h" #define CONFIG_FILE "/share/projectM/config.inp" // Forward declarations extern "C" void projectM_xmms_init(void); extern "C" void projectM_cleanup(void); extern "C" void projectM_about(void); extern "C" void projectM_configure(void); extern "C" void projectM_playback_start(void); extern "C" void projectM_playback_stop(void); extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]); extern "C" void projectM_render_freq(gint16 pcm_data[2][256]); extern "C" int worker_func(void*); std::string read_config(); void saveSnapshotToFile(); extern "C" VisPlugin projectM_vtable; //extern preset_t * active_preset; //FILE * debugFile = fopen("./dwrite-dump", "wb"); // Callback functions // Our worker thread SDL_Thread *worker_thread = NULL; SDL_sem *sem = NULL; SDL_mutex *mutex = NULL; SDL_Event event; SDL_Surface *screen; projectM * globalPM = NULL; int maxsamples=512; int texsize=512; int gx=32,gy=24; int wvw=400,wvh=400; int fvw=1024,fvh=768; int fps=35, fullscreen=0; // char *title; gint disable_projectm(void *something) { projectM_vtable.disable_plugin(&projectM_vtable); return 0; } Uint32 get_xmms_title(Uint32 something, void *somethingelse) { static char check_title = 1; static int last_pos; static char *last_title = NULL; int pos; char *title = NULL; //Nice optimization, but we want the title no matter what so I can display it when the song changes #if 0 if(!(globalPM->showtitle%2)) { /* Repeat less often when not showing title */ return 1000; } #endif pos = audacious_drct_pl_get_pos(); /* Only check every 1 second for title change, otherwise check pos */ if(check_title || pos != last_pos) { title = audacious_drct_pl_get_title(pos); if(title && (!last_title || strcmp(last_title,title))) { globalPM->renderer->title = title; globalPM->renderer->drawtitle = 1; g_free(last_title); last_title = title; } else if(title && last_title != title) { /* New copy of last title */ g_free(title); } check_title = !check_title; } last_pos = pos; /* Repeat every 500ms */ return 500; } int capture = 0; int worker_func(void*) { // char projectM_data[1024]; SDL_TimerID title_timer = NULL; std::string config_file; config_file = read_config(); ConfigFile config(config_file); int wvw = config.read<int>( "Window Width", 512 ); int wvh = config.read<int>( "Window Height", 512 ); int fullscreen = 0; if (config.read("Fullscreen", true)) fullscreen = 1; else fullscreen = 0; init_display(wvw,wvh,&fvw,&fvh,fullscreen); SDL_WM_SetCaption("projectM v1.00", "projectM v1.00"); /** Initialise projectM */ globalPM = new projectM(config_file); title_timer = SDL_AddTimer(500, (SDL_NewTimerCallback) get_xmms_title, NULL); /** Initialise the thread */ // SDL_SemTryWait(sem); while ( SDL_SemValue(sem)==1 ) { projectMEvent evt; projectMKeycode key; projectMModifier mod; /** Process SDL events */ SDL_Event event; while ( SDL_PollEvent( &event ) ) { /** Translate into projectM codes and process */ evt = sdl2pmEvent( event ); key = sdl2pmKeycode( event.key.keysym.sym ); mod = sdl2pmModifier( event.key.keysym.mod ); if ( evt == PROJECTM_KEYDOWN ) { if(key == PROJECTM_K_c) { //SDL_SaveBMP(screen, "/home/pete/1.bmp"); saveSnapshotToFile(); } if(key == PROJECTM_K_v) { // capture++; } if(key == PROJECTM_K_f) { int w, h; if (fullscreen == 0) { w = fvw; h = fvh; } else { w = wvw; h = wvh; } globalPM->fullscreen = fullscreen ^= 1; resize_display(w, h, fullscreen); globalPM->projectM_resetGL( w, h ); } else globalPM->key_handler(evt,key,mod); } else if ( evt == PROJECTM_VIDEORESIZE ) { wvw=event.resize.w; wvh=event.resize.h; resize_display(wvw,wvh,fullscreen); globalPM->projectM_resetGL( wvw, wvh ); } else if ( evt == PROJECTM_VIDEOQUIT ) { (void) g_idle_add((GSourceFunc) disable_projectm, NULL); } } /** Add the waveform data */ /** Render the new frame */ // strcpy(title,xmms_remote_get_playlist_title(projectM_vtable.xmms_session, xmms_remote_get_playlist_pos(projectM_vtable.xmms_session))); //printf("%s\n",title); // strcpy(globalPM->title,title); //SDL_mutexP(mutex); globalPM->renderFrame(); //SDL_mutexV(mutex); SDL_GL_SwapBuffers(); if (capture % 2 == 1) saveSnapshotToFile(); // SDL_SemPost(sem); } printf("Worker thread: Exiting\n"); if(title_timer) SDL_RemoveTimer(title_timer); delete globalPM; globalPM = NULL; close_display(); return 0; } extern "C" void projectM_xmms_init(void) { printf("projectM plugin: Initializing\n"); SDL_EnableUNICODE(1); mutex = SDL_CreateMutex(); sem = SDL_CreateSemaphore(1); worker_thread = SDL_CreateThread ( *worker_func, NULL); } extern "C"void projectM_cleanup(void) { if(worker_thread) { SDL_SemWait(sem); SDL_WaitThread(worker_thread, NULL); SDL_DestroyMutex(mutex); SDL_DestroySemaphore(sem); SDL_Quit(); worker_thread = NULL; sem = NULL; mutex = NULL; printf("projectM plugin: Cleanup completed\n"); } } extern "C" void projectM_about(void) { printf("projectM plugin: About\n"); } extern "C" void projectM_configure(void) { printf("projectM plugin: Configure\n"); } extern "C" void projectM_playback_start(void) {//thread_control = GO; printf("projectM plugin: Playback starting\n"); } extern "C" void projectM_playback_stop(void) {//thread_control = STOP; printf("projectM plugin: Playback stopping\n"); } extern "C" void projectM_render_pcm(gint16 pcm_data[2][512]) { //SDL_mutexP(mutex); if(globalPM) globalPM->beatDetect->pcm->addPCM16(pcm_data); //SDL_mutexV(mutex); } extern "C" void projectM_render_freq(gint16 freq_data[2][256]) { printf("NO GOOD\n"); } std::string read_config() { // int n; char num[512]; FILE *in; FILE *out; char* home; char projectM_home[1024]; char projectM_config[1024]; strcpy(projectM_config, PROJECTM_PREFIX); strcpy(projectM_config+strlen(PROJECTM_PREFIX), CONFIG_FILE); projectM_config[strlen(PROJECTM_PREFIX)+strlen(CONFIG_FILE)]='\0'; printf("dir:%s \n",projectM_config); home=getenv("HOME"); strcpy(projectM_home, home); strcpy(projectM_home+strlen(home), "/.projectM/config.inp"); projectM_home[strlen(home)+strlen("/.projectM/config.inp")]='\0'; if ((in = fopen(projectM_home, "r")) != 0) { printf("reading ~/.projectM/config.inp \n"); fclose(in); return std::string(projectM_home); } else { printf("trying to create ~/.projectM/config.inp \n"); strcpy(projectM_home, home); strcpy(projectM_home+strlen(home), "/.projectM"); projectM_home[strlen(home)+strlen("/.projectM")]='\0'; mkdir(projectM_home,0755); strcpy(projectM_home, home); strcpy(projectM_home+strlen(home), "/.projectM/config.inp"); projectM_home[strlen(home)+strlen("/.projectM/config.inp")]='\0'; if((out = fopen(projectM_home,"w"))!=0) { if ((in = fopen(projectM_config, "r")) != 0) { while(fgets(num,80,in)!=NULL) { fputs(num,out); } fclose(in); fclose(out); if ((in = fopen(projectM_home, "r")) != 0) { printf("created ~/.projectM/config.inp successfully\n"); fclose(in); return std::string(projectM_home); } else{printf("This shouldn't happen, using implementation defualts\n");abort();} } else{printf("Cannot find projectM default config, using implementation defaults\n");abort();} } else { printf("Cannot create ~/.projectM/config.inp, using default config file\n"); if ((in = fopen(projectM_config, "r")) != 0) { printf("Successfully opened default config file\n"); fclose(in); return std::string(projectM_config);} else{ printf("Using implementation defaults, your system is really messed up, I'm suprised we even got this far\n"); abort();} } } abort(); } int frame = 1; char dumpPath[128]; void saveSnapshotToFile() { SDL_Surface * bitmap; GLint viewport[4]; long bytewidth; GLint width, height; long bytes; glReadBuffer(GL_FRONT); glGetIntegerv(GL_VIEWPORT, viewport); width = viewport[2]; height = viewport[3]; bytewidth = width * 4; bytewidth = (bytewidth + 3) & ~3; bytes = bytewidth * height; /* glFinish(); glPixelStorei(GL_PACK_ALIGNMENT, 4); glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); */ bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32,0,0,0,0); glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, bitmap->pixels); sprintf(dumpPath, "/home/pete/.projectM/%.8d.bmp", frame++); SDL_SaveBMP(bitmap, dumpPath); SDL_FreeSurface(bitmap); }