Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/playlist/PlaylistCWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ void PlaylistCWrapper::SetPresetSwitchFailedCallback(projectm_playlist_preset_sw
}


void PlaylistCWrapper::SetPresetLoadCallback(projectm_playlist_preset_load_event callback, void* userData)
{
m_presetLoadEventCallback = callback;
m_presetLoadEventUserData = userData;
}


void PlaylistCWrapper::PlayPresetIndex(uint32_t index, bool hardCut, bool resetFailureCount)
{
m_hardCutRequested = hardCut;
Expand All @@ -117,8 +124,22 @@ void PlaylistCWrapper::PlayPresetIndex(uint32_t index, bool hardCut, bool resetF
return;
}

projectm_load_preset_file(m_projectMInstance,
playlistItems.at(index).Filename().c_str(), !hardCut);
const auto& filename = playlistItems.at(index).Filename();

// If a preset load callback is set, give the application a chance to handle loading
if (m_presetLoadEventCallback != nullptr)
{
if (m_presetLoadEventCallback(index, filename.c_str(), hardCut, m_presetLoadEventUserData))
{
// Application handled the load - return without further action.
// The app is responsible for calling projectm_load_preset_file/data,
// handling errors, and firing the switched event when ready.
return;
}
}

// Default behavior: load from filesystem
projectm_load_preset_file(m_projectMInstance, filename.c_str(), !hardCut);

if (!m_lastPresetSwitchFailed)
{
Expand Down Expand Up @@ -249,6 +270,15 @@ void projectm_playlist_set_preset_switch_failed_event_callback(projectm_playlist
}


void projectm_playlist_set_preset_load_event_callback(projectm_playlist_handle instance,
projectm_playlist_preset_load_event callback,
void* user_data)
{
auto* playlist = playlist_handle_to_instance(instance);
playlist->SetPresetLoadCallback(callback, user_data);
}


void projectm_playlist_connect(projectm_playlist_handle instance, projectm_handle projectm_instance)
{
auto* playlist = playlist_handle_to_instance(instance);
Expand Down
11 changes: 11 additions & 0 deletions src/playlist/PlaylistCWrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ class PlaylistCWrapper : public Playlist
virtual void SetPresetSwitchFailedCallback(projectm_playlist_preset_switch_failed_event callback,
void* userData);

/**
* @brief Sets the preset load callback.
* @param callback The callback pointer.
* @param userData The callback context data.
*/
virtual void SetPresetLoadCallback(projectm_playlist_preset_load_event callback,
void* userData);

/**
* @brief Sets the last navigation direction used to switch a preset.
* This is used when retrying on a failed preset load, keeping the same direction/logic as in the original switch.
Expand Down Expand Up @@ -111,6 +119,9 @@ class PlaylistCWrapper : public Playlist
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.

projectm_playlist_preset_load_event m_presetLoadEventCallback{nullptr}; //!< Preset load callback pointer set by the application.
void* m_presetLoadEventUserData{nullptr}; //!< Context data pointer set by the application.

NavigationDirection m_lastNavigationDirection{NavigationDirection::Next}; //!< Last direction used to switch a preset.
};

Expand Down
55 changes: 55 additions & 0 deletions src/playlist/api/projectM-4/playlist_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,42 @@ typedef void (*projectm_playlist_preset_switched_event)(bool is_hard_cut, unsign
typedef void (*projectm_playlist_preset_switch_failed_event)(const char* preset_filename,
const char* message, void* user_data);

/**
* @brief Callback function that is executed when the playlist wants to load a preset.
*
* This callback allows applications to handle preset loading themselves instead of
* letting the playlist library load presets from the filesystem. This is useful for:
* - Loading presets from archives (e.g., ZIP files)
* - Loading presets from network sources (e.g., HTTP)
* - Custom preset storage solutions
*
* When this callback is set and returns true, the playlist library will NOT attempt
* to load the preset file itself and will return immediately without firing any events.
* The application takes full responsibility for:
* - Calling projectm_load_preset_file() or projectm_load_preset_data() with the preset content
* - Handling any loading errors
* - Firing the preset_switched_event callback when the preset is ready (if desired)
*
* Note: If implementing asynchronous loading, the application must complete the load and
* fire the preset_switched_event callback itself after the async operation completes.
*
* If the callback returns false or is not set, the playlist library will use the
* default behavior of loading the preset from the filesystem.
*
* @note The filename pointer is only valid inside the callback. Make a copy if it needs
* to be retained for later use.
* @note Do not call any playlist preset-switching functions from within this callback.
* @param index The playlist index of the preset to be loaded.
* @param filename The preset filename/URL at this index. Can be used as a key or path.
* @param hard_cut True if this should be a hard cut, false for a smooth transition.
* @param user_data A user-defined data pointer that was provided when registering the callback,
* e.g. context information.
* @return True if the application handles preset loading, false to use default behavior.
* @since 4.2.0
*/
typedef bool (*projectm_playlist_preset_load_event)(unsigned int index, const char* filename,
bool hard_cut, void* user_data);


/**
* @brief Sets a callback function that will be called when a preset changes.
Expand Down Expand Up @@ -105,6 +141,25 @@ PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_preset_switch_failed_event_c
projectm_playlist_preset_switch_failed_event callback,
void* user_data);

/**
* @brief Sets a callback function that will be called when the playlist wants to load a preset.
*
* This allows applications to handle preset loading themselves, e.g., from archives,
* network sources, or using custom storage. When set, this callback is called before
* the playlist library attempts to load a preset file.
*
* 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.
* @since 4.2.0
*/
PROJECTM_PLAYLIST_EXPORT void projectm_playlist_set_preset_load_event_callback(projectm_playlist_handle instance,
projectm_playlist_preset_load_event callback,
void* user_data);

#ifdef __cplusplus
} // extern "C"
#endif
Loading