Skip to content

Commit

Permalink
support VST2 plugins in jackrack module (#1013)
Browse files Browse the repository at this point in the history
  • Loading branch information
ddennedy committed Aug 14, 2024
1 parent 7301390 commit a19e8ad
Show file tree
Hide file tree
Showing 20 changed files with 4,123 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ option(MOD_GLAXNIMATE "Enable Glaxnimate module (Qt5)" OFF)
option(MOD_GLAXNIMATE_QT6 "Enable Glaxnimate module (Qt6)" OFF)
option(MOD_JACKRACK "Enable JACK Rack module" ON)
option(USE_LV2 "Enable LV2 features" ON)
option(USE_VST2 "Enable LV2 features" ON)
option(MOD_KDENLIVE "Enable Kdenlive module" ON)
option(MOD_NDI "Enable NDI module" OFF)
option(MOD_NORMALIZE "Enable Normalize module (GPL)" ON)
Expand Down Expand Up @@ -641,5 +642,6 @@ add_feature_info("SWIG: Python" SWIG_PYTHON "")
add_feature_info("SWIG: Ruby" SWIG_RUBY "")
add_feature_info("SWIG: Tcl" SWIG_TCL "")
add_feature_info("lv2: LV2 Plugins support" USE_LV2 "")
add_feature_info("vst2: VST2 Plugins support" USE_VST2 "")

feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
18 changes: 17 additions & 1 deletion src/modules/jackrack/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ if(TARGET JACK::JACK)
install(FILES consumer_jack.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack)
endif()

if(USE_LV2)
if(USE_LV2 AND GPL)
target_compile_definitions(mltjackrack PRIVATE WITH_LV2)
install(FILES filter_lv2.yml producer_lv2.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack)
endif()

if(USE_VST2 AND GPL)
target_compile_definitions(mltjackrack PRIVATE WITH_VST2)
install(FILES filter_vst2.yml producer_vst2.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack)
endif()

if(GPL AND TARGET PkgConfig::xml AND TARGET PkgConfig::glib AND ladspa_h_FOUND)
target_sources(mltjackrack PRIVATE
jack_rack.c jack_rack.h
Expand Down Expand Up @@ -58,6 +63,17 @@ if(GPL AND TARGET PkgConfig::xml AND TARGET PkgConfig::glib AND ladspa_h_FOUND)
install(FILES filter_lv2.yml producer_lv2.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack)
endif()

if(USE_VST2)
target_sources(mltjackrack PRIVATE
filter_vst2.c producer_vst2.c
vst2_context.c vst2_context.h
vst2_plugin.c vst2_plugin.h
vst2_process.c vst2_process.h
vst2_plugin_settings.c vst2_plugin_settings.h
vestige.h)
install(FILES filter_vst2.yml producer_vst2.yml DESTINATION ${MLT_INSTALL_DATA_DIR}/jackrack)
endif()

endif()

set_target_properties(mltjackrack PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${MLT_MODULE_OUTPUT_DIRECTORY}")
Expand Down
218 changes: 218 additions & 0 deletions src/modules/jackrack/factory.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,31 @@ extern mlt_producer producer_lv2_init(mlt_profile profile,
char *arg);
#endif

#ifdef WITH_VST2

#include "vestige.h"

extern mlt_filter filter_vst2_init(mlt_profile profile,
mlt_service_type type,
const char *id,
char *arg);
extern mlt_producer producer_vst2_init(mlt_profile profile,
mlt_service_type type,
const char *id,
char *arg);

#endif

plugin_mgr_t *g_jackrack_plugin_mgr = NULL;

#ifdef WITH_LV2
lv2_mgr_t *g_lv2_plugin_mgr = NULL;
#endif

#ifdef WITH_VST2
vst2_mgr_t *g_vst2_plugin_mgr = NULL;
#endif

static void add_port_to_metadata(mlt_properties p, plugin_desc_t *desc, int j)
{
LADSPA_Data sample_rate = 48000;
Expand Down Expand Up @@ -441,6 +460,181 @@ static mlt_properties lv2_metadata(mlt_service_type type, const char *id, char *

#endif

#ifdef WITH_VST2

static void vst2_add_port_to_metadata(mlt_properties p, vst2_plugin_desc_t *desc, int j)
{
LADSPA_Data sample_rate = 48000;
LADSPA_PortRangeHintDescriptor hint_descriptor = desc->port_range_hints[j].HintDescriptor;

mlt_properties_set(p, "title", desc->port_names[j]);
if (LADSPA_IS_HINT_INTEGER(hint_descriptor)) {
mlt_properties_set(p, "type", "integer");
mlt_properties_set_int(p,
"default",
vst2_plugin_desc_get_default_control_value(
desc,
j - (desc->effect->numInputs + desc->effect->numOutputs),
sample_rate));
} else if (LADSPA_IS_HINT_TOGGLED(hint_descriptor)) {
mlt_properties_set(p, "type", "boolean");
mlt_properties_set_int(p,
"default",
vst2_plugin_desc_get_default_control_value(
desc,
j - (desc->effect->numInputs + desc->effect->numOutputs),
sample_rate));
} else {
mlt_properties_set(p, "type", "float");
mlt_properties_set_double(p,
"default",
vst2_plugin_desc_get_default_control_value(
desc,
j - (desc->effect->numInputs + desc->effect->numOutputs),
sample_rate));
mlt_properties_set_double(p, "minimum", 0.0);
mlt_properties_set_double(p, "maximum", 1.0);
}
/* set upper and lower, possibly adjusted to the sample rate */
if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) {
LADSPA_Data lower = desc->port_range_hints[j].LowerBound;
if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor))
lower *= sample_rate;
if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) {
if (lower < FLT_EPSILON)
lower = FLT_EPSILON;
}
mlt_properties_set_double(p, "minimum", lower);
}
if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) {
LADSPA_Data upper = desc->port_range_hints[j].UpperBound;
if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor))
upper *= sample_rate;
mlt_properties_set_double(p, "maximum", upper);
}
if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor))
mlt_properties_set(p, "scale", "log");
mlt_properties_set(p, "mutable", "yes");
mlt_properties_set(p, "animation", "yes");
}

