mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-15 19:16:40 +01:00
VST3: Implement host classes
This commit is contained in:
parent
9bd8c43693
commit
84a86fa21a
3 changed files with 1199 additions and 1 deletions
414
libs/ardour/ardour/vst3_host.h
Normal file
414
libs/ardour/ardour/vst3_host.h
Normal file
|
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2020 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_vst3_host_h_
|
||||
#define _ardour_vst3_host_h_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "ardour/libardour_visibility.h"
|
||||
#include "vst3/vst3.h"
|
||||
|
||||
#define QUERY_INTERFACE_IMPL(Interface) \
|
||||
tresult queryInterface (const TUID _iid, void** obj) \
|
||||
{ \
|
||||
QUERY_INTERFACE (_iid, obj, FUnknown::iid, Interface) \
|
||||
QUERY_INTERFACE (_iid, obj, Interface::iid, Interface) \
|
||||
*obj = nullptr; \
|
||||
return kNoInterface; \
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
#endif
|
||||
|
||||
namespace Steinberg {
|
||||
|
||||
LIBARDOUR_API extern std::string tchar_to_utf8 (Vst::TChar const* s);
|
||||
LIBARDOUR_API extern bool utf8_to_tchar (Vst::TChar* rv, const char* s, size_t l = 0);
|
||||
LIBARDOUR_API extern bool utf8_to_tchar (Vst::TChar* rv, std::string const& s, size_t l = 0);
|
||||
|
||||
namespace Vst {
|
||||
/* see public.sdk/source/vst/vstpresetfile.cpp */
|
||||
typedef char ChunkID[4]; // using ChunkID = char[4];
|
||||
static const int32 kClassIDSize = 32; // ASCII-encoded FUID
|
||||
static const int32 kHeaderSize = sizeof (ChunkID) + sizeof (int32) + kClassIDSize + sizeof (TSize);
|
||||
static const int32 kListOffsetPos = kHeaderSize - sizeof (TSize);
|
||||
}
|
||||
|
||||
class LIBARDOUR_API HostAttribute
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
kInteger,
|
||||
kFloat,
|
||||
kString,
|
||||
kBinary
|
||||
};
|
||||
|
||||
HostAttribute (int64 value)
|
||||
: _size (0)
|
||||
, _type (kInteger)
|
||||
{
|
||||
v.intValue = value;
|
||||
}
|
||||
|
||||
HostAttribute (double value)
|
||||
: _size (0)
|
||||
, _type (kFloat)
|
||||
{
|
||||
v.floatValue = value;
|
||||
}
|
||||
|
||||
HostAttribute (const Vst::TChar* value, uint32 size)
|
||||
: _size (size)
|
||||
, _type (kString)
|
||||
{
|
||||
v.stringValue = new Vst::TChar[_size];
|
||||
memcpy (v.stringValue, value, _size * sizeof (Vst::TChar));
|
||||
}
|
||||
|
||||
HostAttribute (const void* value, uint32 size)
|
||||
: _size (size)
|
||||
, _type (kBinary)
|
||||
{
|
||||
v.binaryValue = new char[_size];
|
||||
memcpy (v.binaryValue, value, _size);
|
||||
}
|
||||
|
||||
~HostAttribute ()
|
||||
{
|
||||
if (_size) {
|
||||
delete[] v.binaryValue;
|
||||
}
|
||||
}
|
||||
|
||||
Type getType () const { return _type; }
|
||||
int64 intValue () const { return v.intValue; }
|
||||
double floatValue () const { return v.floatValue; }
|
||||
|
||||
const Vst::TChar* stringValue (uint32& stringSize)
|
||||
{
|
||||
stringSize = _size;
|
||||
return v.stringValue;
|
||||
}
|
||||
|
||||
const void* binaryValue (uint32& binarySize)
|
||||
{
|
||||
binarySize = _size;
|
||||
return v.binaryValue;
|
||||
}
|
||||
|
||||
protected:
|
||||
union v {
|
||||
int64 intValue;
|
||||
double floatValue;
|
||||
Vst::TChar* stringValue;
|
||||
char* binaryValue;
|
||||
} v;
|
||||
|
||||
uint32 _size;
|
||||
Type _type;
|
||||
|
||||
private:
|
||||
/* prevent copy construction */
|
||||
HostAttribute (HostAttribute const& other);
|
||||
};
|
||||
|
||||
class LIBARDOUR_API RefObject : public FUnknown
|
||||
{
|
||||
public:
|
||||
RefObject ();
|
||||
virtual ~RefObject () {}
|
||||
uint32 addRef ();
|
||||
uint32 release ();
|
||||
|
||||
private:
|
||||
gint _cnt; // atomic
|
||||
};
|
||||
|
||||
class LIBARDOUR_API HostAttributeList : public Vst::IAttributeList, public RefObject
|
||||
{
|
||||
public:
|
||||
HostAttributeList ();
|
||||
virtual ~HostAttributeList ();
|
||||
|
||||
QUERY_INTERFACE_IMPL (Vst::IAttributeList);
|
||||
uint32 addRef () SMTG_OVERRIDE { return RefObject::addRef (); }
|
||||
uint32 release () SMTG_OVERRIDE { return RefObject::release (); }
|
||||
|
||||
tresult setInt (AttrID aid, int64 value) SMTG_OVERRIDE;
|
||||
tresult getInt (AttrID aid, int64& value) SMTG_OVERRIDE;
|
||||
tresult setFloat (AttrID aid, double value) SMTG_OVERRIDE;
|
||||
tresult getFloat (AttrID aid, double& value) SMTG_OVERRIDE;
|
||||
tresult setString (AttrID aid, const Vst::TChar* string) SMTG_OVERRIDE;
|
||||
tresult getString (AttrID aid, Vst::TChar* string, uint32 size) SMTG_OVERRIDE;
|
||||
tresult setBinary (AttrID aid, const void* data, uint32 size) SMTG_OVERRIDE;
|
||||
tresult getBinary (AttrID aid, const void*& data, uint32& size) SMTG_OVERRIDE;
|
||||
|
||||
protected:
|
||||
void removeAttrID (AttrID aid);
|
||||
|
||||
std::map<std::string, HostAttribute*> list;
|
||||
};
|
||||
|
||||
class LIBARDOUR_API HostMessage : public Vst::IMessage, public RefObject
|
||||
{
|
||||
public:
|
||||
HostMessage ();
|
||||
virtual ~HostMessage ();
|
||||
|
||||
QUERY_INTERFACE_IMPL (Vst::IMessage);
|
||||
uint32 addRef () SMTG_OVERRIDE { return RefObject::addRef (); }
|
||||
uint32 release () SMTG_OVERRIDE { return RefObject::release (); }
|
||||
|
||||
const char* getMessageID () SMTG_OVERRIDE;
|
||||
void setMessageID (const char* messageID) SMTG_OVERRIDE;
|
||||
Vst::IAttributeList* getAttributes () SMTG_OVERRIDE;
|
||||
|
||||
protected:
|
||||
char* _messageId;
|
||||
boost::shared_ptr<HostAttributeList> _attribute_list;
|
||||
};
|
||||
|
||||
class LIBARDOUR_API PlugInterfaceSupport : public Vst::IPlugInterfaceSupport
|
||||
{
|
||||
public:
|
||||
PlugInterfaceSupport ();
|
||||
QUERY_INTERFACE_IMPL (Vst::IPlugInterfaceSupport);
|
||||
uint32 addRef () SMTG_OVERRIDE { return 1; }
|
||||
uint32 release () SMTG_OVERRIDE { return 1; }
|
||||
|
||||
tresult isPlugInterfaceSupported (const TUID) SMTG_OVERRIDE;
|
||||
void addPlugInterfaceSupported (const TUID);
|
||||
|
||||
private:
|
||||
std::vector<FUID> _interfaces;
|
||||
};
|
||||
|
||||
class LIBARDOUR_API HostApplication : public Vst::IHostApplication
|
||||
{
|
||||
public:
|
||||
static Vst::IHostApplication* getHostContext ()
|
||||
{
|
||||
static HostApplication* app = new HostApplication;
|
||||
return app;
|
||||
}
|
||||
|
||||
HostApplication ();
|
||||
virtual ~HostApplication () {}
|
||||
tresult queryInterface (const TUID _iid, void** obj) SMTG_OVERRIDE;
|
||||
|
||||
uint32 addRef () SMTG_OVERRIDE { return 1; }
|
||||
uint32 release () SMTG_OVERRIDE { return 1; }
|
||||
|
||||
tresult getName (Vst::String128 name) SMTG_OVERRIDE;
|
||||
tresult createInstance (TUID cid, TUID _iid, void** obj) SMTG_OVERRIDE;
|
||||
|
||||
protected:
|
||||
boost::shared_ptr<PlugInterfaceSupport> _plug_interface_support;
|
||||
};
|
||||
|
||||
class LIBARDOUR_LOCAL Vst3ParamValueQueue : public Vst::IParamValueQueue
|
||||
{
|
||||
public:
|
||||
QUERY_INTERFACE_IMPL (Vst::IParamValueQueue);
|
||||
uint32 addRef () SMTG_OVERRIDE { return 1; }
|
||||
uint32 release () SMTG_OVERRIDE { return 1; }
|
||||
|
||||
static const int maxNumPoints = 64;
|
||||
|
||||
Vst3ParamValueQueue() {
|
||||
_values.reserve (maxNumPoints);
|
||||
_id = Vst::kNoParamId;
|
||||
}
|
||||
|
||||
Vst::ParamID getParameterId() SMTG_OVERRIDE { return _id; }
|
||||
|
||||
void setParameterId (Vst::ParamID id) {
|
||||
_values.clear();
|
||||
_id = id;
|
||||
}
|
||||
|
||||
int32 getPointCount() SMTG_OVERRIDE { return _values.size(); }
|
||||
tresult getPoint (int32 index, int32&, Vst::ParamValue&) SMTG_OVERRIDE;
|
||||
tresult addPoint (int32, Vst::ParamValue, int32&) SMTG_OVERRIDE;
|
||||
|
||||
protected:
|
||||
struct Value {
|
||||
Value (Vst::ParamValue v, int32 offset)
|
||||
: value(v)
|
||||
, sampleOffset(offset)
|
||||
{}
|
||||
Vst::ParamValue value;
|
||||
int32 sampleOffset;
|
||||
};
|
||||
|
||||
std::vector<Value> _values;
|
||||
Vst::ParamID _id;
|
||||
};
|
||||
|
||||
class LIBARDOUR_LOCAL Vst3ParameterChanges : public Vst::IParameterChanges
|
||||
{
|
||||
public:
|
||||
QUERY_INTERFACE_IMPL (Vst::IParameterChanges);
|
||||
uint32 addRef () SMTG_OVERRIDE { return 1; }
|
||||
uint32 release () SMTG_OVERRIDE { return 1; }
|
||||
|
||||
Vst3ParameterChanges () {
|
||||
clear ();
|
||||
}
|
||||
|
||||
void set_n_params (int n) {
|
||||
_queue.resize(n);
|
||||
}
|
||||
|
||||
void clear () {
|
||||
_used_queue_count = 0;
|
||||
}
|
||||
|
||||
int32 getParameterCount() SMTG_OVERRIDE {
|
||||
return _used_queue_count;
|
||||
}
|
||||
|
||||
Vst::IParamValueQueue* getParameterData (int32 index) SMTG_OVERRIDE;
|
||||
Vst::IParamValueQueue* addParameterData (Vst::ParamID const& id, int32& index) SMTG_OVERRIDE;
|
||||
|
||||
protected:
|
||||
std::vector<Vst3ParamValueQueue> _queue;
|
||||
int _used_queue_count;
|
||||
};
|
||||
|
||||
class LIBARDOUR_LOCAL Vst3EventList : public Vst::IEventList
|
||||
{
|
||||
public:
|
||||
Vst3EventList() {
|
||||
_events.reserve (128);
|
||||
}
|
||||
|
||||
QUERY_INTERFACE_IMPL (Vst::IEventList)
|
||||
uint32 addRef () SMTG_OVERRIDE { return 1; }
|
||||
uint32 release () SMTG_OVERRIDE { return 1; }
|
||||
|
||||
int32 PLUGIN_API getEventCount() {
|
||||
return _events.size ();
|
||||
}
|
||||
|
||||
tresult PLUGIN_API getEvent (int32 index, Vst::Event& e) {
|
||||
if (index >= 0 && index < (int32)_events.size ()) {
|
||||
e = _events[index];
|
||||
return kResultTrue;
|
||||
} else {
|
||||
return kResultFalse;
|
||||
}
|
||||
}
|
||||
|
||||
tresult PLUGIN_API addEvent (Vst::Event& e) {
|
||||
_events.push_back (e);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_events.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<Vst::Event> _events;
|
||||
};
|
||||
|
||||
class LIBARDOUR_LOCAL RAMStream : public IBStream
|
||||
{
|
||||
public:
|
||||
RAMStream ();
|
||||
RAMStream (uint8_t* data, size_t size);
|
||||
RAMStream (std::string const& fn);
|
||||
|
||||
virtual ~RAMStream ();
|
||||
|
||||
QUERY_INTERFACE_IMPL (IBStream)
|
||||
uint32 addRef () SMTG_OVERRIDE { return 1; }
|
||||
uint32 release () SMTG_OVERRIDE { return 1; }
|
||||
|
||||
/* IBStream API */
|
||||
tresult PLUGIN_API read (void* buffer, int32 numBytes, int32* numBytesRead) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API write (void* buffer, int32 numBytes, int32* numBytesWritten) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API seek (int64 pos, int32 mode, int64* result) SMTG_OVERRIDE;
|
||||
tresult PLUGIN_API tell (int64* pos) SMTG_OVERRIDE;
|
||||
|
||||
/* convenience API for state I/O */
|
||||
void rewind () { _pos = 0; }
|
||||
bool readonly () const { return _readonly; }
|
||||
|
||||
bool write_int32 (int32 i);
|
||||
bool write_int64 (int64 i);
|
||||
bool write_ChunkID (const Vst::ChunkID& id);
|
||||
bool write_TUID (const TUID& tuid);
|
||||
|
||||
bool read_int32 (int32& i);
|
||||
bool read_int64 (int64& i);
|
||||
bool read_ChunkID (Vst::ChunkID& id);
|
||||
bool read_TUID (TUID& tuid);
|
||||
|
||||
/* direct access */
|
||||
uint8_t const* data () const { return _data; }
|
||||
int64 size () const { return _size; }
|
||||
|
||||
#ifndef NDEBUG
|
||||
void hexdump (int64 max_len = 64) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
bool reallocate_buffer (int64 size, bool exact);
|
||||
|
||||
template<typename T> bool read_pod (T& t) {
|
||||
int32 n_read = 0;
|
||||
read ((void *)&t, sizeof(T), &n_read);
|
||||
return n_read == sizeof(T);
|
||||
}
|
||||
|
||||
template<typename T> bool write_pod (const T& t) {
|
||||
int32 written = 0;
|
||||
write (const_cast<void*>((const void *)&t), sizeof(T), &written);
|
||||
return written == sizeof(T);
|
||||
}
|
||||
|
||||
uint8_t* _data;
|
||||
int64 _size;
|
||||
int64 _alloc;
|
||||
int64 _pos;
|
||||
bool _readonly;
|
||||
};
|
||||
|
||||
#if defined(__clang__)
|
||||
# pragma clang diagnostic pop
|
||||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace Steinberg
|
||||
#endif
|
||||
784
libs/ardour/vst3_host.cc
Normal file
784
libs/ardour/vst3_host.cc
Normal file
|
|
@ -0,0 +1,784 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2020 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2019 Steinberg Media Technologies GmbH
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if (__cplusplus >= 201103L)
|
||||
#include <boost/make_unique.hpp>
|
||||
#endif
|
||||
|
||||
#include "ardour/vst3_host.h"
|
||||
|
||||
using namespace Steinberg;
|
||||
|
||||
DEF_CLASS_IID (FUnknown)
|
||||
DEF_CLASS_IID (IBStream)
|
||||
DEF_CLASS_IID (IPluginBase)
|
||||
DEF_CLASS_IID (IPluginFactory)
|
||||
DEF_CLASS_IID (IPluginFactory2)
|
||||
DEF_CLASS_IID (IPlugFrame)
|
||||
DEF_CLASS_IID (IPlugView)
|
||||
DEF_CLASS_IID (Vst::IAttributeList)
|
||||
DEF_CLASS_IID (Vst::IAudioProcessor)
|
||||
DEF_CLASS_IID (Vst::IAutomationState)
|
||||
DEF_CLASS_IID (Vst::IComponent)
|
||||
DEF_CLASS_IID (Vst::IComponentHandler)
|
||||
DEF_CLASS_IID (Vst::IConnectionPoint)
|
||||
DEF_CLASS_IID (Vst::IEditController)
|
||||
DEF_CLASS_IID (Vst::IEventList)
|
||||
DEF_CLASS_IID (Vst::IHostApplication)
|
||||
DEF_CLASS_IID (Vst::IMessage)
|
||||
DEF_CLASS_IID (Vst::IMidiMapping)
|
||||
DEF_CLASS_IID (Vst::IParameterChanges)
|
||||
DEF_CLASS_IID (Vst::IParamValueQueue)
|
||||
DEF_CLASS_IID (Vst::IPlugInterfaceSupport)
|
||||
DEF_CLASS_IID (Vst::IProgramListData)
|
||||
DEF_CLASS_IID (Vst::IUnitData)
|
||||
DEF_CLASS_IID (Vst::IUnitInfo)
|
||||
|
||||
#if SMTG_OS_LINUX
|
||||
DEF_CLASS_IID (Linux::IRunLoop);
|
||||
#endif
|
||||
|
||||
std::string
|
||||
Steinberg::tchar_to_utf8 (Vst::TChar const* s)
|
||||
{
|
||||
glong len;
|
||||
gchar* utf8 = g_utf16_to_utf8 ((const gunichar2*)s, -1, NULL, &len, NULL);
|
||||
if (!utf8 || len == 0) {
|
||||
return "";
|
||||
}
|
||||
std::string rv (utf8, len);
|
||||
g_free (utf8);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool
|
||||
Steinberg::utf8_to_tchar (Vst::TChar* rv, const char* s, size_t l)
|
||||
{
|
||||
glong len;
|
||||
gunichar2* s16 = g_utf8_to_utf16 (s, -1, NULL, &len, NULL);
|
||||
if (!s16 || len == 0) {
|
||||
memset (rv, 0, sizeof (Vst::TChar));
|
||||
return false;
|
||||
}
|
||||
if (l > 0 && l < len) {
|
||||
len = l;
|
||||
}
|
||||
memcpy (rv, s16, len * sizeof (Vst::TChar));
|
||||
g_free (s16);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Steinberg::utf8_to_tchar (Vst::TChar* rv, std::string const& s, size_t l)
|
||||
{
|
||||
return utf8_to_tchar (rv, s.c_str(), l);
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
RefObject::RefObject ()
|
||||
{
|
||||
g_atomic_int_set (&_cnt, 1);
|
||||
}
|
||||
|
||||
uint32
|
||||
RefObject::addRef ()
|
||||
{
|
||||
g_atomic_int_inc (&_cnt);
|
||||
return g_atomic_int_get (&_cnt);
|
||||
}
|
||||
|
||||
uint32
|
||||
RefObject::release ()
|
||||
{
|
||||
if (g_atomic_int_dec_and_test (&_cnt)) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return g_atomic_int_get (&_cnt);
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
/* copy/edit from public.sdk/source/vst/hosting/hostclasses.cpp */
|
||||
/* ****************************************************************************/
|
||||
|
||||
#include "vst3/pluginterfaces/base/funknown.cpp"
|
||||
|
||||
HostAttributeList::HostAttributeList ()
|
||||
{
|
||||
}
|
||||
|
||||
HostAttributeList::~HostAttributeList ()
|
||||
{
|
||||
std::map<std::string, HostAttribute*>::reverse_iterator it = list.rbegin ();
|
||||
while (it != list.rend ()) {
|
||||
delete it->second;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HostAttributeList::removeAttrID (AttrID aid)
|
||||
{
|
||||
std::map<std::string, HostAttribute*>::iterator it = list.find (aid);
|
||||
if (it != list.end ()) {
|
||||
delete it->second;
|
||||
list.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::setInt (AttrID aid, int64 value)
|
||||
{
|
||||
removeAttrID (aid);
|
||||
list[aid] = new HostAttribute (value);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::getInt (AttrID aid, int64& value)
|
||||
{
|
||||
std::map<std::string, HostAttribute*>::iterator it = list.find (aid);
|
||||
if (it != list.end () && it->second) {
|
||||
value = it->second->intValue ();
|
||||
return kResultTrue;
|
||||
}
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::setFloat (AttrID aid, double value)
|
||||
{
|
||||
removeAttrID (aid);
|
||||
list[aid] = new HostAttribute (value);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::getFloat (AttrID aid, double& value)
|
||||
{
|
||||
std::map<std::string, HostAttribute*>::iterator it = list.find (aid);
|
||||
if (it != list.end () && it->second) {
|
||||
value = it->second->floatValue ();
|
||||
return kResultTrue;
|
||||
}
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::setString (AttrID aid, const Vst::TChar* string)
|
||||
{
|
||||
removeAttrID (aid);
|
||||
list[aid] = new HostAttribute (string, wcslen ((const wchar_t*)string));
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::getString (AttrID aid, Vst::TChar* string, uint32 size)
|
||||
{
|
||||
std::map<std::string, HostAttribute*>::iterator it = list.find (aid);
|
||||
if (it != list.end () && it->second) {
|
||||
uint32 stringSize = 0;
|
||||
const Vst::TChar* _string = it->second->stringValue (stringSize);
|
||||
memcpy (string, _string, std::min<uint32> (stringSize, size) * sizeof (Vst::TChar));
|
||||
return kResultTrue;
|
||||
}
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::setBinary (AttrID aid, const void* data, uint32 size)
|
||||
{
|
||||
removeAttrID (aid);
|
||||
list[aid] = new HostAttribute (data, size);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostAttributeList::getBinary (AttrID aid, const void*& data, uint32& size)
|
||||
{
|
||||
std::map<std::string, HostAttribute*>::iterator it = list.find (aid);
|
||||
if (it != list.end () && it->second) {
|
||||
data = it->second->binaryValue (size);
|
||||
return kResultTrue;
|
||||
}
|
||||
size = 0;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
HostMessage::HostMessage ()
|
||||
: _messageId (0)
|
||||
{
|
||||
}
|
||||
|
||||
HostMessage::~HostMessage ()
|
||||
{
|
||||
setMessageID (0);
|
||||
if (_attribute_list) {
|
||||
//_attribute_list->release ();
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
HostMessage::getMessageID ()
|
||||
{
|
||||
return _messageId;
|
||||
}
|
||||
|
||||
void
|
||||
HostMessage::setMessageID (const char* mid)
|
||||
{
|
||||
if (_messageId) {
|
||||
delete[] _messageId;
|
||||
}
|
||||
if (mid) {
|
||||
size_t len = strlen (mid) + 1;
|
||||
_messageId = new char[len];
|
||||
strcpy (_messageId, mid);
|
||||
} else {
|
||||
_messageId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Vst::IAttributeList*
|
||||
HostMessage::getAttributes ()
|
||||
{
|
||||
if (!_attribute_list) {
|
||||
_attribute_list.reset (new HostAttributeList);
|
||||
}
|
||||
return _attribute_list.get ();
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
PlugInterfaceSupport::PlugInterfaceSupport ()
|
||||
{
|
||||
using namespace Vst;
|
||||
|
||||
//---VST 3.0.0--------------------------------
|
||||
addPlugInterfaceSupported (IComponent::iid);
|
||||
addPlugInterfaceSupported (IAudioProcessor::iid);
|
||||
addPlugInterfaceSupported (IEditController::iid);
|
||||
addPlugInterfaceSupported (IConnectionPoint::iid);
|
||||
|
||||
addPlugInterfaceSupported (IUnitInfo::iid);
|
||||
addPlugInterfaceSupported (IUnitData::iid);
|
||||
addPlugInterfaceSupported (IProgramListData::iid);
|
||||
|
||||
//---VST 3.0.1--------------------------------
|
||||
addPlugInterfaceSupported (IMidiMapping::iid);
|
||||
|
||||
#if 0
|
||||
//---VST 3.1----------------------------------
|
||||
addPlugInterfaceSupported (IEditController2::iid);
|
||||
|
||||
//---VST 3.0.2--------------------------------
|
||||
addPlugInterfaceSupported (IParameterFinder::iid);
|
||||
|
||||
//---VST 3.1----------------------------------
|
||||
addPlugInterfaceSupported (IAudioPresentationLatency::iid);
|
||||
|
||||
//---VST 3.5----------------------------------
|
||||
addPlugInterfaceSupported (IKeyswitchController::iid);
|
||||
addPlugInterfaceSupported (IContextMenuTarget::iid);
|
||||
addPlugInterfaceSupported (IEditControllerHostEditing::iid);
|
||||
addPlugInterfaceSupported (IXmlRepresentationController::iid);
|
||||
addPlugInterfaceSupported (INoteExpressionController::iid);
|
||||
|
||||
//---VST 3.6.5--------------------------------
|
||||
addPlugInterfaceSupported (ChannelContext::IInfoListener::iid);
|
||||
addPlugInterfaceSupported (IPrefetchableSupport::iid);
|
||||
addPlugInterfaceSupported (IAutomationState::iid);
|
||||
|
||||
//---VST 3.6.11--------------------------------
|
||||
addPlugInterfaceSupported (INoteExpressionPhysicalUIMapping::iid);
|
||||
|
||||
//---VST 3.6.12--------------------------------
|
||||
addPlugInterfaceSupported (IMidiLearn::iid);
|
||||
#endif
|
||||
}
|
||||
|
||||
tresult
|
||||
PlugInterfaceSupport::isPlugInterfaceSupported (const TUID _iid)
|
||||
{
|
||||
const FUID uid = FUID::fromTUID (_iid);
|
||||
if (std::find (_interfaces.begin (), _interfaces.end (), uid) != _interfaces.end ()) {
|
||||
return kResultTrue;
|
||||
}
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
void
|
||||
PlugInterfaceSupport::addPlugInterfaceSupported (const TUID id)
|
||||
{
|
||||
_interfaces.push_back (FUID::fromTUID (id));
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
HostApplication::HostApplication ()
|
||||
{
|
||||
#if (__cplusplus >= 201103L)
|
||||
_plug_interface_support = boost::make_unique<PlugInterfaceSupport> ();
|
||||
#else
|
||||
_plug_interface_support.reset (new PlugInterfaceSupport);
|
||||
#endif
|
||||
}
|
||||
|
||||
tresult
|
||||
HostApplication::queryInterface (const char* _iid, void** obj)
|
||||
{
|
||||
QUERY_INTERFACE (_iid, obj, FUnknown::iid, IHostApplication)
|
||||
QUERY_INTERFACE (_iid, obj, IHostApplication::iid, IHostApplication)
|
||||
|
||||
if (_plug_interface_support && _plug_interface_support->queryInterface (Vst::IHostApplication::iid, obj) == kResultTrue) {
|
||||
return kResultOk;
|
||||
}
|
||||
|
||||
*obj = nullptr;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostApplication::getName (Vst::String128 name)
|
||||
{
|
||||
utf8_to_tchar (name, PROGRAM_NAME, 128);
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
HostApplication::createInstance (TUID cid, TUID _iid, void** obj)
|
||||
{
|
||||
FUID classID (FUID::fromTUID (cid));
|
||||
FUID interfaceID (FUID::fromTUID (_iid));
|
||||
if (classID == Vst::IMessage::iid && interfaceID == Vst::IMessage::iid) {
|
||||
*obj = (Vst::IMessage*)new HostMessage;
|
||||
return kResultTrue;
|
||||
} else if (classID == Vst::IAttributeList::iid && interfaceID == Vst::IAttributeList::iid) {
|
||||
*obj = (Vst::IAttributeList*)new HostAttributeList;
|
||||
return kResultTrue;
|
||||
}
|
||||
*obj = nullptr;
|
||||
return kResultFalse;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
tresult
|
||||
Vst3ParamValueQueue::getPoint (int32 index, int32& sampleOffset, Vst::ParamValue& value)
|
||||
{
|
||||
if (index >=0 && index < (int32)_values.size ()) {
|
||||
const Value& v = _values[index];
|
||||
sampleOffset = v.sampleOffset;
|
||||
value = v.value;
|
||||
return kResultTrue;
|
||||
}
|
||||
return kResultFalse;
|
||||
|
||||
}
|
||||
|
||||
tresult
|
||||
Vst3ParamValueQueue::addPoint (int32 sampleOffset, Vst::ParamValue value, int32& index)
|
||||
{
|
||||
int32 dest_index = (int32)_values.size ();
|
||||
for (uint32 i = 0; i < _values.size (); ++i) {
|
||||
if (_values[i].sampleOffset == sampleOffset) {
|
||||
_values[i].value = value;
|
||||
index = i;
|
||||
return kResultTrue;
|
||||
} else if (_values[i].sampleOffset > sampleOffset) {
|
||||
dest_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Value v (value, sampleOffset);
|
||||
if (dest_index == (int32)_values.size ()) {
|
||||
_values.push_back (v);
|
||||
} else {
|
||||
_values.insert (_values.begin () + dest_index, v);
|
||||
}
|
||||
|
||||
index = dest_index;
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
Vst::IParamValueQueue*
|
||||
Vst3ParameterChanges::getParameterData (int32 index)
|
||||
{
|
||||
if (index < _used_queue_count) {
|
||||
return &_queue[index];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vst::IParamValueQueue*
|
||||
Vst3ParameterChanges::addParameterData (Vst::ParamID const& pid, int32& index)
|
||||
{
|
||||
for (int32 i = 0; i < _used_queue_count; ++i) {
|
||||
if (_queue[i].getParameterId () == pid) {
|
||||
index = i;
|
||||
return &_queue[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (_used_queue_count < (int32)_queue.size ()) {
|
||||
index = _used_queue_count++;
|
||||
_queue[index].setParameterId (pid);
|
||||
return &_queue[index];
|
||||
}
|
||||
index = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ****************************************************************************/
|
||||
|
||||
RAMStream::RAMStream ()
|
||||
: _data (0)
|
||||
, _size (0)
|
||||
, _alloc (0)
|
||||
, _pos (0)
|
||||
, _readonly (false)
|
||||
{
|
||||
}
|
||||
|
||||
RAMStream::RAMStream (uint8_t* data, size_t size)
|
||||
: _data (0)
|
||||
, _size (size)
|
||||
, _alloc (0)
|
||||
, _pos (0)
|
||||
, _readonly (true)
|
||||
{
|
||||
if (reallocate_buffer (_size, true)) {
|
||||
memcpy (_data, data, _size);
|
||||
} else {
|
||||
_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
RAMStream::RAMStream (std::string const& fn)
|
||||
: _data (0)
|
||||
, _size (0)
|
||||
, _alloc (0)
|
||||
, _pos (0)
|
||||
, _readonly (true)
|
||||
{
|
||||
gchar* buf = NULL;
|
||||
gsize length = 0;
|
||||
|
||||
if (!g_file_get_contents (fn.c_str (), &buf, &length, NULL)) {
|
||||
return;
|
||||
}
|
||||
if (reallocate_buffer (length, true)) {
|
||||
_size = length;
|
||||
memcpy (_data, buf, _size);
|
||||
}
|
||||
g_free (buf);
|
||||
}
|
||||
|
||||
RAMStream::~RAMStream ()
|
||||
{
|
||||
free (_data);
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::reallocate_buffer (int64 size, bool exact)
|
||||
{
|
||||
if (size <= 0) {
|
||||
free (_data);
|
||||
_data = 0;
|
||||
_alloc = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (size == _alloc) {
|
||||
assert (_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!exact) {
|
||||
if (size <= _alloc) {
|
||||
/* don't shrink */
|
||||
assert (_data);
|
||||
return true;
|
||||
}
|
||||
if (size > _alloc) {
|
||||
size = (((size - 1) / 8192) + 1) * 8192;
|
||||
}
|
||||
}
|
||||
|
||||
_data = (uint8_t*) realloc (_data, size);
|
||||
|
||||
if (_data) {
|
||||
_alloc = size;
|
||||
return true;
|
||||
} else {
|
||||
_alloc = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tresult
|
||||
RAMStream::read (void* buffer, int32 n_bytes, int32* n_read)
|
||||
{
|
||||
assert (_pos >= 0 && _pos <= _size);
|
||||
int64 available = _size - _pos;
|
||||
|
||||
if (n_bytes < 0 || available < 0) {
|
||||
n_bytes = 0;
|
||||
} else if (n_bytes > available) {
|
||||
n_bytes = available;
|
||||
}
|
||||
|
||||
if (n_bytes > 0) {
|
||||
memcpy(buffer, &_data[_pos], n_bytes);
|
||||
_pos += n_bytes;
|
||||
}
|
||||
if (n_read) {
|
||||
*n_read = n_bytes;
|
||||
}
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
RAMStream::write (void* buffer, int32 n_bytes, int32* n_written)
|
||||
{
|
||||
if (_readonly) {
|
||||
return kResultFalse;
|
||||
}
|
||||
if (n_bytes < 0) {
|
||||
return kInvalidArgument;
|
||||
}
|
||||
|
||||
if (!reallocate_buffer (_pos + n_bytes, false)) {
|
||||
return kOutOfMemory;
|
||||
}
|
||||
|
||||
if (buffer && _data && _pos >= 0 && n_bytes > 0) {
|
||||
memcpy (&_data[_pos], buffer, n_bytes);
|
||||
_pos += n_bytes;
|
||||
_size = _pos;
|
||||
} else {
|
||||
n_bytes = 0;
|
||||
}
|
||||
|
||||
if (n_written) {
|
||||
*n_written = n_bytes;
|
||||
}
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
RAMStream::seek (int64 pos, int32 mode, int64* result)
|
||||
{
|
||||
switch (mode) {
|
||||
case kIBSeekSet:
|
||||
_pos = pos;
|
||||
break;
|
||||
case kIBSeekCur:
|
||||
_pos += pos;
|
||||
break;
|
||||
case kIBSeekEnd:
|
||||
_pos = _size + pos;
|
||||
break;
|
||||
default:
|
||||
return kInvalidArgument;
|
||||
}
|
||||
if (_pos < 0) {
|
||||
_pos = 0;
|
||||
}
|
||||
if (result) {
|
||||
*result = _pos;
|
||||
}
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult
|
||||
RAMStream::tell (int64* pos)
|
||||
{
|
||||
if (!pos) {
|
||||
return kInvalidArgument;
|
||||
}
|
||||
*pos = _pos;
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::write_int32 (int32 i) {
|
||||
/* pluginterfaces/base/ftypes.h */
|
||||
#if BYTEORDER == kBigEndian
|
||||
SWAP_32 (i)
|
||||
#endif
|
||||
return write_pod (i);
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::write_int64 (int64 i)
|
||||
{
|
||||
/* pluginterfaces/base/ftypes.h */
|
||||
#if BYTEORDER == kBigEndian
|
||||
SWAP_64 (i)
|
||||
#endif
|
||||
return write_pod (i);
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::write_ChunkID (const Vst::ChunkID& id)
|
||||
{
|
||||
return write_pod (id);
|
||||
}
|
||||
|
||||
#if COM_COMPATIBLE
|
||||
/* pluginterfaces/base/funknown.cpp */
|
||||
struct GUIDStruct {
|
||||
uint32_t data1;
|
||||
uint16_t data2;
|
||||
uint16_t data3;
|
||||
uint8_t data4[8];
|
||||
};
|
||||
#endif
|
||||
|
||||
bool
|
||||
RAMStream::write_TUID (const TUID& tuid)
|
||||
{
|
||||
int i = 0;
|
||||
int32 n_bytes = 0;
|
||||
char buf[Vst::kClassIDSize + 1];
|
||||
|
||||
#if COM_COMPATIBLE
|
||||
GUIDStruct guid;
|
||||
memcpy (&guid, tuid, sizeof(GUIDStruct));
|
||||
sprintf(buf, "%08X%04X%04X", guid.data1, guid.data2, guid.data3);
|
||||
i += 8;
|
||||
#endif
|
||||
|
||||
for (; i < (int)sizeof(TUID); ++i){
|
||||
sprintf(buf + 2 * i, "%02X", (uint8_t)tuid[i]);
|
||||
}
|
||||
write (buf, Vst::kClassIDSize, &n_bytes);
|
||||
return n_bytes == Vst::kClassIDSize;
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::read_int32 (int32& i) {
|
||||
if (!read_pod (i)) {
|
||||
return false;
|
||||
}
|
||||
#if BYTEORDER == kBigEndian
|
||||
SWAP_32 (i)
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::read_int64 (int64& i) {
|
||||
if (!read_pod (i)) {
|
||||
return false;
|
||||
}
|
||||
#if BYTEORDER == kBigEndian
|
||||
SWAP_64 (i)
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::read_ChunkID (Vst::ChunkID& id)
|
||||
{
|
||||
return read_pod (id);
|
||||
}
|
||||
|
||||
bool
|
||||
RAMStream::read_TUID (TUID& tuid)
|
||||
{
|
||||
int i = 0;
|
||||
int32 n_bytes = 0;
|
||||
char buf[Vst::kClassIDSize+1];
|
||||
|
||||
read((void *)buf, Vst::kClassIDSize, &n_bytes);
|
||||
if (n_bytes != Vst::kClassIDSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[Vst::kClassIDSize] = '\0';
|
||||
|
||||
#if COM_COMPATIBLE
|
||||
GUIDStruct guid;
|
||||
sscanf (buf, "%08x", &guid.data1);
|
||||
sscanf (buf+8, "%04hx", &guid.data2);
|
||||
sscanf (buf+12, "%04hx", &guid.data3);
|
||||
memcpy (tuid, &guid, sizeof(TUID) >> 1);
|
||||
i += 16;
|
||||
#endif
|
||||
|
||||
for (; i < Vst::kClassIDSize; i += 2){
|
||||
uint32_t temp;
|
||||
sscanf (buf + i, "%02X", &temp);
|
||||
tuid[i >> 1] = temp;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
void
|
||||
RAMStream::hexdump (int64 max_len) const
|
||||
{
|
||||
std::ostringstream out;
|
||||
|
||||
size_t row_size = 16;
|
||||
size_t length = max_len > 0 ? std::min (max_len, _size) : _size;
|
||||
|
||||
out << std::setfill('0');
|
||||
for (size_t i = 0; i < length; i += row_size) {
|
||||
out << "0x" << std::setw(6) << std::hex << i << ": ";
|
||||
for (size_t j = 0; j < row_size; ++j) {
|
||||
if (i + j < length) {
|
||||
out << std::hex << std::setw(2) << static_cast<int>(_data[i + j]) << " ";
|
||||
} else {
|
||||
out << " ";
|
||||
}
|
||||
}
|
||||
out << " ";
|
||||
if (true) {
|
||||
for (size_t j = 0; j < row_size; ++j) {
|
||||
if (i + j < length) {
|
||||
if (std::isprint(_data[i + j])) {
|
||||
out << static_cast<char>(_data[i + j]);
|
||||
} else {
|
||||
out << ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
std::cout << out.str ();
|
||||
}
|
||||
#endif
|
||||
|
|
@ -460,7 +460,7 @@ def build(bld):
|
|||
obj.defines += [ 'MACVST_SUPPORT' ]
|
||||
|
||||
if bld.is_defined('VST3_SUPPORT'):
|
||||
obj.source += [ 'vst3_plugin.cc', 'vst3_module.cc' ]
|
||||
obj.source += [ 'vst3_plugin.cc', 'vst3_module.cc', 'vst3_host.cc' ]
|
||||
obj.defines += [ 'VST3_SUPPORT' ]
|
||||
|
||||
if bld.is_defined('HAVE_COREAUDIO'):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue