13
0

Console1: Add plugin interface

This commit is contained in:
Hoger Dehnhardt 2023-05-12 23:17:09 +02:00 committed by Paul Davis
parent f1bb18ae53
commit 835598c802
6 changed files with 405 additions and 6 deletions

View File

@ -45,10 +45,13 @@ class ControllerButton : public Controller
ControllerButton (Console1& console1, ControllerButton (Console1& console1,
ControllerID id, ControllerID id,
boost::function<void (uint32_t)> action, boost::function<void (uint32_t)> action,
boost::function<void (uint32_t)> shift_action = 0) boost::function<void (uint32_t)> shift_action = 0,
boost::function<void (uint32_t)> plugin_action = 0
)
: Controller (console1, id) : Controller (console1, id)
, action (action) , action (action)
, shift_action (shift_action) , shift_action (shift_action)
, plugin_action (plugin_action)
{ {
console1.buttons.insert (std::make_pair (id, *this)); console1.buttons.insert (std::make_pair (id, *this));
} }
@ -78,6 +81,7 @@ class ControllerButton : public Controller
} }
boost::function<void (uint32_t)> action; boost::function<void (uint32_t)> action;
boost::function<void (uint32_t)> shift_action; boost::function<void (uint32_t)> shift_action;
boost::function<void (uint32_t)> plugin_action;
}; };
class MultiStateButton : public Controller class MultiStateButton : public Controller

View File