static mlt_properties vst2_metadata(mlt_service_type type, const char *id, char *data)
{
char file[PATH_MAX];
if (type == mlt_service_filter_type) {
snprintf(file,
PATH_MAX,
"%s/jackrack/%s",
mlt_environment("MLT_DATA"),
strncmp(id, "vst2.", 5) ? data : "filter_vst2.yml");
} else {
snprintf(file,
PATH_MAX,
"%s/jackrack/%s",
mlt_environment("MLT_DATA"),
strncmp(id, "vst2.", 5) ? data : "producer_vst2.yml");
}
mlt_properties result = mlt_properties_parse_yaml(file);

if (!strncmp(id, "vst2.", 5)) {
// Annotate the yaml properties with ladspa control port info.
vst2_plugin_desc_t *desc = vst2_mgr_get_any_desc(g_vst2_plugin_mgr,
strtol(id + 5, NULL, 10));

if (desc) {
mlt_properties params = mlt_properties_new();
mlt_properties p;
char key[20];
int i;

mlt_properties_set(result, "identifier", id);
mlt_properties_set(result, "title", desc->name);
mlt_properties_set(result, "creator", desc->maker ? desc->maker : "unknown");
mlt_properties_set(result, "description", "VST2 plugin");
mlt_properties_set_data(result,
"parameters",
params,
0,
(mlt_destructor) mlt_properties_close,
NULL);
for (i = 0; i < desc->control_port_count; i++) {
int j = desc->control_port_indicies[i];

p = mlt_properties_new();
snprintf(key, sizeof(key), "%d", mlt_properties_count(params));
mlt_properties_set_data(params,
key,
p,
0,
(mlt_destructor) mlt_properties_close,
NULL);
snprintf(key,
sizeof(key),
"%d",
j - (desc->effect->numInputs + desc->effect->numOutputs));
mlt_properties_set(p, "identifier", key);
vst2_add_port_to_metadata(p, desc, j);
mlt_properties_set(p, "mutable", "yes");
}
/* for (i = 0; i < desc->status_port_count; i++) {
int j = desc->status_port_indicies[i];
p = mlt_properties_new();
snprintf(key, sizeof(key), "%d", mlt_properties_count(params));
mlt_properties_set_data(params,
key,
p,
0,
(mlt_destructor) mlt_properties_close,
NULL);
snprintf(key, sizeof(key), "%d[*]", j);
mlt_properties_set(p, "identifier", key);
vst2_add_port_to_metadata(p, desc, j);
mlt_properties_set(p, "readonly", "yes");
} */

p = mlt_properties_new();
snprintf(key, sizeof(key), "%d", mlt_properties_count(params));
mlt_properties_set_data(params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL);
mlt_properties_set(p, "identifier", "instances");
mlt_properties_set(p, "title", "Instances");
mlt_properties_set(p,
"description",
"The number of instances of the plugin that are in use.\n"
"MLT will create the number of plugins that are required "
"to support the number of audio channels.\n"
"Status parameters (readonly) are provided for each instance "
"and are accessed by specifying the instance number after the "
"identifier (starting at zero).\n"
"e.g. 9[0] provides the value of status 9 for the first instance.");
mlt_properties_set(p, "type", "integer");
mlt_properties_set(p, "readonly", "yes");

if (type == mlt_service_filter_type) {
p = mlt_properties_new();
snprintf(key, sizeof(key), "%d", mlt_properties_count(params));
mlt_properties_set_data(params,
key,
p,
0,
(mlt_destructor) mlt_properties_close,
NULL);
mlt_properties_set(p, "identifier", "wetness");
mlt_properties_set(p, "title", "Wet/Dry");
mlt_properties_set(p, "type", "float");
mlt_properties_set_double(p, "default", 1);
mlt_properties_set_double(p, "minimum", 0);
mlt_properties_set_double(p, "maximum", 1);
mlt_properties_set(p, "mutable", "yes");
mlt_properties_set(p, "animation", "yes");
}
}
}

return result;
}

