From fddcd4b169066a6f36ea362cbe59aa02d3019fd7 Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Tue, 6 Aug 2024 15:54:07 +0200 Subject: [PATCH 1/2] Update addon to use the projectM 4.0 API --- CMakeLists.txt | 22 +-- FindOpenGLES.cmake | 69 --------- FindOpenGl.cmake | 41 ------ FindProjectM.cmake | 60 -------- Findglm.cmake | 25 ---- src/Main.cpp | 345 +++++++++++++++++++++++++++++++++------------ src/Main.h | 30 ++-- 7 files changed, 273 insertions(+), 319 deletions(-) delete mode 100644 FindOpenGLES.cmake delete mode 100644 FindOpenGl.cmake delete mode 100644 FindProjectM.cmake delete mode 100644 Findglm.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 2da6daf..9313f20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,25 +1,11 @@ -cmake_minimum_required(VERSION 3.5) -project(visualization.projectm) +cmake_minimum_required(VERSION 3.21) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}) +project(visualization.projectm) find_package(Kodi REQUIRED) -find_package(glm REQUIRED) -find_package(ProjectM REQUIRED) - -if(NOT WIN32 AND (APP_RENDER_SYSTEM STREQUAL "gl" OR NOT APP_RENDER_SYSTEM)) - find_package(OpenGl REQUIRED) - set(DEPLIBS ${OPENGL_LIBRARIES}) - set(includes ${OPENGL_INCLUDE_DIR}) - add_definitions(${OPENGL_DEFINITIONS}) -else() - find_package(OpenGLES REQUIRED) - set(DEPLIBS ${OPENGLES_LIBRARIES}) - set(includes ${OPENGLES_INCLUDE_DIR}) - add_definitions(${OPENGLES_DEFINITIONS}) -endif() +find_package(projectM4 REQUIRED COMPONENTS Playlist) -list(APPEND DEPLIBS ${PROJECTM_LIBRARIES}) +list(APPEND DEPLIBS libprojectM::playlist) include_directories(${includes} ${PROJECTM_INCLUDE_DIRS} diff --git a/FindOpenGLES.cmake b/FindOpenGLES.cmake deleted file mode 100644 index aaae6d0..0000000 --- a/FindOpenGLES.cmake +++ /dev/null @@ -1,69 +0,0 @@ -#.rst: -# FindOpenGLES -# ------------ -# Finds the OpenGLES2 and OpenGLES3 library -# -# This will define the following variables: -# -# OPENGLES_FOUND - system has OpenGLES -# OPENGLES_INCLUDE_DIRS - the OpenGLES include directory -# OPENGLES_LIBRARIES - the OpenGLES libraries -# OPENGLES_DEFINITIONS - the OpenGLES definitions -# -# Note: -# On Windows with angle the *_INCLUDE_DIRS and -# *_DEFINITIONS are undefined, but are set -# global by the kodi-angle package. - -if(WIN32) - # defined here and not on addon to have it free of OS related 'if' - # and this file as standard for addons where need it - find_package(kodi-angle REQUIRED) - set(OPENGLES_LIBRARIES kodi::angle::libGLESv2 kodi::angle::libEGL) - set(OPENGLES_FOUND ${kodi-angle_FOUND}) - set(OPENGLES_DEFINITIONS -DHAS_GLES=3) -else() - if(CORE_PLATFORM_NAME_LC STREQUAL rbpi) - set(_brcmprefix brcm) - endif() - - if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_OPENGLES ${_brcmprefix}glesv2 QUIET) - endif() - - if(NOT CORE_SYSTEM_NAME STREQUAL ios AND - NOT CORE_SYSTEM_NAME STREQUAL darwin_embedded) - find_path(OPENGLES_INCLUDE_DIR GLES2/gl2.h - PATHS ${PC_OPENGLES_INCLUDEDIR}) - find_library(OPENGLES_gl_LIBRARY NAMES ${_brcmprefix}GLESv2 - PATHS ${PC_OPENGLES_LIBDIR}) - else() - find_library(OPENGLES_gl_LIBRARY NAMES OpenGLES - PATHS ${CMAKE_OSX_SYSROOT}/System/Library - PATH_SUFFIXES Frameworks - NO_DEFAULT_PATH) - set(OPENGLES_INCLUDE_DIR ${OPENGLES_gl_LIBRARY}/Headers) - endif() - - find_path(OPENGLES3_INCLUDE_DIR GLES3/gl3.h) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(OpenGLES - REQUIRED_VARS OPENGLES_gl_LIBRARY OPENGLES_INCLUDE_DIR) - - find_path(OPENGLES3_INCLUDE_DIR GLES3/gl3.h - PATHS ${PC_OPENGLES_INCLUDEDIR}) - - if(OPENGLES_FOUND) - set(OPENGLES_LIBRARIES ${OPENGLES_gl_LIBRARY}) - if(OPENGLES3_INCLUDE_DIR) - set(OPENGLES_INCLUDE_DIRS ${OPENGLES_INCLUDE_DIR} ${OPENGLES3_INCLUDE_DIR}) - set(OPENGLES_DEFINITIONS -DHAS_GLES=3) - mark_as_advanced(OPENGLES_INCLUDE_DIR OPENGLES3_INCLUDE_DIR OPENGLES_gl_LIBRARY) - else() - set(OPENGLES_INCLUDE_DIRS ${OPENGLES_INCLUDE_DIR}) - set(OPENGLES_DEFINITIONS -DHAS_GLES=2) - mark_as_advanced(OPENGLES_INCLUDE_DIR OPENGLES_gl_LIBRARY) - endif() - endif() -endif() diff --git a/FindOpenGl.cmake b/FindOpenGl.cmake deleted file mode 100644 index 67a6dc2..0000000 --- a/FindOpenGl.cmake +++ /dev/null @@ -1,41 +0,0 @@ -#.rst: -# FindOpenGl -# ---------- -# Finds the FindOpenGl library -# -# This will define the following variables:: -# -# OPENGL_FOUND - system has OpenGl -# OPENGL_INCLUDE_DIRS - the OpenGl include directory -# OPENGL_LIBRARIES - the OpenGl libraries -# OPENGL_DEFINITIONS - the OpenGl definitions - -if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_OPENGL gl QUIET) -endif() - -if(NOT CORE_SYSTEM_NAME STREQUAL osx) - find_path(OPENGL_INCLUDE_DIR GL/gl.h - PATHS ${PC_OPENGL_gl_INCLUDEDIR}) - find_library(OPENGL_gl_LIBRARY NAMES GL OpenGL - PATHS ${PC_OPENGL_gl_LIBDIR}) -else() - find_library(OPENGL_gl_LIBRARY NAMES OpenGL - PATHS ${CMAKE_OSX_SYSROOT}/System/Library - PATH_SUFFIXES Frameworks - NO_DEFAULT_PATH) - set(OPENGL_INCLUDE_DIR ${OPENGL_gl_LIBRARY}/Headers) -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(OpenGl - REQUIRED_VARS OPENGL_gl_LIBRARY OPENGL_INCLUDE_DIR) - -if(OPENGL_FOUND) - set(OPENGL_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) - set(OPENGL_LIBRARIES ${OPENGL_gl_LIBRARY}) - set(OPENGL_DEFINITIONS -DHAS_GL=1) -endif() - -mark_as_advanced(OPENGL_INCLUDE_DIR OPENGL_gl_LIBRARY) - diff --git a/FindProjectM.cmake b/FindProjectM.cmake deleted file mode 100644 index a38ea7e..0000000 --- a/FindProjectM.cmake +++ /dev/null @@ -1,60 +0,0 @@ -# - Try to find ProjectM -# Once done this will define -# -# PROJECTM_FOUND - system has libprojectM -# PROJECTM_INCLUDE_DIRS - the libprojectM include directory -# PROJECTM_PKGDATADIR - the libprojectM directory with required data, e.g. presets -# PROJECTM_LIBRARIES - The libprojectM libraries - -if(WIN32) - find_path(PROJECTM_INCLUDE_DIRS libprojectM/projectM.hpp) - find_path(PROJECTM_PKGDATADIR NAMES config.inp PATH_SUFFIXES share/projectM) - find_library(PROJECTM_LIBRARIES projectM) - - if(PROJECTM_INCLUDE_DIRS AND PROJECTM_PKGDATADIR AND PROJECTM_LIBRARIES) - set(PROJECTM_FOUND TRUE) - endif() - - find_package(dlfcn-win32 REQUIRED) - list(APPEND PROJECTM_LIBRARIES ${dlfcn-win32_LIBRARIES}) - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(projectM DEFAULT_MSG PROJECTM_INCLUDE_DIRS PROJECTM_LIBRARIES PROJECTM_DATA) - - mark_as_advanced(PROJECTM_INCLUDE_DIRS PROJECTM_LIBRARIES PROJECTM_DATA) -else() - find_package(PkgConfig) - if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_PROJECTM libprojectM QUIET) - - if(EXISTS ${PC_PROJECTM_PREFIX}/share/projectM) - set(PC_PROJECTM_PKGDATADIR ${PC_PROJECTM_PREFIX}/share/projectM) - else() - execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=pkgdatadir libprojectM --prefix-variable=${PC_PROJECTM_PREFIX} - OUTPUT_VARIABLE PC_PROJECTM_PKGDATADIR - RESULT_VARIABLE _pkgconfig_failed) - if (_pkgconfig_failed) - message(FATAL_ERROR "Missing libprojectM pkgdatadir") - endif() - - string(REGEX REPLACE "[\r\n]" "" PC_PROJECTM_PKGDATADIR "${PC_PROJECTM_PKGDATADIR}") - endif() - endif() - - find_path(PROJECTM_INCLUDE_DIRS libprojectM/projectM.hpp - PATHS ${PC_PROJECTM_INCLUDEDIR}) - find_path(PROJECTM_PKGDATADIR NAMES config.inp presets/presets_projectM - PATH_SUFFIXES projectM - PATHS ${PC_PROJECTM_PKGDATADIR}) - find_library(PROJECTM_LIBRARIES NAMES projectM - PATHS ${PC_PROJECTM_LIBDIR}) - - if(APPLE) - set(PROJECTM_LIBRARIES "-framework CoreFoundation" ${PROJECTM_LIBRARIES}) - endif() - - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(projectM REQUIRED_VARS PROJECTM_INCLUDE_DIRS PROJECTM_LIBRARIES PROJECTM_PKGDATADIR) - - mark_as_advanced(PROJECTM_INCLUDE_DIRS PROJECTM_LIBRARIES PROJECTM_PKGDATADIR) -endif() diff --git a/Findglm.cmake b/Findglm.cmake deleted file mode 100644 index a21f4ea..0000000 --- a/Findglm.cmake +++ /dev/null @@ -1,25 +0,0 @@ -#.rst: -# Findglm -# ------------ -# Finds the OpenGL Mathematics (GLM) as a header only C++ mathematics library. -# -# This will define the following variables: -# -# GLM_FOUND - system has OpenGLES -# GLM_INCLUDE_DIR - the OpenGLES include directory -# -# Note: Install was removed from GLM on version 0.9.9.6. - -find_package(PkgConfig) -if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_GLM glm QUIET) -endif() - -find_path(GLM_INCLUDE_DIR glm.hpp - PATHS ${PC_GLM_INCLUDEDIR} - PATH_SUFFIXES glm) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(glm REQUIRED_VARS GLM_INCLUDE_DIR) - -mark_as_advanced(GLM_INCLUDE_DIR) diff --git a/src/Main.cpp b/src/Main.cpp index 142713f..482d0a8 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -46,59 +46,89 @@ d4rk@xbmc.org // Called once when the visualisation is created by Kodi. Do any setup here. //----------------------------------------------------------------------------- CVisualizationProjectM::CVisualizationProjectM() - : m_projectM(nullptr), - m_UserPackFolder(false) { - m_configPM.meshX = gx; - m_configPM.meshY = gy; - m_configPM.fps = fps; - m_configPM.windowWidth = Width(); - m_configPM.windowHeight = Height(); - m_configPM.aspectCorrection = true; - m_configPM.easterEgg = 0.0; - m_configPM.titleFontURL = kodi::addon::GetAddonPath("resources/projectM/fonts/Vera.ttf"); - m_configPM.menuFontURL = kodi::addon::GetAddonPath("resources/projectM/fonts/VeraMono.ttf"); - m_configPM.datadir = kodi::addon::GetAddonPath("resources/projectM"); + if (!InitProjectM()) + { + return; + } + + projectm_set_mesh_size(m_projectM, gx, gy); + projectm_set_fps(m_projectM, fps); + projectm_set_window_size(m_projectM, Width(), Height()); + projectm_set_aspect_correction(m_projectM, true); + projectm_set_easter_egg(m_projectM, 0.0); + + auto texturePath = kodi::addon::GetAddonPath("resources/projectM/textures"); + std::vector texturePaths = {texturePath.data()}; + projectm_set_texture_search_paths(m_projectM, texturePaths.data(), texturePaths.size()); + m_lastPresetIdx = kodi::addon::GetSettingInt("last_preset_idx"); #ifdef DEBUG m_lastLoggedPresetIdx = m_lastPresetIdx; #endif - m_configPM.textureSize = kodi::addon::GetSettingInt("quality"); - m_configPM.shuffleEnabled = kodi::addon::GetSettingBoolean("shuffle"); + projectm_playlist_set_shuffle(m_playlist, kodi::addon::GetSettingBoolean("shuffle")); m_lastLockStatus = kodi::addon::GetSettingBoolean("last_locked_status"); - m_lastPresetDir = kodi::addon::GetSettingString("last_preset_folder"); - m_configPM.smoothPresetDuration = kodi::addon::GetSettingInt("smooth_duration"); - m_configPM.presetDuration = kodi::addon::GetSettingInt("preset_duration"); + m_presetDir = kodi::addon::GetSettingString("last_preset_folder"); + + projectm_set_soft_cut_duration(m_projectM, static_cast(kodi::addon::GetSettingFloat("smooth_duration"))); + projectm_set_preset_duration(m_projectM, static_cast(kodi::addon::GetSettingFloat("preset_duration"))); + projectm_set_beat_sensitivity(m_projectM, kodi::addon::GetSettingFloat("beat_sens")); ChoosePresetPack(kodi::addon::GetSettingInt("preset_pack")); ChooseUserPresetFolder(kodi::addon::GetSettingString("user_preset_folder")); - m_configPM.beatSensitivity = kodi::addon::GetSettingInt("beat_sens") * 2; -#ifndef _WIN32 - InitProjectM(); -#endif + // Populate playlist and set initial index + projectm_playlist_add_path(m_playlist, m_presetDir.c_str(), true, false); + + // If it is not the first run AND if this is the same preset pack as last time + if (kodi::addon::GetSettingString("last_preset_folder", "") == m_presetDir && m_lastPresetIdx > 0) + { + projectm_playlist_set_position(m_playlist, m_lastPresetIdx, true); + projectm_set_preset_locked(m_projectM, m_lastLockStatus); + } + else + { + // If it is the first run or a newly chosen preset pack we choose a random preset as first + if (projectm_playlist_size(m_playlist) > 0) + { + auto shuffleEnabled = projectm_playlist_get_shuffle(m_playlist); + projectm_playlist_set_shuffle(m_playlist, true); + projectm_playlist_play_next(m_playlist, false); + projectm_playlist_set_shuffle(m_playlist, shuffleEnabled); + } + } } CVisualizationProjectM::~CVisualizationProjectM() { - unsigned int lastindex = 0; - m_projectM->selectedPresetIndex(lastindex); m_shutdown = true; - kodi::addon::SetSettingInt("last_preset_idx", lastindex); - kodi::addon::SetSettingString("last_preset_folder", m_projectM->settings().presetURL); - kodi::addon::SetSettingBoolean("last_locked_status", m_projectM->isPresetLocked()); + + if (m_playlist && m_projectM) + { + auto lastindex = projectm_playlist_get_position(m_playlist); + kodi::addon::SetSettingInt("last_preset_idx", lastindex); + kodi::addon::SetSettingString("last_preset_folder", m_presetDir); + kodi::addon::SetSettingBoolean("last_locked_status", projectm_get_preset_locked(m_projectM)); + } + + if(m_playlist) + { + projectm_playlist_destroy(m_playlist); + m_playlist = nullptr; + } if (m_projectM) { - delete m_projectM; + projectm_destroy(m_projectM); m_projectM = nullptr; } } bool CVisualizationProjectM::Start(int channels, int samplesPerSec, int bitsPerSample, const std::string& songName) { + // Todo: Store channels, pass this value in AudioData() to projectM #ifdef _WIN32 InitProjectM(); @@ -120,7 +150,9 @@ void CVisualizationProjectM::AudioData(const float* pAudioData, size_t iAudioDat { std::unique_lock lock(m_pmMutex); if (m_projectM) - m_projectM->pcm()->addPCMfloat_2ch(pAudioData, iAudioDataLength); + { + projectm_pcm_add_float(m_projectM, pAudioData, iAudioDataLength / 2, PROJECTM_STEREO); + } } //-- Render ------------------------------------------------------------------- @@ -131,13 +163,12 @@ void CVisualizationProjectM::Render() std::unique_lock lock(m_pmMutex); if (m_projectM) { - m_projectM->renderFrame(); + projectm_opengl_render_frame(m_projectM); #ifdef DEBUG - unsigned preset; - m_projectM->selectedPresetIndex(preset); - if (m_lastLoggedPresetIdx != preset) - CLog::Log(ADDON_LOG_DEBUG,"PROJECTM - Changed preset to: %s",g_presets[preset]); - m_lastLoggedPresetIdx = preset; + auto preset = projectm_playlist_get_position(m_playlist); + if (m_lastLoggedPresetIdx != preset) + CLog::Log(ADDON_LOG_DEBUG,"PROJECTM - Changed preset to: %s",g_presets[preset]); + m_lastLoggedPresetIdx = preset; #endif } } @@ -145,18 +176,20 @@ void CVisualizationProjectM::Render() bool CVisualizationProjectM::LoadPreset(int select) { std::unique_lock lock(m_pmMutex); - m_projectM->selectPreset(select); + if (m_playlist) + { + projectm_playlist_set_position(m_playlist, select, true); + } return true; } bool CVisualizationProjectM::PrevPreset() { std::unique_lock lock(m_pmMutex); -// switchPreset(ALPHA_PREVIOUS, SOFT_CUT); - if (!m_projectM->isShuffleEnabled()) - m_projectM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_p, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS - else - m_projectM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS + if (m_playlist) + { + projectm_playlist_play_previous(m_playlist, false); + } return true; } @@ -164,29 +197,35 @@ bool CVisualizationProjectM::PrevPreset() bool CVisualizationProjectM::NextPreset() { std::unique_lock lock(m_pmMutex); -// switchPreset(ALPHA_NEXT, SOFT_CUT); - if (!m_projectM->isShuffleEnabled()) - m_projectM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_n, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS - else - m_projectM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS + if (m_playlist) + { + projectm_playlist_play_next(m_playlist, false); + } + return true; } bool CVisualizationProjectM::RandomPreset() { std::unique_lock lock(m_pmMutex); - m_projectM->setShuffleEnabled(m_configPM.shuffleEnabled); - return true; + if (m_playlist) + { + auto shuffleEnabled = projectm_playlist_get_shuffle(m_playlist); + projectm_playlist_set_shuffle(m_playlist, true); + projectm_playlist_play_next(m_playlist, false); + projectm_playlist_set_shuffle(m_playlist, shuffleEnabled); + } + return true; } bool CVisualizationProjectM::LockPreset(bool lockUnlock) { std::unique_lock lock(m_pmMutex); - m_projectM->setPresetLock(lockUnlock); - unsigned preset; - m_projectM->selectedPresetIndex(preset); - m_projectM->selectPreset(preset); - return true; + if (m_projectM) + { + projectm_set_preset_locked(m_projectM, lockUnlock); + } + return true; } //-- GetPresets --------------------------------------------------------------- @@ -195,13 +234,23 @@ bool CVisualizationProjectM::LockPreset(bool lockUnlock) bool CVisualizationProjectM::GetPresets(std::vector& presets) { std::unique_lock lock(m_pmMutex); - int numPresets = m_projectM ? m_projectM->getPlaylistSize() : 0; - if (numPresets > 0) + if (!m_playlist) + { + return false; + } + + char** playlistItems = projectm_playlist_items(m_playlist, 0, projectm_playlist_size(m_playlist)); + + char** item = playlistItems; + while (*item) { - for (unsigned i = 0; i < numPresets; i++) - presets.push_back(m_projectM->getPresetName(i)); + presets.push_back(GetBasename(*item)); + item++; } - return (numPresets > 0) ? true : false; + + projectm_playlist_free_string_array(playlistItems); + + return !presets.empty(); } //-- GetPreset ---------------------------------------------------------------- @@ -211,8 +260,10 @@ int CVisualizationProjectM::GetActivePreset() { unsigned preset; std::unique_lock lock(m_pmMutex); - if(m_projectM && m_projectM->selectedPresetIndex(preset)) - return preset; + if (m_playlist && projectm_playlist_get_position(m_playlist)) + { + return static_cast(projectm_playlist_get_position(m_playlist)); + } return 0; } @@ -223,49 +274,91 @@ int CVisualizationProjectM::GetActivePreset() bool CVisualizationProjectM::IsLocked() { std::unique_lock lock(m_pmMutex); - if(m_projectM) - return m_projectM->isPresetLocked(); + if (m_projectM) + { + return projectm_get_preset_locked(m_projectM); + } else + { return false; + } } //-- UpdateSetting ------------------------------------------------------------ // Handle setting change request from Kodi //----------------------------------------------------------------------------- -ADDON_STATUS CVisualizationProjectM::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) +ADDON_STATUS +CVisualizationProjectM::SetSetting(const std::string& settingName, const kodi::addon::CSettingValue& settingValue) { if (settingName.empty() || settingValue.empty()) + { return ADDON_STATUS_UNKNOWN; + } { std::unique_lock lock(m_pmMutex); + if (!m_projectM || !m_playlist) + { + return ADDON_STATUS_UNKNOWN; + } + // It is now time to set the settings got from xmbc - if (settingName == "quality") - m_configPM.textureSize = settingValue.GetInt(); - else if (settingName == "shuffle") - m_configPM.shuffleEnabled = settingValue.GetBoolean(); + if (settingName == "shuffle") + { + projectm_playlist_set_shuffle(m_playlist, settingValue.GetBoolean()); + } else if (settingName == "last_preset_idx") + { m_lastPresetIdx = settingValue.GetInt(); + projectm_playlist_set_position(m_playlist, m_lastPresetIdx, false); + } else if (settingName == "last_locked_status") + { m_lastLockStatus = settingValue.GetBoolean(); + projectm_set_preset_locked(m_projectM, m_lastLockStatus); + } else if (settingName == "last_preset_folder") - m_lastPresetDir = settingValue.GetString(); + { + m_presetDir = settingValue.GetString(); + ReloadPlaylist(); + } else if (settingName == "smooth_duration") - m_configPM.smoothPresetDuration = (settingValue.GetInt() * 5 + 5); + { + projectm_set_soft_cut_duration(m_projectM, static_cast(settingValue.GetFloat())); + } else if (settingName == "preset_duration") - m_configPM.presetDuration = (settingValue.GetInt() * 5 + 5); + { + projectm_set_preset_duration(m_projectM, static_cast(settingValue.GetFloat())); + } else if (settingName == "preset_pack") + { ChoosePresetPack(settingValue.GetInt()); + if (kodi::addon::GetSettingString("last_preset_folder", "") != m_presetDir) + { + ReloadPlaylist(); + } + } else if (settingName == "user_preset_folder") + { ChooseUserPresetFolder(settingValue.GetString()); + if (kodi::addon::GetSettingString("last_preset_folder", "") != m_presetDir) + { + ReloadPlaylist(); + } + } else if (settingName == "beat_sens") - m_configPM.beatSensitivity = settingValue.GetInt() * 2; + { + projectm_set_beat_sensitivity(m_projectM, settingValue.GetFloat()); + } } if (settingName == "beat_sens" && !m_shutdown) // becomes changed in future by a additional value on function { - if (!InitProjectM()) //The last setting value is already set so we (re)initalize + if (!InitProjectM()) + { + // The last setting value is already set so we (re)initalize return ADDON_STATUS_UNKNOWN; + } } return ADDON_STATUS_OK; } @@ -273,21 +366,47 @@ ADDON_STATUS CVisualizationProjectM::SetSetting(const std::string& settingName, bool CVisualizationProjectM::InitProjectM() { std::unique_lock lock(m_pmMutex); - delete m_projectM; //We are re-initializing the engine + if (m_playlist) + { + projectm_playlist_connect(m_playlist, nullptr); + } + + if (m_projectM) + { + projectm_destroy(m_projectM); // We are re-initializing the engine + m_projectM = nullptr; + } + try { - m_projectM = new projectM(m_configPM); - if (m_configPM.presetURL == m_lastPresetDir) //If it is not the first run AND if this is the same preset pack as last time + + m_projectM = projectm_create(); + if (!m_projectM) + { + kodi::Log(ADDON_LOG_FATAL, "Could not create projectM instance."); + return false; + } + + if (!m_playlist) { - m_projectM->setPresetLock(m_lastLockStatus); - m_projectM->selectPreset(m_lastPresetIdx); + m_playlist = projectm_playlist_create(m_projectM); + if (!m_playlist) + { + projectm_destroy(m_projectM); + m_projectM = nullptr; + kodi::Log(ADDON_LOG_FATAL, "Could not create projectM playlist instance."); + return false; + } + + // Automatically update last preset index if it changes + projectm_playlist_set_preset_switched_event_callback(m_playlist, &CVisualizationProjectM::PresetSwitchedEvent, static_cast(this)); } else { - //If it is the first run or a newly chosen preset pack we choose a random preset as first - if (m_projectM->getPlaylistSize()) - m_projectM->selectPreset((rand() % (m_projectM->getPlaylistSize()))); + // Reconnect new instance with existing playlist manager + projectm_playlist_connect(m_playlist, m_projectM); } + return true; } catch (...) @@ -307,60 +426,61 @@ void CVisualizationProjectM::ChoosePresetPack(int pvalue) case 0: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_bltc201"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_bltc201"); break; case 1: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_milkdrop"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_milkdrop"); break; case 2: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_milkdrop_104"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_milkdrop_104"); break; case 3: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_milkdrop_200"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_milkdrop_200"); break; case 4: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_mischa_collection"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_mischa_collection"); break; case 5: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_projectM"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_projectM"); case 6: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_stock"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_stock"); break; case 7: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_tryptonaut"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_tryptonaut"); break; case 8: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_yin"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_yin"); break; case 9: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/tests"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/tests"); break; case 10: m_UserPackFolder = false; - m_configPM.presetURL = kodi::addon::GetAddonPath("resources/projectM/presets/presets_eyetune"); + m_presetDir = kodi::addon::GetAddonPath("resources/projectM/presets/presets_eyetune"); break; default: - kodi::Log(ADDON_LOG_FATAL, "CVisualizationProjectM::%s: Should never called with unknown preset pack (%i)", __func__, pvalue); + kodi::Log(ADDON_LOG_FATAL, "CVisualizationProjectM::%s: Should never called with unknown preset pack (%i)", + __func__, pvalue); break; } } @@ -370,9 +490,48 @@ void CVisualizationProjectM::ChooseUserPresetFolder(std::string pvalue) if (m_UserPackFolder && !pvalue.empty()) { if (pvalue.back() == '/') - pvalue.erase(pvalue.length()-1,1); //Remove "/" from the end - m_configPM.presetURL = pvalue; + { + pvalue.erase(pvalue.length() - 1, 1); + } //Remove "/" from the end + m_presetDir = pvalue; + } +} + +std::string CVisualizationProjectM::GetBasename(std::string fullPath) +{ + auto lastSlash = fullPath.find_last_of("/\\"); + if (lastSlash != std::string::npos) + { + fullPath = fullPath.substr(lastSlash + 1); + } + + auto lastExt = fullPath.find_last_of("."); + if (lastExt != std::string::npos && lastExt != 0) + { + fullPath = fullPath.substr(0, lastExt); + } + + return fullPath; +} + +void CVisualizationProjectM::ReloadPlaylist() +{ + // Load new playlist and select a random preset + projectm_playlist_clear(m_playlist); + projectm_playlist_add_path(m_playlist, m_presetDir.c_str(), true, false); + if (projectm_playlist_size(m_playlist) > 0) + { + auto shuffleEnabled = projectm_playlist_get_shuffle(m_playlist); + projectm_playlist_set_shuffle(m_playlist, true); + projectm_playlist_play_next(m_playlist, true); + projectm_playlist_set_shuffle(m_playlist, shuffleEnabled); } } +void CVisualizationProjectM::PresetSwitchedEvent(bool isHardCut, unsigned int index, void* context) +{ + auto that = reinterpret_cast(context); + that->m_lastPresetIdx = static_cast(projectm_playlist_get_position(that->m_playlist)); +} + ADDONCREATOR(CVisualizationProjectM) diff --git a/src/Main.h b/src/Main.h index 71b6bf8..ada4d94 100644 --- a/src/Main.h +++ b/src/Main.h @@ -44,8 +44,10 @@ d4rk@xbmc.org #include #include +#include -#include +#include +#include class ATTR_DLL_LOCAL CVisualizationProjectM : public kodi::addon::CAddonBase, @@ -72,27 +74,29 @@ class ATTR_DLL_LOCAL CVisualizationProjectM bool InitProjectM(); void ChoosePresetPack(int pvalue); void ChooseUserPresetFolder(std::string pvalue); + std::string GetBasename(std::string fullPath); + void ReloadPlaylist(); + static void PresetSwitchedEvent(bool isHardCut, unsigned int index, void* context); - projectM* m_projectM; - projectM::Settings m_configPM; + projectm_handle m_projectM{nullptr}; + projectm_playlist_handle m_playlist{nullptr}; std::mutex m_pmMutex; - bool m_UserPackFolder; - std::string m_lastPresetDir; - int m_lastPresetIdx; + bool m_UserPackFolder{false}; + std::string m_presetDir; + std::atomic_int m_lastPresetIdx{}; #ifdef DEBUG - unsigned int m_lastLoggedPresetIdx; + unsigned int m_lastLoggedPresetIdx{}; #endif - bool m_lastLockStatus; - bool m_shutdown = false; + bool m_lastLockStatus{false}; + std::atomic_bool m_shutdown{false}; #ifdef _WIN32 bool m_presetsSet = false; #endif // some projectm globals - const static int maxSamples=512; - const static int texsize=512; - const static int gx=40,gy=30; - const static int fps=100; + const static int gx{40}; + const static int gy{30}; + const static int fps{60}; }; From 9c57521cfc9e1bf7b03b92c05da38baaee7d6071 Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Tue, 6 Aug 2024 16:08:41 +0200 Subject: [PATCH 2/2] Changed some settings to float and removed unused "quality" option --- visualization.projectm/resources/settings.xml | 56 ++++++++----------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/visualization.projectm/resources/settings.xml b/visualization.projectm/resources/settings.xml index 2e332f4..476f3e0 100644 --- a/visualization.projectm/resources/settings.xml +++ b/visualization.projectm/resources/settings.xml @@ -54,49 +54,37 @@ true - - 512 + + 3.0 - - - - - - - - - - - 10 - - 5 - 5 - 50 + 0.0 + 0.1 + 10.0 - - 30050 - + + false + - + 20 - 5 - 5 - 50 + 1.0 + 1.0 + 60.0 - - 30050 - + + false + - - 20 + + 1.0 - 0 - 10 - 100 + 0.0 + 0.05 + 2.0 - - 30051 + + false