From 14f4bcac65b026bee61fbbb40812e30878fe1ff5 Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Tue, 17 Aug 2021 00:06:02 +0200 Subject: [PATCH] Added a C-style interface header and wrapper for projectM. This will make it easier to integrate projectM into C applications and also removes potential issues of STL/C++ version differences between host and library. Changed visibility of all symbols except the C API to "hidden". This effectively prevents the C++ API from being used in the shared library. Added an option "ENABLE_CXX_INTERFACE" to re-enable the old export behaviour, displaying a prominent author warning after configuring the build if enabled. --- CMakeLists.txt | 20 + src/libprojectM/CMakeLists.txt | 14 + src/libprojectM/PresetLoader.cpp | 2 +- src/libprojectM/PresetLoader.hpp | 2 +- src/libprojectM/ProjectMCWrapper.cpp | 631 +++++++++++++ src/libprojectM/ProjectMCWrapper.hpp | 50 ++ src/libprojectM/Renderer/MilkdropWaveform.hpp | 9 +- src/libprojectM/projectM.cpp | 4 +- src/libprojectM/projectM.h | 833 ++++++++++++++++++ src/libprojectM/projectM.hpp | 8 +- 10 files changed, 1564 insertions(+), 9 deletions(-) create mode 100644 src/libprojectM/ProjectMCWrapper.cpp create mode 100644 src/libprojectM/ProjectMCWrapper.hpp create mode 100644 src/libprojectM/projectM.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ef7b4e157..aef6f1620 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ set(PROJECTM_LIB_DIR "lib" CACHE STRING "Library installation directory, relativ set(PROJECTM_INCLUDE_DIR "include" CACHE STRING "Header installation directory, relative to the install prefix.") # Feature options, including dependencies. +option(ENABLE_CXX_INTERFACE "Enable exporting all C++ symbols, not only the C API, in the shared library. Warning: This is dangerous!" OFF) option(ENABLE_PRESETS "Build and install bundled presets" ON) option(ENABLE_NATIVE_PRESETS "Build and install native libraries written in C/C++" OFF) option(ENABLE_TESTING "Build and install the projectM test suite" OFF) @@ -161,6 +162,16 @@ if(ENABLE_LIBVISUAL) set(PROJECTM_LIBVISUAL_DIR "${LIBVISUAL_PLUGINSBASEDIR}/actor" CACHE STRING "Installation directory for the libvisual plug-in library.") endif() +if(ENABLE_CXX_INTERFACE) + set(CMAKE_C_VISIBILITY_PRESET default) + set(CMAKE_CXX_VISIBILITY_PRESET default) + set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF) +else() + set(CMAKE_C_VISIBILITY_PRESET hidden) + set(CMAKE_CXX_VISIBILITY_PRESET hidden) + set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) +endif() + include(features.cmake) add_subdirectory(presets) @@ -224,6 +235,15 @@ message(AUTHOR_WARNING "DO NOT base any production work on it yet!\n" ) +if(ENABLE_CXX_INTERFACE) + message(AUTHOR_WARNING "This build is configured to export all C++ symbols in the shared library.\n" + "Using C++ STL types across library borders only works if all components were built " + "with the exact same toolchain and C++ language level, otherwise it will cause crashes.\n" + "Enabling this option will not export additional symbols in Windows DLL builds.\n" + "Only use this if you know what you're doing. You have been warned!" + ) +endif() + # Create CPack configuration set(CPACK_PACKAGE_NAME "projectM") set(CPACK_VERBATIM_VARIABLES YES) diff --git a/src/libprojectM/CMakeLists.txt b/src/libprojectM/CMakeLists.txt index b9ac571ce..d70ad4e15 100644 --- a/src/libprojectM/CMakeLists.txt +++ b/src/libprojectM/CMakeLists.txt @@ -67,8 +67,11 @@ add_library(projectM_main OBJECT PresetLoader.cpp PresetLoader.hpp projectM.cpp + projectM.h projectM.hpp projectM-opengl.h + ProjectMCWrapper.cpp + ProjectMCWrapper.hpp RandomNumberGenerators.hpp resource.h sdltoprojectM.h @@ -84,6 +87,8 @@ add_library(projectM_main OBJECT target_include_directories(projectM_main PRIVATE + "${CMAKE_CURRENT_BINARY_DIR}/include" + "${CMAKE_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/Renderer" "${CMAKE_CURRENT_SOURCE_DIR}/Renderer/hlslparser/src" @@ -99,6 +104,13 @@ target_link_libraries(projectM_main ${PROJECTM_OPENGL_LIBRARIES} ) +include(GenerateExportHeader) + +generate_export_header(projectM_main + BASE_NAME projectM + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/libprojectM/projectM_export.h" + ) + add_library(projectM_static STATIC # Xcode needs at least one source file, otherwise it won't create the static library. StaticLibDummy.cpp @@ -244,7 +256,9 @@ install(FILES dlldefs.h event.h fatal.h + projectM.h projectM.hpp + "${CMAKE_CURRENT_BINARY_DIR}/include/libprojectM/projectM_export.h" DESTINATION "${PROJECTM_INCLUDE_DIR}/libprojectM" COMPONENT Devel ) diff --git a/src/libprojectM/PresetLoader.cpp b/src/libprojectM/PresetLoader.cpp index 4731484f0..6948bad47 100644 --- a/src/libprojectM/PresetLoader.cpp +++ b/src/libprojectM/PresetLoader.cpp @@ -157,7 +157,7 @@ const std::vector &PresetLoader::getPresetNames() const } // Get the preset index given a name -const unsigned int PresetLoader::getPresetIndex(std::string &name) const +unsigned int PresetLoader::getPresetIndex(const std::string& name) const { return find(_presetNames.begin(), _presetNames.end(), name) - _presetNames.begin(); } diff --git a/src/libprojectM/PresetLoader.hpp b/src/libprojectM/PresetLoader.hpp index 6de901b70..891546911 100644 --- a/src/libprojectM/PresetLoader.hpp +++ b/src/libprojectM/PresetLoader.hpp @@ -74,7 +74,7 @@ class PresetLoader { const std::vector & getPresetNames() const; /// Get the preset index given a name - const unsigned int getPresetIndex(std::string &name) const; + unsigned int getPresetIndex(const std::string& name) const; /// Returns the number of presets in the active directory inline std::size_t size() const { diff --git a/src/libprojectM/ProjectMCWrapper.cpp b/src/libprojectM/ProjectMCWrapper.cpp new file mode 100644 index 000000000..07c4fb147 --- /dev/null +++ b/src/libprojectM/ProjectMCWrapper.cpp @@ -0,0 +1,631 @@ +#include "ProjectMCWrapper.hpp" + +#include "projectM.h" + +#include +#include + +projectMWrapper::projectMWrapper(std::string configFile, int flags) + : projectM(std::move(configFile), flags) +{ +} + +projectMWrapper::projectMWrapper(projectM::Settings settings, int flags) + : projectM(std::move(settings), flags) +{ +} + +void projectMWrapper::presetSwitchedEvent(bool isHardCut, size_t presetIndex) const +{ + if (_presetSwitchedEventCallback) + { + _presetSwitchedEventCallback(isHardCut, presetIndex); + } +} + +void projectMWrapper::shuffleEnabledValueChanged(bool shuffle_enabled) const +{ + if (_shuffleEnableChangedEventCallback) + { + _shuffleEnableChangedEventCallback(shuffle_enabled); + } +} + +void projectMWrapper::presetSwitchFailedEvent(bool isHardCut, unsigned int presetIndex, + const std::string& failureMessage) const +{ + if (_presetSwitchFailedEventCallback) + { + _presetSwitchFailedEventCallback(isHardCut, presetIndex, failureMessage.c_str()); + } +} + +void projectMWrapper::presetRatingChanged(unsigned int presetIndex, int rating, PresetRatingType ratingType) const +{ + if (_presetRatingChangedEventCallback) + { + _presetRatingChangedEventCallback(presetIndex, rating, static_cast(ratingType)); + } +} + +projectMWrapper* handle_to_instance(projectm_handle instance) +{ + return reinterpret_cast(instance); +} + +char* projectm_alloc_string(unsigned int length) +{ + try + { + return new char[length]{}; + } + catch (...) + { + return nullptr; + } +} + +char* projectm_alloc_string_from_std_string(const std::string& str) +{ + auto pointer = projectm_alloc_string(str.length() + 1); + if (pointer) + { + memcpy(pointer, str.c_str(), str.length()); + } + return pointer; +} + +void projectm_free_string(const char* str) +{ + delete[] str; +} + +projectm_settings_t* projectm_alloc_settings() +{ + try + { + return new projectm_settings_t{}; + } + catch (...) + { + return nullptr; + } +} + +void projectm_free_settings(projectm_settings_t* settings) +{ + if (settings) + { + projectm_free_string(settings->preset_url); + projectm_free_string(settings->title_font_url); + projectm_free_string(settings->menu_font_url); + projectm_free_string(settings->data_dir); + } + + delete settings; +} + +projectm_handle projectm_create(const char* setting_file_path, int flags) +{ + try + { + auto projectMInstance = new projectMWrapper(std::string(setting_file_path), flags); + return reinterpret_cast(projectMInstance); + } + catch (...) + { + return nullptr; + } +} + +projectm_handle projectm_create_settings(const projectm_settings_t* settings, int flags) +{ + try + { + projectM::Settings cppSettings; + cppSettings.meshX = settings->mesh_x; + cppSettings.meshY = settings->mesh_y; + cppSettings.fps = settings->fps; + cppSettings.textureSize = settings->texture_size; + cppSettings.windowWidth = settings->window_width; + cppSettings.windowHeight = settings->window_height; + cppSettings.presetURL = settings->preset_url ? settings->preset_url : ""; + cppSettings.titleFontURL = settings->title_font_url ? settings->title_font_url : ""; + cppSettings.menuFontURL = settings->menu_font_url ? settings->menu_font_url : ""; + cppSettings.datadir = settings->data_dir ? settings->data_dir : ""; + cppSettings.smoothPresetDuration = settings->smooth_preset_duration; + cppSettings.presetDuration = settings->preset_duration; + cppSettings.hardcutEnabled = settings->hardcut_enabled; + cppSettings.hardcutDuration = settings->hardcut_duration; + cppSettings.hardcutSensitivity = settings->hardcut_sensitivity; + cppSettings.beatSensitivity = settings->beat_sensitivity; + cppSettings.aspectCorrection = settings->aspect_correction; + cppSettings.easterEgg = settings->easter_egg; + cppSettings.shuffleEnabled = settings->shuffle_enabled; + cppSettings.softCutRatingsEnabled = settings->soft_cut_ratings_enabled; + + auto projectMInstance = new projectMWrapper(cppSettings, flags); + return reinterpret_cast(projectMInstance); + } + catch (...) + { + return nullptr; + } +} + +void projectm_destroy(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + delete projectMInstance; +} + +void projectm_set_preset_switched_event_callback(projectm_handle instance, projectm_preset_switched_event callback) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->_presetSwitchedEventCallback = callback; +} + +void projectm_set_shuffle_enable_changed_event_callback(projectm_handle instance, + projectm_shuffle_enable_changed_event callback) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->_shuffleEnableChangedEventCallback = callback; +} + +void projectm_set_preset_switch_failed_event_callback(projectm_handle instance, + projectm_preset_switch_failed_event callback) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->_presetSwitchFailedEventCallback = callback; +} + +void projectm_set_preset_rating_changed_event_callback(projectm_handle instance, + projectm_preset_rating_changed_event callback) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->_presetRatingChangedEventCallback = callback; +} + +void projectm_reset_gl(projectm_handle instance, int width, int height) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->projectM_resetGL(width, height); +} + +void projectm_reset_textures(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->projectM_resetTextures(); +} + +void projectm_set_title(projectm_handle instance, const char* title) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->projectM_setTitle(title); +} + +void projectm_render_frame(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->renderFrame(); +} + +unsigned int projectm_init_render_to_texture(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->initRenderToTexture(); +} + +void projectm_key_handler(projectm_handle instance, projectMEvent event, projectMKeycode keycode, + projectMModifier modifier) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->key_handler(event, keycode, modifier); +} + +void projectm_default_key_handler(projectm_handle instance, projectMEvent event, projectMKeycode keycode) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->default_key_handler(event, keycode); +} + +void projectm_set_texture_size(projectm_handle instance, int size) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->changeTextureSize(size); +} + +void projectm_set_hardcut_duration(projectm_handle instance, double seconds) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->changeHardcutDuration(seconds); +} + +void projectm_set_preset_duration(projectm_handle instance, double seconds) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->changePresetDuration(seconds); +} + +void projectm_get_mesh_size(projectm_handle instance, int* width, int* height) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->getMeshSize(width, height); +} + +void projectm_touch(projectm_handle instance, float x, float y, int pressure, projectm_touch_type touch_type) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->touch(x, y, pressure, touch_type); +} + +void projectm_touch_drag(projectm_handle instance, float x, float y, int pressure) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->touchDrag(x, y, pressure); +} + +void projectm_touch_destroy(projectm_handle instance, float x, float y) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->touchDestroy(x, y); +} + +void projectm_touch_destroy_all(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->touchDestroyAll(); +} + +void projectm_set_help_text(projectm_handle instance, const char* help_text) +{ + if (!help_text) + { + return; + } + + auto projectMInstance = handle_to_instance(instance); + projectMInstance->setHelpText(help_text); +} + +void projectm_set_toast_message(projectm_handle instance, const char* toast_message) +{ + if (!toast_message) + { + return; + } + + auto projectMInstance = handle_to_instance(instance); + projectMInstance->setToastMessage(toast_message); +} + +projectm_settings_t* projectm_get_settings(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + const auto& settings = projectMInstance->settings(); + + auto settingsStruct = projectm_alloc_settings(); + settingsStruct->mesh_x = settings.meshX; + settingsStruct->mesh_y = settings.meshY; + settingsStruct->fps = settings.fps; + settingsStruct->texture_size = settings.textureSize; + settingsStruct->window_width = settings.windowWidth; + settingsStruct->window_height = settings.windowHeight; + settingsStruct->preset_url = projectm_alloc_string_from_std_string(settings.presetURL); + settingsStruct->title_font_url = projectm_alloc_string_from_std_string(settings.titleFontURL); + settingsStruct->menu_font_url = projectm_alloc_string_from_std_string(settings.menuFontURL); + settingsStruct->data_dir = projectm_alloc_string_from_std_string(settings.datadir); + settingsStruct->smooth_preset_duration = settings.smoothPresetDuration; + settingsStruct->preset_duration = settings.presetDuration; + settingsStruct->hardcut_enabled = settings.hardcutEnabled; + settingsStruct->hardcut_duration = settings.hardcutDuration; + settingsStruct->hardcut_sensitivity = settings.hardcutSensitivity; + settingsStruct->beat_sensitivity = settings.beatSensitivity; + settingsStruct->aspect_correction = settings.aspectCorrection; + settingsStruct->easter_egg = settings.easterEgg; + settingsStruct->shuffle_enabled = settings.shuffleEnabled; + settingsStruct->soft_cut_ratings_enabled = settings.softCutRatingsEnabled; + + return settingsStruct; +} + +void projectm_write_config(const char* config_file, const projectm_settings_t* settings) +{ + projectM::Settings cppSettings; + cppSettings.meshX = settings->mesh_x; + cppSettings.meshY = settings->mesh_y; + cppSettings.fps = settings->fps; + cppSettings.textureSize = settings->texture_size; + cppSettings.windowWidth = settings->window_width; + cppSettings.windowHeight = settings->window_height; + cppSettings.presetURL = settings->preset_url ? settings->preset_url : ""; + cppSettings.titleFontURL = settings->title_font_url ? settings->title_font_url : ""; + cppSettings.menuFontURL = settings->menu_font_url ? settings->menu_font_url : ""; + cppSettings.datadir = settings->data_dir ? settings->data_dir : ""; + cppSettings.smoothPresetDuration = settings->smooth_preset_duration; + cppSettings.presetDuration = settings->preset_duration; + cppSettings.hardcutEnabled = settings->hardcut_enabled; + cppSettings.hardcutDuration = settings->hardcut_duration; + cppSettings.hardcutSensitivity = settings->hardcut_sensitivity; + cppSettings.beatSensitivity = settings->beat_sensitivity; + cppSettings.aspectCorrection = settings->aspect_correction; + cppSettings.easterEgg = settings->easter_egg; + cppSettings.shuffleEnabled = settings->shuffle_enabled; + cppSettings.softCutRatingsEnabled = settings->soft_cut_ratings_enabled; + + projectM::writeConfig(config_file, cppSettings); +} + +void projectm_select_preset_position(projectm_handle instance, unsigned int index) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->selectPresetPosition(index); +} + +void projectm_select_preset(projectm_handle instance, unsigned int index, bool hard_cut) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->selectPreset(index, hard_cut); +} + +void projectm_populate_preset_menu(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->populatePresetMenu(); +} + +void projectm_remove_preset(projectm_handle instance, unsigned int index) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->removePreset(index); +} + +void projectm_clear_playlist(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->clearPlaylist(); +} + +void projectm_lock_preset(projectm_handle instance, bool lock) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->setPresetLock(lock); +} + +bool projectm_is_text_input_active(projectm_handle instance, bool no_minimum_length) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->isTextInputActive(no_minimum_length); +} + +unsigned int projectm_get_preset_index(projectm_handle instance, const char* preset_name) +{ + if (!preset_name) + { + return 0; + } + + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getPresetIndex(preset_name); +} + +void projectm_select_preset_by_name(projectm_handle instance, const char* preset_name, bool hard_cut) +{ + if (!preset_name) + { + return; + } + + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->selectPresetByName(preset_name, hard_cut); +} + +void projectm_set_search_text(projectm_handle instance, const char* search_text) +{ + if (!search_text) + { + return; + } + + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->setSearchText(search_text); +} + +void projectm_delete_search_text(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->deleteSearchText(); +} + +void projectm_reset_search_text(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->resetSearchText(); +} + +bool projectm_selected_preset_index(projectm_handle instance, unsigned int* index) +{ + if (!index) + { + return false; + } + + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->selectedPresetIndex(*index); +} + +void projectm_add_preset_url(projectm_handle instance, const char* preset_url, const char* preset_name, + int* rating_list, unsigned int rating_list_length) +{ + if (!preset_url + || !preset_name + || (!rating_list && rating_list_length > 0) + || rating_list_length != TOTAL_RATING_TYPES) + { + return; + } + + RatingList ratingList; + for (unsigned int ratingIndex = 0; ratingIndex < rating_list_length; ratingIndex++) + { + ratingList.push_back(rating_list[ratingIndex]); + } + + auto projectMInstance = handle_to_instance(instance); + projectMInstance->addPresetURL(preset_url, preset_name, ratingList); +} + +void projectm_insert_preset_url(projectm_handle instance, unsigned int index, const char* preset_url, + const char* preset_name, int* rating_list, unsigned int rating_list_length) +{ + if (!preset_url + || !preset_name + || (!rating_list && rating_list_length > 0) + || rating_list_length != TOTAL_RATING_TYPES) + { + return; + } + + RatingList ratingList; + for (unsigned int ratingIndex = 0; ratingIndex < rating_list_length; ratingIndex++) + { + ratingList.push_back(rating_list[ratingIndex]); + } + + auto projectMInstance = handle_to_instance(instance); + projectMInstance->insertPresetURL(index, preset_url, preset_name, ratingList); +} + +bool projectm_preset_position_valid(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->presetPositionValid(); +} + +const char* projectm_get_preset_url(projectm_handle instance, unsigned int index) +{ + auto projectMInstance = handle_to_instance(instance); + return projectm_alloc_string_from_std_string(projectMInstance->getPresetURL(index)); +} + +const char* projectm_get_preset_name(projectm_handle instance, unsigned int index) +{ + auto projectMInstance = handle_to_instance(instance); + return projectm_alloc_string_from_std_string(projectMInstance->getPresetName(index)); +} + +void projectm_change_preset_name(projectm_handle instance, unsigned int index, const char* name) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->changePresetName(index, name); +} + +int projectm_get_preset_rating(projectm_handle instance, unsigned int index, projectm_preset_rating_type rating_type) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getPresetRating(index, static_cast(rating_type)); +} + +void projectm_change_preset_rating(projectm_handle instance, unsigned int index, int rating, + projectm_preset_rating_type rating_type) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->changePresetRating(index, rating, static_cast(rating_type)); +} + +unsigned int projectm_get_playlist_size(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getPlaylistSize(); +} + +void projectm_set_shuffle_enabled(projectm_handle instance, bool shuffle_enabled) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->setShuffleEnabled(shuffle_enabled); +} + +bool projectm_is_shuffle_enabled(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->isShuffleEnabled(); +} + +unsigned int projectm_get_search_index(projectm_handle instance, const char* name) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getSearchIndex(name); +} + +void projectm_select_previous(projectm_handle instance, bool hard_cut) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->selectPrevious(hard_cut); +} + +void projectm_select_next(projectm_handle instance, bool hard_cut) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->selectNext(hard_cut); +} + +void projectm_select_random(projectm_handle instance, bool hard_cut) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->selectRandom(hard_cut); +} + +int projectm_get_window_width(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getWindowWidth(); +} + +int projectm_get_window_height(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getWindowHeight(); +} + +bool projectm_get_error_loading_current_preset(projectm_handle instance) +{ + auto projectMInstance = handle_to_instance(instance); + return projectMInstance->getErrorLoadingCurrentPreset(); +} + +void projectm_pcm_add_float_1ch_data(projectm_handle instance, const float* pcm_data, unsigned int sample_count) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->pcm()->addPCMfloat(pcm_data, sample_count); +} + +void projectm_pcm_add_float_2ch_data(projectm_handle instance, const float* pcm_data, unsigned int sample_count) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->pcm()->addPCMfloat_2ch(pcm_data, sample_count); +} + +void projectm_pcm_add_16bit_2ch_512(projectm_handle instance, const short (* pcm_data)[512]) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->pcm()->addPCM16(pcm_data); +} + +void projectm_pcm_add_16bit_2ch_data(projectm_handle instance, const short* pcm_data, unsigned int sample_count) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->pcm()->addPCM16Data(pcm_data, sample_count); +} + +void projectm_pcm_add_8bit_2ch_1024(projectm_handle instance, const unsigned char (* pcm_data)[1024]) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->pcm()->addPCM8(pcm_data); +} + +void projectm_pcm_add_8bit_2ch_512(projectm_handle instance, const unsigned char (* pcm_data)[512]) +{ + auto projectMInstance = handle_to_instance(instance); + projectMInstance->pcm()->addPCM8_512(pcm_data); +} + diff --git a/src/libprojectM/ProjectMCWrapper.hpp b/src/libprojectM/ProjectMCWrapper.hpp new file mode 100644 index 000000000..1bd346aa4 --- /dev/null +++ b/src/libprojectM/ProjectMCWrapper.hpp @@ -0,0 +1,50 @@ +/* + * projectM -- Milkdrop-esque visualisation SDK + * Copyright (C)2003-2021 projectM Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * See 'LICENSE.txt' included within this release + * + */ + +#pragma once + +#include "projectM.hpp" + +extern "C" { +#include "projectM.h" +} + +class projectMWrapper : public projectM +{ +public: + projectMWrapper(std::string configFile, int flags); + + projectMWrapper(Settings settings, int flags); + + void presetSwitchedEvent(bool isHardCut, size_t presetIndex) const override; + + void shuffleEnabledValueChanged(bool shuffle_enabled) const override; + + void presetSwitchFailedEvent(bool isHardCut, unsigned int presetIndex, + const std::string& failureMessage) const override; + + void presetRatingChanged(unsigned int presetIndex, int rating, PresetRatingType ratingType) const override; + + projectm_preset_switched_event _presetSwitchedEventCallback{ nullptr }; + projectm_shuffle_enable_changed_event _shuffleEnableChangedEventCallback{ nullptr }; + projectm_preset_switch_failed_event _presetSwitchFailedEventCallback{ nullptr }; + projectm_preset_rating_changed_event _presetRatingChangedEventCallback{ nullptr }; +}; diff --git a/src/libprojectM/Renderer/MilkdropWaveform.hpp b/src/libprojectM/Renderer/MilkdropWaveform.hpp index 3d8b6c0e5..6d33184a8 100644 --- a/src/libprojectM/Renderer/MilkdropWaveform.hpp +++ b/src/libprojectM/Renderer/MilkdropWaveform.hpp @@ -12,7 +12,14 @@ enum MilkdropWaveformMode { - Circle=0, RadialBlob, Blob2, Blob3, DerivativeLine, Blob5, Line, DoubleLine, + Circle = 1, + RadialBlob, + Blob2, + Blob3, + DerivativeLine, + Blob5, + Line, + DoubleLine, last // last is a placeholder to find enum size. Please ignore and leave this here. }; diff --git a/src/libprojectM/projectM.cpp b/src/libprojectM/projectM.cpp index 208af3b9b..f166fa66c 100644 --- a/src/libprojectM/projectM.cpp +++ b/src/libprojectM/projectM.cpp @@ -1146,7 +1146,7 @@ void projectM::toggleSearchText() } // get index from search results based on preset name -unsigned int projectM::getSearchIndex(std::string &name) const +unsigned int projectM::getSearchIndex(const std::string& name) const { for (auto& it : renderer->m_presetList) { if (it.name == name) return it.id; @@ -1155,7 +1155,7 @@ unsigned int projectM::getSearchIndex(std::string &name) const } // get preset index based on preset name -unsigned int projectM::getPresetIndex(std::string& name) const +unsigned int projectM::getPresetIndex(const std::string& name) const { return m_presetLoader->getPresetIndex(name); } diff --git a/src/libprojectM/projectM.h b/src/libprojectM/projectM.h new file mode 100644 index 000000000..959a6197c --- /dev/null +++ b/src/libprojectM/projectM.h @@ -0,0 +1,833 @@ +/* + * projectM -- Milkdrop-esque visualisation SDK + * Copyright (C)2003-2021 projectM Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * See 'LICENSE.txt' included within this release + * + */ + +#pragma once + +#include "libprojectM/projectM_export.h" +#include "libprojectM/event.h" + +struct projectm; //!< Opaque projectM instance type. +typedef projectm* projectm_handle; //!< A pointer to the opaque projectM instance. + +/** + * @brief projectM instance settings. + * + *

