M data/org.zrythm.Zrythm.gschema.xml => data/org.zrythm.Zrythm.gschema.xml +22 -1
@@ 204,7 204,7 @@
be auto-connected.</description>
</key>
- <!-- Selected language -->
+ <!-- KEY: language -->
<key name="language"
enum="org.zrythm.Zrythm.preferences.language-enum">
<default>"english"</default>
@@ 214,6 214,7 @@
</description>
</key>
+ <!-- KEY: open-plugin-uis-on-instantiate -->
<key name="open-plugin-uis-on-instantiate" type="i">
<default>1</default>
<summary>Open plugin UIs when they are instantiated</summary>
@@ 224,6 225,26 @@
</description>
</key>
+ <!-- KEY: sfz-search-path -->
+ <key name="sfz-search-paths" type="as">
+ <default>[]</default>
+ <summary>Search paths for SFZ instruments</summary>
+ <description>
+ The search paths to scan for SFZ
+ instruments.
+ </description>
+ </key>
+
+ <!-- KEY: sf2-search-path -->
+ <key name="sf2-search-paths" type="as">
+ <default>[]</default>
+ <summary>Search paths for SF2 instruments</summary>
+ <description>
+ The search paths to scan for SF2
+ instruments.
+ </description>
+ </key>
+
<key name="edit-region-size" type="i">
<default>4</default>
<summary>Region Size</summary>
M inc/audio/automatable.h => inc/audio/automatable.h +6 -0
@@ 20,11 20,15 @@
#ifndef __AUDIO_AUTOMATABLE_H__
#define __AUDIO_AUTOMATABLE_H__
+#include "config.h"
+
#include "audio/port.h"
#include "plugins/lv2/control.h"
#include "utils/yaml.h"
+#ifdef HAVE_CARLA
#include "CarlaNativePlugin.h"
+#endif
#define IS_AUTOMATABLE_LV2_CONTROL(x) x->type == AUTOMATABLE_TYPE_PLUGIN_CONTROL && \
x->control
@@ 188,6 192,7 @@ automatable_create_lv2_control (
Plugin * plugin,
Lv2Control * control);
+#ifdef HAVE_CARLA
/**
* Creates an automatable for a Carla native
* plugin control.
@@ 196,6 201,7 @@ Automatable *
automatable_create_carla_control (
Plugin * plugin,
const NativeParameter * param);
+#endif
Automatable *
automatable_create_plugin_enabled (Plugin * plugin);
M inc/plugins/carla/engine_interface.h => inc/plugins/carla/engine_interface.h +1 -1
@@ 25,7 25,7 @@
#include "config.h"
-#ifdef HAVE_CARLA_NATIVE_PLUGIN
+#ifdef HAVE_CARLA
#ifndef __PLUGINS_CARLA_ENGINE_INTERFACE_H__
#define __PLUGINS_CARLA_ENGINE_INTERFACE_H__
M inc/plugins/carla/native_plugin.h => inc/plugins/carla/native_plugin.h +22 -12
@@ 25,12 25,13 @@
#include "config.h"
-#ifdef HAVE_CARLA_NATIVE_PLUGIN
+#ifdef HAVE_CARLA
#ifndef __PLUGINS_CARLA_NATIVE_PLUGIN_H__
#define __PLUGINS_CARLA_NATIVE_PLUGIN_H__
-#include "CarlaNativePlugin.h"
+#include <CarlaNativePlugin.h>
+#include <CarlaUtils.h>
typedef struct PluginDescriptor PluginDescriptor;
typedef void * CarlaPluginHandle;
@@ 46,6 47,7 @@ typedef void * CarlaPluginHandle;
*/
typedef enum CarlaPluginType
{
+ CARLA_PLUGIN_NONE,
CARLA_PLUGIN_RACK,
CARLA_PLUGIN_PATCHBAY,
CARLA_PLUGIN_PATCHBAY16,
@@ 59,7 61,7 @@ typedef struct CarlaNativePlugin
NativeHostDescriptor host;
const NativePluginDescriptor * descriptor;
- uint32_t midi_event_count;
+ uint32_t num_midi_events;
NativeMidiEvent midi_events[200];
NativeTimeInfo time_info;
@@ 90,22 92,30 @@ typedef struct CarlaNativePlugin
* Creates an instance of a CarlaNativePlugin inside
* the given Plugin.
*
- * The given Plugin must have its descriptor filled in.
+ * The given Plugin must have its descriptor filled
+ * in.
*/
void
carla_native_plugin_create (
Plugin * plugin);
/**
- * Returns a filled in descriptor for the given
- * type.
- *
- * @param ins Set the descriptor to be an instrument.
+ * Returns a filled in descriptor from the
+ * given binary path.
+ */
+PluginDescriptor *
+carla_native_plugin_get_descriptor_from_path (
+ const char * path,
+ PluginType type);
+
+/**
+ * Returns a filled in descriptor from the
+ * CarlaCachedPluginInfo.
*/
PluginDescriptor *
-carla_native_plugin_get_descriptor (
- CarlaPluginType type,
- int ins);
+carla_native_plugin_get_descriptor_from_cached (
+ const CarlaCachedPluginInfo * info,
+ PluginType type);
/**
* Wrapper to get param count.
@@ 200,4 210,4 @@ carla_native_plugin_free (
#endif // header guard
-#endif // HAVE_CARLA_NATIVE_PLUGIN
+#endif // HAVE_CARLA
M inc/plugins/carla/plugin_interface.h => inc/plugins/carla/plugin_interface.h +61 -1
@@ 25,7 25,7 @@
#include "config.h"
-#ifdef HAVE_CARLA_NATIVE_PLUGIN
+#ifdef HAVE_CARLA
#ifndef __PLUGINS_CARLA_PLUGIN_INTERFACE_H__
#define __PLUGINS_CARLA_PLUGIN_INTERFACE_H__
@@ 56,6 56,66 @@ carla_plugin_process (
float ** const cv_out,
const uint32_t frames);
+void
+carla_plugin_get_real_name (
+ CarlaPluginHandle handle,
+ char * const name);
+
+void
+carla_plugin_get_maker (
+ CarlaPluginHandle handle,
+ char * const name);
+
+int
+carla_plugin_get_category (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_audio_in_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_audio_out_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_cv_in_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_cv_out_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_midi_in_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_midi_out_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_parameter_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_parameter_in_count (
+ CarlaPluginHandle handle);
+
+uint32_t
+carla_plugin_get_parameter_out_count (
+ CarlaPluginHandle handle);
+
+int
+carla_plugin_save_state_to_file (
+ CarlaPluginHandle handle,
+ const char * const filename);
+
+int
+carla_plugin_load_state_from_file (
+ CarlaPluginHandle handle,
+ const char * const filename);
+
#ifdef __cplusplus
}
#endif
M inc/plugins/plugin.h => inc/plugins/plugin.h +37 -6
@@ 92,13 92,28 @@ typedef enum PluginProtocol
{
/** LV2 plugin. */
PROT_LV2,
+ /** DSSI. */
PROT_DSSI,
+ /** LADSPA. */
PROT_LADSPA,
+ /** VST2. */
PROT_VST,
+ /** VST3. **/
PROT_VST3,
-
- /** Carla native plugin. */
- PROT_CARLA,
+ /** AU (Mac). */
+ PROT_AU,
+ /** SoundFont 2 file. */
+ PROT_SF2,
+ /** SoundFont file. */
+ PROT_SFZ,
+ /** JACK application. */
+ PROT_JACK,
+#ifdef HAVE_CARLA
+ /** Carla internal plugin (rack, patchbay, or
+ * other plugins that are maintained by Carla
+ * such as Bypass and LFO). */
+ PROT_CARLA_INTERNAL,
+#endif
} PluginProtocol;
typedef enum PluginArchitecture
@@ 140,12 155,18 @@ typedef struct PluginDescriptor
PluginArchitecture arch;
/** Plugin protocol (Lv2/DSSI/LADSPA/VST...). */
PluginProtocol protocol;
- /** Path, if not an Lv2Plugin which uses URIs. */
+ /** Path, if not an Lv2Plugin which uses URIs.
+ * Carla will use this. */
char * path;
/** Lv2Plugin URI. */
char * uri;
- /** Carla plugin type, if Carla. */
+#ifdef HAVE_CARLA_NATIVE_PLUGIN
+ /** 1 if this plugin is to be instantiated
+ * through Carla. */
+ int open_with_carla;
+ /** Carla plugin type, if Carla internal plugin. */
CarlaPluginType carla_type;
+#endif
} PluginDescriptor;
/**
@@ 157,8 178,10 @@ typedef struct Plugin
/** Pointer LV2 plugin, if LV2. */
Lv2Plugin * lv2;
+#ifdef HAVE_CARLA
/** Pointer to CarlaNativePlugin, if Carla. */
CarlaNativePlugin * carla;
+#endif
/** Descriptor. */
PluginDescriptor * descr;
@@ 262,7 285,8 @@ descriptor_fields_schema[] =
PluginDescriptor, name,
0, CYAML_UNLIMITED),
CYAML_FIELD_STRING_PTR (
- "website", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
+ "website",
+ CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
PluginDescriptor, website,
0, CYAML_UNLIMITED),
CYAML_FIELD_STRING_PTR (
@@ 476,6 500,13 @@ plugin_descriptor_string_to_category (
const char * str);
/**
+ * Frees the plugin descriptor.
+ */
+void
+plugin_descriptor_free (
+ PluginDescriptor * self);
+
+/**
* Moves the Plugin's automation from one Channel
* to another.
*/
M inc/utils/io.h => inc/utils/io.h +16 -2
@@ 117,9 117,23 @@ io_rmdir (
* @return a NULL terminated array of strings that
* must be free'd with g_strfreev().
*/
+#define io_get_files_in_dir(dir) \
+ io_get_files_in_dir_ending_in (dir, 0, NULL)
+
+/**
+ * Returns a list of the files in the given
+ * directory.
+ *
+ * @param dir The directory to look for.
+ *
+ * @return a NULL terminated array of strings that
+ * must be free'd with g_strfreev().
+ */
char **
-io_get_files_in_dir (
- const char * dir);
+io_get_files_in_dir_ending_in (
+ const char * dir,
+ const int recursive,
+ const char * end_string);
/**
* Returns a newly allocated path that is either
M inc/utils/string.h => inc/utils/string.h +51 -0
@@ 33,6 33,16 @@
*/
/**
+ * Returns if the character is ASCII.
+ */
+static inline int
+string_char_is_ascii (
+ const char character)
+{
+ return character >= 32 && character <= 126;
+}
+
+/**
* Returns if the string is ASCII.
*/
int
@@ 40,6 50,15 @@ string_is_ascii (
const char * string);
/**
+ * Returns a new string up to the character before
+ * the first non-ascii character, or until the
+ * end.
+ */
+char *
+string_stop_at_first_non_ascii (
+ const char * str);
+
+/**
* Returns the matched string if the string array
* contains the given substring.
*/
@@ 62,6 81,29 @@ string_contains_substr (
const char * substr,
const int accept_alternatives);
+int
+string_ends_with (
+ const char * str,
+ const char * end_str,
+ const int ignore_case);
+
+/**
+ * Removes non-ascii characters from the given
+ * string.
+ */
+void
+string_remove_non_ascii_chars (
+ char * str);
+
+/**
+ * Removes occurrences of the given character
+ * from the string.
+ */
+void
+string_remove_char (
+ char * str,
+ const char remove);
+
/**
* Returns if the two strings are equal.
*/
@@ 82,6 124,15 @@ string_convert_to_filename (
const char * str);
/**
+ * Returns the index of the first occurrence of
+ * the search char, or -1 if not found.
+ */
+int
+string_index_of_char (
+ const char * str,
+ const char search_char);
+
+/**
* Removes any bak, bak1 etc suffixes from the
* string and returns a newly allocated string.
*/
M meson.build => meson.build +40 -17
@@ 206,7 206,7 @@ test_strict_cflags = [
'-Werror=overlength-strings',
'-Werror=stringop-truncation',
'-Werror=missing-declarations',
- '-Werror=redundant-decls',
+ #'-Werror=redundant-decls',
'-Werror=shadow',
'-Werror=undef',
'-Werror=unused',
@@ 332,23 332,11 @@ cyaml_dep = dependency(
if (cyaml_dep.found ())
cdata.set('HAVE_CYAML', 1)
endif
+
carla_native_plugin_dep = dependency(
'carla-native-plugin', required: false)
-if (carla_native_plugin_dep.found ())
- cdata.set('HAVE_CARLA_NATIVE_PLUGIN', 1)
- carla_native_plugin_dep = declare_dependency(
- link_args: [
- '-Wl,-rpath=/usr/lib/carla',
- '-L/usr/lib/carla',
- '-lcarla_native-plugin',
- ],
- compile_args: [
- '-DREAL_BUILD',
- '-I/usr/include/carla',
- '-I/usr/include/carla/includes'
- ])
-endif
-
+carla_utils_dep = dependency(
+ 'carla-utils', required: false)
qt5_dep = dependency('Qt5Widgets', required: false)
yaml_dep = dependency('yaml-0.1')
gtk_dep = dependency('gtk+-3.0', version: '>=3.22')
@@ 364,7 352,6 @@ zrythm_deps = [
alsa_dep,
suil_dep,
cyaml_dep,
- carla_native_plugin_dep,
dependency('threads'),
dependency('lilv-0', version: '>=0.24.2'),
dependency('samplerate', version: '>=0.1.8'),
@@ 378,6 365,42 @@ if (qt5_dep.found() and get_option('enable_qt5'))
zrythm_deps += qt5_dep
endif
+if (carla_native_plugin_dep.found() and carla_utils_dep.found() and get_option('enable_carla'))
+ cdata.set('HAVE_CARLA', 1)
+ # workaround because carla's pc files are broken
+ carla_includedir = carla_native_plugin_dep.get_pkgconfig_variable('includedir')
+ carla_libdir = carla_native_plugin_dep.get_pkgconfig_variable('libdir')
+ carla_native_plugin_dep = declare_dependency(
+ link_args: [
+ '-Wl,-rpath=' + carla_libdir,
+ '-L' + carla_libdir,
+ '-lcarla_native-plugin',
+ ],
+ compile_args: [
+ '-DREAL_BUILD',
+ '-I' + carla_includedir,
+ '-I' + join_paths (carla_includedir, 'includes'),
+ ])
+ # workaround because carla's pc files are broken
+ carla_includedir = carla_utils_dep.get_pkgconfig_variable('includedir')
+ carla_libdir = carla_utils_dep.get_pkgconfig_variable('libdir')
+ carla_utils_dep = declare_dependency(
+ link_args: [
+ '-Wl,-rpath=' + carla_libdir,
+ '-L' + carla_libdir,
+ '-lcarla_utils',
+ ],
+ compile_args: [
+ '-DREAL_BUILD',
+ '-I' + carla_includedir,
+ '-I' + join_paths (carla_includedir, 'includes'),
+ '-I' + join_paths (carla_includedir, 'utils'),
+ ])
+ zrythm_deps += [
+ carla_native_plugin_dep,
+ carla_utils_dep, ]
+endif
+
if os_linux
zrythm_deps += cc.find_library('rt')
endif
M meson_options.txt => meson_options.txt +6 -0
@@ 40,6 40,12 @@ option (
description: 'Compile with ffmpeg (for MP3 support)')
option (
+ 'enable_carla',
+ type: 'boolean',
+ value: false,
+ description: 'Compile with Carla (for VST support)')
+
+option (
'gen_dev_docs',
type: 'boolean',
value: false,
M src/audio/automatable.c => src/audio/automatable.c +2 -0
@@ 223,6 223,7 @@ automatable_create_lv2_control (
return a;
}
+#ifdef HAVE_CARLA
/**
* Creates an automatable for a Carla native
* plugin control.
@@ 252,6 253,7 @@ automatable_create_carla_control (
return a;
}
+#endif
Automatable *
automatable_create_plugin_enabled (
M src/plugins/carla/engine_interface.cpp => src/plugins/carla/engine_interface.cpp +7 -1
@@ 17,8 17,12 @@
* along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
+#ifdef HAVE_CARLA
+
#include "plugins/carla/engine_interface.h"
-#include "CarlaEngine.hpp"
+#include <CarlaEngine.hpp>
extern "C"
{
@@ 81,3 85,5 @@ carla_engine_get_plugin (
#undef GET_ENGINE
}
+
+#endif // if HAVE_CARLA
M src/plugins/carla/native_plugin.c => src/plugins/carla/native_plugin.c +594 -140
@@ 17,9 17,14 @@
* along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
+#ifdef HAVE_CARLA
+
#include <stdlib.h>
#include "audio/engine.h"
+#include "audio/midi.h"
#include "audio/transport.h"
#include "gui/widgets/main_window.h"
#include "plugins/plugin.h"
@@ 29,11 34,35 @@
#include "project.h"
#include "utils/gtk.h"
#include "utils/io.h"
+#include "utils/string.h"
#include "zrythm.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+/**
+ * Tick callback for the plugin UI.
+ */
+static int
+carla_plugin_tick_cb (
+ GtkWidget * widget,
+ GdkFrameClock * frame_clock,
+ CarlaNativePlugin * self)
+{
+ if (self->plugin->visible &&
+ MAIN_WINDOW)
+ {
+ CarlaPluginHandle plugin =
+ carla_native_plugin_get_plugin_handle (
+ self);
+ carla_plugin_ui_idle (plugin);
+
+ return G_SOURCE_CONTINUE;
+ }
+ else
+ return G_SOURCE_REMOVE;
+}
+
static uint32_t
host_get_buffer_size (
NativeHostHandle handle)
@@ 121,8 150,61 @@ host_dispatcher (
return 0;
}
+/**
+ * Carla engine callback.
+ */
+static void
+engine_callback (
+ void* ptr,
+ EngineCallbackOpcode action,
+ unsigned int pluginId,
+ int value1,
+ int value2,
+ float value3,
+ const char* valueStr)
+{
+ CarlaNativePlugin * self =
+ (CarlaNativePlugin *) ptr;
+
+ switch (action)
+ {
+ case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED:
+ break;
+ case ENGINE_CALLBACK_PLUGIN_ADDED:
+ self->carla_plugin_id = pluginId;
+ /*g_message ("Carla: plugin added");*/
+ break;
+ case ENGINE_CALLBACK_UI_STATE_CHANGED:
+ if (value1 == 1)
+ {
+ self->plugin->visible = value1;
+ g_message ("plugin ui visible");
+ }
+ else if (value1 == 0)
+ {
+ self->plugin->visible = value1;
+ }
+ else
+ {
+ g_warning (
+ "Plugin \"%s\" UI crashed",
+ self->plugin->descr->name);
+ }
+ break;
+ case ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED:
+ case ENGINE_CALLBACK_PATCHBAY_PORT_ADDED:
+ case ENGINE_CALLBACK_IDLE:
+ case ENGINE_CALLBACK_ENGINE_STOPPED:
+ /* ignore */
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+}
+
static CarlaNativePlugin *
-create (CarlaPluginType type)
+_create ()
{
CarlaNativePlugin * self =
calloc (1, sizeof (CarlaNativePlugin));
@@ 171,6 253,15 @@ create (CarlaPluginType type)
self->time_info.bbt.valid = 1;
+ return self;
+}
+
+static CarlaNativePlugin *
+create_carla_internal (CarlaPluginType type)
+{
+ CarlaNativePlugin * self =
+ _create ();
+
switch (type)
{
case CARLA_PLUGIN_RACK:
@@ 192,6 283,34 @@ create (CarlaPluginType type)
return self;
}
+static CarlaNativePlugin *
+create_plugin (
+ const PluginDescriptor * descr,
+ PluginType type)
+{
+ CarlaNativePlugin * self =
+ _create ();
+
+ /* instantiate the plugin to get its info */
+ self->descriptor =
+ carla_get_native_rack_plugin ();
+ self->handle =
+ self->descriptor->instantiate (
+ &self->host);
+ CarlaEngineHandle engine =
+ carla_engine_get_from_native_plugin (
+ self->descriptor, self->handle);
+ carla_engine_set_callback (
+ engine, engine_callback, self);
+ self->carla_plugin_id = 0;
+ carla_engine_add_plugin_simple (
+ engine, type,
+ descr->path, descr->name, descr->name,
+ 0, NULL);
+
+ return self;
+}
+
/**
* Wrapper to get the CarlaPlugin instance.
*/
@@ 218,26 337,6 @@ carla_native_plugin_proces (
const long g_start_frames,
const nframes_t nframes)
{
- const float * inbuf[] =
- {
- self->stereo_in->l->buf,
- self->stereo_in->r->buf
- };
- float * outbuf[] =
- {
- self->stereo_out->l->buf,
- self->stereo_out->r->buf
- };
- const float * cvinbuf[] =
- {
- self->cv_in->l->buf,
- self->cv_in->r->buf
- };
- float * cvoutbuf[] =
- {
- self->cv_out->l->buf,
- self->cv_out->r->buf
- };
self->time_info.playing =
TRANSPORT_IS_ROLLING;
@@ 269,11 368,84 @@ carla_native_plugin_proces (
self->time_info.bbt.beatsPerMinute =
TRANSPORT->bpm;
- CarlaPluginHandle plugin =
- carla_native_plugin_get_plugin_handle (self);
- carla_plugin_process (
- plugin, inbuf,
- outbuf, cvinbuf, cvoutbuf, nframes);
+ switch (self->plugin->descr->protocol)
+ {
+ case PROT_VST:
+ {
+ const float * inbuf[] =
+ {
+ self->stereo_in->l->buf,
+ self->stereo_in->r->buf
+ };
+ float * outbuf[] =
+ {
+ self->stereo_out->l->buf,
+ self->stereo_out->r->buf
+ };
+ const float * cvinbuf[] =
+ {
+ self->cv_in->l->buf,
+ self->cv_in->r->buf
+ };
+ float * cvoutbuf[] =
+ {
+ self->cv_out->l->buf,
+ self->cv_out->r->buf
+ };
+ CarlaPluginHandle plugin =
+ carla_native_plugin_get_plugin_handle (self);
+ g_warn_if_fail (plugin);
+ carla_plugin_process (
+ plugin, inbuf,
+ outbuf, cvinbuf, cvoutbuf, nframes);
+ }
+ break;
+ case PROT_SFZ:
+ {
+ float * inbuf[] =
+ {
+ self->stereo_in->l->buf,
+ self->stereo_in->r->buf
+ };
+ float * outbuf[] =
+ {
+ self->stereo_out->l->buf,
+ self->stereo_out->r->buf
+ };
+ for (int i = 0;
+ i < self->midi_in->midi_events->
+ num_events; i++)
+ {
+ MidiEvent * ev =
+ &self->midi_in->midi_events->events[i];
+ self->midi_events[i].time =
+ ev->time;
+ self->midi_events[i].size = 3;
+ self->midi_events[i].data[0] =
+ ev->raw_buffer[0];
+ self->midi_events[i].data[1] =
+ ev->raw_buffer[1];
+ self->midi_events[i].data[2] =
+ ev->raw_buffer[2];
+ }
+ self->num_midi_events =
+ (uint32_t)
+ self->midi_in->midi_events->num_events;
+ if (self->num_midi_events > 0)
+ {
+ g_message (
+ "Carla plugin %s has %d MIDI events",
+ self->plugin->descr->name,
+ self->num_midi_events);
+ }
+ self->descriptor->process (
+ self->handle, inbuf, outbuf, nframes,
+ self->midi_events, self->num_midi_events);
+ }
+ break;
+ default:
+ break;
+ }
}
/**
@@ 281,43 453,378 @@ carla_native_plugin_proces (
* type.
*
* @param ins Set the descriptor to be an instrument.
+ *
+ * FIXME delete
+ */
+/*PluginDescriptor **/
+/*carla_native_plugin_get_descriptor (*/
+ /*CarlaPluginType type,*/
+ /*int ins)*/
+/*{*/
+ /*CarlaNativePlugin * plugin =*/
+ /*create (type);*/
+ /*const NativePluginDescriptor * descr =*/
+ /*plugin->descriptor;*/
+
+ /*PluginDescriptor * self =*/
+ /*calloc (1, sizeof (PluginDescriptor));*/
+
+ /*self->author =*/
+ /*g_strdup (descr->maker);*/
+ /*self->name =*/
+ /*g_strdup_printf (*/
+ /*"Zrythm %s: %s",*/
+ /*ins ? "Instrument" : "Effect",*/
+ /*descr->name);*/
+ /*if (ins)*/
+ /*self->category = PC_INSTRUMENT;*/
+ /*else*/
+ /*self->category = PC_UTILITY;*/
+ /*self->category_str =*/
+ /*g_strdup (_("Plugin Adapter"));*/
+ /*self->num_audio_ins = (int) descr->audioIns;*/
+ /*self->num_audio_outs = (int) descr->audioOuts;*/
+ /*self->num_midi_ins = (int) descr->midiIns;*/
+ /*self->num_midi_outs = (int) descr->midiOuts;*/
+ /*self->num_ctrl_ins = (int) descr->paramIns;*/
+ /*self->num_ctrl_outs = (int) descr->paramOuts;*/
+ /*self->protocol = PROT_CARLA;*/
+ /*self->carla_type = type;*/
+
+ /*carla_native_plugin_free (plugin);*/
+
+ /*return self;*/
+/*}*/
+
+static ZPluginCategory
+carla_category_to_zrythm_category (
+ int category)
+{
+ switch (category)
+ {
+ case PLUGIN_CATEGORY_NONE:
+ return PC_NONE;
+ break;
+ case PLUGIN_CATEGORY_SYNTH:
+ return PC_INSTRUMENT;
+ break;
+ case PLUGIN_CATEGORY_DELAY:
+ return PC_DELAY;
+ break;
+ case PLUGIN_CATEGORY_EQ:
+ return PC_EQ;
+ break;
+ case PLUGIN_CATEGORY_FILTER:
+ return PC_FILTER;
+ break;
+ case PLUGIN_CATEGORY_DISTORTION:
+ return PC_DISTORTION;
+ break;
+ case PLUGIN_CATEGORY_DYNAMICS:
+ return PC_DYNAMICS;
+ break;
+ case PLUGIN_CATEGORY_MODULATOR:
+ return PC_MODULATOR;
+ break;
+ case PLUGIN_CATEGORY_UTILITY:
+ return PC_UTILITY;
+ break;
+ case PLUGIN_CATEGORY_OTHER:
+ return PC_NONE;
+ break;
+ }
+ g_return_val_if_reached (PC_NONE);
+}
+
+static char *
+carla_category_to_zrythm_category_str (
+ int category)
+{
+ switch (category)
+ {
+ case PLUGIN_CATEGORY_NONE:
+ return g_strdup ("Plugin");
+ break;
+ case PLUGIN_CATEGORY_SYNTH:
+ return g_strdup ("Instrument");
+ break;
+ case PLUGIN_CATEGORY_DELAY:
+ return g_strdup ("Delay");
+ break;
+ case PLUGIN_CATEGORY_EQ:
+ return g_strdup ("Equalizer");
+ break;
+ case PLUGIN_CATEGORY_FILTER:
+ return g_strdup ("Filter");
+ break;
+ case PLUGIN_CATEGORY_DISTORTION:
+ return g_strdup ("Distortion");
+ break;
+ case PLUGIN_CATEGORY_DYNAMICS:
+ return g_strdup ("Dynamics");
+ break;
+ case PLUGIN_CATEGORY_MODULATOR:
+ return g_strdup ("Modulator");
+ break;
+ case PLUGIN_CATEGORY_UTILITY:
+ return g_strdup ("Utility");
+ break;
+ case PLUGIN_CATEGORY_OTHER:
+ return g_strdup ("Plugin");
+ break;
+ }
+ g_return_val_if_reached (NULL);
+}
+
+/**
+ * Returns a filled in descriptor from the
+ * given binary path.
*/
PluginDescriptor *
-carla_native_plugin_get_descriptor (
- CarlaPluginType type,
- int ins)
+carla_native_plugin_get_descriptor_from_path (
+ const char * path,
+ PluginType type)
{
- CarlaNativePlugin * plugin =
- create (type);
- const NativePluginDescriptor * descr =
- plugin->descriptor;
+ PluginDescriptor * descr =
+ calloc (1, sizeof (PluginDescriptor));
+
+ descr->path =
+ g_strdup (path);
+
+ descr->open_with_carla = 1;
+ switch (type)
+ {
+ case PLUGIN_INTERNAL:
+ descr->protocol = PROT_CARLA_INTERNAL;
+ break;
+ case PLUGIN_LADSPA:
+ descr->protocol = PROT_LADSPA;
+ break;
+ case PLUGIN_DSSI:
+ descr->protocol = PROT_DSSI;
+ break;
+ case PLUGIN_LV2:
+ descr->protocol = PROT_LV2;
+ break;
+ case PLUGIN_VST2:
+ descr->protocol = PROT_VST;
+ break;
+ case PLUGIN_SF2:
+ descr->protocol = PROT_SF2;
+ break;
+ case PLUGIN_SFZ:
+ descr->protocol = PROT_SFZ;
+ break;
+ case PLUGIN_JACK:
+ descr->protocol = PROT_JACK;
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+
+ if (descr->protocol == PROT_VST)
+ {
+ char * carla_discovery_native =
+ g_build_filename (
+ carla_get_library_folder (),
+ "carla-discovery-native",
+ NULL);
+
+ /* read plugin info */
+ FILE *fp;
+ char line[1035];
+
+ /* Open the command for reading. */
+ char * command =
+ g_strdup_printf (
+ "%s vst %s",
+ carla_discovery_native,
+ path);
+ fp = popen (command, "r");
+ g_free (command);
+ if (fp == NULL)
+ g_return_val_if_reached (NULL);
+
+ /* Read the output a line at a time -
+ * output it. */
+ while (fgets (
+ line, sizeof (line) - 1, fp) !=
+ NULL)
+ {
+ if (g_str_has_prefix (
+ line,
+ "carla-discovery::name::"))
+ {
+ descr->name =
+ g_strdup (
+ g_strchomp (&line[23]));
+ }
+ else if (
+ g_str_has_prefix (
+ line, "carla-discovery::maker::"))
+ {
+ descr->author =
+ g_strdup (
+ g_strchomp (&line[24]));
+ }
+ else if (
+ g_str_has_prefix (
+ line,
+ "carla-discovery::audio.ins::"))
+ {
+ descr->num_audio_ins =
+ atoi (g_strchomp (&line[28]));
+ }
+ else if (
+ g_str_has_prefix (
+ line,
+ "carla-discovery::audio.outs::"))
+ {
+ descr->num_audio_outs =
+ atoi (g_strchomp (&line[29]));
+ }
+ else if (
+ g_str_has_prefix (
+ line,
+ "carla-discovery::midi.ins::"))
+ {
+ descr->num_midi_ins =
+ atoi (g_strchomp (&line[27]));
+ }
+ else if (
+ g_str_has_prefix (
+ line,
+ "carla-discovery::midi.outs::"))
+ {
+ descr->num_midi_outs =
+ atoi (g_strchomp (&line[28]));
+ }
+ else if (
+ g_str_has_prefix (
+ line,
+ "carla-discovery::parameters.ins::"))
+ {
+ descr->num_ctrl_ins =
+ atoi (g_strchomp (&line[33]));
+ }
+ }
+
+ /* close */
+ pclose (fp);
+
+ descr->category = PC_NONE;
+ descr->category_str =
+ g_strdup ("Plugin");
+
+ if (!descr->name)
+ {
+ plugin_descriptor_free (descr);
+ return NULL;
+ }
+ }
- PluginDescriptor * self =
+ return descr;
+}
+
+/**
+ * Returns a filled in descriptor from the
+ * CarlaCachedPluginInfo.
+ */
+PluginDescriptor *
+carla_native_plugin_get_descriptor_from_cached (
+ const CarlaCachedPluginInfo * info,
+ PluginType type)
+{
+ PluginDescriptor * descr =
calloc (1, sizeof (PluginDescriptor));
- self->author =
- g_strdup (descr->maker);
- self->name =
- g_strdup_printf (
- "Zrythm %s: %s",
- ins ? "Instrument" : "Effect",
- descr->name);
- if (ins)
- self->category = PC_INSTRUMENT;
- else
- self->category = PC_UTILITY;
- self->category_str =
- g_strdup (_("Plugin Adapter"));
- self->num_audio_ins = (int) descr->audioIns;
- self->num_audio_outs = (int) descr->audioOuts;
- self->num_midi_ins = (int) descr->midiIns;
- self->num_midi_outs = (int) descr->midiOuts;
- self->num_ctrl_ins = (int) descr->paramIns;
- self->num_ctrl_outs = (int) descr->paramOuts;
- self->protocol = PROT_CARLA;
- self->carla_type = type;
-
- carla_native_plugin_free (plugin);
+ descr->open_with_carla = 1;
+ switch (type)
+ {
+ case PLUGIN_INTERNAL:
+ descr->protocol = PROT_CARLA_INTERNAL;
+ break;
+ case PLUGIN_LADSPA:
+ descr->protocol = PROT_LADSPA;
+ break;
+ case PLUGIN_DSSI:
+ descr->protocol = PROT_DSSI;
+ break;
+ case PLUGIN_LV2:
+ descr->protocol = PROT_LV2;
+ break;
+ case PLUGIN_VST2:
+ descr->protocol = PROT_VST;
+ break;
+ case PLUGIN_SF2:
+ descr->protocol = PROT_SF2;
+ break;
+ case PLUGIN_SFZ:
+ descr->protocol = PROT_SFZ;
+ break;
+ case PLUGIN_JACK:
+ descr->protocol = PROT_JACK;
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+ descr->name =
+ g_strdup (info->name);
+ descr->author =
+ g_strdup (info->maker);
+ descr->num_audio_ins = (int) info->audioIns;
+ descr->num_audio_outs = (int) info->audioOuts;
+ descr->num_midi_ins = (int) info->midiIns;
+ descr->num_midi_outs = (int) info->midiOuts;
+ descr->num_ctrl_ins = (int) info->parameterIns;
+ descr->num_ctrl_outs = (int) info->parameterOuts;
+
+ descr->category =
+ carla_category_to_zrythm_category (
+ info->category);
+ descr->category_str =
+ carla_category_to_zrythm_category_str (
+ info->category);
+
+ return descr;
+}
+
+static CarlaNativePlugin *
+create_from_descr (
+ PluginDescriptor * descr)
+{
+ g_return_val_if_fail (
+ descr->open_with_carla ||
+ (descr->protocol == PROT_CARLA_INTERNAL &&
+ descr->carla_type > CARLA_PLUGIN_NONE),
+ NULL);
+
+ CarlaNativePlugin * self = NULL;
+ switch (descr->protocol)
+ {
+ case PROT_LV2:
+ self =
+ create_plugin (descr, PLUGIN_LV2);
+ break;
+ case PROT_VST:
+ self =
+ create_plugin (descr, PLUGIN_VST2);
+ break;
+ case PROT_SFZ:
+ self =
+ create_plugin (descr, PLUGIN_SFZ);
+ break;
+ case PROT_CARLA_INTERNAL:
+ create_carla_internal (
+ descr->carla_type);
+ break;
+ default:
+ g_warn_if_reached ();
+ break;
+ }
+ g_warn_if_fail (self);
return self;
}
@@ 333,7 840,7 @@ carla_native_plugin_create (
Plugin * plugin)
{
CarlaNativePlugin * self =
- create (plugin->descr->carla_type);
+ create_from_descr (plugin->descr);
plugin->carla = self;
self->plugin = plugin;
@@ 454,52 961,6 @@ create_ports (
}
/**
- * Carla engine callback.
- */
-static void
-engine_callback (
- void* ptr,
- EngineCallbackOpcode action,
- unsigned int pluginId,
- int value1,
- int value2,
- float value3,
- const char* valueStr)
-{
- CarlaNativePlugin * self =
- (CarlaNativePlugin *) ptr;
-
- switch (action)
- {
- case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED:
- break;
- case ENGINE_CALLBACK_PLUGIN_ADDED:
- self->carla_plugin_id = pluginId;
- break;
- case ENGINE_CALLBACK_UI_STATE_CHANGED:
- if (value1 == 1 ||
- value1 == 0)
- {
- self->plugin->visible = value1;
- }
- else
- {
- g_warning (
- "Plugin \"%s\" UI crashed",
- self->plugin->descr->name);
- }
- break;
- case ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED:
- case ENGINE_CALLBACK_PATCHBAY_PORT_ADDED:
- /* ignore */
- break;
- default:
- g_warn_if_reached ();
- break;
- }
-}
-
-/**
* Instantiates the plugin.
*
* @ret 0 if no errors, non-zero if errors.
@@ 522,9 983,10 @@ carla_native_plugin_instantiate (
engine, engine_callback, self);
carla_engine_add_plugin_simple (
engine, PLUGIN_VST2,
- "/usr/lib/vst/3BandEQ-vst.so",
- "3BandEQ VST",
- "label123", 0, NULL);
+ self->plugin->descr->path,
+ self->plugin->descr->name,
+ self->plugin->descr->name,
+ 0, NULL);
/* create ports */
create_ports (self);
@@ 537,29 999,6 @@ carla_native_plugin_instantiate (
}
/**
- * Tick callback for the plugin UI.
- */
-static int
-carla_plugin_tick_cb (
- GtkWidget * widget,
- GdkFrameClock * frame_clock,
- CarlaNativePlugin * self)
-{
- if (self->plugin->visible &&
- MAIN_WINDOW)
- {
- CarlaPluginHandle plugin =
- carla_native_plugin_get_plugin_handle (
- self);
- carla_plugin_ui_idle (plugin);
-
- return G_SOURCE_CONTINUE;
- }
- else
- return G_SOURCE_REMOVE;
-}
-
-/**
* Shows or hides the UI.
*/
void
@@ 567,16 1006,29 @@ carla_native_plugin_show_ui (
CarlaNativePlugin * self,
int show)
{
- CarlaPluginHandle plugin =
- carla_native_plugin_get_plugin_handle (self);
- carla_plugin_show_custom_ui (
- plugin, show);
-
- g_warn_if_fail (MAIN_WINDOW);
- gtk_widget_add_tick_callback (
- GTK_WIDGET (MAIN_WINDOW),
- (GtkTickCallback) carla_plugin_tick_cb,
- self, NULL);
+ switch (self->plugin->descr->protocol)
+ {
+ case PROT_VST:
+ {
+ CarlaPluginHandle plugin =
+ carla_native_plugin_get_plugin_handle (
+ self);
+ g_warn_if_fail (plugin);
+ carla_plugin_show_custom_ui (
+ plugin, show);
+ self->plugin->visible = 1;
+
+ g_warn_if_fail (MAIN_WINDOW);
+ gtk_widget_add_tick_callback (
+ GTK_WIDGET (MAIN_WINDOW),
+ (GtkTickCallback) carla_plugin_tick_cb,
+ self, NULL);
+ }
+ break;
+ case PROT_SFZ:
+ break;
+ default: break;
+ }
}
/**
@@ 630,3 1082,5 @@ carla_native_plugin_free (
free (self);
}
+
+#endif // HAVE_CARLA
M src/plugins/carla/plugin_interface.cpp => src/plugins/carla/plugin_interface.cpp +129 -0
@@ 17,6 17,10 @@
* along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
+#ifdef HAVE_CARLA
+
#include "plugins/carla/plugin_interface.h"
#include "CarlaPlugin.hpp"
@@ 58,4 62,129 @@ carla_plugin_process (
audio_in, audio_out, cv_in, cv_out, frames);
}
+void
+carla_plugin_get_real_name (
+ CarlaPluginHandle handle,
+ char * const name)
+{
+ GET_PLUGIN;
+ plugin->getRealName (name);
+}
+
+void
+carla_plugin_get_maker (
+ CarlaPluginHandle handle,
+ char * const name)
+{
+ GET_PLUGIN;
+ plugin->getMaker (name);
+}
+
+
+int
+carla_plugin_get_category (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getCategory ();
+}
+
+uint32_t
+carla_plugin_get_audio_in_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getAudioInCount ();
+}
+
+uint32_t
+carla_plugin_get_audio_out_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getAudioOutCount ();
+}
+
+uint32_t
+carla_plugin_get_cv_in_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getCVInCount ();
+}
+
+uint32_t
+carla_plugin_get_cv_out_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getCVOutCount ();
+}
+
+uint32_t
+carla_plugin_get_midi_in_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getMidiInCount ();
+}
+
+uint32_t
+carla_plugin_get_midi_out_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getMidiOutCount ();
+}
+
+uint32_t
+carla_plugin_get_parameter_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ return plugin->getParameterCount ();
+}
+
+uint32_t
+carla_plugin_get_parameter_in_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ uint32_t ins, outs;
+ plugin->getParameterCountInfo (
+ ins, outs);
+ return ins;
+}
+
+uint32_t
+carla_plugin_get_parameter_out_count (
+ CarlaPluginHandle handle)
+{
+ GET_PLUGIN;
+ uint32_t ins, outs;
+ plugin->getParameterCountInfo (
+ ins, outs);
+ return outs;
}
+
+int
+carla_plugin_save_state_to_file (
+ CarlaPluginHandle handle,
+ const char * const filename)
+{
+ GET_PLUGIN;
+ return plugin->saveStateToFile (filename);
+}
+
+int
+carla_plugin_load_state_from_file (
+ CarlaPluginHandle handle,
+ const char * const filename)
+{
+ GET_PLUGIN;
+ return plugin->loadStateFromFile (filename);
+}
+
+}
+
+#endif // HAVE_CARLA
M src/plugins/plugin.c => src/plugins/plugin.c +142 -77
@@ 129,20 129,28 @@ plugin_new_from_descr (
plugin_clone_descr (descr);
plugin_init (plugin);
- switch (plugin->descr->protocol)
+#ifdef HAVE_CARLA
+ if (plugin->descr->open_with_carla)
{
- case PROT_LV2:
- lv2_create_from_uri (plugin, descr->uri);
- break;
- case PROT_CARLA:
carla_native_plugin_create (plugin);
- break;
- default:
- g_warning (
- "Plugin protocol %d not supported",
- plugin->descr->protocol);
- break;
}
+ else
+ {
+#endif
+ switch (plugin->descr->protocol)
+ {
+ case PROT_LV2:
+ lv2_create_from_uri (plugin, descr->uri);
+ break;
+ default:
+ g_warning (
+ "Plugin protocol %d not supported",
+ plugin->descr->protocol);
+ break;
+ }
+#ifdef HAVE_CARLA
+ }
+#endif
return plugin;
}
@@ 191,7 199,10 @@ plugin_copy_descr (
dest->protocol = src->protocol;
dest->path = g_strdup (src->path);
dest->uri = g_strdup (src->uri);
+#ifdef HAVE_CARLA
+ dest->open_with_carla = src->open_with_carla;
dest->carla_type = src->carla_type;
+#endif
}
/**
@@ 425,24 436,9 @@ plugin_generate_automation_tracks (
plugin, at);
/* add plugin control automatables */
- switch (plugin->descr->protocol)
+#ifdef HAVE_CARLA
+ if (plugin->descr->open_with_carla)
{
- case PROT_LV2:
- for (int j = 0;
- j < plugin->lv2->controls.n_controls;
- j++)
- {
- Lv2Control * control =
- plugin->lv2->controls.controls[j];
- a =
- automatable_create_lv2_control (
- plugin, control);
- at = automation_track_new (a);
- plugin_add_automation_track (
- plugin, at);
- }
- break;
- case PROT_CARLA:
for (uint32_t i = 0;
i <
carla_native_plugin_get_param_count (
@@ 459,13 455,36 @@ plugin_generate_automation_tracks (
plugin_add_automation_track (
plugin, at);
}
- break;
- default:
- g_warning (
- "Plugin protocol not supported yet "
- "(gen automatables)");
- break;
}
+ else
+ {
+#endif
+ switch (plugin->descr->protocol)
+ {
+ case PROT_LV2:
+ for (int j = 0;
+ j < plugin->lv2->controls.n_controls;
+ j++)
+ {
+ Lv2Control * control =
+ plugin->lv2->controls.controls[j];
+ a =
+ automatable_create_lv2_control (
+ plugin, control);
+ at = automation_track_new (a);
+ plugin_add_automation_track (
+ plugin, at);
+ }
+ break;
+ default:
+ g_warning (
+ "Plugin protocol not supported yet "
+ "(gen automatables)");
+ break;
+ }
+#ifdef HAVE_CARLA
+ }
+#endif
}
#define IS_CAT(x) \
@@ 639,6 658,27 @@ plugin_descriptor_string_to_category (
}
/**
+ * Frees the plugin descriptor.
+ */
+void
+plugin_descriptor_free (
+ PluginDescriptor * self)
+{
+ if (self->category_str)
+ g_free (self->category_str);
+ if (self->author)
+ g_free (self->author);
+ if (self->website)
+ g_free (self->website);
+ if (self->path)
+ g_free (self->path);
+ if (self->uri)
+ g_free (self->uri);
+
+ free (self);
+}
+
+/**
* Sets the track and track_pos on the plugin.
*/
void
@@ 677,27 717,34 @@ plugin_instantiate (
g_message ("Instantiating %s...",
pl->descr->name);
- switch (pl->descr->protocol)
+#ifdef HAVE_CARLA
+ if (pl->descr->open_with_carla)
{
- case PROT_LV2:
- g_message ("state file: %s",
- pl->lv2->state_file);
- if (lv2_plugin_instantiate (
- pl->lv2, NULL))
- {
- g_warning ("lv2 instantiate failed");
- return -1;
- }
- break;
- case PROT_CARLA:
carla_native_plugin_instantiate (
pl->carla);
- break;
- default:
- g_warn_if_reached ();
- return -1;
- break;
}
+ else
+ {
+#endif
+ switch (pl->descr->protocol)
+ {
+ case PROT_LV2:
+ g_message ("state file: %s",
+ pl->lv2->state_file);
+ if (lv2_plugin_instantiate (
+ pl->lv2, NULL))
+ {
+ g_warning ("lv2 instantiate failed");
+ return -1;
+ }
+ break;
+ default:
+ g_return_val_if_reached (-1);
+ break;
+ }
+#ifdef HAVE_CARLA
+ }
+#endif
pl->enabled = 1;
return 0;
@@ 715,19 762,27 @@ plugin_process (
const long g_start_frames,
const nframes_t nframes)
{
- switch (plugin->descr->protocol)
+#ifdef HAVE_CARLA
+ if (plugin->descr->open_with_carla)
{
- case PROT_LV2:
- lv2_plugin_process (
- plugin->lv2, g_start_frames, nframes);
- break;
- case PROT_CARLA:
carla_native_plugin_proces (
plugin->carla, g_start_frames, nframes);
- break;
- default:
- g_warn_if_reached ();
}
+ else
+ {
+#endif
+ switch (plugin->descr->protocol)
+ {
+ case PROT_LV2:
+ lv2_plugin_process (
+ plugin->lv2, g_start_frames, nframes);
+ break;
+ default:
+ g_warn_if_reached ();
+ }
+#ifdef HAVE_CARLA
+ }
+#endif
}
/**
@@ 736,26 791,34 @@ plugin_process (
void
plugin_open_ui (Plugin *plugin)
{
- switch (plugin->descr->protocol)
+#ifdef HAVE_CARLA
+ if (plugin->descr->open_with_carla)
{
- case PROT_LV2:
- if (GTK_IS_WINDOW (plugin->lv2->window))
- {
- gtk_window_present (
- GTK_WINDOW (plugin->lv2->window));
- }
- else
- {
- lv2_open_ui (plugin->lv2);
- }
- break;
- case PROT_CARLA:
carla_native_plugin_show_ui (
plugin->carla, 1);
- break;
- default:
- g_return_if_reached ();
}
+ else
+ {
+#endif
+ switch (plugin->descr->protocol)
+ {
+ case PROT_LV2:
+ if (GTK_IS_WINDOW (plugin->lv2->window))
+ {
+ gtk_window_present (
+ GTK_WINDOW (plugin->lv2->window));
+ }
+ else
+ {
+ lv2_open_ui (plugin->lv2);
+ }
+ break;
+ default:
+ g_return_if_reached ();
+ }
+#ifdef HAVE_CARLA
+ }
+#endif
}
/**
@@ 828,10 891,12 @@ plugin_clone (
/* delete the state file */
io_remove (pl->lv2->state_file);
}
- else if (prot == PROT_CARLA)
+#ifdef HAVE_CARLA
+ else if (prot == PROT_CARLA_INTERNAL)
{
/* TODO */
}
+#endif
g_return_val_if_fail (clone, NULL);
clone->slot = pl->slot;
M src/plugins/plugin_manager.c => src/plugins/plugin_manager.c +166 -14
@@ 29,6 29,7 @@
#include "plugins/plugin_manager.h"
#include "plugins/lv2_plugin.h"
#include "utils/arrays.h"
+#include "utils/io.h"
#include "utils/string.h"
#include "utils/ui.h"
#include "zrythm.h"
@@ 36,6 37,10 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#ifdef HAVE_CARLA
+#include <CarlaUtils.h>
+#endif
+
#include <lv2/lv2plug.in/ns/ext/event/event.h>
#include <lv2/lv2plug.in/ns/ext/options/options.h>
#include <lv2/lv2plug.in/ns/ext/parameters/parameters.h>
@@ 127,13 132,11 @@ static int sort_plugin_func (
/*}*/
/*}*/
-/**
- * scans for plugins.
- */
static void
-scan_plugins (PluginManager * self)
+scan_and_add_lv2 (
+ PluginManager * self)
{
- g_message ("scanning plugins...");
+ g_message ("Scanning LV2...");
/* load all plugins with lilv */
LilvWorld * world = LILV_WORLD;
@@ 161,24 164,173 @@ scan_plugins (PluginManager * self)
self, descriptor->category_str);
}
}
+}
- /* add carla */
- for (int i = CARLA_PLUGIN_RACK;
- i <= CARLA_PLUGIN_PATCHBAY; i++)
+#ifdef HAVE_CARLA
+static void
+scan_and_add_vst2 (
+ PluginManager * self)
+{
+ char * vst_path =
+ g_strdup (getenv ("VST_PATH"));
+ if (!vst_path)
+ vst_path =
+ g_strdup ("/usr/lib/vst:/usr/local/lib/vst");
+
+ char ** paths =
+ g_strsplit (vst_path, ":", 0);
+ int path_idx = 0;
+ char * path;
+ while ((path = paths[path_idx++]) != NULL)
{
- for (int j = 0; j < 2; j++)
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ continue;
+
+ char ** plugins =
+ io_get_files_in_dir_ending_in (
+ path, 1, ".so");
+ if (!plugins)
+ continue;
+
+ char * plugin;
+ int plugin_idx = 0;
+ while ((plugin = plugins[plugin_idx++]) !=
+ NULL)
{
- PluginDescriptor * descr =
- carla_native_plugin_get_descriptor (
- i, j);
- g_warn_if_fail (descr);
+ PluginDescriptor * descriptor =
+ carla_native_plugin_get_descriptor_from_path (
+ plugin, PLUGIN_VST2);
+
+ if (descriptor)
+ {
+ /*g_message ("found VST2: %s",*/
+ /*descriptor->name);*/
+ array_append (
+ self->plugin_descriptors,
+ self->num_plugins,
+ descriptor);
+ add_category (
+ self, descriptor->category_str);
+ }
+ }
+ g_strfreev (plugins);
+ }
+
+ g_free (vst_path);
+}
+#endif
+
+#ifdef HAVE_CARLA
+static void
+scan_and_add_sfz (
+ PluginManager * self)
+{
+ /* scan SFZ */
+ char ** sfz_search_paths =
+ g_settings_get_strv (
+ S_PREFERENCES, "sfz-search-paths");
+ char * path;
+ int path_idx = 0;
+ while ((path = sfz_search_paths[path_idx++]) !=
+ NULL)
+ {
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ continue;
+
+ unsigned int count =
+ carla_get_cached_plugin_count (
+ PLUGIN_SFZ, path);
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const CarlaCachedPluginInfo * info =
+ carla_get_cached_plugin_info (
+ PLUGIN_SFZ, i);
+
+ if (!info->valid)
+ continue;
+
+ PluginDescriptor * descriptor =
+ carla_native_plugin_get_descriptor_from_cached (
+ info, PLUGIN_SFZ);
+ /*g_message ("found SFZ: %s", info->name);*/
array_append (
self->plugin_descriptors,
self->num_plugins,
- descr);
+ descriptor);
+ add_category (
+ self, descriptor->category_str);
+ }
+ }
+ g_strfreev (sfz_search_paths);
+}
+#endif
+
+#ifdef HAVE_CARLA
+static void
+scan_and_add_sf2 (
+ PluginManager * self)
+{
+ /* scan SF2 */
+ char ** sf2_search_paths =
+ g_settings_get_strv (
+ S_PREFERENCES, "sf2-search-paths");
+ char * path;
+ int path_idx = 0;
+ while ((path = sf2_search_paths[path_idx++]) !=
+ NULL)
+ {
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ continue;
+
+ char ** plugins =
+ io_get_files_in_dir_ending_in (
+ path, 1, ".sf2");
+ if (!plugins)
+ continue;
+
+ char * plugin;
+ int plugin_idx = 0;
+ while ((plugin = plugins[plugin_idx++]) !=
+ NULL)
+ {
+ PluginDescriptor * descriptor =
+ carla_native_plugin_get_descriptor_from_path (
+ plugin, PLUGIN_SF2);
+
+ if (descriptor)
+ {
+ g_message ("found SF2: %s",
+ descriptor->name);
+ array_append (
+ self->plugin_descriptors,
+ self->num_plugins,
+ descriptor);
+ add_category (
+ self, descriptor->category_str);
+ }
}
+ g_strfreev (plugins);
}
+ g_strfreev (sf2_search_paths);
+}
+#endif
+
+/**
+ * scans for plugins.
+ */
+static void
+scan_plugins (PluginManager * self)
+{
+ g_message ("scanning plugins...");
+
+ scan_and_add_lv2 (self);
+#ifdef HAVE_CARLA
+ scan_and_add_sfz (self);
+ (void) scan_and_add_sf2;
+ /*scan_and_add_sf2 (self);*/
+ scan_and_add_vst2 (self);
+#endif
/* sort alphabetically */
qsort (PLUGIN_MANAGER->plugin_descriptors,
M src/utils/io.c => src/utils/io.c +63 -18
@@ 215,39 215,84 @@ io_rmdir (
}
/**
- * Returns a list of the files in the given
- * directory.
+ * Appends files to the given array from the given
+ * dir if they end in the given string.
*
- * @return a NULL terminated array of strings that
- * must be free'd with g_strfreev().
+ * @param end_string If empty, appends all files.
*/
-char **
-io_get_files_in_dir (
- const char * _dir)
+static void
+append_files_from_dir_ending_in (
+ char *** files,
+ int * num_files,
+ const int recursive,
+ const char * _dir,
+ const char * end_string)
{
GDir *dir;
GError *error;
const gchar *filename;
-
- char ** arr =
- calloc (1, sizeof (char *));
- int count = 0;
+ char * full_path;
dir = g_dir_open (_dir, 0, &error);
while ((filename = g_dir_read_name (dir)))
{
- arr =
- realloc (
- arr,
- sizeof (char *) * (size_t) (count + 2));
- arr[count] =
+ full_path =
g_build_filename (
_dir, filename, NULL);
- count++;
+
+ /* recurse if necessary */
+ if (recursive &&
+ g_file_test (
+ full_path, G_FILE_TEST_IS_DIR))
+ {
+ append_files_from_dir_ending_in (
+ files, num_files, recursive, full_path,
+ end_string);
+ }
+
+ if (!end_string ||
+ (end_string &&
+ g_str_has_suffix (
+ full_path, end_string)))
+ {
+ *files =
+ realloc (
+ *files,
+ sizeof (char *) *
+ (size_t) (*num_files + 2));
+ (*files)[(*num_files)] =
+ g_strdup (full_path);
+ (*num_files)++;
+ }
+
+ g_free (full_path);
}
/* NULL terminate */
- arr[count] = NULL;
+ (*files)[*num_files] = NULL;
+}
+
+/**
+ * Returns a list of the files in the given
+ * directory.
+ *
+ * @param dir The directory to look for.
+ *
+ * @return a NULL terminated array of strings that
+ * must be free'd with g_strfreev().
+ */
+char **
+io_get_files_in_dir_ending_in (
+ const char * _dir,
+ const int recursive,
+ const char * end_string)
+{
+ char ** arr =
+ calloc (1, sizeof (char *));
+ int count = 0;
+
+ append_files_from_dir_ending_in (
+ &arr, &count, recursive, _dir, end_string);
return arr;
}
M src/utils/string.c => src/utils/string.c +107 -2
@@ 21,10 21,14 @@
#include <string.h>
+#include "utils/arrays.h"
#include "utils/string.h"
#include <gtk/gtk.h>
+/**
+ * Returns if the string is ASCII.
+ */
int
string_is_ascii (const char * string)
{
@@ 33,8 37,7 @@ string_is_ascii (const char * string)
return 0;
for (i = 0; i < strlen (string); i++)
{
- if (string[i] < 32 ||
- string[i] > 126)
+ if (!string_char_is_ascii (string[i]))
{
return 0;
}
@@ 43,6 46,25 @@ string_is_ascii (const char * string)
}
/**
+ * Returns a new string up to the character before
+ * the first non-ascii character, or until the
+ * end.
+ */
+char *
+string_stop_at_first_non_ascii (
+ const char * str)
+{
+ for (int i = 0; i < (int) strlen (str); i++)
+ {
+ if (!string_char_is_ascii (str[i]))
+ return
+ g_strdup_printf (
+ "%.*s", i, str);
+ }
+ return g_strdup (str);
+}
+
+/**
* Returns the matched string if the string array
* contains the given substring.
*/
@@ 115,6 137,16 @@ string_contains_substr (
accept_alternatives);
}
+int
+string_ends_with (
+ const char * str,
+ const char * end_str,
+ const int ignore_case)
+{
+ /* TODO */
+ g_return_val_if_reached (-1);
+}
+
/**
* Returns a newly allocated string that is a
* filename version of the given string.
@@ 153,6 185,79 @@ string_convert_to_filename (
}
/**
+ * Removes non-ascii characters from the given
+ * string.
+ */
+void
+string_remove_non_ascii_chars (
+ char * str)
+{
+ int count, len;
+ for (len = 0; str[len] != '\0'; ++len);
+ g_warn_if_fail (len > 0);
+
+ count = len - 1;
+ while (count >= 0 && str[count] != 0)
+ {
+ char chr = str[count];
+ if (chr < 32 ||
+ chr > 126)
+ {
+ array_delete (
+ str, len, chr);
+ len--;
+ }
+ count--;
+ }
+}
+
+/**
+ * Removes occurrences of the given character
+ * from the string.
+ */
+void
+string_remove_char (
+ char * str,
+ const char remove)
+{
+ int count, len;
+ for (len = 0; str[len] != '\0'; ++len);
+ g_warn_if_fail (len > 0);
+
+ count = len - 1;
+ while (count >= 0 && str[count] != 0)
+ {
+ char chr = str[count];
+ if (chr == remove)
+ {
+ array_delete (
+ str, len, chr);
+ len--;
+ }
+ count--;
+ }
+}
+
+/**
+ * Returns the index of the first occurrence of
+ * the search char, or -1 if not found.
+ */
+int
+string_index_of_char (
+ const char * str,
+ const char search_char)
+{
+ int len = (int) strlen (str);
+ for (int i = 0; i < len; i++)
+ {
+ if (str[i] == search_char)
+ return i;
+ }
+
+ return -1;
+}
+
+/**
* Removes any bak, bak1 etc suffixes from the
* string and returns a newly allocated string.
*/
M src/zrythm.c => src/zrythm.c +3 -1
@@ 171,8 171,10 @@ init_recent_projects ()
}
ZRYTHM->recent_projects[
- ZRYTHM->num_recent_projects++] = prj;
+ ZRYTHM->num_recent_projects++] =
+ g_strdup (prj);
}
+ g_strfreev (recent_projects);
/* set last element to NULL because the call
* takes a NULL terminated array */