commit 028060954a99720de194a43d8d03b6d694c66850
parent ac7c0ee3fa7e926f5413302c0d9a6f116c9b4fdf
Author: falkTX <falktx@falktx.com>
Date: Fri, 19 Aug 2022 02:58:05 +0100
Make selftest more generally useful, inform plugins of such
Diffstat:
4 files changed, 102 insertions(+), 67 deletions(-)
diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp
@@ -951,6 +951,16 @@ public:
*/
bool isDummyInstance() const noexcept;
+ /**
+ Check if this plugin instance is a "selftest" one used for automated plugin tests.@n
+ To enable this mode build with `DPF_RUNTIME_TESTING` macro defined (i.e. set as compiler build flag),
+ and run the JACK/Standalone executable with "selftest" as its only and single argument.
+
+ A few basic DSP and UI tests will run in self-test mode, with once instance having this function returning true.@n
+ You can use this chance to do a few tests of your own as well.
+ */
+ bool isSelfTestInstance() const noexcept;
+
#if DISTRHO_PLUGIN_WANT_TIMEPOS
/**
Get the current host transport time position.@n
diff --git a/distrho/src/DistrhoPlugin.cpp b/distrho/src/DistrhoPlugin.cpp
@@ -25,6 +25,7 @@ uint32_t d_nextBufferSize = 0;
double d_nextSampleRate = 0.0;
const char* d_nextBundlePath = nullptr;
bool d_nextPluginIsDummy = false;
+bool d_nextPluginIsSelfTest = false;
bool d_nextCanRequestParameterValueChanges = false;
/* ------------------------------------------------------------------------------------------------------------
@@ -42,45 +43,45 @@ const PortGroupWithId PluginExporter::sFallbackPortGroup;
Plugin::Plugin(uint32_t parameterCount, uint32_t programCount, uint32_t stateCount)
: pData(new PrivateData())
{
-#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
+ #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
pData->audioPorts = new AudioPortWithBusId[DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS];
-#endif
+ #endif
-#ifdef DPF_ABORT_ON_ERROR
-# define DPF_ABORT abort();
-#else
-# define DPF_ABORT
-#endif
+ #if defined(DPF_ABORT_ON_ERROR) || defined(DPF_RUNTIME_TESTING)
+ #define DPF_ABORT abort();
+ #else
+ #define DPF_ABORT
+ #endif
if (parameterCount > 0)
{
pData->parameterCount = parameterCount;
- pData->parameters = new Parameter[parameterCount];
+ pData->parameters = new Parameter[parameterCount];
}
if (programCount > 0)
{
-#if DISTRHO_PLUGIN_WANT_PROGRAMS
+ #if DISTRHO_PLUGIN_WANT_PROGRAMS
pData->programCount = programCount;
pData->programNames = new String[programCount];
-#else
+ #else
d_stderr2("DPF warning: Plugins with programs must define `DISTRHO_PLUGIN_WANT_PROGRAMS` to 1");
DPF_ABORT
-#endif
+ #endif
}
if (stateCount > 0)
{
-#if DISTRHO_PLUGIN_WANT_STATE
+ #if DISTRHO_PLUGIN_WANT_STATE
pData->stateCount = stateCount;
- pData->states = new State[stateCount];
-#else
+ pData->states = new State[stateCount];
+ #else
d_stderr2("DPF warning: Plugins with state must define `DISTRHO_PLUGIN_WANT_STATE` to 1");
DPF_ABORT
-#endif
+ #endif
}
-#undef DPF_ABORT
+ #undef DPF_ABORT
}
Plugin::~Plugin()
@@ -111,6 +112,11 @@ bool Plugin::isDummyInstance() const noexcept
return pData->isDummy;
}
+bool Plugin::isSelfTestInstance() const noexcept
+{
+ return pData->isSelfTest;
+}
+
#if DISTRHO_PLUGIN_WANT_TIMEPOS
const TimePosition& Plugin::getTimePosition() const noexcept
{
diff --git a/distrho/src/DistrhoPluginInternal.hpp b/distrho/src/DistrhoPluginInternal.hpp
@@ -39,6 +39,7 @@ extern uint32_t d_nextBufferSize;
extern double d_nextSampleRate;
extern const char* d_nextBundlePath;
extern bool d_nextPluginIsDummy;
+extern bool d_nextPluginIsSelfTest;
extern bool d_nextCanRequestParameterValueChanges;
// -----------------------------------------------------------------------
@@ -92,6 +93,7 @@ static void fillInPredefinedPortGroupData(const uint32_t groupId, PortGroup& por
struct Plugin::PrivateData {
const bool canRequestParameterValueChanges;
const bool isDummy;
+ const bool isSelfTest;
bool isProcessing;
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
@@ -136,6 +138,7 @@ struct Plugin::PrivateData {
PrivateData() noexcept
: canRequestParameterValueChanges(d_nextCanRequestParameterValueChanges),
isDummy(d_nextPluginIsDummy),
+ isSelfTest(d_nextPluginIsSelfTest),
isProcessing(false),
#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0
audioPorts(nullptr),
diff --git a/distrho/src/DistrhoPluginJACK.cpp b/distrho/src/DistrhoPluginJACK.cpp
@@ -795,11 +795,11 @@ protected:
while (! shouldThreadExit())
{
-#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+ #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
plugin.run(inputs, outputs, 128, nullptr, 0);
-#else
+ #else
plugin.run(inputs, outputs, 128);
-#endif
+ #endif
d_msleep(100);
}
@@ -824,7 +824,17 @@ bool runSelfTests()
// simple processing
{
+ d_nextPluginIsSelfTest = true;
PluginExporter plugin(nullptr, nullptr, nullptr, nullptr);
+ d_nextPluginIsSelfTest = false;
+
+ #if DISTRHO_PLUGIN_HAS_UI
+ UIExporter ui(nullptr, 0, plugin.getSampleRate(),
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ plugin.getInstancePointer(), 0.0);
+ ui.showAndFocus();
+ #endif
+
plugin.activate();
plugin.deactivate();
plugin.setBufferSize(128);
@@ -839,15 +849,21 @@ bool runSelfTests()
for (int i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
outputs[i] = buffer;
-#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
+ #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
plugin.run(inputs, outputs, 128, nullptr, 0);
-#else
+ #else
plugin.run(inputs, outputs, 128);
-#endif
+ #endif
plugin.deactivate();
+
+ #if DISTRHO_PLUGIN_HAS_UI
+ ui.plugin_idle();
+ #endif
}
+ return true;
+
// multi-threaded processing with UI
{
PluginExporter pluginA(nullptr, nullptr, nullptr, nullptr);
@@ -866,7 +882,7 @@ bool runSelfTests()
// stop the 2nd instance now
procTestB.stopThread(5000);
-#if DISTRHO_PLUGIN_HAS_UI
+ #if DISTRHO_PLUGIN_HAS_UI
// start UI in the middle of this
{
UIExporter uiA(nullptr, 0, pluginA.getSampleRate(),
@@ -893,7 +909,7 @@ bool runSelfTests()
d_msleep(100);
}
}
-#endif
+ #endif
procTestA.stopThread(5000);
procTestC.stopThread(5000);
@@ -911,12 +927,47 @@ int main(int argc, char* argv[])
{
USE_NAMESPACE_DISTRHO;
-#ifdef DPF_RUNTIME_TESTING
+ initSignalHandler();
+
+ #if !defined(DISTRHO_OS_WINDOWS) && !defined(STATIC_BUILD)
+ // find plugin bundle
+ static String bundlePath;
+ if (bundlePath.isEmpty())
+ {
+ String tmpPath(getBinaryFilename());
+ tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
+ #ifdef DISTRHO_OS_MAC
+ if (tmpPath.endsWith("/MacOS"))
+ {
+ tmpPath.truncate(tmpPath.rfind('/'));
+ if (tmpPath.endsWith("/Contents"))
+ {
+ tmpPath.truncate(tmpPath.rfind('/'));
+ bundlePath = tmpPath;
+ d_nextBundlePath = bundlePath.buffer();
+ }
+ }
+ #else
+ if (access(tmpPath + DISTRHO_OS_SEP_STR "resources", F_OK) == 0)
+ {
+ bundlePath = tmpPath;
+ d_nextBundlePath = bundlePath.buffer();
+ }
+ #endif
+ }
+ #endif
+
if (argc == 2 && std::strcmp(argv[1], "selftest") == 0)
+ {
+ #ifdef DPF_RUNTIME_TESTING
return runSelfTests() ? 0 : 1;
-#endif
+ #else
+ d_stderr2("Code was built without DPF_RUNTIME_TESTING macro enabled, selftest option is not available");
+ return 1;
+ #endif
+ }
-#if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI
+ #if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI
/* the code below is based on
* https://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/
*/
@@ -944,7 +995,7 @@ int main(int argc, char* argv[])
hasConsole = true;
}
-#endif
+ #endif
jack_status_t status = jack_status_t(0x0);
jack_client_t* client = jackbridge_client_open(DISTRHO_PLUGIN_NAME, JackNoStartServer, &status);
@@ -1023,49 +1074,19 @@ int main(int argc, char* argv[])
return 1;
}
- initSignalHandler();
-
d_nextBufferSize = jackbridge_get_buffer_size(client);
d_nextSampleRate = jackbridge_get_sample_rate(client);
d_nextCanRequestParameterValueChanges = true;
- #if !defined(DISTRHO_OS_WINDOWS) && !defined(STATIC_BUILD)
- // find plugin bundle
- static String bundlePath;
- if (bundlePath.isEmpty())
- {
- String tmpPath(getBinaryFilename());
- tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
- #ifdef DISTRHO_OS_MAC
- if (tmpPath.endsWith("/MacOS"))
- {
- tmpPath.truncate(tmpPath.rfind('/'));
- if (tmpPath.endsWith("/Contents"))
- {
- tmpPath.truncate(tmpPath.rfind('/'));
- bundlePath = tmpPath;
- d_nextBundlePath = bundlePath.buffer();
- }
- }
- #else
- if (access(tmpPath + DISTRHO_OS_SEP_STR "resources", F_OK) == 0)
- {
- bundlePath = tmpPath;
- d_nextBundlePath = bundlePath.buffer();
- }
- #endif
- }
- #endif
-
uintptr_t winId = 0;
-#if DISTRHO_PLUGIN_HAS_UI
+ #if DISTRHO_PLUGIN_HAS_UI
if (argc == 3 && std::strcmp(argv[1], "embed") == 0)
winId = static_cast<uintptr_t>(std::atoll(argv[2]));
-#endif
+ #endif
const PluginJack p(client, winId);
-#if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI
+ #if defined(DISTRHO_OS_WINDOWS) && DISTRHO_PLUGIN_HAS_UI
/* the code below is based on
* https://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/
*/
@@ -1091,14 +1112,9 @@ int main(int argc, char* argv[])
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
-#endif
+ #endif
return 0;
-
-#ifndef DPF_RUNTIME_TESTING
- // unused
- (void)argc; (void)argv;
-#endif
}
// -----------------------------------------------------------------------