Use this struct to provide settings for projectM, for example if your application handles projectM configuration + * internally instead of using the default configuration file.

+ * + *

Always allocate the struct using the projectm_alloc_settings() and free it with the projectm_free_settings() + * function.

+ * + *

To allocate memory for char* members, always use projectm_alloc_string(). If any pointer is not NULL, + * projectm_free_settings() will automatically call projectm_free_string() on it. If you free it on your own, remember + * to reset the pointer to NULL after doing so!

+ */ +typedef struct projectm_settings +{ + int mesh_x; //!< Per-pixel mesh X resolution. + int mesh_y; //!< Per-pixel mesh Y resolution. + int fps; //!< Target rendering frames per second. + int texture_size; //!< Size of the render texture. Must be a power of 2. + int window_width; //!< Width of the rendering viewport. + int window_height; //!< Height of the rendering viewport. + char* preset_url; //!< Path to a preset playlist in XML format to be loaded. Use FLAG_DISABLE_PLAYLIST_LOAD to skip loading a playlist. + char* title_font_url; //!< Path to the "title" font that is used to render the preset name. + char* menu_font_url; //!< Path to the "menu" font that is used to render the built-in on-screen menu. + char* data_dir; //!< Path to data files like default fonts and presets. + double smooth_preset_duration; //!< Blend-over duration between two presets in seconds. + double preset_duration; //!< Display duration for each preset in seconds. + bool hardcut_enabled; //!< Set to true to enable fast beat-driven preset switches. + int hardcut_duration; //!< Minimum time a preset is displayed before a hardcut can happen in seconds. + float hardcut_sensitivity; //!< Beat sensitivity value that must be surpassed for a hardcut. + float beat_sensitivity; //!< Beat sensitivity. Standard sensitivity is 1.0. + bool aspect_correction; //!< Use aspect ration correction in presets that support it. + float easter_egg; //!< Used as the "sigma" value for a gaussian RNG to randomize preset duration. Unused on Windows. + bool shuffle_enabled; //!< Enable playlist shuffle, selecting a random preset on each switch instead of the next in list. + bool soft_cut_ratings_enabled; //!< If true, use soft cut ratings on soft cuts and hard cut ratings on hard cuts. If false, the hard cut rating is always used. +} projectm_settings_t; + +/** + * Flags that influence projectM instance creation. + */ +enum projectm_flags +{ + PROJECTM_FLAG_NONE = 0, //!< No flags. + PROJECTM_FLAG_DISABLE_PLAYLIST_LOAD = 1 << 0 //!< Set this flag to disable loading a preset playlist on startup. +}; + +/** + * Rating types supported by projectM. Used to control preset selection for different types + * of transitions (hard/soft). + */ +enum projectm_preset_rating_type +{ + PROJECTM_HARD_CUT_RATING_TYPE, //!< Rating for hard cuts. + PROJECTM_SOFT_CUT_RATING_TYPE //!< Rating for soft cuts. +}; + +/** + * Placeholder values that can be used to address channel indices in PCM data arrays. + */ +enum projectm_pcm_channel +{ + PROJECTM_CHANNEL_L = 0, //!< Left audio channel. + PROJECTM_CHANNEL_0 = 0, //!< Left audio channel. + PROJECTM_CHANNEL_R = 1, //!< Right audio channel. + PROJECTM_CHANNEL_1 = 1 //!< Right audio channel. +}; + +/** + * Waveform render types used in the touch start method. + */ +enum projectm_touch_type +{ + PROJECTM_TOUCH_TYPE_RANDOM, //!< Random waveform type. + PROJECTM_TOUCH_TYPE_CIRCLE, //!< Draws a circular waveform. + PROJECTM_TOUCH_TYPE_RADIAL_BLOB, //!< Draws a radial blob waveform. + PROJECTM_TOUCH_TYPE_BLOB2,//!< Draws a blob-style waveform. + PROJECTM_TOUCH_TYPE_BLOB3, //!< Draws another blob-style waveform. + PROJECTM_TOUCH_TYPE_DERIVATIVE_LINE, //!< Draws a derivative-line waveform. + PROJECTM_TOUCH_TYPE_BLOB5, //!< Draws a five-blob waveform. + PROJECTM_TOUCH_TYPE_LINE, //!< Draws a single-line waveform. + PROJECTM_TOUCH_TYPE_DOUBLE_LINE //!< Draws a double-line waveform. +}; + +/** + * @brief Allocates memory for a string and returns the pointer. + * + * To free the allocated memory, call projectm_free_string(). Do not use free()! + * + * @return A pointer to a zero-initialized memory area. + */ +PROJECTM_EXPORT char* projectm_alloc_string(unsigned int length); + +/** + * @brief Frees the memory of an allocated string. + * + * Frees the memory allocated by a call to projectm_alloc_string() or any + * (const) char* pointers returned by an API call. + * + * Do not use free() to delete the pointer! + * + * @param settings A pointer returned by projectm_alloc_string(). + */ +PROJECTM_EXPORT void projectm_free_string(const char* str); + +/** + * @brief Allocates memory for a projectm_settings_t struct and returns the pointer. + * + * To free the allocated memory, call projectm_free_settings(). Do not use free()! + * + * @return A pointer to a zero-initialized projectm_settings_t struct. + */ +PROJECTM_EXPORT projectm_settings_t* projectm_alloc_settings(); + +/** + * @brief Frees the memory of an allocated projectm_settings_t structure. + * + * Frees the memory allocated by a call to projectm_alloc_settings() or any + * projectm_settings_t* returned by an API call. + * + * Do not use free() to delete the pointer! + * + * @param settings A pointer returned by projectm_alloc_settings(). + */ +PROJECTM_EXPORT void projectm_free_settings(const projectm_settings_t* settings); + + +/** + * @brief Callback function that is executed on each preset change. + * + * Can be used for example to update the application window title. + * + * @param is_hard_cut True if the preset was switched using a hard cut via beat detection. + * @param index The playlist index of the new preset. + */ +typedef void(* projectm_preset_switched_event)(bool is_hard_cut, unsigned int index); + +/** + * @brief Callback function that is executed is the shuffle setting has changed. + * @param shuffle_enabled True if shuffle is enabled, false if it was disabled. + */ +typedef void(* projectm_shuffle_enable_changed_event)(bool shuffle_enabled); + +/** + * @brief Callback function that is executed if a preset change failed. + * + * The message pointer is only valid inside the callback. Make a copy if it must be kept + * for later use. + * + * @param is_hard_cut True if the preset was switched using a hard cut via beat detection. + * @param index The playlist index of the new preset. + * @param message The error message. + */ +typedef void(* projectm_preset_switch_failed_event)(bool is_hard_cut, unsigned int index, const char* message); + +/** + * @brief Callback function that is executed if a preset rating has been changed. + * + * Can be used for example to update the rating display in the host application. + * + * @param index The playlist index of the new preset. + * @param rating The new rating value. + * @param rating_type The rating type that has been changed. + */ +typedef void(* projectm_preset_rating_changed_event)(unsigned int index, int rating, + projectm_preset_rating_type rating_type); + + + +/** + * @brief Creates a new projectM instance, reading settings from the given file. + * @param setting_file_path A path to the settings file to read the configuration from. + * If NULL or an empty path are provided, default settings will be used. + * @param flags Any combination of values from the projectm_flags enumeration. + * @return A projectM handle for the newly created instance that must be used in subsequent API calls. + * NULL if the instance could not be created successfully. + */ +PROJECTM_EXPORT projectm_handle projectm_create(const char* setting_file_path, int flags); + +/** + * @brief Creates a new projectM instance, reading settings from the given file. + * @param settings A pointer to a projectm_settings_t with the settings to be used by the new instance. + * If this pointer is NULL, default settings will be used. + * @param flags Any combination of values from the projectm_flags enumeration. + * @return A projectM handle for the newly created instance that must be used in subsequent API calls. + * NULL if the instance could not be created successfully. + */ +PROJECTM_EXPORT projectm_handle projectm_create_settings(projectm_settings_t* settings, int flags); + +/** + * @brief Destroys the given instance and frees the resources. + * + * After destroying the handle, it must not be used for any other calls to the API. + * + * @param instance A handle returned by projectm_create() or projectm_create_settings(). + */ +PROJECTM_EXPORT void projectm_destroy(projectm_handle instance); + +/** + * @brief Sets a callback function that will be called when a preset changes. + * @param instance The projectM instance handle. + * @param callback A pointer to the callback function. + */ +PROJECTM_EXPORT void projectm_set_preset_switched_event_callback(projectm_handle instance, + projectm_preset_switched_event callback); + +/** + * @brief Sets a callback function that will be called when the shuffle setting changes. + * @param instance The projectM instance handle. + * @param callback A pointer to the callback function. + */ +PROJECTM_EXPORT void projectm_set_shuffle_enable_changed_event_callback(projectm_handle instance, + projectm_shuffle_enable_changed_event callback); + +/** + * @brief Sets a callback function that will be called when a preset change failed. + * @param instance The projectM instance handle. + * @param callback A pointer to the callback function. + */ +PROJECTM_EXPORT void projectm_set_preset_switch_failed_event_callback(projectm_handle instance, + projectm_preset_switch_failed_event callback); + +/** + * @brief Sets a callback function that will be called when a preset rating changed. + * @param instance The projectM instance handle. + * @param callback A pointer to the callback function. + */ +PROJECTM_EXPORT void projectm_set_preset_rating_changed_event_callback(projectm_handle instance, + projectm_preset_rating_changed_event callback); + +/** + * @brief Reset the projectM OpenGL renderer. + * + * Required if anything invalidates the state of the current OpenGL context projectM is rendering to. + * This is the case on window resizes, restoring a window from minimized state or other events that + * required recreating of OpenGL objects. + * + * @param instance The projectM instance handle. + * @param width The rendering viewport width. + * @param height The rendering viewport height. + */ +PROJECTM_EXPORT void projectm_reset_gl(projectm_handle instance, int width, int height); + + +/** + * @brief Reloads all textures. + * + * Also resets the OpenGL renderer without changing the viewport size. Useful if preset paths were changed. + * + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_reset_textures(projectm_handle instance); + +/** + * @brief Sets the current title text and displays it. + * @param instance The projectM instance handle. + * @param title The title text to display. + */ +PROJECTM_EXPORT void projectm_set_title(projectm_handle instance, const char* title); + +/** + * @brief Renders a single frame. + * + * @note Separate two-pass frame rendering is currently not supported by the C API as it is rarely used + * and also depends on the loaded preset. + * + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_render_frame(projectm_handle instance); + +/** + * @brief Enables render-to-texture. + * + * Useful if projectM output will be part of a more complex OpenGL scene. The size of the texture is determined by the + * given viewport size and the dimensions should be a power of 2. + * + * @param instance The projectM instance handle. + * @return A GLuint value with the texture ID projectM will render to. + */ +PROJECTM_EXPORT unsigned int projectm_init_render_to_texture(projectm_handle instance); + +/** + * @brief Key handler that processes user input. + * + * This method can be used to send user input in the host application to projectM, for example + * to switch presets, display the help and search menus or change settings like beat sensitivity. + * + * All actions executed by the key handler can also be run programmatically if the host application + * is not able to redirect keyboard input to projectM. + * + * @param instance The projectM instance handle. + * @param event The key event, valid are either PROJECTM_KEYUP or PROJECTM_KEYDOWN. + * @param keycode The key code, mapped to a value of the projectMKeycode enumeration. + * @param modifier The key modifier as a value from the projectMModifier. + */ +PROJECTM_EXPORT void projectm_key_handler(projectm_handle instance, projectMEvent event, + projectMKeycode keycode, projectMModifier modifier); + +/** + * @brief Default key handler that processes user input. + * + * This method can be used to send user input in the host application to projectM, for example + * to switch presets, display the help and search menus or change settings like beat sensitivity. + * + * All actions executed by the key handler can also be run programmatically if the host application + * is not able to redirect keyboard input to projectM. + * + * @param instance The projectM instance handle. + * @param event The key event, valid are either PROJECTM_KEYUP or PROJECTM_KEYDOWN. + * @param keycode The key code, mapped to a value of the projectMKeycode enumeration. + */ +PROJECTM_EXPORT void projectm_default_key_handler(projectm_handle instance, projectMEvent event, + projectMKeycode keycode); +/** + * @brief Changes the size of the internal render texture. + * @note This will recreate the internal renderer. + * @param instance The projectM instance handle. + * @param size The new size of the render texture. Must be a power of 2. + */ +PROJECTM_EXPORT void projectm_set_texture_size(projectm_handle instance, int size); + +/** + * @brief Sets the minimum display time before a hard cut can happen. + * + *

Hard cuts are beat-sensitive preset transitions, immediately changing from + * one preset to the next without a smooth blending period.

+ * + *

Set this to a higher value than preset duration to disable hard cuts.

+ * + * @param instance The projectM instance handle. + * @param seconds Minimum number of seconds the preset will be displayed before a hard cut. + */ +PROJECTM_EXPORT void projectm_set_hardcut_duration(projectm_handle instance, double seconds); + +/** + * @brief Sets the preset display duration before switching to the next using a soft cut. + * @param instance The projectM instance handle. + * @param seconds The number of seconds a preset will be displayed before the next is shown. + */ +PROJECTM_EXPORT void projectm_set_preset_duration(projectm_handle instance, double seconds); + +/** + * @brief returns the per-pixel equation mesh size in units. + * @param instance The projectM instance handle. + * @param width The width of the mesh. + * @param height The height of the mesh. + */ +PROJECTM_EXPORT void projectm_get_mesh_size(projectm_handle instance, int* width, int* height); + +/** + * @brief Starts a touch event or moves an existing waveform. + * + * This will add or move waveforms in addition to the preset waveforms. If there is an existing waveform + * at the given coordinates, it will be centered on the new coordinates. If there is no waveform, a new one + * will be added. + * + * @param instance The projectM instance handle. + * @param x The x coordinate of the touch event. + * @param y The y coordinate of the touch event. + * @param pressure The amount of pressure applied in a range from 0.0 to 1.0. + * @param touch_type The waveform type that will be rendered on touch. + */ +PROJECTM_EXPORT void projectm_touch(projectm_handle instance, float x, float y, + int pressure, projectm_touch_type touch_type); + +/** + * @brief Centers any waveforms under the coordinates to simulate dragging. + * @param instance The projectM instance handle. + * @param x The x coordinate of the drag. + * @param y the y coordinate of the drag. + * @param pressure The amount of pressure applied in a range from 0.0 to 1.0. + */ +PROJECTM_EXPORT void projectm_touch_drag(projectm_handle instance, float x, float y, int pressure); + +/** + * @brief Removes any additional touch waveforms under the given coordinates. + * @param instance The projectM instance handle. + * @param x The last known x touch coordinate. + * @param y The last known y touch coordinate. + */ +PROJECTM_EXPORT void projectm_touch_destroy(projectm_handle instance, float x, float y); + +/** + * @brief Removes all touch waveforms from the screen. + * + * Preset-defined waveforms will still be displayed. + * + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_touch_destroy_all(projectm_handle instance); + +/** + * @brief Sets the help menu text. + * + * The help menu will be toggled if the key mapped to PROJECTM_K_F1 is pressed. + * + * @param instance The projectM instance handle. + * @param help_text The help text to be displayed. + */ +PROJECTM_EXPORT void projectm_set_help_text(projectm_handle instance, const char* help_text); + +/** + * @brief Displays a short message in the center of the rendering area for a few seconds. + * + *

Useful to display song titles and changed audio settings. Used internally by projectM to display setting + * changes like preset lock.

+ * + *

Only one toast message is shown at a time. If this method is called while another message is shown, it + * will be replaced immediately.

+ * + * @param instance The projectM instance handle. + * @param toast_message The message to display. + */ +PROJECTM_EXPORT void projectm_set_toast_message(projectm_handle instance, const char* toast_message); + +/** + * @brief Returns a structure with the current projectM settings. + * @param instance The projectM instance handle. + * @return A struct with all currently used settings. + */ +PROJECTM_EXPORT projectm_settings_t* projectm_get_settings(projectm_handle instance); + +/** + * @brief Saves the given settings struct into a file. + * + * The file can be loaded during projectM initialization. This is useful if the application needs to + * keep settings separate from the global system/user configuration. + * + * @param config_file The filename to store the settings in. + * @param settings The settings struct to store. + */ +PROJECTM_EXPORT void projectm_write_config(const char* config_file, const projectm_settings_t* settings); + +/** + * @brief Selects a preset, but does not display it. + * @param instance The projectM instance handle. + * @param index The preset index to select. + */ +PROJECTM_EXPORT void projectm_select_preset_position(projectm_handle instance, unsigned int index); + +/** + * @brief Selects and displays the preset. + * @param instance The projectM instance handle. + * @param index the preset to display. + * @param hard_cut If true, a hard cut is made, otherwise it will be blended smoothly. + */ +PROJECTM_EXPORT void projectm_select_preset(projectm_handle instance, unsigned int index, bool hard_cut); + +/** + * @brief Populates the on-screen preset menu. + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_populate_preset_menu(projectm_handle instance); + +/** + * @brief Removes a preset from the playlist. + * @param instance The projectM instance handle. + * @param index The preset index to remove from the playlist. + */ +PROJECTM_EXPORT void projectm_remove_preset(projectm_handle instance, unsigned int index); + +/** + * @brief Clears the preset playlist. + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_clear_playlist(projectm_handle instance); + +/** + * @brief Locks or unlocks the current preset. + * + * Locking effectively disables automatic preset transitions, both hard and soft cuts. Programmatic + * preset switches will still be executed. + * + * @param instance The projectM instance handle. + * @param lock True to lock the current preset, false to enable automatic transitions. + */ +PROJECTM_EXPORT void projectm_lock_preset(projectm_handle instance, bool lock); + +/** + * @brief Returns whether the search text input mode is active or not. + * @param instance The projectM instance handle. + * @param no_minimum_length If set to true, will return true if at least one character has been typed, otherwise + * a minimum length of three characters is required. + * @return True if text input mode is active, false otherwise. + */ +PROJECTM_EXPORT bool projectm_is_text_input_active(projectm_handle instance, bool no_minimum_length); + +/** + * @brief Returns the playlist index for the given preset name. + * + * If the preset name is found multiple times, the first matching index will be returned. + * + * @param instance The projectM instance handle. + * @param preset_name The preset name to search for. + * @return The first found playlist index of the requested preset, or 0 if the preset wasn't found. + */ +PROJECTM_EXPORT unsigned int projectm_get_preset_index(projectm_handle instance, const char* preset_name); + +/** + * @brief Displays the preset with the given name. + * @param instance The projectM instance handle. + * @param preset_name The preset name to search for. + * @param hard_cut If true, the preset will be shown immediately, if false a soft transition will be rendered. + */ +PROJECTM_EXPORT void projectm_select_preset_by_name(projectm_handle instance, const char* preset_name, bool hard_cut); + +/** + * @brief Sets the current preset search text. + * @param instance The projectM instance handle. + * @param search_text The search text used to search for presets in the current playlist. + */ +PROJECTM_EXPORT void projectm_set_search_text(projectm_handle instance, const char* search_text); + +/** + * @brief Deletes one character from the preset search text. + * + * This is equivalent to pressing DEL in a text box. + * + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_delete_search_text(projectm_handle instance); + +/** + * @brief Deletes the whole search text. + * + * This will effectively leave preset search mode. + * + * @param instance The projectM instance handle. + */ +PROJECTM_EXPORT void projectm_reset_search_text(projectm_handle instance); + +/** + * @brief Returns the currently selected preset index. + * @param instance The projectM instance handle. + * @param index A valid pointer to an unsigned int that will receive the preset index. + * @return True if a preset idnex was returned, false if no preset was selected, e.g. the playlist is empty. + */ +PROJECTM_EXPORT bool projectm_selected_preset_index(projectm_handle instance, unsigned int* index); + +/** + * @brief Adds a new preset at the end of the playlist. + * + * The rating list is one rating per value of the projectm_preset_rating_type enumeration, with each actual enum + * value used as the index. If the rating list has the wrong length, the preset will not be added. + * + * @param instance The projectM instance handle. + * @param preset_url The full path and filename of the preset. + * @param preset_name The display name of the preset. + * @param rating_list A list with ratings for the preset, one rating per rating type. + * @param rating_list_length Length of the preset rating list. + */ +PROJECTM_EXPORT void projectm_add_preset_url(projectm_handle instance, const char* preset_url, + const char* preset_name, int* rating_list, + unsigned int rating_list_length); + +/** + * @brief Adds a new preset at the given position in the playlist. + * + * The rating list is one rating per value of the projectm_preset_rating_type enumeration, with each actual enum + * value used as the index. If the rating list has the wrong length, the preset will not be added. + * + * @param instance The projectM instance handle. + * @param index The playlist index to insert the preset at. Must be less than or equal to the length of + * the playlist. + * @param preset_url The full path and filename of the preset. + * @param preset_name The display name of the preset. + * @param rating_list A list with ratings for the preset, one rating per rating type. + * @param rating_list_length Length of the preset rating list. + */ +PROJECTM_EXPORT void projectm_insert_preset_url(projectm_handle instance, unsigned int index, const char* preset_url, + const char* preset_name, int* rating_list, + unsigned int rating_list_length); + +/** + * @brief Returns whether the currently selected preset has a valid position in the playlist. + * + * This function is useful to check if the currently displayed preset is still inside the bounds of + * the current playlist, for example after the playlist was changed. + * + * @param instance The projectM instance handle. + * @return True if the position is valid, false if outside bounds. + */ +PROJECTM_EXPORT bool projectm_preset_position_valid(projectm_handle instance); + +/** + * @brief Returns the path and filename of the preset at the requested playlist index. + * @note Make sure the index is inside the playlist bounds! + * @param instance The projectM instance handle. + * @param index The playlist index to return the filename for. + * @return The full path and filename of the preset at the given index. + */ +PROJECTM_EXPORT const char* projectm_get_preset_url(projectm_handle instance, unsigned int index); +/** + * @brief Returns the display name of the preset at the requested playlist index. + * @note Make sure the index is inside the playlist bounds! + * @param instance The projectM instance handle. + * @param index The playlist index to return the display name for. + * @return The display name of the preset at the given index. + */ +PROJECTM_EXPORT const char* projectm_get_preset_name(projectm_handle instance, unsigned int index); + +/** + * @brief Changes the display name of the given preset in the playlist. + * @param instance The projectM instance handle. + * @param index the playlist item index to change. + * @param name The new display name. + */ +PROJECTM_EXPORT void projectm_change_preset_name(projectm_handle instance, unsigned int index, const char* name); + +/** + * @brief Returns the rating for the given index and transition type. + * @param instance The projectM instance handle. + * @param index The playlist item to retrieve the rating from. + * @param rating_type The rating type to retrieve, either hard or soft cut. + * @return The rating value of the requested item and type. + */ +PROJECTM_EXPORT int projectm_get_preset_rating(projectm_handle instance, unsigned int index, + projectm_preset_rating_type rating_type); + +/** + * @brief Changes the rating or a playlist item and type. + * @param instance The projectM instance handle. + * @param index the playlist item to change the rating of. + * @param rating The new rating value. + * @param rating_type The type of the rating, either hard or soft cut. + */ +PROJECTM_EXPORT void projectm_change_preset_rating(projectm_handle instance, unsigned int index, int rating, + projectm_preset_rating_type rating_type); + +/** + * @brief Returns the number of presets in the current playlist. + * @param instance The projectM instance handle. + * @return The number of presets in the currently loaded playlist. + */ +PROJECTM_EXPORT unsigned int projectm_get_playlist_size(projectm_handle instance); + +/** + * @brief Enables or disables preset playlist shuffling. + * @param instance The projectM instance handle. + * @param shuffle_enabled True to randomly select the next preset, false to skip to the next item in line. + */ +PROJECTM_EXPORT void projectm_set_shuffle_enabled(projectm_handle instance, bool shuffle_enabled); + +/** + * @brief Returns whether playlist shuffling is currently enabled or not. + * @param instance The projectM instance handle. + * @return True if shuffle is enabled, false if not. + */ +PROJECTM_EXPORT bool projectm_is_shuffle_enabled(projectm_handle instance); + +/** + * @brief Gets the index of the provided preset name in the current search result list. + * @param instance The projectM instance handle. + * @param name The name of the preset to return the index for. + * @return The search result list index of the given preset name. + */ +PROJECTM_EXPORT unsigned int projectm_get_search_index(projectm_handle instance, const char* name); + +/** + * @brief Switches to the previous preset in the current playlist. + * + * This is unaffected by the shuffle mode and will always switch to the previous item. + * + * @param instance The projectM instance handle. + * @param hard_cut True to immediately perform to the previous preset, false to do a soft transition. + */ +PROJECTM_EXPORT void projectm_select_previous(projectm_handle instance, bool hard_cut); + +/** + * @brief Switches to the next preset in the current playlist. + * + * This is unaffected by the shuffle mode and will always switch to the next item. + * + * @param instance The projectM instance handle. + * @param hard_cut True to immediately perform to the next preset, false to do a soft transition. + */ +PROJECTM_EXPORT void projectm_select_next(projectm_handle instance, bool hard_cut); + +/** + * @brief Switches to a random preset in the current playlist. + * + * This is unaffected by the shuffle mode and will always switch to a random item. + * + * @param instance The projectM instance handle. + * @param hard_cut True to immediately perform to a random preset, false to do a soft transition. + */ +PROJECTM_EXPORT void projectm_select_random(projectm_handle instance, bool hard_cut); + +/** + * @brief Returns the current viewport width in pixels. + * @param instance The projectM instance handle. + * @return The viewport width in pixels. + */ +PROJECTM_EXPORT int projectm_get_window_width(projectm_handle instance); + +/** + * @brief Returns the current viewport height in pixels. + * @param instance The projectM instance handle. + * @return The viewport height in pixels. + */ +PROJECTM_EXPORT int projectm_get_window_height(projectm_handle instance); + +/** + * @brief Returns whether the current preset was loaded successfully or not. + * @param instance The projectM instance handle. + * @return True if the preset was not loaded successfully, false if it is displayed correctly. + */ +PROJECTM_EXPORT bool projectm_get_error_loading_current_preset(projectm_handle instance); + + +/** + * @brief Adds 1-channel 32-bit floating-point audio samples. + * + *

This function is used to add new audio data to projectM's internal audio buffer. It is internally converted + * to 2-channel float data, duplicating the channel.

+ * + *

If possible, always use projectm_pcm_add_float_2ch_data() for best performance and quality.

+ * + * @param instance The projectM instance handle. + * @param pcm_data An array of PCM samples. + * @param sample_count The number of audio samples in pcm_data. + */ +PROJECTM_EXPORT void projectm_pcm_add_float_1ch_data(projectm_handle instance, const float* pcm_data, + unsigned int sample_count); + +/** + * @brief Adds 2-channel 32-bit floating-point audio samples. + * + *

This function is used to add new audio data to projectM's internal audio buffer.

+ * + *

This function represents projectM's internal audio data format. If possible, always use this function for best + * performance and quality.

+ * + *

Channel order in pcm_data is LRLRLR.

+ * + * @param instance The projectM instance handle. + * @param pcm_data An array of PCM samples, two floats per sample. + * @param sample_count The number of audio samples in pcm_data. Half the actual size of pcm_data. + */ +PROJECTM_EXPORT void projectm_pcm_add_float_2ch_data(projectm_handle instance, const float* pcm_data, + unsigned int sample_count); + +/** + * @brief Adds 512 2-channel 16-bit integer audio samples. + * + *

This function is used to add new audio data to projectM's internal audio buffer. It is internally converted + * to 2-channel float data.

+ * + *

If possible, always use projectm_pcm_add_float_2ch_data() for best performance and quality.

+ * + *

Channel indices are 0 for the left channel and 1 for the right channel. Use the projectm_pcm_channel + * enum values instead of numerical indices for readability.

+ * + * @param instance The projectM instance handle. + * @param pcm_data The audio data. + */ +PROJECTM_EXPORT void projectm_pcm_add_16bit_2ch_512(projectm_handle instance, const short pcm_data[2][512]); + +/** + * @brief Adds 2-channel 16-bit integer audio samples.

+ * + *

This function is used to add new audio data to projectM's internal audio buffer. It is internally converted + * to 2-channel float data.

+ * + *

If possible, always use projectm_pcm_add_float_2ch_data() for best performance and quality.

+ * + *

Channel order in pcm_data is LRLRLR.

+ * + * @param instance The projectM instance handle. + * @param pcm_data The audio data. + */ +PROJECTM_EXPORT void projectm_pcm_add_16bit_2ch_data(projectm_handle instance, const short* pcm_data, + unsigned int sample_count); + +/** + * @brief Adds 1024 2-channel 8-bit integer audio samples. + * + *

This function is used to add new audio data to projectM's internal audio buffer. It is internally converted + * to 2-channel float data.

+ * + *

If possible, always use projectm_pcm_add_float_2ch_data() for best performance and quality.

+ * + *

Channel indices are 0 for the left channel and 1 for the right channel. Use the projectm_pcm_channel + * enum values instead of numerical indices for readability.

+ * + * @param instance The projectM instance handle. + * @param pcm_data The audio data. + */ +PROJECTM_EXPORT void projectm_pcm_add_8bit_2ch_1024(projectm_handle instance, const unsigned char pcm_data[2][1024]); + +/** + * @brief Adds 512 2-channel 8-bit integer audio samples. + * + *

This function is used to add new audio data to projectM's internal audio buffer. It is internally converted + * to 2-channel float data.

+ * + *

If possible, always use projectm_pcm_add_float_2ch_data() for best performance and quality.

+ * + *

Channel indices are 0 for the left channel and 1 for the right channel. Use the projectm_pcm_channel + * enum values instead of numerical indices for readability.

+ * + * @param instance The projectM instance handle. + * @param pcm_data The audio data. + */ +PROJECTM_EXPORT void projectm_pcm_add_8bit_2ch_512(projectm_handle instance, const unsigned char pcm_data[2][512]); diff --git a/src/libprojectM/projectM.hpp b/src/libprojectM/projectM.hpp index 71cbc0772..dca5af913 100644 --- a/src/libprojectM/projectM.hpp +++ b/src/libprojectM/projectM.hpp @@ -166,6 +166,8 @@ public: projectM(std::string config_file, int flags = FLAG_NONE); projectM(Settings settings, int flags = FLAG_NONE); + virtual ~projectM(); + void projectM_resetGL( int width, int height ); void projectM_resetTextures(); void projectM_setTitle( std::string title ); @@ -177,8 +179,6 @@ public: void key_handler( projectMEvent event, projectMKeycode keycode, projectMModifier modifier ); - virtual ~projectM(); - void changeTextureSize(int size); void changeHardcutDuration(int seconds); void changeHardcutDuration(double seconds); @@ -235,7 +235,7 @@ public: /// Returns true if the text based search menu is up. bool isTextInputActive(bool nomin = false) const; - unsigned int getPresetIndex(std::string &url) const; + unsigned int getPresetIndex(const std::string& url) const; /// Plays a preset immediately when given preset name void selectPresetByName(std::string name, bool hardCut = true); @@ -317,7 +317,7 @@ public: std::vector presetFuture; /// Get the preset index given a name - unsigned int getSearchIndex(std::string &name) const; + unsigned int getSearchIndex(const std::string& name) const; void selectPrevious(const bool); void selectNext(const bool);