2 * Copyright (C) 2007-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 xmms-projectM v0.99 - xmms-projectm.sourceforge.net
23 --------------------------------------------------
25 Lead Developers: Carmelo Piccione (cep@andrew.cmu.edu) &
26 Peter Sperl (peter@sperl.com)
28 We have also been advised by some professors at CMU, namely Roger B. Dannenberg.
29 http://www-2.cs.cmu.edu/~rbd/
31 The inspiration for this program was Milkdrop by Ryan Geiss. Obviously.
33 This code is distributed under the GPL.
36 THANKS FOR THE CODE!!!
37 -------------------------------------------------
38 The base for this program was andy@nobugs.org's XMMS plugin tutorial
39 http://www.xmms.org/docs/vis-plugin.html
41 We used some FFT code by Takuya OOURA instead of XMMS' built-in fft code
42 fftsg.c - http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html
44 For font rendering we used GLF by Roman Podobedov
45 glf.c - http://astronomy.swin.edu.au/~pbourke/opengl/glf/
47 and some beat detection code was inspired by Frederic Patin @
48 www.gamedev.net/reference/programming/features/beatdetection/
51 "ported" to XBMC by d4rk
56 #include "addons/include/xbmc_vis_dll.h"
57 #include "addons/include/xbmc_addon_cpp_dll.h"
59 #include "libprojectM/projectM.hpp"
61 #include <utils/log.h>
63 projectM *globalPM = NULL;
65 // some projectm globals
72 char **g_presets=NULL;
73 unsigned int g_numPresets = 0;
74 projectM::Settings g_configPM;
76 bool g_UserPackFolder;
77 char lastPresetDir[1024];
80 unsigned int lastLoggedPresetIdx;
82 //-- Create -------------------------------------------------------------------
83 // Called once when the visualisation is created by XBMC. Do any setup here.
84 //-----------------------------------------------------------------------------
85 extern "C" ADDON_STATUS ADDON_Create(void* hdl, void* props)
88 return ADDON_STATUS_UNKNOWN;
90 VIS_PROPS* visprops = (VIS_PROPS*)props;
92 strcpy(g_visName, visprops->name);
93 g_configPM.meshX = gx;
94 g_configPM.meshY = gy;
96 g_configPM.textureSize = texsize;
97 g_configPM.windowWidth = visprops->width;
98 g_configPM.windowHeight = visprops->height;
99 g_configPM.aspectCorrection = true;
100 g_configPM.easterEgg = 0.0;
101 g_configPM.windowLeft = visprops->x;
102 g_configPM.windowBottom = visprops->y;
103 lastLoggedPresetIdx = lastPresetIdx;
105 return ADDON_STATUS_NEED_SAVEDSETTINGS;
108 //-- Start --------------------------------------------------------------------
109 // Called when a new soundtrack is played
110 //-----------------------------------------------------------------------------
111 extern "C" void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName)
113 //printf("Got Start Command\n");
116 //-- Audiodata ----------------------------------------------------------------
117 // Called by XBMC to pass new audio data to the vis
118 //-----------------------------------------------------------------------------
119 extern "C" void AudioData(const float* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
122 globalPM->pcm()->addPCMfloat(pAudioData, iAudioDataLength);
125 //-- Render -------------------------------------------------------------------
126 // Called once per frame. Do all rendering here.
127 //-----------------------------------------------------------------------------
128 extern "C" void Render()
132 globalPM->renderFrame();
136 globalPM->selectedPresetIndex(preset);
137 if (lastLoggedPresetIdx != preset)
138 CLog::Log(LOGDEBUG,"PROJECTM - Changed preset to: %s",g_presets[preset]);
139 lastLoggedPresetIdx = preset;
144 //-- GetInfo ------------------------------------------------------------------
145 // Tell XBMC our requirements
146 //-----------------------------------------------------------------------------
147 extern "C" void GetInfo(VIS_INFO* pInfo)
149 pInfo->bWantsFreq = false;
150 pInfo->iSyncDelay = 0;
153 //-- OnAction -----------------------------------------------------------------
154 // Handle XBMC actions such as next preset, lock preset, album art changed etc
155 //-----------------------------------------------------------------------------
156 extern "C" bool OnAction(long flags, const void *param)
163 if (flags == VIS_ACTION_LOAD_PRESET && param)
165 int pindex = *((int *)param);
166 globalPM->selectPreset(pindex);
169 else if (flags == VIS_ACTION_NEXT_PRESET)
171 // switchPreset(ALPHA_NEXT, SOFT_CUT);
172 if (!globalPM->isShuffleEnabled())
173 globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_n, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
175 globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
178 else if (flags == VIS_ACTION_PREV_PRESET)
180 // switchPreset(ALPHA_PREVIOUS, SOFT_CUT);
181 if (!globalPM->isShuffleEnabled())
182 globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_p, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
184 globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
188 else if (flags == VIS_ACTION_RANDOM_PRESET)
190 globalPM->setShuffleEnabled(g_configPM.shuffleEnabled);
193 else if (flags == VIS_ACTION_LOCK_PRESET)
195 globalPM->setPresetLock(!globalPM->isPresetLocked());
197 globalPM->selectedPresetIndex(preset);
198 globalPM->selectPreset(preset);
204 //-- GetPresets ---------------------------------------------------------------
205 // Return a list of presets to XBMC for display
206 //-----------------------------------------------------------------------------
207 extern "C" unsigned int GetPresets(char ***presets)
209 g_numPresets = globalPM ? globalPM->getPlaylistSize() : 0;
210 if (g_numPresets > 0)
212 g_presets = (char**) malloc(sizeof(char*)*g_numPresets);
213 for (unsigned i = 0; i < g_numPresets; i++)
215 g_presets[i] = (char*) malloc(strlen(globalPM->getPresetName(i).c_str())+2);
217 strcpy(g_presets[i], globalPM->getPresetName(i).c_str());
219 *presets = g_presets;
224 //-- GetPreset ----------------------------------------------------------------
225 // Return the index of the current playing preset
226 //-----------------------------------------------------------------------------
227 extern "C" unsigned GetPreset()
232 if(globalPM && globalPM->selectedPresetIndex(preset))
238 //-- IsLocked -----------------------------------------------------------------
239 // Returns true if this add-on use settings
240 //-----------------------------------------------------------------------------
241 extern "C" bool IsLocked()
244 return globalPM->isPresetLocked();
249 //-- Stop ---------------------------------------------------------------------
250 // Do everything before unload of this add-on
251 // !!! Add-on master function !!!
252 //-----------------------------------------------------------------------------
253 extern "C" void ADDON_Stop()
262 for (unsigned i = 0; i <g_numPresets; i++)
272 //-- Destroy-------------------------------------------------------------------
273 // Do everything before unload of this add-on
274 // !!! Add-on master function !!!
275 //-----------------------------------------------------------------------------
276 extern "C" void ADDON_Destroy()
280 //-- HasSettings --------------------------------------------------------------
281 // Returns true if this add-on use settings
282 // !!! Add-on master function !!!
283 //-----------------------------------------------------------------------------
284 extern "C" bool ADDON_HasSettings()
289 //-- GetStatus ---------------------------------------------------------------
290 // Returns the current Status of this visualisation
291 // !!! Add-on master function !!!
292 //-----------------------------------------------------------------------------
293 extern "C" ADDON_STATUS ADDON_GetStatus()
295 return ADDON_STATUS_OK;
298 //-- GetSettings --------------------------------------------------------------
299 // Return the settings for XBMC to display
300 //-----------------------------------------------------------------------------
302 extern "C" unsigned int ADDON_GetSettings(ADDON_StructSetting ***sSet)
307 //-- FreeSettings --------------------------------------------------------------
308 // Free the settings struct passed from XBMC
309 //-----------------------------------------------------------------------------
311 extern "C" void ADDON_FreeSettings()
315 void ChooseQuality (int pvalue)
320 g_configPM.textureSize = 256;
323 g_configPM.textureSize = 512;
326 g_configPM.textureSize = 1024;
329 g_configPM.textureSize = 2048;
334 void ChoosePresetPack(int pvalue)
336 g_UserPackFolder = false;
338 g_configPM.presetURL = "zip://special%3A%2F%2Fxbmc%2Faddons%2Fvisualization%2Eprojectm%2Fresources%2Fpresets%2Ezip";
339 else if (pvalue == 1) //User preset folder has been chosen
340 g_UserPackFolder = true;
343 void ChooseUserPresetFolder(std::string pvalue)
345 if (g_UserPackFolder)
347 pvalue.erase(pvalue.length()-1,1); //Remove "/" from the end
348 g_configPM.presetURL = pvalue;
354 if (globalPM) delete globalPM; //We are re-initalizing the engine
357 globalPM = new projectM(g_configPM);
358 if (g_configPM.presetURL == lastPresetDir) //If it is not the first run AND if this is the same preset pack as last time
360 globalPM->setPresetLock(lastLockStatus);
361 globalPM->selectPreset(lastPresetIdx);
365 //If it is the first run or a newly chosen preset pack we choose a random preset as first
366 if (globalPM->getPlaylistSize())
367 globalPM->selectPreset((rand() % (globalPM->getPlaylistSize())));
373 printf("exception in projectM ctor");
378 //-- UpdateSetting ------------------------------------------------------------
379 // Handle setting change request from XBMC
380 //-----------------------------------------------------------------------------
381 extern "C" ADDON_STATUS ADDON_SetSetting(const char* id, const void* value)
384 return ADDON_STATUS_UNKNOWN;
386 if (strcmp(id, "###GetSavedSettings") == 0) // We have some settings to be saved in the settings.xml file
390 return ADDON_STATUS_UNKNOWN;
392 if (strcmp((char*)value, "0") == 0)
394 strcpy((char*)id, "lastpresetfolder");
395 strcpy((char*)value, globalPM->settings().presetURL.c_str());
397 if (strcmp((char*)value, "1") == 0)
399 strcpy((char*)id, "lastlockedstatus");
400 strcpy((char*)value, (globalPM->isPresetLocked() ? "true" : "false"));
402 if (strcmp((char*)value, "2") == 0)
404 strcpy((char*)id, "lastpresetidx");
405 unsigned int lastindex;
406 globalPM->selectedPresetIndex(lastindex);
407 sprintf ((char*)value, "%i", (int)lastindex);
409 if (strcmp((char*)value, "3") == 0)
411 strcpy((char*)id, "###End");
413 return ADDON_STATUS_OK;
415 // It is now time to set the settings got from xbmc
416 if (strcmp(id, "quality")==0)
417 ChooseQuality (*(int*)value);
418 else if (strcmp(id, "shuffle")==0)
419 g_configPM.shuffleEnabled = *(bool*)value;
421 else if (strcmp(id, "lastpresetidx")==0)
422 lastPresetIdx = *(int*)value;
423 else if (strcmp(id, "lastlockedstatus")==0)
424 lastLockStatus = *(bool*)value;
425 else if (strcmp(id, "lastpresetfolder")==0)
426 strcpy(lastPresetDir, (char*)value);
428 else if (strcmp(id, "smooth_duration")==0)
429 g_configPM.smoothPresetDuration = (*(int*)value * 5 + 5);
430 else if (strcmp(id, "preset_duration")==0)
431 g_configPM.presetDuration = (*(int*)value * 5 + 5);
432 else if (strcmp(id, "preset pack")==0)
433 ChoosePresetPack(*(int*)value);
434 else if (strcmp(id, "user preset folder") == 0)
435 ChooseUserPresetFolder((char*)value);
436 else if (strcmp(id, "beat_sens")==0)
438 g_configPM.beatSensitivity = *(int*)value * 2;
439 if (!InitProjectM()) //The last setting value is already set so we (re)initalize
440 return ADDON_STATUS_UNKNOWN;
442 return ADDON_STATUS_OK;
445 //-- GetSubModules ------------------------------------------------------------
446 // Return any sub modules supported by this vis
447 //-----------------------------------------------------------------------------
448 extern "C" unsigned int GetSubModules(char ***names)
450 return 0; // this vis supports 0 sub modules
453 //-- Announce -----------------------------------------------------------------
454 // Receive announcements from XBMC
455 //-----------------------------------------------------------------------------
456 extern "C" void ADDON_Announce(const char *flag, const char *sender, const char *message, const void *data)