diff --git a/src/playlist/CMakeLists.txt b/src/playlist/CMakeLists.txt index 4565c2a45..4dfe82bb7 100644 --- a/src/playlist/CMakeLists.txt +++ b/src/playlist/CMakeLists.txt @@ -32,6 +32,8 @@ set_target_properties(projectM_playlist PROPERTIES # Adds fallback support to boost if std::filesystem is unavailable. include(FilesystemSupport.cmake) +add_library(projectM::playlist ALIAS projectM_playlist) + install(TARGETS projectM_playlist EXPORT libprojectMPlaylist LIBRARY DESTINATION "${PROJECTM_LIB_DIR}" COMPONENT Runtime diff --git a/src/playlist/Playlist.cpp b/src/playlist/Playlist.cpp index 73526f9e9..38f94918c 100644 --- a/src/playlist/Playlist.cpp +++ b/src/playlist/Playlist.cpp @@ -244,7 +244,7 @@ auto Playlist::PreviousPresetIndex() -> size_t { if (m_currentPosition == 0) { - m_currentPosition = m_items.size() -1; + m_currentPosition = m_items.size() - 1; } else { diff --git a/src/playlist/PlaylistCWrapper.cpp b/src/playlist/PlaylistCWrapper.cpp index b4dbb88cf..384c0aff2 100644 --- a/src/playlist/PlaylistCWrapper.cpp +++ b/src/playlist/PlaylistCWrapper.cpp @@ -93,6 +93,13 @@ auto PlaylistCWrapper::RetryCount() -> uint32_t } +void PlaylistCWrapper::SetPresetSwitchedCallback(projectm_playlist_preset_switched_event callback, void* userData) +{ + m_presetSwitchedEventCallback = callback; + m_presetSwitchedEventUserData = userData; +} + + void PlaylistCWrapper::SetPresetSwitchFailedCallback(projectm_playlist_preset_switch_failed_event callback, void* userData) { m_presetSwitchFailedEventCallback = callback; @@ -118,6 +125,11 @@ void PlaylistCWrapper::PlayPresetIndex(size_t index, bool hardCut, bool resetFai projectm_load_preset_file(m_projectMInstance, playlistItems.at(index).Filename().c_str(), !hardCut); + + if (m_presetSwitchedEventCallback != nullptr) + { + m_presetSwitchedEventCallback(hardCut, index, m_presetSwitchedEventUserData); + } } @@ -167,6 +179,15 @@ void projectm_playlist_destroy(projectm_playlist_handle instance) } +void projectm_playlist_set_preset_switched_event_callback(projectm_playlist_handle instance, + projectm_playlist_preset_switched_event callback, + void* user_data) +{ + auto* playlist = playlist_handle_to_instance(instance); + playlist->SetPresetSwitchedCallback(callback, user_data); +} + + void projectm_playlist_set_preset_switch_failed_event_callback(projectm_playlist_handle instance, projectm_playlist_preset_switch_failed_event callback, void* user_data) diff --git a/src/playlist/PlaylistCWrapper.h b/src/playlist/PlaylistCWrapper.h index 3d655a85f..47a46935f 100644 --- a/src/playlist/PlaylistCWrapper.h +++ b/src/playlist/PlaylistCWrapper.h @@ -54,8 +54,21 @@ public: */ virtual auto RetryCount() -> uint32_t; + /** + * @brief Sets the preset switched callback. + * @param callback The callback pointer. + * @param userData The callback context data. + */ + virtual void SetPresetSwitchedCallback(projectm_playlist_preset_switched_event callback, + void* userData); + + /** + * @brief Sets the preset switch failed callback. + * @param callback The callback pointer. + * @param userData The callback context data. + */ virtual void SetPresetSwitchFailedCallback(projectm_playlist_preset_switch_failed_event callback, - void* userData); + void* userData); private: projectm_handle m_projectMInstance{nullptr}; //!< The projectM instance handle this instance is connected to. @@ -65,6 +78,9 @@ private: bool m_hardCutRequested{false}; //!< Stores the type of the last requested switch attempt. + projectm_playlist_preset_switched_event m_presetSwitchedEventCallback{nullptr}; //!< Preset switched callback pointer set by the application. + void* m_presetSwitchedEventUserData{nullptr}; //!< Context data pointer set by the application. + projectm_playlist_preset_switch_failed_event m_presetSwitchFailedEventCallback{nullptr}; //!< Preset switch failed callback pointer set by the application. - void* m_presetSwitchFailedEventUserData{nullptr}; //!< Context data pointer set by the application. + void* m_presetSwitchFailedEventUserData{nullptr}; //!< Context data pointer set by the application. }; diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 35fa08044..84b454d30 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -49,6 +49,20 @@ void projectm_playlist_free_string(char* string); */ void projectm_playlist_free_string_array(char** array); +/** + * @brief Callback function that is executed on each preset change. + * + * Can be used for example to update the application window title. Applications must not + * switch presets inside this callback, as it can lead to infinite recursion. + * + * @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 user_data A user-defined data pointer that was provided when registering the callback, + * e.g. context information. + */ +typedef void (*projectm_playlist_preset_switched_event)(bool is_hard_cut, unsigned int index, + void* user_data); + /** * @brief Callback function that is executed if a preset change failed too often. * @@ -93,6 +107,20 @@ projectm_playlist_handle projectm_playlist_create(projectm_handle projectm_insta */ void projectm_playlist_destroy(projectm_playlist_handle instance); +/** + * @brief Sets a callback function that will be called when a preset changes. + * + * Only one callback can be registered per playlist instance. To remove the callback, use NULL. + * + * @param instance The playlist manager instance. + * @param callback A pointer to the callback function. + * @param user_data A pointer to any data that will be sent back in the callback, e.g. context + * information. + */ +void projectm_playlist_set_preset_switched_event_callback(projectm_playlist_handle instance, + projectm_playlist_preset_switched_event callback, + void* user_data); + /** * @brief Sets a callback function that will be called when a preset change failed. * diff --git a/tests/playlist/APITest.cpp b/tests/playlist/APITest.cpp index 37aa89fda..49ee96b0b 100644 --- a/tests/playlist/APITest.cpp +++ b/tests/playlist/APITest.cpp @@ -493,6 +493,22 @@ TEST(projectMPlaylistAPI, PlayLastException) } +TEST(projectMPlaylistAPI, SetPresetSwitchedCallback) +{ + PlaylistCWrapperMock mockPlaylist; + + projectm_playlist_preset_switched_event dummyCallback = [](bool is_hard_cut, + uint32_t index, + void* user_data) {}; + void* dummyData{reinterpret_cast(2973246)}; + + EXPECT_CALL(mockPlaylist, SetPresetSwitchedCallback(dummyCallback, dummyData)) + .Times(1); + + projectm_playlist_set_preset_switched_event_callback(reinterpret_cast(&mockPlaylist), dummyCallback, dummyData); +} + + TEST(projectMPlaylistAPI, SetPresetSwitchFailedCallback) { PlaylistCWrapperMock mockPlaylist; diff --git a/tests/playlist/PlaylistCWrapperMock.h b/tests/playlist/PlaylistCWrapperMock.h index 68ff50f5a..69f19175a 100644 --- a/tests/playlist/PlaylistCWrapperMock.h +++ b/tests/playlist/PlaylistCWrapperMock.h @@ -32,7 +32,8 @@ public: MOCK_METHOD(size_t, SetPresetIndex, (size_t)); MOCK_METHOD(void, PlayPresetIndex, (size_t, bool, bool) ); MOCK_METHOD(void, RemoveLastHistoryEntry, ()); - MOCK_METHOD(void, SetPresetSwitchFailedCallback, (projectm_playlist_preset_switch_failed_event, void*)); + MOCK_METHOD(void, SetPresetSwitchedCallback, (projectm_playlist_preset_switched_event, void*) ); + MOCK_METHOD(void, SetPresetSwitchFailedCallback, (projectm_playlist_preset_switch_failed_event, void*) ); MOCK_METHOD(class ProjectM::Playlist::Filter&, Filter, ()); MOCK_METHOD(size_t, ApplyFilter, ()); };