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

pluginTester.cpp (5361B)


      1 #include <chrono>
      2 
      3 #include "fakeAudioDevice.h"
      4 #include "pluginHost.h"
      5 #include "logger.h"
      6 #include "baseLib/commandline.h"
      7 #include "baseLib/filesystem.h"
      8 
      9 class JuceAppLifetimeObjects
     10 {
     11 public:
     12 	JuceAppLifetimeObjects()
     13 	{
     14 		MessageManager::getInstance();
     15 	}
     16 	~JuceAppLifetimeObjects()
     17 	{
     18         DeletedAtShutdown::deleteAll();
     19 		MessageManager::deleteInstance();
     20 	}
     21 private:
     22 	JUCE_DECLARE_NON_COPYABLE(JuceAppLifetimeObjects)
     23 	JUCE_DECLARE_NON_MOVEABLE(JuceAppLifetimeObjects)
     24 };
     25 
     26 int main(const int _argc, char* _argv[])
     27 {
     28 	baseLib::CommandLine cmdLine(_argc, _argv);
     29 
     30 	StdoutLogger logger;
     31 
     32 	auto error = [](const String& _msg) -> int
     33 	{
     34 		Logger::writeToLog("Error: " + _msg);
     35 		Logger::writeToLog("Usage:\n"
     36 			"pluginTester -plugin <pathToPlugin> [-seconds n -blocks n -blocksize n -samplerate x -forever]");
     37 		return 1;
     38 	};
     39 	try
     40 	{
     41 	    ConsoleApplication app;
     42 
     43 		std::string pluginPathName = cmdLine.get("plugin");
     44 
     45 		if (pluginPathName.empty())
     46 		{
     47 			return error("No plugin specified");
     48 		}
     49 
     50 	    {
     51 		    // juce wants the folder for a VST3/LV2 plugin instead of the actual file
     52 		    const auto lowercase = baseLib::filesystem::lowercase(pluginPathName);
     53 
     54 		    auto start = lowercase.find(".vst3");
     55 		    if (start == std::string::npos)
     56 				start = lowercase.find(".lv2");
     57 		    if (start == std::string::npos)
     58 			    start = lowercase.find(".component");
     59 		    if (start == std::string::npos)
     60 			    start = lowercase.find(".vst");
     61 
     62 		    if (start != std::string::npos)
     63 		    {
     64 			    auto slash = pluginPathName.find_first_of("\\/", start);
     65 
     66 			    if (slash != std::string::npos)
     67 				    pluginPathName = pluginPathName.substr(0, slash);
     68 		    }
     69 	    }
     70 
     71 	    JuceAppLifetimeObjects jalto;
     72 
     73 	    CommandLinePluginHost pluginHost;
     74 
     75 		const auto& formatManager = pluginHost.getFormatManager();
     76 
     77 		PluginDescription desc;
     78 
     79 		for (int i = 0; i < formatManager.getNumFormats(); ++i)
     80 		{
     81 			auto* format = formatManager.getFormat(i);
     82 
     83 			if (!format)
     84 				continue;
     85 
     86 			Logger::writeToLog("Attempt to load plugin as type " + format->getName());
     87 
     88 		    KnownPluginList plugins;
     89 
     90 			OwnedArray<PluginDescription> typesFound;
     91 			plugins.scanAndAddFile(pluginPathName, true,typesFound, *format);
     92 
     93 			const auto types = plugins.getTypes();
     94 
     95 			if (types.isEmpty())
     96 				continue;
     97 
     98 			desc = types.getFirst();
     99 			break;
    100 		}
    101 
    102 		if (desc.fileOrIdentifier.isEmpty())
    103 			return error("Failed to find plugin " + pluginPathName);
    104 
    105 	    if (!pluginHost.loadPlugin(desc))
    106 			return error("Failed to load plugin " + pluginPathName);
    107 
    108 		FakeAudioIODevice audioDevice;
    109 
    110 		const uint32_t numIns = pluginHost.getCurrentProcessor()->getTotalNumInputChannels();
    111 		const uint32_t numOuts = pluginHost.getCurrentProcessor()->getTotalNumOutputChannels();
    112 
    113 		const auto blocksize = cmdLine.getInt("blocksize", 512);
    114 		const auto samplerate = cmdLine.getFloat("samplerate", 48000.0f);
    115 
    116 		auto res = audioDevice.open(numIns, numOuts, samplerate, blocksize);
    117 
    118 		if (res.isNotEmpty())
    119 			return error("Failed to open audio device: " + res);
    120 
    121 		audioDevice.start(&pluginHost);
    122 
    123 		const auto forever = cmdLine.contains("forever");
    124 
    125 		if (forever)
    126 		{
    127 			uint64_t blockCount = 0;
    128 			uint64_t sr = static_cast<uint64_t>(samplerate);
    129 
    130 			uint64_t lastMinutes = 0;
    131 
    132 			using Clock = std::chrono::high_resolution_clock;
    133 
    134 			const auto tBegin = Clock::now();
    135 
    136 			while (true)
    137 			{
    138 				audioDevice.processAudio();
    139 				++blockCount;
    140 
    141 				auto formatDuration = [](const uint64_t _seconds) -> std::string
    142 				{
    143 					char temp[64];
    144 					const auto minutes = _seconds / 60;
    145 					const auto hours = minutes / 60;
    146 					const auto s = _seconds - minutes * 60;
    147 					const auto m = minutes - hours * 60;
    148 					(void)snprintf(temp, sizeof(temp), "%02uh %02um %02us", static_cast<uint32_t>(hours), static_cast<uint32_t>(m), static_cast<uint32_t>(s));
    149 					return temp;
    150 				};
    151 
    152 				const auto totalSeconds = blockCount * blocksize / sr;
    153 				const auto minutes = totalSeconds / 60;
    154 
    155 				if (minutes != lastMinutes)
    156 				{
    157 					const auto t2 = Clock::now();
    158 					const auto duration = std::chrono::duration_cast<std::chrono::seconds>(t2 - tBegin).count();
    159 
    160 					const auto speed = static_cast<double>(totalSeconds) * 100.0 / static_cast<double>(duration);
    161 
    162 					char temp[64];
    163 					(void)snprintf(temp, sizeof(temp), "Processed %s, elapsed %s, speed %2.2f%%", formatDuration(totalSeconds).c_str(), formatDuration(duration).c_str(), speed);
    164 					Logger::writeToLog(temp);
    165 					lastMinutes = minutes;
    166 				}
    167 			}
    168 		}
    169 
    170 		const auto seconds = cmdLine.getInt("seconds", 0);
    171 		auto blocks = cmdLine.getInt("blocks", 0);
    172 
    173 		if (blocks && seconds)
    174 			return error("Cannot specify both blocks and seconds");
    175 
    176 		if (seconds)
    177 		{
    178 			blocks = static_cast<int>(samplerate) / blocksize * seconds;
    179 			if (blocks == 0)
    180 				blocks = 1;
    181 		}
    182 
    183 		int lastPercent = -1;
    184 
    185 		char temp[64];
    186 
    187 		for (int i=0; i<blocks; ++i)
    188 		{
    189 			audioDevice.processAudio();
    190 
    191 			const auto percent = i * 100 / blocks;
    192 
    193 			if (percent == lastPercent)
    194 				continue;
    195 			lastPercent = percent;
    196 
    197 			(void)snprintf(temp, sizeof(temp), "Progress: %d%% (%d/%d blocks)", percent, i, blocks);
    198 			Logger::writeToLog(temp);
    199 		}
    200 
    201 		(void)snprintf(temp, sizeof(temp), "Progress: %d%% (%d/%d blocks)", 100, blocks, blocks);
    202 		Logger::writeToLog(temp);
    203 
    204 	    return 0;
    205 	}
    206 	catch (const std::exception& e)
    207 	{
    208 		juce::Logger::writeToLog(e.what());
    209 		return 1;
    210 	}
    211 }