Browse Source

Make selftest more generally useful, inform plugins of such

pull/321/merge
falkTX 3 years ago
parent
commit
028060954a
4 changed files with 102 additions and 67 deletions
  1. +10
    -0
      distrho/DistrhoPlugin.hpp
  2. +22
    -16
      distrho/src/DistrhoPlugin.cpp
  3. +3
    -0
      distrho/src/DistrhoPluginInternal.hpp
  4. +67
    -51
      distrho/src/DistrhoPluginJACK.cpp

+ 10
- 0
distrho/DistrhoPlugin.hpp View File

@@ -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


+ 22
- 16
distrho/src/DistrhoPlugin.cpp View File

@@ -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
{


+ 3
- 0
distrho/src/DistrhoPluginInternal.hpp View File

@@ -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),


+ 67
- 51
distrho/src/DistrhoPluginJACK.cpp View File

@@ -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
}

// -----------------------------------------------------------------------

Loading…
Cancel
Save