13
0

VST3: Implement ContextInfo (console) extension

This commit is contained in:
Robin Gareus 2020-10-06 03:03:08 +02:00
parent e3ca1f0605
commit e4bbb1bc81
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
3 changed files with 340 additions and 1 deletions

View File

@ -19,6 +19,10 @@
#ifndef _ardour_vst3_plugin_h_
#define _ardour_vst3_plugin_h_
#include <map>
#include <set>
#include <vector>
#include <boost/optional.hpp>
#include "pbd/signals.h"
@ -53,6 +57,7 @@ class LIBARDOUR_API VST3PI
, public Vst::IConnectionPoint
, public Vst::IUnitHandler
, public IPlugFrame
, public Presonus::IContextInfoProvider3
{
public:
VST3PI (boost::shared_ptr<ARDOUR::VST3PluginModule> m, std::string unique_id);
@ -82,6 +87,16 @@ public:
tresult PLUGIN_API notifyUnitSelection (Vst::UnitID) SMTG_OVERRIDE;
tresult PLUGIN_API notifyProgramListChange (Vst::ProgramListID, int32) SMTG_OVERRIDE;
/* IContextInfoProvider3 API */
tresult PLUGIN_API getContextInfoValue (int32&, FIDString);
tresult PLUGIN_API getContextInfoString (Vst::TChar*, int32, FIDString);
tresult PLUGIN_API getContextInfoValue (double&, FIDString);
tresult PLUGIN_API setContextInfoValue (FIDString, double);
tresult PLUGIN_API setContextInfoValue (FIDString, int32);
tresult PLUGIN_API setContextInfoString (FIDString, Vst::TChar*);
tresult PLUGIN_API beginEditContextInfoValue (FIDString);
tresult PLUGIN_API endEditContextInfoValue (FIDString);
/* GUI */
bool has_editor () const;
IPlugView* view ();
@ -193,7 +208,13 @@ private:
void setup_info_listener ();
void stripable_property_changed (PBD::PropertyChange const&);
PBD::ScopedConnectionList _strip_connections;
void setup_psl_info_handler ();
void psl_subscribe_to (boost::shared_ptr<ARDOUR::AutomationControl>, FIDString);
void psl_stripable_property_changed (PBD::PropertyChange const&);
PBD::ScopedConnectionList _strip_connections;
PBD::ScopedConnectionList _ac_connection_list;
std::set<Evoral::Parameter> _ac_subscriptions;
boost::shared_ptr<ARDOUR::VST3PluginModule> _module;

View File

@ -338,6 +338,11 @@ PlugInterfaceSupport::PlugInterfaceSupport ()
//---VST 3.6.12--------------------------------
#endif
addPlugInterfaceSupported (IMidiLearn::iid);
//---PSL --------------------------------------
addPlugInterfaceSupported (Presonus::ISlaveControllerHandler::iid);
addPlugInterfaceSupported (Presonus::IEditControllerExtra::iid);
addPlugInterfaceSupported (Presonus::IContextInfoHandler2::iid);
}
tresult

View File