@ -146,6 +146,14 @@ Console1::shift (const uint32_t val)
ShiftChange (val); ShiftChange (val);
} }
void
Console1::plugin_state (const uint32_t)
{
DEBUG_TRACE (DEBUG::Console1, "plugin_state()\n");
in_plugin_state = !in_plugin_state;
PluginStateChange (in_plugin_state);
}
void void
Console1::solo (const uint32_t) Console1::solo (const uint32_t)
{ {
@ -657,6 +665,28 @@ Console1::map_shift (bool shift)
} }
} }
void
Console1::map_plugin_state (bool plugin_state)
{
DEBUG_TRACE (DEBUG::Console1, "map_plugin_state()\n");
try {
ControllerButton& controllerButton = static_cast<ControllerButton&> (get_button (TRACK_GROUP));
controllerButton.set_led_state (in_plugin_state);
} catch (ControlNotFoundException& e) {
DEBUG_TRACE (DEBUG::Console1, "Button not found\n");
}
if (!plugin_state) {
for (uint32_t i = 0; i < bank_size; ++i) {
stop_blinking (ControllerID (FOCUS1 + i));
}
map_stripable_state ();
} else {
// I don't plan shift functionality with plugins...
shift (0);
// map all plugin related operations
}
}
void void
Console1::map_solo () Console1::map_solo ()
{ {

View File

@ -0,0 +1,240 @@
/*
* Copyright (C) 2023 Holger Dehnhardt <holger@dehnhardt.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 <iostream>
#include <sstream>
#include <vector>
#include <boost/algorithm/string/trim.hpp>
#include "glib-2.0/gio/gio.h"
#include "glib-2.0/glib/gstdio.h"
#include "glibmm-2.4/glibmm/main.h"
#include "glibmm-2.4/glibmm/miscutils.h"
#include "pbd/debug.h"
#include "ardour/filesystem_paths.h"
#include "ardour/plugin_insert.h"
#include "ardour/processor.h"
#include "ardour/route.h"
#include "c1_control.h"
#include "console1.h"
using namespace ARDOUR;
using namespace ArdourSurface;
using namespace PBD;
using namespace Glib;
using namespace std;
namespace ArdourSurface {
uint32_t
Console1::load_mappings ()
{
uint32_t i = 0;
std::string path = Glib::build_filename (user_config_directory (), "c1mappings");
GError* error;
GFile* dir = g_file_new_for_path (path.c_str ());
if (!g_file_test (path.c_str (), G_FILE_TEST_IS_DIR)) {
g_file_make_directory (dir, NULL, &error);
}
const gchar* fileName;
GDir* gdir = g_dir_open (path.c_str (), 0, NULL);
if (gdir == NULL)
return 0;
while ((fileName = g_dir_read_name (gdir)) != NULL) {
// if (!g_str_has_suffix (name, ".remmina"))
// continue;
DEBUG_TRACE (DEBUG::Console1,
string_compose ("Console1::load_mappings - found mapping file: '%1'\n", fileName));
std::string filePath = Glib::build_filename (path, fileName);
FILE* fin = g_fopen (filePath.c_str (), "r");
if (fin) {
DEBUG_TRACE (DEBUG::Console1,
string_compose ("Console1::load_mappings - opened mapping file: '%1'\n", filePath));
load_mapping (fin);
fclose (fin);
}
++i;
}
DEBUG_TRACE (DEBUG::Console1, string_compose ("Console1::load_mappings - found %1 mapping files\n", i));
g_dir_close (gdir);
return i;
}
bool
Console1::load_mapping (FILE* fin)
{
char tmp[1024];
PluginMapping pm;
while (fgets (tmp, 1024, fin) != NULL) {
istringstream line (tmp);
std::string token;
vector<string> strings;
while (getline (line, token, ';')) {
boost::algorithm::trim (token);
strings.push_back (std::move (token));
}
if (strings.size () < 2)
continue;
DEBUG_TRACE (DEBUG::Console1,
string_compose ("Console1::load_mapping - Name: '%1', Val1: '%2', Val2: '%3' \n",
strings.at (0),
strings.at (1),
strings.size () > 2 ? strings.at (2) : ""));
if (strings.at (0) == "ID") {
pm.id = strings.at (1);
} else if (strings.at (0) == "NAME") {
pm.name = strings.at (1);
} else {
try {
uint32_t index = std::stoi (strings.at (0));
// Only store complete mappings: Indey, Name, ControllerId
if (strings.size () < 3)
continue;
PluginParameterMapping parmap;
parmap.paramIndex = index;
parmap.name = strings.at (1);
ControllerMap::const_iterator m = controllerMap.find (strings.at (2));
if (m == controllerMap.end ())
continue;
parmap.controllerId = m->second;
pm.parameters[index] = std::move (parmap);
} catch (std::invalid_argument&) {
continue;
}
}
}
pluginMappingMap[pm.id] = pm;
return true;
}
void
Console1::select_plugin (uint32_t plugin_index)
{
DEBUG_TRACE (DEBUG::Console1, "Console1::select_plugin\n");
current_plugin_index = plugin_index;
map_select_plugin ();
}
void
Console1::map_select_plugin ()
{
DEBUG_TRACE (DEBUG::Console1, "map_select_plugin())\n");
bool plugin_availabe = spill_plugins (current_plugin_index);
for (uint32_t i = 0; i < bank_size; ++i) {
if (i == current_plugin_index && plugin_availabe) {
start_blinking (ControllerID (FOCUS1 + i));
} else if (i != current_strippable_index) {
stop_blinking (ControllerID (FOCUS1 + i));
}
}
}
bool
Console1::spill_plugins (uint32_t plugin_index)
{
DEBUG_TRACE (DEBUG::Console1, string_compose ("spill_plugins(%1)\n", plugin_index));
std::shared_ptr<Route> r = std::dynamic_pointer_cast<Route> (_current_stripable);
if (!r) {
return false;
}
// drop_ctrl_connections ();
// switching to "Mode Track" -> calls FaderPort8::notify_fader_mode_changed()
// which drops the references, disconnects the signal and re-spills tracks
/*r->DropReferences.connect (
processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this);
// update when processor change
r->processors_changed.connect (
processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::spill_plugins, this), this);*/
// count available
std::shared_ptr<Processor> proc;
proc = r->nth_plugin (plugin_index);
if (!proc) {
return false;
}
if (!proc->display_to_user ()) {
return false;
}
#ifdef MIXBUS
/* don't show channelstrip plugins, use "well known" */
if (std::dynamic_pointer_cast<PluginInsert> (proc)->is_channelstrip ()) {
continue;
}
#endif
int n_controls = 0;
DEBUG_TRACE (DEBUG::Console1, string_compose ("Found plugin %1\n", proc->name ()));
std::shared_ptr<PluginInsert> plugin_insert = std::dynamic_pointer_cast<PluginInsert> (proc);
if (!plugin_insert)
return false;
std::shared_ptr<Plugin> plugin = plugin_insert->plugin ();
if (!plugin)
return false;
DEBUG_TRACE (DEBUG::Console1, string_compose ("Found plugin id %1\n", plugin->unique_id ()));
PluginMappingMap::iterator pmmit = pluginMappingMap.find (plugin->unique_id ());
if (pmmit == pluginMappingMap.end ()) {
return false;
}
PluginMapping pluginMapping = pmmit->second;
DEBUG_TRACE (DEBUG::Console1,
string_compose ("Plugin mapping found for id %1, name %2\n", pluginMapping.id, pluginMapping.name));
set<Evoral::Parameter> p = proc->what_can_be_automated ();
for (set<Evoral::Parameter>::iterator j = p.begin (); j != p.end (); ++j) {
std::string n = proc->describe_parameter (*j);
DEBUG_TRACE (DEBUG::Console1, string_compose ("Plugin parameter %1: %2\n", n_controls, n));
if (n == "hidden") {
continue;
}
ParameterDescriptor parameterDescriptor;
plugin->get_parameter_descriptor (n_controls, parameterDescriptor);
if (plugin->parameter_is_input (n_controls)) {
std::shared_ptr<AutomationControl> c =
plugin_insert->automation_control (Evoral::Parameter (PluginAutomation, 0, n_controls));
if (c) {
bool swtch = false;
if (parameterDescriptor.integer_step && parameterDescriptor.upper == 1) {
swtch = true;
}
PluginParameterMapping ppm = pluginMapping.parameters[n_controls];
ppm.controllerId;
// c->Changed.connect (plugin_connections, MISSING_INVALIDATOR, boost::bind
// (&OSCSelectObserver::plugin_parameter_changed, this, pid, swtch, c), OSC::instance());
// plugin_parameter_changed (pid, swtch, c);
}
}
++n_controls;
}
return true;
}
}

