VST2: new scanner implementation
This commit is contained in:
parent
a74b4e8ef0
commit
ef06f01c7b
49
gtk2_ardour/arvst2
Executable file
49
gtk2_ardour/arvst2
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
TOP=`dirname "$0"`/..
|
||||
. $TOP/build/gtk2_ardour/ardev_common_waf.sh
|
||||
export UBUNTU_MENUPROXY=""
|
||||
|
||||
if [ $# -gt 0 ] ; then
|
||||
case $1 in
|
||||
-g|--gdb) DBG=gdb; shift ;;
|
||||
esac
|
||||
case $1 in
|
||||
--valgrind) DBG=valgrind; shift ;;
|
||||
esac
|
||||
case $1 in
|
||||
--callgrind) DBG=callgrind; shift ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -z "$DBG"; then
|
||||
exec $TOP/build/libs/fst/ardour-vst-scanner "$@"
|
||||
fi
|
||||
|
||||
if test "$DBG" = "valgrind"; then
|
||||
export ARDOUR_RUNNING_UNDER_VALGRIND=TRUE
|
||||
exec valgrind \
|
||||
--error-limit=no --num-callers=50 \
|
||||
--tool=memcheck \
|
||||
--track-origins=yes \
|
||||
--leak-check=full --show-leak-kinds=all \
|
||||
--suppressions=${TOP}/tools/valgrind.supp \
|
||||
$TOP/build/libs/fst/ardour-vst-scanner "$@"
|
||||
fi
|
||||
|
||||
if test "$DBG" = "callgrind"; then
|
||||
exec valgrind \
|
||||
--error-limit=no --num-callers=50 \
|
||||
--tool=callgrind \
|
||||
--separate-callers=3 \
|
||||
--separate-threads=yes \
|
||||
--collect-systime=yes \
|
||||
--collect-jumps=yes \
|
||||
$TOP/build/libs/fst/ardour-vst-scanner "$@"
|
||||
fi
|
||||
|
||||
if test -n "`which gdb`"; then
|
||||
exec gdb --args $TOP/build/libs/fst/ardour-vst-scanner "$@"
|
||||
fi
|
||||
if test -n "`which lldb`"; then
|
||||
exec lldb -- $TOP/build/libs/fst/ardour-vst-scanner "$@"
|
||||
fi
|
81
libs/ardour/ardour/vst2_scan.h
Normal file
81
libs/ardour/ardour/vst2_scan.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _ardour_vst2_scan_h_
|
||||
#define _ardour_vst2_scan_h_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "pbd/xml++.h"
|
||||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "ardour/types.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
struct VST2Info {
|
||||
VST2Info ()
|
||||
: id (0)
|
||||
, n_inputs (0)
|
||||
, n_outputs (0)
|
||||
, n_midi_inputs (0)
|
||||
, n_midi_outputs (0)
|
||||
, is_instrument (false)
|
||||
, can_process_replace (false)
|
||||
, has_editor (false)
|
||||
{}
|
||||
|
||||
VST2Info (XMLNode const&);
|
||||
XMLNode& state () const;
|
||||
|
||||
int32_t id;
|
||||
std::string name;
|
||||
std::string creator; // vendor;
|
||||
std::string category;
|
||||
std::string version;
|
||||
|
||||
int n_inputs;
|
||||
int n_outputs;
|
||||
int n_midi_inputs;
|
||||
int n_midi_outputs;
|
||||
|
||||
bool is_instrument;
|
||||
bool can_process_replace;
|
||||
bool has_editor;
|
||||
};
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
vst2_arch ();
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
vst2_id_to_str (int32_t);
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
vst2_cache_file (std::string const& path);
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
vst2_valid_cache_file (std::string const& path, bool verbose = false, bool* is_new = NULL);
|
||||
|
||||
LIBARDOUR_API extern bool
|
||||
vst2_scan_and_cache (std::string const& path, ARDOUR::PluginType, boost::function<void (std::string const&, PluginType, VST2Info const&)> cb, bool verbose = false);
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif
|
756
libs/ardour/vst2_scan.cc
Normal file
756
libs/ardour/vst2_scan.cc
Normal file
@ -0,0 +1,756 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include <glib.h>
|
||||
#include "pbd/gstdio_compat.h"
|
||||
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#include <sys/utime.h>
|
||||
#else
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#include "pbd/basename.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/linux_vst_support.h"
|
||||
#include "ardour/mac_vst_support.h"
|
||||
#include "ardour/vst_types.h"
|
||||
#include "ardour/vst2_scan.h"
|
||||
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
#include <fst.h>
|
||||
#endif
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/* ID for shell plugins */
|
||||
static int vstfx_current_loading_id = 0;
|
||||
static bool vstfx_verbose_log = false;
|
||||
|
||||
/* ****************************************************************************
|
||||
* VST system-under-test methods
|
||||
*/
|
||||
|
||||
static
|
||||
bool vstfx_midi_input (VSTState* vstfx)
|
||||
{
|
||||
AEffect* plugin = vstfx->plugin;
|
||||
|
||||
if ((plugin->flags & effFlagsIsSynth)
|
||||
|| (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("receiveVstEvents"), 0.0f) > 0)
|
||||
|| (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("receiveVstMidiEvent"), 0.0f) > 0)
|
||||
|| (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("receiveVstMidiEvents"), 0.0f) > 0)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
bool vstfx_midi_output (VSTState* vstfx)
|
||||
{
|
||||
AEffect* plugin = vstfx->plugin;
|
||||
|
||||
int const vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, 0, 0.0f);
|
||||
|
||||
if (vst_version >= 2) {
|
||||
|
||||
if ( (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("sendVstEvents"), 0.0f) > 0)
|
||||
|| (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("sendVstMidiEvent"), 0.0f) > 0)
|
||||
|| (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("sendVstMidiEvents"), 0.0f) > 0)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** simple 'dummy' audiomaster callback to instantiate the plugin
|
||||
* and query information
|
||||
*/
|
||||
static intptr_t
|
||||
simple_master_callback (AEffect *, int32_t opcode, int32_t, intptr_t, void *ptr, float)
|
||||
{
|
||||
const char* vstfx_can_do_strings[] = {
|
||||
"supplyIdle",
|
||||
"sendVstTimeInfo",
|
||||
"sendVstEvents",
|
||||
"sendVstMidiEvent",
|
||||
"receiveVstEvents",
|
||||
"receiveVstMidiEvent",
|
||||
"supportShell",
|
||||
"shellCategory",
|
||||
"shellCategorycurID",
|
||||
"sizeWindow"
|
||||
};
|
||||
const int vstfx_can_do_string_count = 9;
|
||||
|
||||
if (opcode == audioMasterVersion) {
|
||||
return 2400;
|
||||
}
|
||||
else if (opcode == audioMasterCanDo) {
|
||||
intptr_t rv = 0;
|
||||
for (int i = 0; i < vstfx_can_do_string_count; i++) {
|
||||
if (! strcmp (vstfx_can_do_strings[i], (const char*)ptr)) {
|
||||
rv = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (vstfx_verbose_log) {
|
||||
PBD::info << string_compose ("Callback CanDo '%1': %2", (const char*)ptr, rv ? "yes" : "no") << endmsg;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
else if (opcode == audioMasterCurrentId) {
|
||||
return vstfx_current_loading_id;
|
||||
}
|
||||
else {
|
||||
if (vstfx_verbose_log) {
|
||||
PBD::info << string_compose ("Callback opcode = %1 (ignored)", opcode) << endmsg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** query VST Info */
|
||||
static void
|
||||
vstfx_parse_vst_state (ARDOUR::VST2Info& nfo, VSTState* vstfx, bool verbose)
|
||||
{
|
||||
assert (vstfx);
|
||||
/* We need to init the creator because some plugins
|
||||
* fail to implement getVendorString, and so won't stuff the
|
||||
* string with any name */
|
||||
|
||||
char creator[65] = "Unknown";
|
||||
char name[65] = "";
|
||||
|
||||
AEffect* plugin = vstfx->plugin;
|
||||
|
||||
plugin->dispatcher (plugin, effGetEffectName, 0, 0, name, 0);
|
||||
|
||||
if (strlen (name) == 0) {
|
||||
plugin->dispatcher (plugin, effGetProductString, 0, 0, name, 0);
|
||||
}
|
||||
|
||||
if (strlen (name) == 0) {
|
||||
nfo.name = vstfx->handle->name;
|
||||
} else {
|
||||
nfo.name = name;
|
||||
}
|
||||
|
||||
/*If the plugin doesn't bother to implement GetVendorString we will
|
||||
* have pre-stuffed the string with 'Unknown' */
|
||||
|
||||
plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
|
||||
|
||||
/* Some plugins DO implement GetVendorString, but DON'T put a name in it
|
||||
* so if its just a zero length string we replace it with 'Unknown' */
|
||||
|
||||
if (strlen (creator) == 0) {
|
||||
nfo.creator = "Unknown";
|
||||
} else {
|
||||
nfo.creator = creator;
|
||||
}
|
||||
|
||||
switch (plugin->dispatcher (plugin, effGetPlugCategory, 0, 0, 0, 0))
|
||||
{
|
||||
case kPlugCategEffect: nfo.category = "Effect"; break;
|
||||
case kPlugCategSynth: nfo.category = "Instrument"; break;
|
||||
case kPlugCategAnalysis: nfo.category = "Analyser"; break;
|
||||
case kPlugCategMastering: nfo.category = "Mastering"; break;
|
||||
case kPlugCategSpacializer: nfo.category = "Spatial"; break;
|
||||
case kPlugCategRoomFx: nfo.category = "RoomFx"; break;
|
||||
case kPlugSurroundFx: nfo.category = "SurroundFx"; break;
|
||||
case kPlugCategRestoration: nfo.category = "Restoration"; break;
|
||||
case kPlugCategOfflineProcess: nfo.category = "Offline"; break;
|
||||
case kPlugCategShell: nfo.category = "Shell"; break;
|
||||
case kPlugCategGenerator: nfo.category = "Generator"; break;
|
||||
default: nfo.category = "Unknown"; break;
|
||||
}
|
||||
|
||||
nfo.id = plugin->uniqueID;
|
||||
nfo.n_inputs = plugin->numInputs;
|
||||
nfo.n_outputs = plugin->numOutputs;
|
||||
nfo.has_editor = plugin->flags & effFlagsHasEditor ? true : false;
|
||||
nfo.can_process_replace = plugin->flags & effFlagsCanReplacing ? true : false;
|
||||
nfo.n_midi_inputs = vstfx_midi_input (vstfx) ? 1 : 0;
|
||||
nfo.n_midi_outputs = vstfx_midi_output (vstfx) ? 1 : 0;
|
||||
nfo.is_instrument = (plugin->flags & effFlagsIsSynth) ? 1 : 0;
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (nfo.has_editor) {
|
||||
/* we only support Cocoa UIs (just like Reaper) */
|
||||
nfo.has_editor = (plugin->dispatcher (plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f) & 0xffff0000) == 0xbeef0000;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < plugin->numParams; ++i) {
|
||||
char name[VestigeMaxLabelLen];
|
||||
char label[VestigeMaxLabelLen];
|
||||
|
||||
/* Not all plugins give parameters labels as well as names */
|
||||
strcpy (name, "No Name");
|
||||
strcpy (label, "No Label");
|
||||
|
||||
plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
|
||||
plugin->dispatcher (plugin, 6 /* effGetParamLabel */, i, 0, label, 0);
|
||||
|
||||
nfp.param[name] = label;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
vst2_close (VSTState* vstfx, ARDOUR::PluginType type)
|
||||
{
|
||||
/* mark as used, prevent *_close from unloading the plugin */
|
||||
VSTHandle* h = vstfx->handle;
|
||||
h->plugincnt++;
|
||||
|
||||
switch (type) {
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
case ARDOUR::Windows_VST:
|
||||
fst_close (vstfx);
|
||||
break;
|
||||
#endif
|
||||
#ifdef LXVST_SUPPORT
|
||||
case ARDOUR::LXVST:
|
||||
vstfx_close (vstfx);
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACVST_SUPPORT
|
||||
case ARDOUR::MacVST:
|
||||
mac_vst_close (vstfx);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert (0);
|
||||
break;
|
||||
}
|
||||
h->plugincnt--;
|
||||
}
|
||||
|
||||
static void
|
||||
vst2_unload (VSTHandle* h, ARDOUR::PluginType type)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
case ARDOUR::Windows_VST:
|
||||
fst_unload (&h);
|
||||
break;
|
||||
#endif
|
||||
#ifdef LXVST_SUPPORT
|
||||
case ARDOUR::LXVST:
|
||||
vstfx_unload (h);
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACVST_SUPPORT
|
||||
case ARDOUR::MacVST:
|
||||
mac_vst_unload (h);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static VSTHandle*
|
||||
vstfx_load (const char* dllpath, ARDOUR::PluginType type)
|
||||
{
|
||||
VSTHandle* h = NULL;
|
||||
switch (type) {
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
case ARDOUR::Windows_VST:
|
||||
h = fst_load (dllpath);
|
||||
break;
|
||||
#endif
|
||||
#ifdef LXVST_SUPPORT
|
||||
case ARDOUR::LXVST:
|
||||
h = vstfx_load (dllpath);
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACVST_SUPPORT
|
||||
case ARDOUR::MacVST:
|
||||
h = mac_vst_load (dllpath);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert (0);
|
||||
break;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static VSTState*
|
||||
vst2_instantiate (VSTHandle* h, ARDOUR::PluginType type)
|
||||
{
|
||||
VSTState* s = NULL;
|
||||
switch (type) {
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
case ARDOUR::Windows_VST:
|
||||
s = fst_instantiate (h, simple_master_callback, 0);
|
||||
break;
|
||||
#endif
|
||||
#ifdef LXVST_SUPPORT
|
||||
case ARDOUR::LXVST:
|
||||
s = vstfx_instantiate (h, simple_master_callback, 0);
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACVST_SUPPORT
|
||||
case ARDOUR::MacVST:
|
||||
s = mac_vst_instantiate (h, simple_master_callback, 0);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
assert (0);
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
static std::string
|
||||
dll_info (std::string path)
|
||||
{
|
||||
std::string rv;
|
||||
uint8_t buf[68];
|
||||
uint16_t type = 0;
|
||||
off_t pe_hdr_off = 0;
|
||||
|
||||
int fd = g_open(path.c_str(), O_RDONLY, 0444);
|
||||
|
||||
if (fd < 0) {
|
||||
return string_compose (_("cannot open dll '%1' (%2)"), path, g_strerror (errno));
|
||||
}
|
||||
|
||||
if (68 != read (fd, buf, 68)) {
|
||||
rv = _("invalid dll, file too small");
|
||||
goto errorout;
|
||||
}
|
||||
if (buf[0] != 'M' && buf[1] != 'Z') {
|
||||
rv = _("not a dll");
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
pe_hdr_off = *((int32_t*) &buf[60]);
|
||||
if (pe_hdr_off !=lseek (fd, pe_hdr_off, SEEK_SET)) {
|
||||
rv = _("cannot determine dll type");
|
||||
goto errorout;
|
||||
}
|
||||
if (6 != read (fd, buf, 6)) {
|
||||
rv = _("cannot read dll PE header");
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
if (buf[0] != 'P' && buf[1] != 'E') {
|
||||
rv = _("invalid dll PE header");
|
||||
goto errorout;
|
||||
}
|
||||
|
||||
type = *((uint16_t*) &buf[4]);
|
||||
switch (type) {
|
||||
case 0x014c:
|
||||
rv = _("i386 (32-bit)");
|
||||
break;
|
||||
case 0x0200:
|
||||
rv = _("Itanium");
|
||||
break;
|
||||
case 0x8664:
|
||||
rv = _("x64 (64-bit)");
|
||||
break;
|
||||
case 0:
|
||||
rv = _("Native Architecture");
|
||||
break;
|
||||
default:
|
||||
rv = _("Unknown Architecture");
|
||||
break;
|
||||
}
|
||||
errorout:
|
||||
assert (rv.length() > 0);
|
||||
close (fd);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string
|
||||
ARDOUR::vst2_id_to_str (int32_t id)
|
||||
{
|
||||
std::string rv;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
char a = ((char*)&id)[i];
|
||||
if (isprint (a)) {
|
||||
rv += a;
|
||||
} else {
|
||||
rv += '.';
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
std::string
|
||||
ARDOUR::vst2_arch ()
|
||||
{
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
struct utsname utb;
|
||||
if (uname (&utb) >= 0) {
|
||||
return utb.machine;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ( defined(__x86_64__) || defined(_M_X64) )
|
||||
return "x86_64";
|
||||
#elif defined __i386__ || defined _M_IX86
|
||||
return "i386";
|
||||
#elif defined __ppc__ && defined __LP64__
|
||||
return "ppc64";
|
||||
#elif defined __ppc__
|
||||
return "ppc";
|
||||
#elif defined __aarch64__
|
||||
return "aarch64";
|
||||
#elif defined __arm__ && defined __ARM_NEON
|
||||
return "armhf";
|
||||
#elif defined __arm__
|
||||
return "arm";
|
||||
#elif defined __LP64__
|
||||
return "x64";
|
||||
#else
|
||||
return "x32";
|
||||
#endif
|
||||
}
|
||||
|
||||
/** wrapper around \ref vstfx_parse_vst_state,
|
||||
* iterate over plugins in shell, translate VST-info into ardour VSTState
|
||||
*/
|
||||
static void
|
||||
vstfx_info_from_plugin (VSTHandle* h, VSTState* vstfx, vector<ARDOUR::VST2Info>& rv, enum ARDOUR::PluginType type, bool verbose)
|
||||
{
|
||||
assert (vstfx);
|
||||
|
||||
ARDOUR::VST2Info nfo;
|
||||
vstfx_parse_vst_state (nfo, vstfx, verbose);
|
||||
|
||||
if (strncmp (nfo.category.c_str(), "Shell", 5) /*|| vstfx->handle->plugincnt != 1 */) {
|
||||
rv.push_back (nfo);
|
||||
vst2_close (vstfx, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PBD::info << "VST Shell Plugin" << endmsg;
|
||||
}
|
||||
|
||||
/* shell plugin.
|
||||
* read the info for all of the plugins contained in this shell.
|
||||
*/
|
||||
int id;
|
||||
vector< pair<int, string> > ids;
|
||||
AEffect* plugin = vstfx->plugin;
|
||||
|
||||
do {
|
||||
char name[65] = "Unknown";
|
||||
id = plugin->dispatcher (plugin, effShellGetNextPlugin, 0, 0, name, 0);
|
||||
ids.push_back (std::make_pair (id, name));
|
||||
} while (id != 0);
|
||||
|
||||
vst2_close (vstfx, type);
|
||||
|
||||
if (verbose) {
|
||||
PBD::info << "Found " << ids.size() << " Plugin(s) in shell)" << endmsg;
|
||||
}
|
||||
|
||||
for (vector< pair<int, string> >::iterator x = ids.begin (); x != ids.end (); ++x) {
|
||||
id = (*x).first;
|
||||
if (id == 0) {
|
||||
if (verbose) {
|
||||
PBD::info << string_compose (_("Skipping VST2 Shell ID: '%1' Name: '%2'"), id, (*x).second) << endmsg;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* recurse vstfx_get_info() */
|
||||
vstfx_current_loading_id = id;
|
||||
if (verbose) {
|
||||
PBD::info << string_compose (_("Instantiating VST2 Shell ID: '%1' Name: '%2'"), ARDOUR::vst2_id_to_str(id), (*x).second) << endmsg;
|
||||
}
|
||||
vstfx = vst2_instantiate (h, type);
|
||||
if (!vstfx) {
|
||||
PBD::warning << string_compose (_("Error scanning VST2 Shell ID: '%1' Name: '%2'"), ARDOUR::vst2_id_to_str(id), (*x).second) << endmsg;
|
||||
continue;
|
||||
}
|
||||
vstfx_info_from_plugin (h, vstfx, rv, type, verbose);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
discover_vst2 (std::string const& path, ARDOUR::PluginType type, std::vector<ARDOUR::VST2Info>& rv, bool verbose)
|
||||
{
|
||||
VSTHandle* h = vstfx_load (path.c_str (), type);
|
||||
|
||||
if (!h) {
|
||||
PBD::warning << string_compose (_("Cannot get load VST plugin from '%1'"), path) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
vstfx_current_loading_id = 0;
|
||||
vstfx_verbose_log = verbose;
|
||||
VSTState* vstfx = vst2_instantiate (h, type);
|
||||
|
||||
if (!vstfx) {
|
||||
vst2_unload (h, type);
|
||||
PBD::warning << string_compose (_("Cannot get VST information from '%1': instantiation failed."), path) << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
vstfx_info_from_plugin (h, vstfx, rv, type, verbose);
|
||||
vst2_unload (h, type);
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string vst2_suffix () {
|
||||
#ifdef __APPLE__
|
||||
return "";
|
||||
#elif defined PLATFORM_WINDOWS
|
||||
return ".dll";
|
||||
#else // Linux
|
||||
return ".so";
|
||||
#endif
|
||||
}
|
||||
|
||||
static string
|
||||
vst2_info_cache_dir ()
|
||||
{
|
||||
string dir = Glib::build_filename (ARDOUR::user_cache_directory (), "vst");
|
||||
/* if the directory doesn't exist, try to create it */
|
||||
if (!Glib::file_test (dir, Glib::FILE_TEST_IS_DIR)) {
|
||||
if (g_mkdir (dir.c_str (), 0700)) {
|
||||
PBD::fatal << "Cannot create VST info folder '" << dir << "'" << endmsg;
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
#include "sha1.c"
|
||||
|
||||
string
|
||||
ARDOUR::vst2_cache_file (std::string const& path)
|
||||
{
|
||||
char hash[41];
|
||||
Sha1Digest s;
|
||||
sha1_init (&s);
|
||||
sha1_write (&s, (const uint8_t *) path.c_str(), path.size());
|
||||
sha1_result_hash (&s, hash);
|
||||
/* Arch specifix suffix or arch specific folder?
|
||||
* start 32bit Ardour, scan 32bit plugin -> create cache file.
|
||||
* start 64bit Ardour, scan 32bit plugin -> invalid -> cleanup -> cache file is removed
|
||||
*/
|
||||
# if ( defined(__x86_64__) || defined(_M_X64) )
|
||||
return Glib::build_filename (vst2_info_cache_dir (), std::string (hash) + std::string ("-x64.v2i"));
|
||||
#else
|
||||
return Glib::build_filename (vst2_info_cache_dir (), std::string (hash) + std::string ("-x86.v2i"));
|
||||
#endif
|
||||
}
|
||||
|
||||
string
|
||||
ARDOUR::vst2_valid_cache_file (std::string const& path, bool verbose, bool* is_new)
|
||||
{
|
||||
string const cache_file = ARDOUR::vst2_cache_file (path);
|
||||
if (!Glib::file_test (cache_file, Glib::FileTest (Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_REGULAR))) {
|
||||
if (is_new) {
|
||||
*is_new = true;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
if (is_new) {
|
||||
*is_new = false;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PBD::info << "Found cache file: '" << cache_file <<"'" << endmsg;
|
||||
}
|
||||
|
||||
GStatBuf sb_vst;
|
||||
GStatBuf sb_v2i;
|
||||
|
||||
if (g_stat (path.c_str(), &sb_vst) == 0 && g_stat (cache_file.c_str (), &sb_v2i) == 0) {
|
||||
if (sb_vst.st_mtime < sb_v2i.st_mtime) {
|
||||
/* plugin is older than cache file */
|
||||
if (verbose) {
|
||||
PBD::info << "Cache file is up-to-date." << endmsg;
|
||||
}
|
||||
return cache_file;
|
||||
} else if (verbose) {
|
||||
PBD::info << "Stale cache." << endmsg;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static void
|
||||
touch_cachefile (std::string const& path, std::string const& cache_file)
|
||||
{
|
||||
GStatBuf sb_vst;
|
||||
GStatBuf sb_v2i;
|
||||
if (g_stat (path.c_str(), &sb_vst) == 0 && g_stat (cache_file.c_str (), &sb_v2i) == 0) {
|
||||
struct utimbuf utb;
|
||||
utb.actime = sb_v2i.st_atime;
|
||||
utb.modtime = std::max (sb_vst.st_mtime, sb_v2i.st_mtime);
|
||||
g_utime (cache_file.c_str (), &utb);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
vst2_save_cache_file (std::string const& path, XMLNode* root, bool verbose)
|
||||
{
|
||||
string const cache_file = ARDOUR::vst2_cache_file (path);
|
||||
|
||||
XMLTree tree;
|
||||
tree.set_root (root);
|
||||
if (!tree.write (cache_file)) {
|
||||
PBD::error << "Could not save VST2 plugin cache to: " << cache_file << endmsg;
|
||||
return false;
|
||||
} else {
|
||||
touch_cachefile (path, cache_file);
|
||||
}
|
||||
if (verbose) {
|
||||
root->dump (std::cout, "\t");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ARDOUR::vst2_scan_and_cache (std::string const& path, ARDOUR::PluginType type, boost::function<void (std::string const&, PluginType, VST2Info const&)> cb, bool verbose)
|
||||
{
|
||||
XMLNode* root = new XMLNode ("VST2Cache");
|
||||
root->set_property ("version", 1);
|
||||
root->set_property ("binary", path);
|
||||
root->set_property ("arch", vst2_arch ());
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
if (type == ARDOUR::Windows_VST) {
|
||||
PBD::info << "File type: " << dll_info (path) << endmsg;
|
||||
}
|
||||
#endif
|
||||
|
||||
try {
|
||||
std::vector<VST2Info> nfo;
|
||||
if (!discover_vst2 (path, type, nfo, verbose)) {
|
||||
delete root;
|
||||
return false;
|
||||
}
|
||||
if (nfo.empty ()) {
|
||||
cerr << "No plugins in VST2 plugin: '" << path << "'\n";
|
||||
delete root;
|
||||
return false;
|
||||
}
|
||||
for (std::vector<VST2Info>::const_iterator i = nfo.begin(); i != nfo.end(); ++i) {
|
||||
cb (path, type, *i);
|
||||
root->add_child_nocopy (i->state ());
|
||||
}
|
||||
} catch (...) {
|
||||
cerr << "Cannot load VST2 plugin: '" << path << "'\n";
|
||||
delete root;
|
||||
return false;
|
||||
}
|
||||
|
||||
return vst2_save_cache_file (path, root, verbose);
|
||||
}
|
||||
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
VST2Info::VST2Info (XMLNode const& node)
|
||||
: id (0)
|
||||
, n_inputs (0)
|
||||
, n_outputs (0)
|
||||
, n_midi_inputs (0)
|
||||
, n_midi_outputs (0)
|
||||
, is_instrument (false)
|
||||
, can_process_replace (false)
|
||||
, has_editor (false)
|
||||
{
|
||||
bool err = false;
|
||||
|
||||
if (node.name() != "VST2Info") {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
err |= !node.get_property ("id", id);
|
||||
err |= !node.get_property ("name", name);
|
||||
err |= !node.get_property ("creator", creator);
|
||||
err |= !node.get_property ("category", category);
|
||||
err |= !node.get_property ("version", version);
|
||||
|
||||
err |= !node.get_property ("n_inputs", n_inputs);
|
||||
err |= !node.get_property ("n_outputs", n_outputs);
|
||||
err |= !node.get_property ("n_midi_inputs", n_midi_inputs);
|
||||
err |= !node.get_property ("n_midi_outputs", n_midi_outputs);
|
||||
|
||||
err |= !node.get_property ("is_instrument", is_instrument);
|
||||
err |= !node.get_property ("can_process_replace", can_process_replace);
|
||||
err |= !node.get_property ("has_editor", has_editor);
|
||||
|
||||
if (err) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
VST2Info::state () const
|
||||
{
|
||||
XMLNode* node = new XMLNode("VST2Info");
|
||||
node->set_property ("id", id);
|
||||
node->set_property ("name", name);
|
||||
node->set_property ("creator", creator);
|
||||
node->set_property ("category", category);
|
||||
node->set_property ("version", version);
|
||||
|
||||
node->set_property ("n_inputs", n_inputs);
|
||||
node->set_property ("n_outputs", n_outputs);
|
||||
node->set_property ("n_midi_inputs", n_midi_inputs);
|
||||
node->set_property ("n_midi_outputs", n_midi_outputs);
|
||||
|
||||
node->set_property ("is_instrument", is_instrument);
|
||||
node->set_property ("can_process_replace", can_process_replace);
|
||||
node->set_property ("has_editor", has_editor);
|
||||
return *node;
|
||||
}
|
||||
|
@ -1,175 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#include <sys/utime.h>
|
||||
#else
|
||||
#include <strings.h>
|
||||
#include <utime.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "pbd/pbd.h"
|
||||
#include "pbd/transmitter.h"
|
||||
#include "pbd/receiver.h"
|
||||
#include "pbd/win_console.h"
|
||||
|
||||
#ifdef __MINGW64__
|
||||
#define NO_OLDNAMES // no backwards compat _pid_t, conflict with w64 pthread/sched
|
||||
#endif
|
||||
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#ifdef LXVST_SUPPORT
|
||||
#include "ardour/linux_vst_support.h"
|
||||
#endif
|
||||
#include "ardour/vst_info_file.h"
|
||||
|
||||
/* make stupid waf happy.
|
||||
* waf cannot build multiple variants of .o object files from the same
|
||||
* source using different wscripts.. it mingles e.g.
|
||||
* build/libs/ardour/vst_info_file.cc.1.o for
|
||||
* both lib/ardour/wscript and lib/fst/wscript
|
||||
*
|
||||
* ...but waf does track include dependencies.
|
||||
*/
|
||||
#include "../ardour/vst_info_file.cc"
|
||||
#ifdef LXVST_SUPPORT
|
||||
#include "../ardour/linux_vst_support.cc"
|
||||
#endif
|
||||
#ifdef MACVST_SUPPORT
|
||||
#include "../ardour/mac_vst_support.cc"
|
||||
#endif
|
||||
#include "../ardour/filesystem_paths.cc"
|
||||
#include "../ardour/directory_names.cc"
|
||||
|
||||
#include "../ardour/vst_state.cc"
|
||||
|
||||
#ifdef LXVST_SUPPORT
|
||||
void
|
||||
vstfx_destroy_editor (VSTState* /*vstfx*/) { }
|
||||
#endif
|
||||
|
||||
using namespace PBD;
|
||||
|
||||
class DummyReceiver : public Receiver {
|
||||
protected:
|
||||
void receive (Transmitter::Channel chn, const char * str) {
|
||||
const char *prefix = "";
|
||||
switch (chn) {
|
||||
case Transmitter::Debug:
|
||||
/* ignore */
|
||||
return;
|
||||
case Transmitter::Info:
|
||||
/* ignore */
|
||||
return;
|
||||
case Transmitter::Warning:
|
||||
prefix = "[WARNING]: ";
|
||||
break;
|
||||
case Transmitter::Error:
|
||||
prefix = "[ERROR]: ";
|
||||
break;
|
||||
case Transmitter::Fatal:
|
||||
prefix = "[FATAL]: ";
|
||||
break;
|
||||
case Transmitter::Throw:
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cerr << prefix << str << std::endl;
|
||||
|
||||
if (chn == Transmitter::Fatal) {
|
||||
console_madness_end ();
|
||||
::exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DummyReceiver dummy_receiver;
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
char *dllpath = NULL;
|
||||
console_madness_begin ();
|
||||
|
||||
if (argc == 3 && !strcmp("-f", argv[1])) {
|
||||
dllpath = argv[2];
|
||||
const size_t slen = strlen (dllpath);
|
||||
if (
|
||||
(slen > 3 && 0 == g_ascii_strcasecmp (&dllpath[slen-3], ".so"))
|
||||
||
|
||||
(slen > 4 && 0 == g_ascii_strcasecmp (&dllpath[slen-4], ".dll"))
|
||||
) {
|
||||
vstfx_remove_infofile(dllpath);
|
||||
vstfx_un_blacklist(dllpath);
|
||||
}
|
||||
|
||||
}
|
||||
else if (argc != 2) {
|
||||
fprintf(stderr, "usage: %s [-f] <vst>\n", argv[0]);
|
||||
console_madness_end ();
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
dllpath = argv[1];
|
||||
}
|
||||
|
||||
PBD::init();
|
||||
|
||||
dummy_receiver.listen_to (warning);
|
||||
dummy_receiver.listen_to (error);
|
||||
dummy_receiver.listen_to (fatal);
|
||||
|
||||
std::vector<VSTInfo *> *infos = 0;
|
||||
|
||||
const size_t slen = strlen (dllpath);
|
||||
if (0) { }
|
||||
#ifdef LXVST_SUPPORT
|
||||
else if (slen > 3 && 0 == g_ascii_strcasecmp (&dllpath[slen-3], ".so")) {
|
||||
infos = vstfx_get_info_lx(dllpath);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
else if (slen > 4 && 0 == g_ascii_strcasecmp (&dllpath[slen-4], ".dll")) {
|
||||
infos = vstfx_get_info_fst(dllpath);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MACVST_SUPPORT
|
||||
else if (slen > 4 && 0 == g_ascii_strcasecmp (&dllpath[slen-4], ".vst")) {
|
||||
infos = vstfx_get_info_mac(dllpath);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
fprintf(stderr, "'%s' is not a supported VST plugin.\n", dllpath);
|
||||
}
|
||||
|
||||
PBD::cleanup();
|
||||
|
||||
console_madness_end ();
|
||||
|
||||
if (!infos || infos->empty()) {
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
270
libs/fst/vst2-scanner.cc
Normal file
270
libs/fst/vst2-scanner.cc
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef COMPILER_MSVC
|
||||
#include <sys/utime.h>
|
||||
#else
|
||||
#include <utime.h>
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MINGW64__
|
||||
#define NO_OLDNAMES // no backwards compat _pid_t, conflict with w64 pthread/sched
|
||||
#endif
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/transmitter.h"
|
||||
#include "pbd/receiver.h"
|
||||
#include "pbd/pbd.h"
|
||||
#include "pbd/win_console.h"
|
||||
#include "pbd/xml++.h"
|
||||
|
||||
#include "ardour/types.h"
|
||||
#include "ardour/vst_types.h"
|
||||
|
||||
#ifdef __MINGW64__
|
||||
#undef NO_OLDNAMES
|
||||
#endif
|
||||
|
||||
#include "../ardour/filesystem_paths.cc"
|
||||
#include "../ardour/vst_state.cc"
|
||||
#include "../ardour/vst2_scan.cc"
|
||||
|
||||
#ifdef LXVST_SUPPORT
|
||||
#include "../ardour/linux_vst_support.cc"
|
||||
void vstfx_destroy_editor (VSTState* /*vstfx*/) { }
|
||||
#endif
|
||||
|
||||
#ifdef MACVST_SUPPORT
|
||||
#include "../ardour/mac_vst_support.cc"
|
||||
#endif
|
||||
|
||||
using namespace PBD;
|
||||
|
||||
class LogReceiver : public Receiver
|
||||
{
|
||||
protected:
|
||||
void receive (Transmitter::Channel chn, const char * str) {
|
||||
const char *prefix = "";
|
||||
switch (chn) {
|
||||
case Transmitter::Debug:
|
||||
/* ignore */
|
||||
break;
|
||||
case Transmitter::Info:
|
||||
prefix = "[Info]: ";
|
||||
break;
|
||||
case Transmitter::Warning:
|
||||
prefix = "[WARNING]: ";
|
||||
break;
|
||||
case Transmitter::Error:
|
||||
prefix = "[ERROR]: ";
|
||||
break;
|
||||
case Transmitter::Fatal:
|
||||
prefix = "[FATAL]: ";
|
||||
break;
|
||||
case Transmitter::Throw:
|
||||
abort ();
|
||||
}
|
||||
|
||||
std::cout << prefix << str << std::endl;
|
||||
|
||||
if (chn == Transmitter::Fatal) {
|
||||
console_madness_end ();
|
||||
::exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LogReceiver log_receiver;
|
||||
|
||||
static void vst2_plugin (std::string const& module_path, PluginType, VST2Info const& i)
|
||||
{
|
||||
info << "Found Plugin: '" << ARDOUR::vst2_id_to_str (i.id) << "' " << i.name << endmsg;
|
||||
}
|
||||
|
||||
static bool
|
||||
scan_vst2 (std::string const& path, ARDOUR::PluginType type, bool force, bool verbose)
|
||||
{
|
||||
info << "Scanning: " << path << endmsg;
|
||||
|
||||
if (!vst2_valid_cache_file (path, verbose).empty()) {
|
||||
if (!force) {
|
||||
info << "Skipping scan." << endmsg;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (vst2_scan_and_cache (path, type, sigc::ptr_fun (&vst2_plugin), verbose)) {
|
||||
info << string_compose (_("Saved VST2 plugin cache to %1"), vst2_cache_file (path)) << endmsg;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
usage ()
|
||||
{
|
||||
// help2man compatible format (standard GNU help-text)
|
||||
printf ("ardour-vst2-scanner - load and index VST2 plugins.\n\n");
|
||||
printf ("Usage: ardour-vst2-scanner [ OPTIONS ] <VST2-file> [VST2-file]*\n\n");
|
||||
printf ("Options:\n\
|
||||
-f, --force Force update of cache file\n\
|
||||
-h, --help Display this help and exit\n\
|
||||
-q, --quiet Hide usual output, only print errors\n\
|
||||
-v, --verbose Give verbose output (unless quiet)\n\
|
||||
-V, --version Print version information and exit\n\
|
||||
\n");
|
||||
|
||||
printf ("\n\
|
||||
This tool ...\n\
|
||||
\n");
|
||||
|
||||
printf ("Report bugs to <http://tracker.ardour.org/>\n"
|
||||
"Website: <http://ardour.org/>\n");
|
||||
|
||||
console_madness_end ();
|
||||
::exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
bool print_log = true;
|
||||
bool stop_on_error = false;
|
||||
bool force = false;
|
||||
bool verbose = false;
|
||||
|
||||
const char* optstring = "fhqvV";
|
||||
|
||||
/* clang-format off */
|
||||
const struct option longopts[] = {
|
||||
{ "force", no_argument, 0, 'f' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ "quiet", no_argument, 0, 'q' },
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "version", no_argument, 0, 'V' },
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
console_madness_begin ();
|
||||
|
||||
int c = 0;
|
||||
while (EOF != (c = getopt_long (argc, argv, optstring, longopts, (int*)0))) {
|
||||
switch (c) {
|
||||
case 'V':
|
||||
printf ("ardour-vst2-scanner version %s\n\n", VERSIONSTRING);
|
||||
printf ("Copyright (C) GPL 2021 Robin Gareus <robin@gareus.org>\n");
|
||||
console_madness_end ();
|
||||
exit (EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
force = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage ();
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
print_log = false;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << "Error: unrecognized option. See --help for usage information.\n";
|
||||
console_madness_end ();
|
||||
::exit (EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind >= argc) {
|
||||
std::cerr << "Error: Missing parameter. See --help for usage information.\n";
|
||||
console_madness_end ();
|
||||
::exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
PBD::init();
|
||||
|
||||
if (print_log) {
|
||||
log_receiver.listen_to (info);
|
||||
log_receiver.listen_to (warning);
|
||||
log_receiver.listen_to (error);
|
||||
log_receiver.listen_to (fatal);
|
||||
} else {
|
||||
verbose = false;
|
||||
}
|
||||
|
||||
bool err = false;
|
||||
|
||||
while (optind < argc) {
|
||||
const char* dllpath = argv[optind++];
|
||||
const size_t slen = strlen (dllpath);
|
||||
ARDOUR::PluginType type;
|
||||
if (false) { }
|
||||
#ifdef LXVST_SUPPORT
|
||||
else if (slen > 3 && 0 == g_ascii_strcasecmp (&dllpath[slen-3], ".so")) {
|
||||
type = ARDOUR::LXVST;
|
||||
}
|
||||
#endif
|
||||
#ifdef WINDOWS_VST_SUPPORT
|
||||
else if (slen > 4 && 0 == g_ascii_strcasecmp (&dllpath[slen-4], ".dll")) {
|
||||
type = ARDOUR::Windows_VST;
|
||||
}
|
||||
#endif
|
||||
#ifdef MACVST_SUPPORT
|
||||
else if (slen > 4 && 0 == g_ascii_strcasecmp (&dllpath[slen-4], ".vst")) {
|
||||
type = ARDOUR::MacVST;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
error << "'" << dllpath << "' is not a supported VST plugin." << endmsg;
|
||||
//fprintf(stderr, "'%s' is not a supported VST plugin.\n", dllpath);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!scan_vst2 (dllpath, type, force, verbose)) {
|
||||
err = true;
|
||||
}
|
||||
if (stop_on_error) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PBD::cleanup();
|
||||
|
||||
console_madness_end ();
|
||||
|
||||
if (err) {
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
@ -59,16 +59,16 @@ def build(bld):
|
||||
|
||||
if bld.is_defined('WINDOWS_VST_SUPPORT') or bld.is_defined('LXVST_SUPPORT') or bld.is_defined ('MACVST_SUPPORT'):
|
||||
obj = bld (features = 'cxx c cxxprogram')
|
||||
obj.source = ( 'scanner.cc' )
|
||||
obj.source = ( 'vst2-scanner.cc' )
|
||||
obj.target = 'ardour-vst-scanner'
|
||||
if bld.is_defined('WINDOWS_VST_SUPPORT'):
|
||||
bld (features = 'c', name='vstwin', source='vstwin.c', uselib = 'GIOMM', includes = [ '../pbd/', '../ardour/', '.' ])
|
||||
obj.uselib = ['GIOMM', 'DL', 'GDI32']
|
||||
obj.uselib = ['GIOMM', 'DL', 'GDI32', 'XML']
|
||||
obj.linkflags = ['-mwindows']
|
||||
obj.use = [ 'libpbd', 'vstwin' ]
|
||||
obj.use = [ 'libpbd', 'libtemporal', 'libevoral', 'vstwin' ]
|
||||
else:
|
||||
obj.uselib = ['GIOMM', 'DL', 'OSX', 'XML' ]
|
||||
obj.use = [ 'libpbd' ]
|
||||
obj.use = [ 'libpbd', 'libtemporal', 'libevoral' ]
|
||||
|
||||
obj.includes = [ '../pbd/', '../ardour/', '.' ]
|
||||
obj.defines = [
|
||||
@ -77,6 +77,7 @@ def build(bld):
|
||||
'VST_SCANNER_APP',
|
||||
'PACKAGE="' + I18N_PACKAGE + str(bld.env['MAJOR']) + '"',
|
||||
'LIBARDOUR="' + bld.env['lwrcase_dirname'] + '"',
|
||||
'VERSIONSTRING="' + str(bld.env['VERSION']) + '"',
|
||||
]
|
||||
if re.search ("bsd", sys.platform) != None:
|
||||
obj.defines.append('_POSIX_C_SOURCE=200809')
|
||||
|
Loading…
Reference in New Issue
Block a user