gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

import.cpp (4341B)


      1 #include "import.h"
      2 
      3 #include "config.h"
      4 
      5 #include "baseLib/filesystem.h"
      6 
      7 #include "networkLib/logging.h"
      8 
      9 #include "synthLib/deviceException.h"
     10 #include "synthLib/os.h"
     11 
     12 #ifdef _WIN32
     13 #define NOMINMAX
     14 #include <Windows.h>
     15 #define RTLD_LAZY 0
     16 void* dlopen (const char* _filename, int)
     17 {
     18 	return LoadLibraryA(_filename);
     19 }
     20 FARPROC dlsym (void* _handle, const char* _name)
     21 {
     22 	return GetProcAddress (static_cast<HMODULE>(_handle), _name);
     23 }
     24 int dlclose(void* _handle)
     25 {
     26 	return FreeLibrary(static_cast<HMODULE>(_handle));
     27 }
     28 #else
     29 #include <dlfcn.h>
     30 #endif
     31 
     32 namespace bridgeServer
     33 {
     34 	Import::Import(const Config& _config) : m_config(_config)
     35 	{
     36 		findPlugins();
     37 	}
     38 
     39 	Import::~Import()
     40 	{
     41 		for (const auto& it : m_loadedPlugins)
     42 			dlclose(it.second.handle);
     43 		m_loadedPlugins.clear();
     44 	}
     45 
     46 	synthLib::Device* Import::createDevice(const synthLib::DeviceCreateParams& _params, const bridgeLib::PluginDesc& _desc)
     47 	{
     48 		std::scoped_lock lock(m_mutex);
     49 
     50 		auto it = m_loadedPlugins.find(_desc);
     51 
     52 		if(it == m_loadedPlugins.end())
     53 			findPlugins();	// try to load additional plugins if not found
     54 
     55 		it = m_loadedPlugins.find(_desc);
     56 		if(it == m_loadedPlugins.end())
     57 		{
     58 			LOGNET(networkLib::LogLevel::Warning, "Failed to create device for plugin '" << _desc.pluginName << "', version " << _desc.pluginVersion << ", id " << _desc.plugin4CC << ", no matching plugin available");
     59 			return nullptr;	// still not found
     60 		}
     61 
     62 		try
     63 		{
     64 			return it->second.funcCreate(_params);
     65 		}
     66 		catch(synthLib::DeviceException& e)
     67 		{
     68 			LOGNET(networkLib::LogLevel::Error, "Failed to create device for plugin '" << _desc.pluginName << "', version " << _desc.pluginVersion << ", id " << _desc.plugin4CC << 
     69 				", device creation caused exception: code " << static_cast<uint32_t>(e.errorCode()) << ", message: " << e.what());
     70 			return nullptr;
     71 		}
     72 	}
     73 
     74 	bool Import::destroyDevice(const bridgeLib::PluginDesc& _desc, synthLib::Device* _device)
     75 	{
     76 		if(!_device)
     77 			return true;
     78 
     79 		std::scoped_lock lock(m_mutex);
     80 
     81 		const auto it = m_loadedPlugins.find(_desc);
     82 		if(it == m_loadedPlugins.end())
     83 		{
     84 			assert(false && "plugin unloaded before device destroyed");
     85 			return false;
     86 		}
     87 		it->second.funcDestroy(_device);
     88 		return true;
     89 	}
     90 
     91 	void Import::findPlugins()
     92 	{
     93 		findPlugins(m_config.pluginsPath);
     94 		findPlugins(synthLib::getModulePath() + "plugins/");
     95 	}
     96 
     97 	void Import::findPlugins(const std::string& _rootPath)
     98 	{
     99 		findPlugins(_rootPath, ".dll");
    100 		findPlugins(_rootPath, ".so");
    101 		findPlugins(_rootPath, ".dylib");
    102 
    103 		findPlugins(_rootPath, ".vst3");
    104 		findPlugins(_rootPath, ".clap");
    105 		findPlugins(_rootPath, ".lv2");
    106 	}
    107 
    108 	void Import::findPlugins(const std::string& _rootPath, const std::string& _extension)
    109 	{
    110 		const auto path = synthLib::getModulePath() + "plugins/";
    111 		std::vector<std::string> files;
    112 		baseLib::filesystem::findFiles(files, path, _extension, 0, std::numeric_limits<uint32_t>::max());
    113 
    114 		for (const auto& file : files)
    115 			loadPlugin(file);
    116 	}
    117 
    118 	void Import::loadPlugin(const std::string& _file)
    119 	{
    120 		// load each plugin lib only once
    121 		if(m_loadedFiles.find(_file) != m_loadedFiles.end())
    122 			return;
    123 
    124 		Plugin plugin;
    125 
    126 		plugin.handle = dlopen(_file.c_str(), RTLD_LAZY);
    127 		if(!plugin.handle)
    128 			return;
    129 
    130 		plugin.funcCreate = reinterpret_cast<FuncBridgeDeviceCreate>(dlsym(plugin.handle, "bridgeDeviceCreate")); // NOLINT(clang-diagnostic-cast-function-type-strict)
    131 		plugin.funcDestroy = reinterpret_cast<FuncBridgeDeviceDestroy>(dlsym(plugin.handle, "bridgeDeviceDestroy")); // NOLINT(clang-diagnostic-cast-function-type-strict)
    132 		plugin.funcGetDesc = reinterpret_cast<FuncBridgeDeviceGetDesc>(dlsym(plugin.handle, "bridgeDeviceGetDesc")); // NOLINT(clang-diagnostic-cast-function-type-strict)
    133 
    134 		if(!plugin.funcCreate || !plugin.funcDestroy || !plugin.funcGetDesc)
    135 		{
    136 			dlclose(plugin.handle);
    137 			return;
    138 		}
    139 
    140 		bridgeLib::PluginDesc desc;
    141 		plugin.funcGetDesc(desc);
    142 
    143 		if(desc.plugin4CC.empty() || desc.pluginName.empty() || desc.pluginVersion == 0)
    144 		{
    145 			dlclose(plugin.handle);
    146 			return;
    147 		}
    148 
    149 		if(m_loadedPlugins.find(desc) != m_loadedPlugins.end())
    150 		{
    151 			dlclose(plugin.handle);
    152 			return;
    153 		}
    154 
    155 		LOGNET(networkLib::LogLevel::Info, "Found plugin '" << desc.pluginName << "', version " << desc.pluginVersion << ", id " << desc.plugin4CC);
    156 
    157 		m_loadedPlugins.insert({desc, plugin});
    158 		m_loadedFiles.insert(_file);
    159 	}
    160 }