@ -1492,9 +1492,12 @@ VST3PI::set_owner (SessionObject* o)
_owner = o;
if (!o) {
_strip_connections.drop_connections ();
_ac_connection_list.drop_connections ();
_ac_subscriptions.clear();
return;
}
setup_info_listener ();
setup_psl_info_handler ();
}
int32
@ -2424,6 +2427,316 @@ VST3PI::automation_state_changed (uint32_t port, AutoState s, boost::weak_ptr <A
extra_ctrl->setParamAutomationMode (id, am);
}
/* ****************************************************************************/
static
boost::shared_ptr<AutomationControl>
lookup_ac (SessionObject* o, FIDString id)
{
Stripable* s = dynamic_cast<Stripable*> (o);
if (!s) {
return boost::shared_ptr<AutomationControl> ();
}
if (0 == strcmp (id, Presonus::ContextInfo::kMute)) {
return s->mute_control();
} else if (0 == strcmp (id, Presonus::ContextInfo::kSolo)) {
return s->solo_control();
} else if (0 == strcmp (id, Presonus::ContextInfo::kPan)) {
return s->pan_azimuth_control ();
} else if (0 == strcmp (id, Presonus::ContextInfo::kVolume)) {
return s->gain_control ();
} else if (0 == strncmp (id, Presonus::ContextInfo::kSendLevel, strlen (Presonus::ContextInfo::kSendLevel))) {
int send_id = atoi (id + strlen (Presonus::ContextInfo::kSendLevel));
return s->send_level_controllable (send_id);
}
return boost::shared_ptr<AutomationControl> ();
}
tresult
VST3PI::getContextInfoValue (int32& value, FIDString id)
{
Stripable* s = dynamic_cast<Stripable*> (_owner);
assert (s);
if (0 == strcmp (id, Presonus::ContextInfo::kIndexMode)) {
value = Presonus::ContextInfo::kPerTypeIndex;
} else if (0 == strcmp (id, Presonus::ContextInfo::kType)) {
if (s->is_master ()) {
value = Presonus::ContextInfo::kOut;
} else if (s->presentation_info().flags() & PresentationInfo::AudioTrack) {
value = Presonus::ContextInfo::kTrack;
} else if (s->presentation_info().flags() & PresentationInfo::MidiTrack) {
value = Presonus::ContextInfo::kSynth;
} else {
value = Presonus::ContextInfo::kBus;
}
} else if (0 == strcmp (id, Presonus::ContextInfo::kMain)) {
value = s->is_master() ? 1 : 0;
} else if (0 == strcmp (id, Presonus::ContextInfo::kIndex)) {
value = s->presentation_info ().order(); // XXX
} else if (0 == strcmp (id, Presonus::ContextInfo::kColor)) {
value = s->presentation_info ().color();
#if BYTEORDER == kBigEndian
SWAP_32 (value) // RGBA32 -> ABGR32
#endif
} else if (0 == strcmp (id, Presonus::ContextInfo::kVisibility)) {
value = s->is_hidden () ? 0 : 1;
} else if (0 == strcmp (id, Presonus::ContextInfo::kSelected)) {
value = s->is_selected () ? 1 : 0;
} else if (0 == strcmp (id, Presonus::ContextInfo::kFocused)) {
// consider ControlProtocol::first_selected_stripable () == s;
return kNotImplemented;
} else if (0 == strcmp (id, Presonus::ContextInfo::kSendCount)) {
value = 0;
while (s->send_enable_controllable (value)) {
++value;
}
} else if (0 == strcmp (id, Presonus::ContextInfo::kMute)) {
boost::shared_ptr<MuteControl> ac = s->mute_control ();
psl_subscribe_to (ac, id);
return ac->muted_by_self ();
} else if (0 == strcmp (id, Presonus::ContextInfo::kSolo)) {
boost::shared_ptr<SoloControl> ac = s->solo_control ();
if (ac) {
psl_subscribe_to (ac, id);
value = ac->self_soloed ();
}
} else {
return kNotImplemented;
}
return kResultOk;
}
tresult
VST3PI::getContextInfoString (Vst::TChar* string, int32 max_len, FIDString id)
{
if (!_owner) {
return kNotInitialized;
}
if (0 == strcmp (id, Presonus::ContextInfo::kID)) {
utf8_to_tchar (string, _owner->id().to_s (), max_len);
return kResultOk;
} else if (0 == strcmp (id, Presonus::ContextInfo::kName)) {
utf8_to_tchar (string, _owner->name (), max_len);
return kResultOk;
} else if (0 == strcmp (id, Presonus::ContextInfo::kActiveDocumentID)) {
return kNotImplemented; // XXX TODO
} else if (0 == strcmp (id, Presonus::ContextInfo::kDocumentID)) {
return kNotImplemented; // XXX TODO
} else if (0 == strcmp (id, Presonus::ContextInfo::kDocumentName)) {
return kNotImplemented; // XXX TODO
} else if (0 == strcmp (id, Presonus::ContextInfo::kDocumentFolder)) {
return kNotImplemented; // XXX TODO
} else if (0 == strcmp (id, Presonus::ContextInfo::kAudioFolder)) {
return kNotImplemented; // XXX TODO
} else {
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
if (!ac) {
return kInvalidArgument;
}
utf8_to_tchar (string, ac->get_user_string (), max_len);
}
return kResultOk;
}
tresult
VST3PI::getContextInfoValue (double& value, FIDString id)
{
Stripable* s = dynamic_cast<Stripable*> (_owner);
if (!s) {
return kNotInitialized;
}
if (0 == strcmp (id, Presonus::ContextInfo::kMaxVolume)) {
value = 2.0; // Config->get_max_gain();
} else if (0 == strcmp (id, Presonus::ContextInfo::kMaxSendLevel)) {
value = 2.0; // Config->get_max_gain();
} else if (0 == strcmp (id, Presonus::ContextInfo::kVolume)) {
boost::shared_ptr<AutomationControl> ac = s->gain_control ();
value = ac->get_value(); // gain coefficient 0..2 (1.0 = 0dB)
psl_subscribe_to (ac, id);
} else if (0 == strcmp (id, Presonus::ContextInfo::kPan)) {
boost::shared_ptr<AutomationControl> ac = s->pan_azimuth_control ();
if (ac) {
value = ac->internal_to_interface (ac->get_value(), true);
psl_subscribe_to (ac, id);
} else {
value = 0.5; // center
}
} else if (0 == strncmp (id, Presonus::ContextInfo::kSendLevel, strlen (Presonus::ContextInfo::kSendLevel))) {
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
if (ac) {
value = ac->get_value(); // gain cofficient
psl_subscribe_to (ac, id);
} else {
return kInvalidArgument; // send index out of bounds
}
} else {
return kInvalidArgument;
}
return kResultOk;
}
tresult
VST3PI::setContextInfoValue (FIDString id, double value)
{
if (!_owner) {
return kNotInitialized;
}
if (0 == strcmp (id, Presonus::ContextInfo::kVolume)) {
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
ac->set_value (value, Controllable::NoGroup);
} else if (0 == strcmp (id, Presonus::ContextInfo::kPan)) {
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
if (ac) {
ac->set_value (ac->interface_to_internal (value, true), PBD::Controllable::NoGroup);
}
} else if (0 == strncmp (id, Presonus::ContextInfo::kSendLevel, strlen (Presonus::ContextInfo::kSendLevel))) {
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
if (ac) {
ac->set_value (value, Controllable::NoGroup);
} else {
return kInvalidArgument; // send index out of bounds
}
} else {
return kInvalidArgument;
}
return kResultOk;
}
tresult
VST3PI::setContextInfoValue (FIDString id, int32 value)
{
Stripable* s = dynamic_cast<Stripable*> (_owner);
if (!s) {
return kNotInitialized;
}
if (0 == strcmp (id, Presonus::ContextInfo::kColor)) {
#if BYTEORDER == kBigEndian
SWAP_32 (value) // ABGR32 -> RGBA32
#endif
s->presentation_info ().set_color(value);
} else if (0 == strcmp (id, Presonus::ContextInfo::kSelected)) {
return kNotImplemented;
} else if (0 == strcmp (id, Presonus::ContextInfo::kMultiSelect)) {
//_add_to_selection = value != 0;
} else if (0 == strcmp (id, Presonus::ContextInfo::kMute)) {
s->mute_control()->set_value (value != 0, Controllable::NoGroup);
} else if (0 == strcmp (id, Presonus::ContextInfo::kSolo)) {
s->solo_control()->set_value (value != 0, Controllable::NoGroup);
} else {
return kNotImplemented;
}
return kResultOk;
}
tresult
VST3PI::setContextInfoString (FIDString id, Vst::TChar* string)
{
if (!_owner) {
return kNotInitialized;
}
if (0 == strcmp (id, Presonus::ContextInfo::kName)) {
return _owner->set_name (tchar_to_utf8 (string)) ? kResultOk : kResultFalse;
}
return kInvalidArgument;
}
tresult
VST3PI::beginEditContextInfoValue (FIDString id)
{
if (!_owner) {
return kNotInitialized;
}
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
if (!ac) {
return kInvalidArgument;
}
ac->start_touch (ac->session().transport_sample());
return kResultOk;
}
tresult
VST3PI::endEditContextInfoValue (FIDString id)
{
if (!_owner) {
return kNotInitialized;
}
boost::shared_ptr<AutomationControl> ac = lookup_ac (_owner, id);
if (!ac) {
return kInvalidArgument;
}
ac->stop_touch (ac->session().transport_sample());
return kResultOk;
}
void
VST3PI::psl_subscribe_to (boost::shared_ptr<ARDOUR::AutomationControl> ac, FIDString id)
{
FUnknownPtr<Presonus::IContextInfoHandler2> nfo2 (_controller);
if (!nfo2) {
return;
}
std::pair<std::set<Evoral::Parameter>::iterator, bool> r = _ac_subscriptions.insert (ac->parameter ());
if (!r.second) {
return;
}
ac->Changed.connect_same_thread (_ac_connection_list, boost::bind (&Presonus::IContextInfoHandler2::notifyContextInfoChange, nfo2.get(), id));
}
void
VST3PI::psl_stripable_property_changed (PBD::PropertyChange const& what_changed)
{
FUnknownPtr<Presonus::IContextInfoHandler> nfo (_controller);
FUnknownPtr<Presonus::IContextInfoHandler2> nfo2 (_controller);
if (nfo && !nfo2) {
nfo->notifyContextInfoChange ();
}
if (!nfo2) {
return;
}
if (what_changed.contains (Properties::selected)) {
nfo2->notifyContextInfoChange ("Presonus::ContextInfo::kSelected");
//nfo2->notifyContextInfoChange ("Presonus::ContextInfo::kFocused");
}
if (what_changed.contains (Properties::hidden)) {
nfo2->notifyContextInfoChange ("Presonus::ContextInfo::kVisibility");
}
if (what_changed.contains (Properties::name)) {
nfo2->notifyContextInfoChange ("Presonus::ContextInfo::kName");
}
if (what_changed.contains (Properties::color)) {
nfo2->notifyContextInfoChange ("Presonus::ContextInfo::kColor");
}
}
void
VST3PI::setup_psl_info_handler ()
{
/* initial update */
FUnknownPtr<Presonus::IContextInfoHandler> nfo (_controller);
FUnknownPtr<Presonus::IContextInfoHandler2> nfo2 (_controller);
if (nfo2) {
nfo2->notifyContextInfoChange ("");
} else if (nfo) {
nfo->notifyContextInfoChange ();
}
if (!nfo && !nfo2) {
return;
}
Stripable* s = dynamic_cast<Stripable*> (_owner);
s->PropertyChanged.connect_same_thread (_strip_connections, boost::bind (&VST3PI::stripable_property_changed, this, _1));
s->presentation_info().PropertyChanged.connect_same_thread (_strip_connections, boost::bind (&VST3PI::stripable_property_changed, this, _1));
}
/* ****************************************************************************
* GUI
*/