View File

@ -26,6 +26,7 @@
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/debug.h" #include "ardour/debug.h"
#include "ardour/filesystem_paths.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/monitor_control.h" #include "ardour/monitor_control.h"
#include "ardour/phase_control.h" #include "ardour/phase_control.h"
@ -36,8 +37,8 @@
#include "ardour/vca_manager.h" #include "ardour/vca_manager.h"
#include "console1.h" #include "console1.h"
#include "c1_gui.h"
#include "c1_control.h" #include "c1_control.h"
#include "c1_gui.h"
using namespace ARDOUR; using namespace ARDOUR;
using namespace ArdourSurface; using namespace ArdourSurface;
@ -68,7 +69,6 @@ Console1::~Console1 ()
BaseUI::quit (); BaseUI::quit ();
} }
void void
Console1::all_lights_out () Console1::all_lights_out ()
{ {
@ -149,6 +149,7 @@ Console1::begin_using_device ()
f0 7d 20 00 00 00 01 00 7f 49 6f 6c 73 00 f7 f0 7d 20 00 00 00 01 00 7f 49 6f 6c 73 00 f7
*/ */
load_mappings ();
setup_controls (); setup_controls ();
/* /*
@ -208,6 +209,8 @@ Console1::connect_internal_signals ()
{ {
BankChange.connect (console1_connections, MISSING_INVALIDATOR, boost::bind (&Console1::map_bank, this), this); BankChange.connect (console1_connections, MISSING_INVALIDATOR, boost::bind (&Console1::map_bank, this), this);
ShiftChange.connect (console1_connections, MISSING_INVALIDATOR, boost::bind (&Console1::map_shift, this, _1), this); ShiftChange.connect (console1_connections, MISSING_INVALIDATOR, boost::bind (&Console1::map_shift, this, _1), this);
PluginStateChange.connect (
console1_connections, MISSING_INVALIDATOR, boost::bind (&Console1::map_plugin_state, this, _1), this);
GotoView.connect ( GotoView.connect (
console1_connections, console1_connections,
MISSING_INVALIDATOR, MISSING_INVALIDATOR,
@ -227,12 +230,19 @@ Console1::setup_controls ()
ControllerButton track_select_button ( ControllerButton track_select_button (
*this, *this,
ControllerID (FOCUS1 + i), ControllerID (FOCUS1 + i),
boost::function<void (uint32_t)> (boost::bind (&Console1::select, this, i))); boost::function<void (uint32_t)> (boost::bind (&Console1::select, this, i)),
0,
boost::function<void (uint32_t)> (boost::bind (&Console1::select_plugin, this, i)));
} }
ControllerButton shift_button ( ControllerButton shift_button (
*this, ControllerID::PRESET, boost::function<void (uint32_t)> (boost::bind (&Console1::shift, this, _1))); *this, ControllerID::PRESET, boost::function<void (uint32_t)> (boost::bind (&Console1::shift, this, _1)));
ControllerButton plugin_state_button (
*this,
ControllerID::TRACK_GROUP,
boost::function<void (uint32_t)> (boost::bind (&Console1::plugin_state, this, _1)));
ControllerButton rude_solo ( ControllerButton rude_solo (
*this, ControllerID::DISPLAY_ON, boost::function<void (uint32_t)> (boost::bind (&Console1::rude_solo, this, _1))); *this, ControllerID::DISPLAY_ON, boost::function<void (uint32_t)> (boost::bind (&Console1::rude_solo, this, _1)));
ControllerButton zoom_button ( ControllerButton zoom_button (
@ -411,7 +421,10 @@ Console1::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* tb
try { try {
ControllerButton& b = get_button (ControllerID (controller_number)); ControllerButton& b = get_button (ControllerID (controller_number));
if (shift_state && b.shift_action) { if (in_plugin_state && b.plugin_action) {
DEBUG_TRACE (DEBUG::Console1, "Executing plugin_action\n");
b.plugin_action (value);
} else if (shift_state && b.shift_action) {
DEBUG_TRACE (DEBUG::Console1, "Executing shift_action\n"); DEBUG_TRACE (DEBUG::Console1, "Executing shift_action\n");
b.shift_action (value); b.shift_action (value);
} else { } else {

View File

@ -103,6 +103,9 @@ class Console1 : public MIDISurface
std::string input_port_name () const override; std::string input_port_name () const override;
std::string output_port_name () const override; std::string output_port_name () const override;
uint32_t load_mappings ();
bool load_mapping (FILE* fin);
/*XMLNode& get_state () const; /*XMLNode& get_state () const;
int set_state (const XMLNode&, int version);*/ int set_state (const XMLNode&, int version);*/
PBD::Signal0<void> ConnectionChange; PBD::Signal0<void> ConnectionChange;
@ -114,7 +117,7 @@ class Console1 : public MIDISurface
/* Local Signals */ /* Local Signals */
PBD::Signal0<void> BankChange; PBD::Signal0<void> BankChange;
PBD::Signal1<void, bool> ShiftChange; PBD::Signal1<void, bool> ShiftChange;
PBD::Signal1<void, bool> PluginStateChange;
enum ControllerID enum ControllerID
{ {
@ -193,6 +196,81 @@ class Console1 : public MIDISurface
}; };
using ControllerMap = std::map<std::string, ControllerID>;
ControllerMap controllerMap{ { "CONTROLLER_NONE", ControllerID::CONTROLLER_NONE },
{ "VOLUME", ControllerID::VOLUME },
{ "PAN", ControllerID::PAN },
{ "MUTE", ControllerID::MUTE },
{ "SOLO", ControllerID::SOLO },
{ "ORDER", ControllerID::ORDER },
{ "DRIVE", ControllerID::DRIVE },
{ "EXTERNAL_SIDECHAIN", ControllerID::EXTERNAL_SIDECHAIN },
{ "CHARACTER", ControllerID::CHARACTER },
{ "FOCUS1", ControllerID::FOCUS1 },
{ "FOCUS2", ControllerID::FOCUS2 },
{ "FOCUS3", ControllerID::FOCUS3 },
{ "FOCUS4", ControllerID::FOCUS4 },
{ "FOCUS5", ControllerID::FOCUS5 },
{ "FOCUS6", ControllerID::FOCUS6 },
{ "FOCUS7", ControllerID::FOCUS7 },
{ "FOCUS8", ControllerID::FOCUS8 },
{ "FOCUS9", ControllerID::FOCUS9 },
{ "FOCUS10", ControllerID::FOCUS10 },
{ "FOCUS11", ControllerID::FOCUS11 },
{ "FOCUS12", ControllerID::FOCUS12 },
{ "FOCUS13", ControllerID::FOCUS13 },
{ "FOCUS14", ControllerID::FOCUS14 },
{ "FOCUS15", ControllerID::FOCUS15 },
{ "FOCUS16", ControllerID::FOCUS16 },
{ "FOCUS17", ControllerID::FOCUS17 },
{ "FOCUS18", ControllerID::FOCUS18 },
{ "FOCUS19", ControllerID::FOCUS19 },
{ "FOCUS20", ControllerID::FOCUS20 },
{ "COMP", ControllerID::COMP },
{ "COMP_THRESH", ControllerID::COMP_THRESH },
{ "COMP_RELEASE", ControllerID::COMP_RELEASE },
{ "COMP_RATIO", ControllerID::COMP_RATIO },
{ "COMP_PAR", ControllerID::COMP_PAR },
{ "COMP_ATTACK", ControllerID::COMP_ATTACK },
{ "SHAPE", ControllerID::SHAPE },
{ "SHAPE_GATE", ControllerID::SHAPE_GATE },
{ "SHAPE_SUSTAIN", ControllerID::SHAPE_SUSTAIN },
{ "SHAPE_RELEASE", ControllerID::SHAPE_RELEASE },
{ "SHAPE_PUNCH", ControllerID::SHAPE_PUNCH },
{ "PRESET", ControllerID::PRESET },
{ "HARD_GATE", ControllerID::HARD_GATE },
{ "FILTER_TO_COMPRESSORS", ControllerID::FILTER_TO_COMPRESSORS },
{ "HIGH_SHAPE", ControllerID::HIGH_SHAPE },
{ "EQ", ControllerID::EQ },
{ "HIGH_GAIN", ControllerID::HIGH_GAIN },
{ "HIGH_FREQ", ControllerID::HIGH_FREQ },
{ "HIGH_MID_GAIN", ControllerID::HIGH_MID_GAIN },
{ "HIGH_MID_FREQ", ControllerID::HIGH_MID_FREQ },
{ "HIGH_MID_SHAPE", ControllerID::HIGH_MID_SHAPE },
{ "LOW_MID_GAIN", ControllerID::LOW_MID_GAIN },
{ "LOW_MID_FREQ", ControllerID::LOW_MID_FREQ },
{ "LOW_MID_SHAPE", ControllerID::LOW_MID_SHAPE },
{ "LOW_GAIN", ControllerID::LOW_GAIN },
{ "LOW_FREQ", ControllerID::LOW_FREQ },
{ "LOW_SHAPE", ControllerID::LOW_SHAPE },
{ "PAGE_UP", ControllerID::PAGE_UP },
{ "PAGE_DOWN", ControllerID::PAGE_DOWN },
{ "DISPLAY_ON", ControllerID::DISPLAY_ON },
{ "LOW_CUT", ControllerID::LOW_CUT },
{ "MODE", ControllerID::MODE },
{ "HIGH_CUT", ControllerID::HIGH_CUT },
{ "GAIN", ControllerID::GAIN },
{ "PHASE_INV", ControllerID::PHASE_INV },
{ "INPUT_METER_L", ControllerID::INPUT_METER_L },
{ "INPUT_METER_R", ControllerID::INPUT_METER_R },
{ "OUTPUT_METER_L", ControllerID::OUTPUT_METER_L },
{ "OUTPUT_METER_R", ControllerID::OUTPUT_METER_R },
{ "SHAPE_METER", ControllerID::SHAPE_METER },
{ "COMP_METER", ControllerID::COMP_METER },
{ "TRACK_COPY", ControllerID::TRACK_COPY },
{ "TRACK_GROUP", ControllerID::TRACK_GROUP } };
private: private:
/* GUI */ /* GUI */
mutable C1GUI* gui; mutable C1GUI* gui;
@ -201,12 +279,16 @@ class Console1 : public MIDISurface
/* Configuration */ /* Configuration */
const uint32_t bank_size = 20; const uint32_t bank_size = 20;
// Shift button
bool shift_state = false; bool shift_state = false;
bool in_plugin_state = false;
bool rolling = false; bool rolling = false;
uint32_t current_bank = 0; uint32_t current_bank = 0;
uint32_t current_strippable_index = 0; uint32_t current_strippable_index = 0;
uint32_t current_plugin_index = 0;
std::shared_ptr<ARDOUR::AutomationControl> current_pan_control = nullptr; std::shared_ptr<ARDOUR::AutomationControl> current_pan_control = nullptr;
std::shared_ptr<ARDOUR::Stripable> _current_stripable; std::shared_ptr<ARDOUR::Stripable> _current_stripable;
@ -323,6 +405,7 @@ class Console1 : public MIDISurface
void rude_solo (const uint32_t); void rude_solo (const uint32_t);
void select (const uint32_t i); void select (const uint32_t i);
void shift (const uint32_t); void shift (const uint32_t);
void plugin_state (const uint32_t);
void solo (const uint32_t); void solo (const uint32_t);
void trim (const uint32_t value); void trim (const uint32_t value);
void window (const uint32_t value); void window (const uint32_t value);
@ -418,6 +501,7 @@ class Console1 : public MIDISurface
void map_recenable (); void map_recenable ();
void map_select (); void map_select ();
void map_shift (bool shift); void map_shift (bool shift);
void map_plugin_state (bool state);
void map_solo (); void map_solo ();
void map_trim (); void map_trim ();
@ -463,6 +547,33 @@ class Console1 : public MIDISurface
float calculate_meter (float dB); float calculate_meter (float dB);
uint32_t control_to_midi (Controllable controllable, float val, uint32_t max_value_for_type = 127); uint32_t control_to_midi (Controllable controllable, float val, uint32_t max_value_for_type = 127);
float midi_to_control (Controllable controllable, uint32_t val, uint32_t max_value_for_type = 127); float midi_to_control (Controllable controllable, uint32_t val, uint32_t max_value_for_type = 127);
struct PluginParameterMapping
{
int paramIndex;
std::string name;
ControllerID controllerId;
};
using ParameterMap = std::map<uint32_t, PluginParameterMapping>;
struct PluginMapping
{
std::string id;
std::string name;
ParameterMap parameters;
};
/* plugin handling */
bool spill_plugins (uint32_t plugin_index);
/* plugin operations */
void select_plugin (const uint32_t i);
void map_select_plugin ();
using PluginMappingMap = std::map<std::string, PluginMapping>;
PluginMappingMap pluginMappingMap;
}; };
} }
#endif /* ardour_surface_console1_h */ #endif /* ardour_surface_console1_h */

View File

@ -18,6 +18,7 @@ def build(bld):
console1_interface.cc console1_interface.cc
console1.cc console1.cc
c1_operations.cc c1_operations.cc
c1_plugin_operations.cc
c1_gui.cc c1_gui.cc
''' '''
obj.defines = [ 'PACKAGE="ardour_console1"' ] obj.defines = [ 'PACKAGE="ardour_console1"' ]