AU: standalone scanner tool
This commit is contained in:
parent
b166db5496
commit
d4212da693
49
gtk2_ardour/arauv2
Executable file
49
gtk2_ardour/arauv2
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/auscan/ardour-au-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/auscan/ardour-au-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/auscan/ardour-au-scanner "$@"
|
||||
fi
|
||||
|
||||
if test -n "`which gdb`"; then
|
||||
exec gdb --args $TOP/build/libs/auscan/ardour-au-scanner "$@"
|
||||
fi
|
||||
if test -n "`which lldb`"; then
|
||||
exec lldb -- $TOP/build/libs/auscan/ardour-au-scanner "$@"
|
||||
fi
|
103
libs/ardour/ardour/auv2_scan.h
Normal file
103
libs/ardour/ardour/auv2_scan.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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_auv2_scan_h_
|
||||
#define _ardour_auv2_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 AUv2Info {
|
||||
AUv2Info ()
|
||||
: version (0)
|
||||
, n_inputs (0)
|
||||
, n_outputs (0)
|
||||
, n_midi_inputs (0)
|
||||
, n_midi_outputs (0)
|
||||
, max_outputs (0)
|
||||
{}
|
||||
|
||||
AUv2Info (XMLNode const&);
|
||||
XMLNode& state () const;
|
||||
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string creator;
|
||||
std::string category;
|
||||
|
||||
uint32_t version;
|
||||
|
||||
int n_inputs;
|
||||
int n_outputs;
|
||||
int n_midi_inputs; // has_midi_in
|
||||
int n_midi_outputs; // == 0
|
||||
|
||||
int max_outputs;
|
||||
|
||||
std::vector<std::pair<int,int> > io_configs;
|
||||
|
||||
};
|
||||
|
||||
class AUv2DescStr {
|
||||
public:
|
||||
AUv2DescStr (std::string const& desc = "");
|
||||
|
||||
CAComponentDescription desc () const;
|
||||
std::string to_s () const;
|
||||
bool valid () const;
|
||||
|
||||
std::string type;
|
||||
std::string subt;
|
||||
std::string manu;
|
||||
};
|
||||
|
||||
LIBARDOUR_API extern void
|
||||
auv2_blacklist (std::string const&);
|
||||
|
||||
LIBARDOUR_API extern void
|
||||
auv2_whitelist (std::string);
|
||||
|
||||
LIBARDOUR_API extern bool
|
||||
auv2_is_blacklisted (std::string const&);
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
auv2_stringify_descriptor (CAComponentDescription const&);
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
auv2_cache_file (CAComponentDescription const&);
|
||||
|
||||
LIBARDOUR_API extern std::string
|
||||
auv2_valid_cache_file (CAComponentDescription const&, bool verbose = false, bool* is_new = NULL);
|
||||
|
||||
LIBARDOUR_API extern bool
|
||||
auv2_scan_and_cache (CAComponentDescription&, boost::function<void (CAComponentDescription const&, AUv2Info const&)> cb, bool verbose = false);
|
||||
|
||||
LIBARDOUR_API extern void
|
||||
auv2_list_plugins (std::vector<AUv2DescStr>& rv);
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
#endif
|
@ -90,6 +90,7 @@ FILE * AUPluginInfo::_crashlog_fd = NULL;
|
||||
bool AUPluginInfo::_scan_only = true;
|
||||
|
||||
|
||||
#if 1 // remove me -> libs/ardour/auv2_scan.cc
|
||||
static void au_blacklist (std::string id)
|
||||
{
|
||||
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
|
||||
@ -160,6 +161,7 @@ static bool is_blacklisted (std::string id)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static OSStatus
|
||||
@ -2458,6 +2460,7 @@ check_and_get_preset_name (ArdourComponent component, const string& pathstr, str
|
||||
}
|
||||
|
||||
|
||||
#if 1 // remove me
|
||||
static void
|
||||
#ifdef COREAUDIO105
|
||||
get_names (CAComponentDescription& comp_desc, std::string& name, std::string& maker)
|
||||
@ -2523,6 +2526,7 @@ get_names (ArdourComponent& comp, std::string& name, std::string& maker)
|
||||
strip_whitespace_edges (name);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string
|
||||
AUPlugin::current_preset() const
|
||||
@ -2910,8 +2914,7 @@ AUPluginInfo::discover_by_description (PluginInfoList& plugs, CAComponentDescrip
|
||||
|
||||
bool has_midi_in = false;
|
||||
|
||||
AUPluginInfoPtr info (new AUPluginInfo
|
||||
(boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
|
||||
AUPluginInfoPtr info (new AUPluginInfo (boost::shared_ptr<CAComponentDescription> (new CAComponentDescription(temp))));
|
||||
|
||||
/* although apple designed the subtype field to be a "category" indicator,
|
||||
its really turned into a plugin ID field for a given manufacturer. Hence
|
||||
@ -3287,6 +3290,7 @@ AUPluginInfo::load_cached_info ()
|
||||
}
|
||||
|
||||
|
||||
#if 1 // code dup ? -> auv2_scan
|
||||
std::string
|
||||
AUPluginInfo::stringify_descriptor (const CAComponentDescription& desc)
|
||||
{
|
||||
@ -3305,6 +3309,7 @@ AUPluginInfo::stringify_descriptor (const CAComponentDescription& desc)
|
||||
|
||||
return s.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
AUPluginInfo::needs_midi_input () const
|
||||
|
733
libs/ardour/auv2_scan.cc
Normal file
733
libs/ardour/auv2_scan.cc
Normal file
@ -0,0 +1,733 @@
|
||||
/*
|
||||
* 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 <utime.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include "pbd/gstdio_compat.h"
|
||||
|
||||
#include "CAAudioUnit.h"
|
||||
#include "CAAUParameter.h"
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <AudioUnit/AudioUnit.h>
|
||||
#include <AudioToolbox/AudioUnitUtilities.h>
|
||||
#ifdef WITH_CARBON
|
||||
#include <Carbon/Carbon.h>
|
||||
#endif
|
||||
|
||||
#ifdef COREAUDIO105
|
||||
#define ArdourComponent Component
|
||||
#define ArdourDescription ComponentDescription
|
||||
#define ArdourFindNext FindNextComponent
|
||||
#else
|
||||
#define ArdourComponent AudioComponent
|
||||
#define ArdourDescription AudioComponentDescription
|
||||
#define ArdourFindNext AudioComponentFindNext
|
||||
#endif
|
||||
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
|
||||
#include "pbd/basename.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/failed_constructor.h"
|
||||
#include "pbd/whitespace.h"
|
||||
|
||||
#include "ardour/filesystem_paths.h"
|
||||
#include "ardour/auv2_scan.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
|
||||
void
|
||||
ARDOUR::auv2_blacklist (std::string const& id)
|
||||
{
|
||||
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
|
||||
FILE* f = NULL;
|
||||
if (! (f = g_fopen (fn.c_str (), "a"))) {
|
||||
error << "Cannot append to AU blacklist for '" << id <<"'\n";
|
||||
return;
|
||||
}
|
||||
assert (id.find ("\n") == string::npos);
|
||||
fprintf (f, "%s\n", id.c_str ());
|
||||
::fclose (f);
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::auv2_whitelist (std::string id)
|
||||
{
|
||||
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
|
||||
if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
|
||||
warning << _("Expected AUv2 Blacklist file does not exist.") << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string bl;
|
||||
try {
|
||||
bl = Glib::file_get_contents (fn);
|
||||
} catch (Glib::FileError const& err) {
|
||||
return;
|
||||
}
|
||||
::g_unlink (fn.c_str ());
|
||||
|
||||
assert (id.find("\n") == string::npos);
|
||||
|
||||
id += "\n"; // add separator
|
||||
const size_t rpl = bl.find (id);
|
||||
if (rpl != string::npos) {
|
||||
bl.replace (rpl, id.size (), "");
|
||||
}
|
||||
|
||||
if (bl.empty ()) {
|
||||
return;
|
||||
}
|
||||
Glib::file_set_contents (fn, bl);
|
||||
}
|
||||
|
||||
bool
|
||||
ARDOUR::auv2_is_blacklisted (std::string const& id)
|
||||
{
|
||||
string fn = Glib::build_filename (ARDOUR::user_cache_directory(), "au_blacklist.txt");
|
||||
if (!Glib::file_test (fn, Glib::FILE_TEST_EXISTS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string bl;
|
||||
try {
|
||||
bl = Glib::file_get_contents (fn);
|
||||
} catch (Glib::FileError const& err) {
|
||||
return false;
|
||||
}
|
||||
return bl.find (id + "\n") != string::npos;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
ARDOUR::AUv2DescStr::AUv2DescStr (std::string const& desc)
|
||||
{
|
||||
if (desc.empty ()) {
|
||||
return;
|
||||
}
|
||||
if (desc.size () == 14 && desc[4] == '-' && desc[9] == '-') {
|
||||
type = desc.substr (0,4);
|
||||
subt = desc.substr (5,4);
|
||||
manu = desc.substr (10,4);
|
||||
}
|
||||
if (!valid ()) {
|
||||
type = "";
|
||||
subt = "";
|
||||
manu = "";
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
ARDOUR::AUv2DescStr::to_s () const
|
||||
{
|
||||
return type + "-" + subt + "-" + manu;
|
||||
}
|
||||
|
||||
bool
|
||||
ARDOUR::AUv2DescStr::valid () const {
|
||||
return type.size () == 4 && subt.size() == 4 && manu.size() == 4;
|
||||
}
|
||||
|
||||
CAComponentDescription
|
||||
ARDOUR::AUv2DescStr::desc () const {
|
||||
|
||||
CFStringRef s_type = CFStringCreateWithCString (kCFAllocatorDefault, type.c_str(), kCFStringEncodingUTF8);
|
||||
CFStringRef s_subt = CFStringCreateWithCString (kCFAllocatorDefault, subt.c_str(), kCFStringEncodingUTF8);
|
||||
CFStringRef s_manu = CFStringCreateWithCString (kCFAllocatorDefault, manu.c_str(), kCFStringEncodingUTF8);
|
||||
|
||||
OSType t = UTGetOSTypeFromString (s_type);
|
||||
OSType s = UTGetOSTypeFromString (s_subt);
|
||||
OSType m = UTGetOSTypeFromString (s_manu);
|
||||
|
||||
CAComponentDescription desc (t, s, m);
|
||||
|
||||
CFRelease (s_type);
|
||||
CFRelease (s_subt);
|
||||
CFRelease (s_manu);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
/* copied from ardour/utils.cc */
|
||||
static string
|
||||
CFStringRefToStdString(CFStringRef stringRef)
|
||||
{
|
||||
CFIndex size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(stringRef) , kCFStringEncodingUTF8);
|
||||
char *buf = new char[size];
|
||||
|
||||
std::string result;
|
||||
|
||||
if(CFStringGetCString(stringRef, buf, size, kCFStringEncodingUTF8)) {
|
||||
result = buf;
|
||||
}
|
||||
delete [] buf;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string
|
||||
ARDOUR::auv2_stringify_descriptor (CAComponentDescription const& desc)
|
||||
{
|
||||
CFStringRef s_type = UTCreateStringForOSType (desc.Type ());
|
||||
CFStringRef s_subt = UTCreateStringForOSType (desc.SubType ());
|
||||
CFStringRef s_manu = UTCreateStringForOSType (desc.Manu ());
|
||||
|
||||
ARDOUR::AUv2DescStr foo;
|
||||
if (s_type && s_subt && s_manu) {
|
||||
char tmp[5];
|
||||
CFStringGetCString (s_type, tmp, 5, kCFStringEncodingUTF8);
|
||||
foo.type = tmp;
|
||||
CFStringGetCString (s_subt, tmp, 5, kCFStringEncodingUTF8);
|
||||
foo.subt = tmp;
|
||||
CFStringGetCString (s_manu, tmp, 5, kCFStringEncodingUTF8);
|
||||
foo.manu = tmp;
|
||||
} else {
|
||||
assert (0);
|
||||
}
|
||||
|
||||
CFRelease (s_type);
|
||||
CFRelease (s_subt);
|
||||
CFRelease (s_manu);
|
||||
|
||||
return foo.to_s ();
|
||||
}
|
||||
|
||||
static void
|
||||
#ifdef COREAUDIO105
|
||||
get_names (CAComponentDescription& comp_desc, std::string& name, std::string& maker)
|
||||
#else
|
||||
get_names (ArdourComponent& comp, std::string& name, std::string& maker)
|
||||
#endif
|
||||
{
|
||||
CFStringRef itemName = NULL;
|
||||
// Marc Poirier-style item name
|
||||
#ifdef COREAUDIO105
|
||||
CAComponent auComponent (comp_desc);
|
||||
if (auComponent.IsValid()) {
|
||||
CAComponentDescription dummydesc;
|
||||
Handle nameHandle = NewHandle(sizeof(void*));
|
||||
if (nameHandle != NULL) {
|
||||
OSErr err = GetComponentInfo(auComponent.Comp(), &dummydesc, nameHandle, NULL, NULL);
|
||||
if (err == noErr) {
|
||||
ConstStr255Param nameString = (ConstStr255Param) (*nameHandle);
|
||||
if (nameString != NULL) {
|
||||
itemName = CFStringCreateWithPascalString(kCFAllocatorDefault, nameString, CFStringGetSystemEncoding());
|
||||
}
|
||||
}
|
||||
DisposeHandle(nameHandle);
|
||||
}
|
||||
}
|
||||
#else
|
||||
assert (comp);
|
||||
AudioComponentCopyName (comp, &itemName);
|
||||
#endif
|
||||
|
||||
// if Marc-style fails, do the original way
|
||||
if (itemName == NULL) {
|
||||
#ifndef COREAUDIO105
|
||||
CAComponentDescription comp_desc;
|
||||
AudioComponentGetDescription (comp, &comp_desc);
|
||||
#endif
|
||||
CFStringRef compTypeString = UTCreateStringForOSType(comp_desc.componentType);
|
||||
CFStringRef compSubTypeString = UTCreateStringForOSType(comp_desc.componentSubType);
|
||||
CFStringRef compManufacturerString = UTCreateStringForOSType(comp_desc.componentManufacturer);
|
||||
|
||||
itemName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@ - %@ - %@"),
|
||||
compTypeString, compManufacturerString, compSubTypeString);
|
||||
|
||||
if (compTypeString != NULL)
|
||||
CFRelease(compTypeString);
|
||||
if (compSubTypeString != NULL)
|
||||
CFRelease(compSubTypeString);
|
||||
if (compManufacturerString != NULL)
|
||||
CFRelease(compManufacturerString);
|
||||
}
|
||||
|
||||
string str = CFStringRefToStdString(itemName);
|
||||
string::size_type colon = str.find (':');
|
||||
|
||||
if (colon) {
|
||||
name = str.substr (colon+1);
|
||||
maker = str.substr (0, colon);
|
||||
strip_whitespace_edges (maker);
|
||||
strip_whitespace_edges (name);
|
||||
} else {
|
||||
name = str;
|
||||
maker = "unknown";
|
||||
strip_whitespace_edges (name);
|
||||
}
|
||||
#if 0
|
||||
if (itemName != NULL) {
|
||||
CFRelease(itemName);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
auv2_plugin_info (ArdourComponent& comp, CAComponentDescription& desc, std::vector<ARDOUR::AUv2Info>& rv, bool verbose)
|
||||
{
|
||||
ARDOUR::AUv2Info info;
|
||||
|
||||
switch (desc.Type()) {
|
||||
case kAudioUnitType_Panner:
|
||||
case kAudioUnitType_OfflineEffect:
|
||||
case kAudioUnitType_FormatConverter:
|
||||
//
|
||||
return;
|
||||
case kAudioUnitType_Output:
|
||||
info.category = _("Output");
|
||||
break;
|
||||
case kAudioUnitType_MusicDevice:
|
||||
info.category = _("Instrument");
|
||||
info.n_midi_inputs = 1;
|
||||
break;
|
||||
case kAudioUnitType_MusicEffect:
|
||||
info.category = _("Effect");
|
||||
info.n_midi_inputs = 1;
|
||||
break;
|
||||
case kAudioUnitType_Effect:
|
||||
info.category = _("Effect");
|
||||
break;
|
||||
case kAudioUnitType_Mixer:
|
||||
info.category = _("Mixer");
|
||||
break;
|
||||
case kAudioUnitType_Generator:
|
||||
info.category = _("Generator");
|
||||
break;
|
||||
default:
|
||||
info.category = _("(Unknown)");
|
||||
break;
|
||||
}
|
||||
info.id = ARDOUR::auv2_stringify_descriptor (desc);
|
||||
|
||||
#ifdef COREAUDIO105
|
||||
get_names (desc, info.name, info.creator);
|
||||
#else
|
||||
get_names (comp, info.name, info.creator);
|
||||
#endif
|
||||
|
||||
CAComponent cacomp (desc);
|
||||
|
||||
UInt32 version;
|
||||
#ifdef COREAUDIO105
|
||||
if (cacomp.GetResourceVersion (version) != noErr)
|
||||
#else
|
||||
if (cacomp.GetVersion (version) != noErr)
|
||||
#endif
|
||||
{
|
||||
info.version = 0;
|
||||
}
|
||||
|
||||
info.version = version;
|
||||
info.max_outputs = 0;
|
||||
|
||||
/// DEBUG_TRACE (DEBUG::AudioUnitConfig, "get AU channel info\n");
|
||||
|
||||
CAAudioUnit unit;
|
||||
AUChannelInfo* channel_info;
|
||||
UInt32 cnt;
|
||||
int ret;
|
||||
|
||||
try {
|
||||
if (CAAudioUnit::Open (cacomp, unit) != noErr) {
|
||||
return;
|
||||
}
|
||||
} catch (...) {
|
||||
warning << string_compose (_("Could not load AU plugin %1 - ignored"), info.name) << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = unit.GetChannelInfo (&channel_info, cnt)) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
/* AU is expected to deal with same channel valance in and out */
|
||||
info.io_configs.push_back (pair<int,int> (-1, -1));
|
||||
} else {
|
||||
/* CAAudioUnit::GetChannelInfo silently merges bus formats
|
||||
* check if this was the case and if so, add
|
||||
* bus configs as incremental options.
|
||||
*/
|
||||
Boolean* isWritable = 0;
|
||||
UInt32 dataSize = 0;
|
||||
OSStatus result = AudioUnitGetPropertyInfo (unit.AU(),
|
||||
kAudioUnitProperty_SupportedNumChannels,
|
||||
kAudioUnitScope_Global, 0,
|
||||
&dataSize, isWritable);
|
||||
if (result != noErr && (cacomp.Desc().IsGenerator() || cacomp.Desc().IsMusicDevice())) {
|
||||
/* incrementally add busses */
|
||||
int in = 0;
|
||||
int out = 0;
|
||||
for (uint32_t n = 0; n < cnt; ++n) {
|
||||
in += channel_info[n].inChannels;
|
||||
out += channel_info[n].outChannels;
|
||||
info.io_configs.push_back (pair<int,int> (in, out));
|
||||
}
|
||||
} else {
|
||||
/* store each configuration */
|
||||
for (uint32_t n = 0; n < cnt; ++n) {
|
||||
info.io_configs.push_back (pair<int,int> (channel_info[n].inChannels, channel_info[n].outChannels));
|
||||
}
|
||||
}
|
||||
|
||||
free (channel_info);
|
||||
}
|
||||
|
||||
/* here we have to map apple's wildcard system to a simple pair
|
||||
* of values. in ::can_do() we use the whole system, but here
|
||||
* we need a single pair of values. XXX probably means we should
|
||||
* remove any use of these values.
|
||||
*
|
||||
* for now, if the plugin provides a wildcard, treat it as 1. we really
|
||||
* don't care much, because whether we can handle an i/o configuration
|
||||
* depends upon ::configure_variable_io(), not these counts.
|
||||
*
|
||||
* they exist because other parts of ardour try to present i/o configuration
|
||||
* info to the user, which should perhaps be revisited.
|
||||
*/
|
||||
|
||||
const vector<pair<int,int> >& ioc (info.io_configs);
|
||||
for (vector<pair<int,int> >::const_iterator i = ioc.begin(); i != ioc.end(); ++i) {
|
||||
int32_t possible_out = i->second;
|
||||
if (possible_out < 0) {
|
||||
continue;
|
||||
} else if (possible_out > info.max_outputs) {
|
||||
info.max_outputs = possible_out;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t possible_in = ioc.front().first;
|
||||
int32_t possible_out = ioc.front().second;
|
||||
|
||||
if (possible_in > 0) {
|
||||
info.n_inputs = possible_in;
|
||||
} else {
|
||||
info.n_inputs = 1;
|
||||
}
|
||||
|
||||
if (possible_out > 0) {
|
||||
info.n_outputs = possible_out;
|
||||
} else {
|
||||
info.n_outputs = 1;
|
||||
}
|
||||
|
||||
//DEBUG_TRACE (DEBUG::AudioUnitConfig, string_compose ("detected AU %1 with %2 i/o configurations - %3\n", info->name.c_str(), info->cache.io_configs.size(), info->unique_id));
|
||||
|
||||
rv.push_back (info);
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
static bool
|
||||
discover_auv2 (CAComponentDescription& desc, std::vector<ARDOUR::AUv2Info>& rv, bool verbose)
|
||||
{
|
||||
ArdourComponent comp = ArdourFindNext (NULL, &desc);
|
||||
|
||||
if (comp == NULL) {
|
||||
error << ("AU was not found.") << endmsg;
|
||||
return false;
|
||||
}
|
||||
|
||||
while (comp != NULL) {
|
||||
CAComponentDescription temp;
|
||||
#ifdef COREAUDIO105
|
||||
GetComponentInfo (comp, &temp, NULL, NULL, NULL);
|
||||
#else
|
||||
AudioComponentGetDescription (comp, &temp);
|
||||
#endif
|
||||
info << ("Component loaded") << endmsg;
|
||||
|
||||
assert (temp.componentType == desc.componentType);
|
||||
assert (temp.componentSubType == desc.componentSubType);
|
||||
assert (temp.componentManufacturer == desc.componentManufacturer);
|
||||
|
||||
auv2_plugin_info (comp, desc, rv, verbose);
|
||||
|
||||
comp = ArdourFindNext (comp, &desc);
|
||||
assert (comp == NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static string
|
||||
auv2_info_cache_dir ()
|
||||
{
|
||||
string dir = Glib::build_filename (ARDOUR::user_cache_directory (), "auv2");
|
||||
/* 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 AudioUnit cache folder '" << dir << "'" << endmsg;
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
#include "sha1.c"
|
||||
|
||||
string
|
||||
ARDOUR::auv2_cache_file (CAComponentDescription const& desc)
|
||||
{
|
||||
std::string id = auv2_stringify_descriptor (desc);
|
||||
char hash[41];
|
||||
Sha1Digest s;
|
||||
sha1_init (&s);
|
||||
sha1_write (&s, (const uint8_t *) id.c_str(), id.size());
|
||||
sha1_result_hash (&s, hash);
|
||||
return Glib::build_filename (auv2_info_cache_dir (), std::string (hash) + std::string (".a2i"));
|
||||
}
|
||||
|
||||
string
|
||||
ARDOUR::auv2_valid_cache_file (CAComponentDescription const& desc, bool verbose, bool* is_new)
|
||||
{
|
||||
string const cache_file = ARDOUR::auv2_cache_file (desc);
|
||||
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) {
|
||||
info << "Found cache file: '" << cache_file <<"'" << endmsg;
|
||||
}
|
||||
|
||||
// TODO check version
|
||||
|
||||
return cache_file;
|
||||
}
|
||||
|
||||
static bool
|
||||
auv2_save_cache_file (CAComponentDescription& desc, XMLNode* root, bool verbose)
|
||||
{
|
||||
string const cache_file = ARDOUR::auv2_cache_file (desc);
|
||||
|
||||
XMLTree tree;
|
||||
tree.set_root (root);
|
||||
if (!tree.write (cache_file)) {
|
||||
error << "Could not save AUv2 plugin cache to: " << cache_file << endmsg;
|
||||
return false;
|
||||
}
|
||||
if (verbose) {
|
||||
root->dump (std::cout, "\t");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ARDOUR::auv2_scan_and_cache (CAComponentDescription& desc, boost::function<void (CAComponentDescription const&, AUv2Info const&)> cb, bool verbose)
|
||||
{
|
||||
XMLNode* root = new XMLNode ("AUv2Cache");
|
||||
root->set_property ("version", 2);
|
||||
|
||||
try {
|
||||
std::vector<AUv2Info> nfo;
|
||||
if (!discover_auv2 (desc, nfo, verbose)) {
|
||||
delete root;
|
||||
return false;
|
||||
}
|
||||
if (nfo.empty ()) {
|
||||
cerr << "No plugins matching ID: '" << auv2_stringify_descriptor (desc) << "'\n";
|
||||
delete root;
|
||||
return false;
|
||||
}
|
||||
for (std::vector<AUv2Info>::const_iterator i = nfo.begin(); i != nfo.end(); ++i) {
|
||||
cb (desc, *i);
|
||||
root->add_child_nocopy (i->state ());
|
||||
}
|
||||
} catch (...) {
|
||||
cerr << "Cannot load AudioUnit plugin: '" << auv2_stringify_descriptor (desc) << "'\n";
|
||||
delete root;
|
||||
return false;
|
||||
}
|
||||
|
||||
return auv2_save_cache_file (desc, root, verbose);
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
static void
|
||||
index_components (std::vector<ARDOUR::AUv2DescStr>& rv, CAComponentDescription &desc)
|
||||
{
|
||||
ArdourComponent comp = 0;
|
||||
do {
|
||||
CAComponentDescription temp;
|
||||
comp = ArdourFindNext (comp, &desc);
|
||||
|
||||
if (!comp) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef COREAUDIO105
|
||||
GetComponentInfo (comp, &temp, NULL, NULL, NULL);
|
||||
#else
|
||||
AudioComponentGetDescription (comp, &temp);
|
||||
#endif
|
||||
|
||||
CAComponent cacomp (desc);
|
||||
UInt32 version;
|
||||
#ifdef COREAUDIO105
|
||||
if (cacomp.GetResourceVersion (version) != noErr)
|
||||
#else
|
||||
if (cacomp.GetVersion (version) != noErr)
|
||||
#endif
|
||||
{
|
||||
version = 0;
|
||||
//continue;
|
||||
}
|
||||
|
||||
switch (temp.Type()) {
|
||||
case kAudioUnitType_Panner:
|
||||
case kAudioUnitType_OfflineEffect:
|
||||
case kAudioUnitType_FormatConverter:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CFStringRef s_type = UTCreateStringForOSType (temp.componentType);
|
||||
CFStringRef s_subt = UTCreateStringForOSType (temp.componentSubType);
|
||||
CFStringRef s_manu = UTCreateStringForOSType (temp.componentManufacturer);
|
||||
|
||||
if (s_type && s_subt && s_manu) {
|
||||
ARDOUR::AUv2DescStr foo;
|
||||
char tmp[5];
|
||||
CFStringGetCString (s_type, tmp, 5, kCFStringEncodingUTF8);
|
||||
foo.type = tmp;
|
||||
CFStringGetCString (s_subt, tmp, 5, kCFStringEncodingUTF8);
|
||||
foo.subt = tmp;
|
||||
CFStringGetCString (s_manu, tmp, 5, kCFStringEncodingUTF8);
|
||||
foo.manu = tmp;
|
||||
// TODO add version
|
||||
rv.push_back (foo);
|
||||
}
|
||||
|
||||
CFRelease (s_type);
|
||||
CFRelease (s_subt);
|
||||
CFRelease (s_manu);
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::auv2_list_plugins (std::vector<AUv2DescStr>& rv)
|
||||
{
|
||||
CAComponentDescription desc;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentSubType = 0;
|
||||
desc.componentManufacturer = 0;
|
||||
|
||||
desc.componentType = kAudioUnitType_Effect;
|
||||
index_components (rv, desc);
|
||||
|
||||
desc.componentType = kAudioUnitType_MusicEffect;
|
||||
index_components (rv, desc);
|
||||
|
||||
desc.componentType = kAudioUnitType_Generator;
|
||||
index_components (rv, desc);
|
||||
|
||||
desc.componentType = kAudioUnitType_MusicDevice;
|
||||
index_components (rv, desc);
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
AUv2Info::AUv2Info (XMLNode const& node)
|
||||
: version (0)
|
||||
, n_inputs (0)
|
||||
, n_outputs (0)
|
||||
, n_midi_inputs (0)
|
||||
, n_midi_outputs (0)
|
||||
, max_outputs (0)
|
||||
{
|
||||
bool err = false;
|
||||
|
||||
if (node.name() != "AUv2Info") {
|
||||
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 ("max_outputs", max_outputs);
|
||||
|
||||
const XMLNodeList children = node.children();
|
||||
for (XMLNodeConstIterator i = children.begin(); i != children.end(); ++i) {
|
||||
if ((*i)->name() != X_("io_config")) {
|
||||
continue;
|
||||
}
|
||||
int32_t in;
|
||||
int32_t out;
|
||||
if ((*i)->get_property (X_("in"), in) && (*i)->get_property (X_("out"), out)) {
|
||||
io_configs.push_back (std::pair<int,int> (in, out));
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
throw failed_constructor ();
|
||||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
AUv2Info::state () const
|
||||
{
|
||||
XMLNode* node = new XMLNode("AUv2Info");
|
||||
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 ("max_outputs", max_outputs);
|
||||
|
||||
for (vector<pair<int, int> >::const_iterator i = io_configs.begin(); i != io_configs.end(); ++i) {
|
||||
XMLNode* child = new XMLNode (X_("io_config"));
|
||||
child->set_property (X_("in"), i->first);
|
||||
child->set_property (X_("out"), i->second);
|
||||
node->add_child_nocopy (*child);
|
||||
}
|
||||
return *node;
|
||||
}
|
@ -473,7 +473,7 @@ def build(bld):
|
||||
obj.use += ['libappleutility']
|
||||
|
||||
if bld.is_defined('AUDIOUNIT_SUPPORT'):
|
||||
obj.source += [ 'audio_unit.cc' ]
|
||||
obj.source += [ 'audio_unit.cc', 'auv2_scan.cc' ]
|
||||
|
||||
avx_sources = []
|
||||
fma_sources = []
|
||||
|
216
libs/auscan/au-scanner.cc
Normal file
216
libs/auscan/au-scanner.cc
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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 <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <getopt.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/transmitter.h"
|
||||
#include "pbd/receiver.h"
|
||||
#include "pbd/pbd.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "../ardour/auv2_scan.cc"
|
||||
#include "../ardour/filesystem_paths.cc"
|
||||
|
||||
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) {
|
||||
::exit (EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LogReceiver log_receiver;
|
||||
|
||||
static void auv2_plugin (CAComponentDescription const&, AUv2Info const& i)
|
||||
{
|
||||
info << "Found Plugin: '" << i.id << "' " << i.name << endmsg;
|
||||
}
|
||||
|
||||
static bool
|
||||
scan_auv2 (CAComponentDescription& desc, bool force, bool verbose)
|
||||
{
|
||||
info << "Scanning AU: " << desc.Type () << "-" << desc.SubType () << "-" << desc.Manu() << endmsg;
|
||||
|
||||
if (!auv2_valid_cache_file (desc, verbose).empty ()) {
|
||||
if (!force) {
|
||||
info << "Skipping scan." << endmsg;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (auv2_scan_and_cache (desc, sigc::ptr_fun (&auv2_plugin), verbose)) {
|
||||
info << string_compose (_("Saved AUV2 plugin cache to %1"), auv2_cache_file (desc)) << endmsg;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
usage ()
|
||||
{
|
||||
// help2man compatible format (standard GNU help-text)
|
||||
printf ("ardour-au-scanner - load and index AudioUnit plugins.\n\n");
|
||||
printf ("Usage: ardour-au-scanner [ OPTIONS ] <TYPE> <SUBT> <MANU>\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");
|
||||
|
||||
::exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
bool print_log = true;
|
||||
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 */
|
||||
|
||||
int c = 0;
|
||||
while (EOF != (c = getopt_long (argc, argv, optstring, longopts, (int*)0))) {
|
||||
switch (c) {
|
||||
case 'V':
|
||||
printf ("ardour-au-scanner version %s\n\n", VERSIONSTRING);
|
||||
printf ("Copyright (C) GPL 2021 Robin Gareus <robin@gareus.org>\n");
|
||||
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";
|
||||
::exit (EXIT_FAILURE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind + 3 != argc) {
|
||||
std::cerr << "Error: Missing parameter. See --help for usage information.\n";
|
||||
::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;
|
||||
|
||||
CFStringRef s_type = CFStringCreateWithCString (kCFAllocatorDefault, argv[optind++], kCFStringEncodingUTF8);
|
||||
CFStringRef s_subt = CFStringCreateWithCString (kCFAllocatorDefault, argv[optind++], kCFStringEncodingUTF8);
|
||||
CFStringRef s_manu = CFStringCreateWithCString (kCFAllocatorDefault, argv[optind], kCFStringEncodingUTF8);
|
||||
|
||||
OSType type = UTGetOSTypeFromString (s_type);
|
||||
OSType subt = UTGetOSTypeFromString (s_subt);
|
||||
OSType manu = UTGetOSTypeFromString (s_manu);
|
||||
|
||||
CAComponentDescription desc (type, subt, manu);
|
||||
|
||||
if (!scan_auv2 (desc, force, verbose)) {
|
||||
err = true;
|
||||
}
|
||||
|
||||
CFRelease (s_type);
|
||||
CFRelease (s_subt);
|
||||
CFRelease (s_manu);
|
||||
|
||||
PBD::cleanup();
|
||||
|
||||
if (err) {
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
37
libs/auscan/wscript
Normal file
37
libs/auscan/wscript
Normal file
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
from waflib.extras import autowaf as autowaf
|
||||
from waflib import TaskGen
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Mandatory variables
|
||||
top = '.'
|
||||
out = 'build'
|
||||
|
||||
# needed for code used from libardour
|
||||
I18N_PACKAGE = 'ardour'
|
||||
|
||||
def options(opt):
|
||||
autowaf.set_options(opt)
|
||||
|
||||
def configure(conf):
|
||||
conf.load('compiler_cxx')
|
||||
autowaf.configure(conf)
|
||||
|
||||
def build(bld):
|
||||
if bld.is_defined('AUDIOUNIT_SUPPORT'):
|
||||
obj = bld (features = 'cxx c cxxprogram')
|
||||
obj.source = 'au-scanner.cc'
|
||||
obj.target = 'ardour-au-scanner'
|
||||
obj.includes = [ '../pbd/', '../ardour/', '..' ]
|
||||
obj.defines = [
|
||||
'AU_SCANNER_APP',
|
||||
'VERSIONSTRING="' + str(bld.env['VERSION']) + '"',
|
||||
'PACKAGE="' + I18N_PACKAGE + str(bld.env['MAJOR']) + '"',
|
||||
'LIBARDOUR="' + bld.env['lwrcase_dirname'] + '"',
|
||||
'LOCALEDIR="' + os.path.join(os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
|
||||
]
|
||||
obj.use = [ 'libpbd', 'libappleutility', 'libtemporal', 'libevoral' ]
|
||||
obj.uselib = 'GIOMM DL UUID ARCHIVE CURL XML COREAUDIO AUDIOUNITS OSX'
|
||||
obj.install_path = os.path.join(bld.env['LIBDIR'])
|
||||
obj.cxxflags = ['-Wno-deprecated-declarations']
|
Loading…
Reference in New Issue
Block a user