#endif

MLT_REPOSITORY
{
#ifdef GPL
Expand Down Expand Up @@ -499,6 +693,30 @@ MLT_REPOSITORY
}
#endif

#ifdef WITH_VST2

g_vst2_plugin_mgr = vst2_mgr_new();

for (list = g_vst2_plugin_mgr->all_plugins; list; list = g_slist_next(list)) {
vst2_plugin_desc_t *desc = (vst2_plugin_desc_t *) list->data;
char *s = malloc(strlen("vst2.") + 21);

sprintf(s, "vst2.%lu", desc->id);

if (desc->has_input) {
MLT_REGISTER(mlt_service_filter_type, s, filter_vst2_init);
MLT_REGISTER_METADATA(mlt_service_filter_type, s, vst2_metadata, NULL);
} else {
MLT_REGISTER(mlt_service_producer_type, s, producer_vst2_init);
MLT_REGISTER_METADATA(mlt_service_producer_type, s, vst2_metadata, NULL);
}

free(s);
}
mlt_factory_register_for_clean_up(g_vst2_plugin_mgr, (mlt_destructor) vst2_mgr_destroy);

#endif

#ifdef WITH_JACK
MLT_REGISTER(mlt_service_filter_type, "jack", filter_jackrack_init);
MLT_REGISTER_METADATA(mlt_service_filter_type, "jack", metadata, "filter_jack.yml");
Expand Down
Loading

0 comments on commit a19e8ad

Please sign in to comment.