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,
ControllerID id,
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)
, action (action)
, shift_action (shift_action)
, plugin_action (plugin_action)
{
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)> shift_action;
boost::function<void (uint32_t)> plugin_action;
};
class MultiStateButton : public Controller

View File

@ -146,6 +146,14 @@ Console1::shift (const uint32_t 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
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
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/debug.h"
#include "ardour/filesystem_paths.h"
#include "ardour/meter.h"
#include "ardour/monitor_control.h"
#include "ardour/phase_control.h"
@ -36,8 +37,8 @@
#include "ardour/vca_manager.h"
#include "console1.h"
#include "c1_gui.h"
#include "c1_control.h"
#include "c1_gui.h"
using namespace ARDOUR;
using namespace ArdourSurface;
@ -68,7 +69,6 @@ Console1::~Console1 ()
BaseUI::quit ();
}
void
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
*/
load_mappings ();
setup_controls ();
/*
@ -208,6 +209,8 @@ Console1::connect_internal_signals ()
{
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);
PluginStateChange.connect (
console1_connections, MISSING_INVALIDATOR, boost::bind (&Console1::map_plugin_state, this, _1), this);
GotoView.connect (
console1_connections,
MISSING_INVALIDATOR,
@ -227,12 +230,19 @@ Console1::setup_controls ()
ControllerButton track_select_button (
*this,
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 (
*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 (
*this, ControllerID::DISPLAY_ON, boost::function<void (uint32_t)> (boost::bind (&Console1::rude_solo, this, _1)));
ControllerButton zoom_button (
@ -411,7 +421,10 @@ Console1::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* tb
try {
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");
b.shift_action (value);
} else {

View File

@ -103,6 +103,9 @@ class Console1 : public MIDISurface
std::string input_port_name () const override;
std::string output_port_name () const override;
uint32_t load_mappings ();
bool load_mapping (FILE* fin);
/*XMLNode& get_state () const;
int set_state (const XMLNode&, int version);*/
PBD::Signal0<void> ConnectionChange;
@ -114,7 +117,7 @@ class Console1 : public MIDISurface
/* Local Signals */
PBD::Signal0<void> BankChange;
PBD::Signal1<void, bool> ShiftChange;
PBD::Signal1<void, bool> PluginStateChange;
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:
/* GUI */
mutable C1GUI* gui;
@ -201,12 +279,16 @@ class Console1 : public MIDISurface
/* Configuration */
const uint32_t bank_size = 20;
// Shift button
bool shift_state = false;
bool in_plugin_state = false;
bool rolling = false;
uint32_t current_bank = 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::Stripable> _current_stripable;
@ -323,6 +405,7 @@ class Console1 : public MIDISurface
void rude_solo (const uint32_t);
void select (const uint32_t i);
void shift (const uint32_t);
void plugin_state (const uint32_t);
void solo (const uint32_t);
void trim (const uint32_t value);
void window (const uint32_t value);
@ -418,6 +501,7 @@ class Console1 : public MIDISurface
void map_recenable ();
void map_select ();
void map_shift (bool shift);
void map_plugin_state (bool state);
void map_solo ();
void map_trim ();
@ -463,6 +547,33 @@ class Console1 : public MIDISurface
float calculate_meter (float dB);
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);
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 */

View File

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