From d52e5c5ec1851fbaa8afacb9312f3042f991f86c Mon Sep 17 00:00:00 2001 From: Severin Leonhardt Date: Thu, 27 Aug 2026 23:30:08 +0200 Subject: [PATCH 1/3] Add missing heading in changelog --- Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Changelog.md b/Changelog.md index 1291ed5..a143212 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixes + * The dialogs to edit or remove files of a track work again. ## [1.3.0] - 2026-02-07 From ff82b3024c5c3db934a32491fd70f04aa2ca0828 Mon Sep 17 00:00:00 2001 From: Severin Leonhardt Date: Fri, 28 Aug 2026 16:31:06 +0200 Subject: [PATCH 2/3] Actually call mstarPlayerVolumeChanged for plugins Notifying plugins of volume changes in a player was added with version 3 of the plugin API. The actual call was never implemented though. --- Changelog.md | 1 + Source/CDPlayer.cpp | 1 + Source/Player.cpp | 1 + Source/PluginLoader.cpp | 8 ++++++++ Source/PluginLoader.h | 2 ++ 5 files changed, 13 insertions(+) diff --git a/Changelog.md b/Changelog.md index a143212..00db003 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixes * The dialogs to edit or remove files of a track work again. +* Actually call `mstarPlayerVolumeChanged` for plugins. ## [1.3.0] - 2026-02-07 diff --git a/Source/CDPlayer.cpp b/Source/CDPlayer.cpp index 0165d61..3eeb04e 100644 --- a/Source/CDPlayer.cpp +++ b/Source/CDPlayer.cpp @@ -297,6 +297,7 @@ void CDPlayer::setGain(float gain) m_gain = gain; updateGain(); m_pluginLoader.trackVolumeChanged(getName().toRawUTF8(), "", m_gain); + m_pluginLoader.playerVolumeChanged(getName().toRawUTF8(), gain); std::for_each(m_listeners.begin(), m_listeners.end(), std::bind(&MixerControlableChangeListener::gainChanged, std::placeholders::_1, gain)); diff --git a/Source/Player.cpp b/Source/Player.cpp index d017e2b..6914ccc 100644 --- a/Source/Player.cpp +++ b/Source/Player.cpp @@ -99,6 +99,7 @@ void Player::setType(PlayerType type) void Player::setGain(float gain) { m_tracksContainer.setGain(gain); + m_pluginLoader.playerVolumeChanged(getName().toRawUTF8(), gain); std::for_each(m_listeners.begin(), m_listeners.end(), std::bind(&MixerControlableChangeListener::gainChanged, std::placeholders::_1, gain)); diff --git a/Source/PluginLoader.cpp b/Source/PluginLoader.cpp index 560e17f..4071c36 100644 --- a/Source/PluginLoader.cpp +++ b/Source/PluginLoader.cpp @@ -493,6 +493,14 @@ void PluginLoader::trackVolumeChanged(const char* playerName, const char* trackN } } +void PluginLoader::playerVolumeChanged(const char* playerName, float volume) +{ + for (const auto& plugin : pluginsV3) + { + plugin.playerVolumeChangedFunction(playerName, volume); + } +} + void PluginLoader::positionChanged(const char* playerName, double position) { for (const auto& plugin : pluginsV1) diff --git a/Source/PluginLoader.h b/Source/PluginLoader.h index 21fdbdd..0b766d2 100644 --- a/Source/PluginLoader.h +++ b/Source/PluginLoader.h @@ -33,6 +33,8 @@ class PluginLoader void trackVolumeChanged(const char* playerName, const char* trackName, float volume); + void playerVolumeChanged(const char* playerName, float volume); + void positionChanged(const char* playerName, double position); size_t count(); From 1e9cc250874977a5b46fb967fe808bc761e46370 Mon Sep 17 00:00:00 2001 From: Severin Leonhardt Date: Thu, 27 Aug 2026 22:29:01 +0200 Subject: [PATCH 3/3] Introduce plugin API v4 The new plugin API version lets plugins select playlist entry by index. It's a bit odd to use `mstarTrackVolumeChanged` for the volume of the CD Player when there is a dedicated function for the player volume itself. Fix that odd behavior in the new API version. --- Changelog.md | 5 + Source/CDPlayer.cpp | 7 +- Source/CDPlayer.h | 1 + Source/Player.cpp | 5 + Source/Player.h | 1 + Source/PlayerComponent.h | 1 + Source/PlaylistPlayerWindow.cpp | 5 + Source/PlaylistPlayerWindow.h | 2 + Source/PluginInterfaceV4.h | 48 ++++++ Source/PluginLoader.cpp | 255 +++++++++++++++++++++++++++++++- Source/PluginLoader.h | 28 ++++ 11 files changed, 354 insertions(+), 4 deletions(-) create mode 100644 Source/PluginInterfaceV4.h diff --git a/Changelog.md b/Changelog.md index 00db003..1ce9316 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +* Support Plugin V4 API which allows selecting a playlist entry by index. + **Note:** The CD Player volume will use the new `mstarPlayerVolumeChanged` instead of `mstarTrackVolumeChanged` like in previous API versions. + ### Fixes * The dialogs to edit or remove files of a track work again. diff --git a/Source/CDPlayer.cpp b/Source/CDPlayer.cpp index 3eeb04e..58fdabc 100644 --- a/Source/CDPlayer.cpp +++ b/Source/CDPlayer.cpp @@ -249,6 +249,10 @@ void CDPlayer::previousEntry() { m_tracksTable.previous(); } +void CDPlayer::selectEntry(int playlist_index) +{ + m_tracksTable.selectRow(playlist_index); +} void CDPlayer::paint(juce::Graphics& g) { g.fillAll(m_color); @@ -296,8 +300,7 @@ void CDPlayer::setGain(float gain) { m_gain = gain; updateGain(); - m_pluginLoader.trackVolumeChanged(getName().toRawUTF8(), "", m_gain); - m_pluginLoader.playerVolumeChanged(getName().toRawUTF8(), gain); + m_pluginLoader.cdPlayerVolumeChanged(getName().toRawUTF8(), gain); std::for_each(m_listeners.begin(), m_listeners.end(), std::bind(&MixerControlableChangeListener::gainChanged, std::placeholders::_1, gain)); diff --git a/Source/CDPlayer.h b/Source/CDPlayer.h index bc53db1..78e2dc6 100644 --- a/Source/CDPlayer.h +++ b/Source/CDPlayer.h @@ -40,6 +40,7 @@ class CDPlayer void stop() override; void nextEntry(bool onlyIfEntrySaysSo = false) override; void previousEntry() override; + void selectEntry(int playlist_index) override; // XML serialization public: diff --git a/Source/Player.cpp b/Source/Player.cpp index 6914ccc..3bc8c3e 100644 --- a/Source/Player.cpp +++ b/Source/Player.cpp @@ -420,6 +420,11 @@ void Player::previousEntry() m_pluginLoader.previousEntrySelected(getName().toRawUTF8()); } +void Player::selectEntry(int playlist_index) +{ + m_playlistPlayer.selectPlaylistEntry(playlist_index); +} + void Player::playlistEntryChanged(const std::vector& trackConfigs, bool play, int index) { currentPlaylistEntry = index; diff --git a/Source/Player.h b/Source/Player.h index 205eb0e..54aba92 100644 --- a/Source/Player.h +++ b/Source/Player.h @@ -41,6 +41,7 @@ class Player void stop() override; void nextEntry(bool onlyIfEntrySaysSo = false) override; void previousEntry() override; + void selectEntry(int playlist_index) override; void playlistEntryChanged(const std::vector& trackConfigs, bool play, int index); void gainChangedCallback(const char* track_name, float gain); diff --git a/Source/PlayerComponent.h b/Source/PlayerComponent.h index a5420e4..069d152 100644 --- a/Source/PlayerComponent.h +++ b/Source/PlayerComponent.h @@ -14,4 +14,5 @@ class PlayerComponent virtual void stop() = 0; virtual void nextEntry(bool onlyIfEntrySaysSo = false) = 0; virtual void previousEntry() = 0; + virtual void selectEntry(int playlist_index) = 0; }; diff --git a/Source/PlaylistPlayerWindow.cpp b/Source/PlaylistPlayerWindow.cpp index 9b742e3..56f7373 100644 --- a/Source/PlaylistPlayerWindow.cpp +++ b/Source/PlaylistPlayerWindow.cpp @@ -319,3 +319,8 @@ void PlaylistPlayerWindow::previousPlaylistEntry() { m_tableListBox.previous(); } + +void PlaylistPlayerWindow::selectPlaylistEntry(int playlist_index) +{ + m_tableListBox.selectRow(playlist_index); +} diff --git a/Source/PlaylistPlayerWindow.h b/Source/PlaylistPlayerWindow.h index 1d67290..f759dd8 100644 --- a/Source/PlaylistPlayerWindow.h +++ b/Source/PlaylistPlayerWindow.h @@ -44,6 +44,8 @@ class PlaylistPlayerWindow void previousPlaylistEntry(); + void selectPlaylistEntry(int playlist_index); + int getResizerBarPosition() const; void setResizerBarPosition(int position); diff --git a/Source/PluginInterfaceV4.h b/Source/PluginInterfaceV4.h new file mode 100644 index 0000000..c2c994a --- /dev/null +++ b/Source/PluginInterfaceV4.h @@ -0,0 +1,48 @@ +#pragma once + +namespace PluginInterface::V4 +{ +using ListPlayersCallbackFunction = void (*)(const char* player_name, void* userData); +using ListPlayersFunction = void (*)(ListPlayersCallbackFunction callback, void* userData); +using PlayFunction = void (*)(const char* player_name); +using StopFunction = void (*)(const char* player_name); +using NextEntryFunction = void (*)(const char* player_name); +using PreviousEntryFunction = void (*)(const char* player_name); +using SelectEntryFunction = void (*)(const char* player_name, int playlist_index); +using ListTracksCallbackFunction = void (*)(const char* track_name, void* userData); +using ListTracksFunction = void (*)(const char* player_name, ListTracksCallbackFunction callback, void* userData); +using SetPlayerVolumeFunction = void (*)(const char* player_name, float volume); +using SetTrackVolumeFunction = void (*)(const char* player_name, const char* track_name, float volume); + +struct Init +{ + ListPlayersFunction listPlayers; + PlayFunction play; + StopFunction stop; + NextEntryFunction next; + PreviousEntryFunction previous; + SelectEntryFunction select; + ListTracksFunction listTracks; + SetTrackVolumeFunction setTrackVolume; + SetPlayerVolumeFunction setPlayerVolume; +}; + +using InitFunction = void (*)(const Init&); +using PlayingStateChangedFunction = void (*)(const char* playerName, bool isPlaying); +using NextEntrySelectedFunction = void (*)(const char* playerName); +using PreviousEntrySelectedFunction = void (*)(const char* playerName); +using PlaylistEntrySelectedFunction + = void (*)(const char* playerName, int playlist_index, const char* playlistEntryName, double duration); +using PlaylistEntryDurationChangedFunction = void (*)(const char* playerName, int playlist_index, double duration); +using PlaylistEntryNameChangedFunction + = void (*)(const char* playerName, int playlist_index, const char* playlistEntryName); +using TrackVolumeChangedFunction = void (*)(const char* playerName, const char* track_name, double volume); +using PlayerVolumeChangedFunction = void (*)(const char* playerName, double volume); +using PositionChangedFunction = void (*)(const char* playerName, double position); +using ConfigureFunction = void (*)(); +using ShutdownFunction = void (*)(); + +using LoadConfigurationFunction = void (*)(const char* configurationText); +using GetConfigurationFunction = char* (*)(); +using FreeConfigurationTextFunction = void (*)(const char* configurationText); +} diff --git a/Source/PluginLoader.cpp b/Source/PluginLoader.cpp index 4071c36..bfefbed 100644 --- a/Source/PluginLoader.cpp +++ b/Source/PluginLoader.cpp @@ -99,6 +99,14 @@ void previousEntry(const char* playerName) player->previousEntry(); } +void selectEntry(const char* playerName, int playlist_index) +{ + const juce::MessageManagerLock mmLock; + PlayerComponent* player = getPlayer(playerName); + if (player != nullptr) + player->selectEntry(playlist_index); +} + void listTracksV1(const char* playerName, PluginInterface::V1::ListTracksCallbackFunction callback, void* userData) { const PlayerComponent* player = getPlayer(playerName); @@ -267,6 +275,29 @@ PluginLoader::PluginLoader(MyMultiDocumentPanel* pComponent) } break; } + case 4: + { + auto loadResult = loadPluginV4(*dynamicLibrary); + switch (loadResult.index()) + { + case 0: + { + PluginV4 plugin = std::move(std::get<0>(loadResult)); + plugin.name = dirEntry.getFile().getFileNameWithoutExtension().toStdString(); + plugin.dynamicLibrary = std::move(dynamicLibrary); + pluginsV4.emplace_back(std::move(plugin)); + break; + } + case 1: + { + failedPlugins.add({dirEntry.getFile().getFileName(), std::get<1>(loadResult)}); + break; + } + default: + std::terminate(); + } + break; + } default: failedPlugins.add({dirEntry.getFile().getFileName(), "Plugin has version " + juce::String(version) + " but M*Player requires version 1, 2 or 3."}); @@ -323,6 +354,24 @@ PluginLoader::PluginLoader(MyMultiDocumentPanel* pComponent) } } + { + PluginInterface::V4::Init init; + init.listPlayers = &listPlayersV2; + init.listTracks = &listTracksV2; + init.play = &play; + init.stop = &stop; + init.next = &nextEntry; + init.previous = &previousEntry; + init.select = &selectEntry; + init.setPlayerVolume = &playerVolume; + init.setTrackVolume = &trackVolume; + + for (const auto& plugin : pluginsV4) + { + plugin.initFunction(init); + } + } + if (failedPlugins.size() > 0) { juce::String lines; @@ -350,11 +399,15 @@ PluginLoader::~PluginLoader() { plugin.shutdownFunction(); } + for (const auto& plugin : pluginsV4) + { + plugin.shutdownFunction(); + } } size_t PluginLoader::count() { - return pluginsV1.size() + pluginsV2.size() + pluginsV3.size(); + return pluginsV1.size() + pluginsV2.size() + pluginsV3.size() + pluginsV4.size(); } juce::String PluginLoader::pluginName(size_t index) @@ -369,7 +422,12 @@ juce::String PluginLoader::pluginName(size_t index) index -= pluginsV2.size(); - return pluginsV3[index].name; + if (index < pluginsV3.size()) + return pluginsV3[index].name; + + index -= pluginsV3.size(); + + return pluginsV4[index].name; } void PluginLoader::configure(size_t index) @@ -386,6 +444,11 @@ void PluginLoader::configure(size_t index) if (index < pluginsV3.size()) pluginsV3[index].configureFunction(); + + index -= pluginsV3.size(); + + if (index < pluginsV4.size()) + pluginsV4[index].configureFunction(); } void PluginLoader::playingStateChanged(const char* playerName, bool isPlaying) @@ -402,6 +465,10 @@ void PluginLoader::playingStateChanged(const char* playerName, bool isPlaying) { plugin.playingStateChangedFunction(playerName, isPlaying); } + for (const auto& plugin : pluginsV4) + { + plugin.playingStateChangedFunction(playerName, isPlaying); + } } void PluginLoader::nextEntrySelected(const char* playerName) @@ -418,6 +485,10 @@ void PluginLoader::nextEntrySelected(const char* playerName) { plugin.nextEntrySelectedFunction(playerName); } + for (const auto& plugin : pluginsV4) + { + plugin.nextEntrySelectedFunction(playerName); + } } void PluginLoader::previousEntrySelected(const char* playerName) @@ -434,6 +505,10 @@ void PluginLoader::previousEntrySelected(const char* playerName) { plugin.previousEntrySelectedFunction(playerName); } + for (const auto& plugin : pluginsV4) + { + plugin.previousEntrySelectedFunction(playerName); + } } void PluginLoader::playlistEntrySelected( @@ -451,6 +526,10 @@ void PluginLoader::playlistEntrySelected( { plugin.playlistEntrySelectedFunction(playerName, entryIndex, playlistEntryName, duration); } + for (const auto& plugin : pluginsV4) + { + plugin.playlistEntrySelectedFunction(playerName, entryIndex, playlistEntryName, duration); + } } void PluginLoader::playlistEntryNameChanged(const char* playerName, int entryIndex, const char* playlistEntryName) @@ -463,6 +542,10 @@ void PluginLoader::playlistEntryNameChanged(const char* playerName, int entryInd { plugin.playlistEntryNameChangedFunction(playerName, entryIndex, playlistEntryName); } + for (const auto& plugin : pluginsV4) + { + plugin.playlistEntryNameChangedFunction(playerName, entryIndex, playlistEntryName); + } } void PluginLoader::playlistEntryDurationChanged(const char* playerName, int entryIndex, double duration) @@ -475,6 +558,10 @@ void PluginLoader::playlistEntryDurationChanged(const char* playerName, int entr { plugin.playlistEntryDurationChangedFunction(playerName, entryIndex, duration); } + for (const auto& plugin : pluginsV4) + { + plugin.playlistEntryDurationChangedFunction(playerName, entryIndex, duration); + } } void PluginLoader::trackVolumeChanged(const char* playerName, const char* trackName, float volume) @@ -491,6 +578,10 @@ void PluginLoader::trackVolumeChanged(const char* playerName, const char* trackN { plugin.trackVolumeChangedFunction(playerName, trackName, volume); } + for (const auto& plugin : pluginsV4) + { + plugin.trackVolumeChangedFunction(playerName, trackName, volume); + } } void PluginLoader::playerVolumeChanged(const char* playerName, float volume) @@ -499,6 +590,30 @@ void PluginLoader::playerVolumeChanged(const char* playerName, float volume) { plugin.playerVolumeChangedFunction(playerName, volume); } + for (const auto& plugin : pluginsV4) + { + plugin.playerVolumeChangedFunction(playerName, volume); + } +} + +void PluginLoader::cdPlayerVolumeChanged(const char* playerName, float volume) +{ + for (const auto& plugin : pluginsV1) + { + plugin.trackVolumeChangedFunction(playerName, "", volume); + } + for (const auto& plugin : pluginsV2) + { + plugin.trackVolumeChangedFunction(playerName, "", volume); + } + for (const auto& plugin : pluginsV3) + { + plugin.trackVolumeChangedFunction(playerName, "", volume); + } + for (const auto& plugin : pluginsV4) + { + plugin.playerVolumeChangedFunction(playerName, volume); + } } void PluginLoader::positionChanged(const char* playerName, double position) @@ -515,6 +630,10 @@ void PluginLoader::positionChanged(const char* playerName, double position) { plugin.positionChangedFunction(playerName, position); } + for (const auto& plugin : pluginsV4) + { + plugin.positionChangedFunction(playerName, position); + } } void PluginLoader::saveConfigurations(juce::XmlElement* pluginsElement) @@ -546,6 +665,15 @@ void PluginLoader::saveConfigurations(juce::XmlElement* pluginsElement) plugin.freeConfigurationTextFunction(data); pluginsElement->addChildElement(pluginElement); } + for (auto&& plugin : pluginsV4) + { + juce::XmlElement* pluginElement = new juce::XmlElement("Plugin"); + pluginElement->setAttribute("name", plugin.name); + const char* data = plugin.getConfigurationFunction(); + pluginElement->addTextElement(juce::String::fromUTF8(data)); + plugin.freeConfigurationTextFunction(data); + pluginsElement->addChildElement(pluginElement); + } } void PluginLoader::loadConfigurations(juce::XmlElement* pluginsElement) @@ -577,6 +705,13 @@ void PluginLoader::loadConfigurations(juce::XmlElement* pluginsElement) { it3->loadConfigurationFunction(configurationText.toRawUTF8()); } + auto it4 = std::find_if(pluginsV4.begin(), + pluginsV4.end(), + [pluginName](const PluginV4& plugin) { return plugin.name == pluginName; }); + if (it4 != pluginsV4.end()) + { + it4->loadConfigurationFunction(configurationText.toRawUTF8()); + } } } @@ -887,6 +1022,118 @@ std::variant PluginLoader::loadPluginV3(juc return plugin; } +std::variant PluginLoader::loadPluginV4(juce::DynamicLibrary& dynamicLibrary) +{ + PluginV4 plugin; + + plugin.initFunction = reinterpret_cast(dynamicLibrary.getFunction("mstarInit")); + if (!plugin.initFunction) + { + return "Missing function 'init'."; + } + + plugin.playingStateChangedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarPlayingStateChanged")); + if (!plugin.playingStateChangedFunction) + { + return "Missing function 'playingStateChanged'."; + } + + plugin.nextEntrySelectedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarNextEntrySelected")); + if (!plugin.nextEntrySelectedFunction) + { + return "Missing function 'nextEntrySelected'."; + } + + plugin.previousEntrySelectedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarPreviousEntrySelected")); + if (!plugin.previousEntrySelectedFunction) + { + return "Missing function 'previousEntrySelected'."; + } + + plugin.playlistEntrySelectedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarPlaylistEntrySelected")); + if (!plugin.playlistEntrySelectedFunction) + { + return "Missing function 'playlistEntrySelected'."; + } + + plugin.playlistEntryDurationChangedFunction + = reinterpret_cast( + dynamicLibrary.getFunction("mstarPlaylistEntryDurationChanged")); + if (!plugin.playlistEntryDurationChangedFunction) + { + return "Missing function 'playlistEntryDurationChanged'."; + } + + plugin.playlistEntryNameChangedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarPlaylistEntryNameChanged")); + if (!plugin.playlistEntrySelectedFunction) + { + return "Missing function 'playlistEntryNameChanged'."; + } + + plugin.playerVolumeChangedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarPlayerVolumeChanged")); + if (!plugin.playerVolumeChangedFunction) + { + return "Missing function 'playerVolumeChanged'."; + } + + plugin.trackVolumeChangedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarTrackVolumeChanged")); + if (!plugin.trackVolumeChangedFunction) + { + return "Missing function 'trackVolumeChanged'."; + } + + plugin.positionChangedFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarPositionChanged")); + if (!plugin.positionChangedFunction) + { + return "Missing function 'positionChanged'."; + } + + plugin.configureFunction + = reinterpret_cast(dynamicLibrary.getFunction("mstarConfigure")); + if (!plugin.configureFunction) + { + return "Missing function 'configure'."; + } + + plugin.shutdownFunction + = reinterpret_cast(dynamicLibrary.getFunction("mstarShutdown")); + if (!plugin.shutdownFunction) + { + return "Missing function 'shutdown'."; + } + + plugin.loadConfigurationFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarLoadConfiguration")); + if (!plugin.loadConfigurationFunction) + { + return "Missing function 'loadConfiguration'."; + } + + plugin.getConfigurationFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarGetConfiguration")); + if (!plugin.getConfigurationFunction) + { + return "Missing function 'getConfiguration'."; + } + + plugin.freeConfigurationTextFunction = reinterpret_cast( + dynamicLibrary.getFunction("mstarFreeConfigurationText")); + if (!plugin.freeConfigurationTextFunction) + { + return "Missing function 'freeConfigurationText'."; + } + + return plugin; +} + PluginLoader::PluginV1::PluginV1() {} PluginLoader::PluginV1::PluginV1(PluginV1&& other) @@ -914,3 +1161,7 @@ PluginLoader::PluginV2::PluginV2(PluginV2&& other) = default; PluginLoader::PluginV3::PluginV3() {} PluginLoader::PluginV3::PluginV3(PluginV3&& other) = default; + +PluginLoader::PluginV4::PluginV4() {} + +PluginLoader::PluginV4::PluginV4(PluginV4&& other) = default; diff --git a/Source/PluginLoader.h b/Source/PluginLoader.h index 0b766d2..b8040f5 100644 --- a/Source/PluginLoader.h +++ b/Source/PluginLoader.h @@ -9,6 +9,7 @@ #include "PluginInterfaceV1.h" #include "PluginInterfaceV2.h" #include "PluginInterfaceV3.h" +#include "PluginInterfaceV4.h" class PluginLoader { @@ -35,6 +36,8 @@ class PluginLoader void playerVolumeChanged(const char* playerName, float volume); + void cdPlayerVolumeChanged(const char* playerName, float volume); + void positionChanged(const char* playerName, double position); size_t count(); @@ -111,11 +114,36 @@ class PluginLoader PluginInterface::V3::FreeConfigurationTextFunction freeConfigurationTextFunction; }; + struct PluginV4 + { + PluginV4(); + PluginV4(PluginV4&& other); + juce::String name; + std::unique_ptr dynamicLibrary; + PluginInterface::V4::InitFunction initFunction; + PluginInterface::V4::PlayingStateChangedFunction playingStateChangedFunction; + PluginInterface::V4::NextEntrySelectedFunction nextEntrySelectedFunction; + PluginInterface::V4::PreviousEntrySelectedFunction previousEntrySelectedFunction; + PluginInterface::V4::PlaylistEntrySelectedFunction playlistEntrySelectedFunction; + PluginInterface::V4::PlaylistEntryDurationChangedFunction playlistEntryDurationChangedFunction; + PluginInterface::V4::PlaylistEntryNameChangedFunction playlistEntryNameChangedFunction; + PluginInterface::V4::PlayerVolumeChangedFunction playerVolumeChangedFunction; + PluginInterface::V4::TrackVolumeChangedFunction trackVolumeChangedFunction; + PluginInterface::V4::PositionChangedFunction positionChangedFunction; + PluginInterface::V4::ConfigureFunction configureFunction; + PluginInterface::V4::ShutdownFunction shutdownFunction; + PluginInterface::V4::LoadConfigurationFunction loadConfigurationFunction; + PluginInterface::V4::GetConfigurationFunction getConfigurationFunction; + PluginInterface::V4::FreeConfigurationTextFunction freeConfigurationTextFunction; + }; + std::variant loadPluginV1(juce::DynamicLibrary& library); std::variant loadPluginV2(juce::DynamicLibrary& library); std::variant loadPluginV3(juce::DynamicLibrary& library); + std::variant loadPluginV4(juce::DynamicLibrary& library); std::vector pluginsV1; std::vector pluginsV2; std::vector pluginsV3; + std::vector pluginsV4; };