📄 plugin.c
字号:
/* -*- linux-c -*- Copyright (C) 2004 Tom Szilagyi 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., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: plugin.c,v 1.26 2006/09/12 17:52:05 peterszilagyi Exp $*/#include <config.h>#ifdef HAVE_LADSPA#include <stdio.h>#include <stdlib.h>#include <dlfcn.h>#include <unistd.h>#include <dirent.h>#include <lrdf.h>#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include <gtk/gtk.h>#include <gdk/gdkkeysyms.h>#include "common.h"#include "i18n.h"#include "options.h"#include "trashlist.h"#include "plugin.h"#ifdef __FreeBSD__#define dirent64 dirent#define scandir64 scandir#define alphasort64 alphasort#endif /* __FreeBSD__ */extern options_t options;extern GtkWidget* gui_stock_label_button(gchar *blabel, const gchar *bstock);extern volatile int plugin_lock;extern int n_plugins;extern plugin_instance * plugin_vect[MAX_PLUGINS];extern unsigned long ladspa_buflen;extern LADSPA_Data * l_buf;extern LADSPA_Data * r_buf;extern unsigned long out_SR;int fxbuilder_on;GtkWidget * fxbuilder_window;GtkWidget * avail_list;GtkListStore * avail_store = NULL;GtkTreeSelection * avail_select;GtkWidget * running_list;GtkListStore * running_store = NULL;GtkTreeSelection * running_select;GtkWidget * add_button;GtkWidget * remove_button;GtkWidget * conf_button;GtkWidget * rp_menu;GtkWidget * scrolled_win_running;extern GtkWidget * plugin_toggle;typedef struct { plugin_instance * instance; int index;} optdata_t;typedef struct { plugin_instance * instance; float start;} btnpdata_t;int added_plugin = 0;voidset_active_state(void) { GtkTreeIter iter; if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, 0)) { /* disable buttons and menu */ gtk_widget_set_sensitive(remove_button, FALSE); gtk_widget_set_sensitive(conf_button, FALSE); } else { /* enable buttons and menu */ gtk_widget_set_sensitive(remove_button, TRUE); gtk_widget_set_sensitive(conf_button, TRUE); }}static intrdf_filter(const struct dirent64 * de) { if (de->d_type != DT_UNKNOWN && de->d_type != DT_REG && de->d_type != DT_LNK) return 0; if (de->d_name[0] == '.') return 0; return (((strlen(de->d_name) >= 4) && (strcmp(de->d_name + strlen(de->d_name) - 3, ".n3") == 0)) || ((strlen(de->d_name) >= 5) && (strcmp(de->d_name + strlen(de->d_name) - 4, ".rdf") == 0)) || ((strlen(de->d_name) >= 6) && (strcmp(de->d_name + strlen(de->d_name) - 5, ".rdfs") == 0)));}static intso_filter(const struct dirent64 * de) { if (de->d_type != DT_UNKNOWN && de->d_type != DT_REG && de->d_type != DT_LNK) return 0; if (de->d_name[0] == '.') return 0; return ((strlen(de->d_name) >= 4) && (strcmp(de->d_name + strlen(de->d_name) - 3, ".so") == 0));}voidparse_lrdf_data(void) { char * str; char lrdf_path[MAXLEN]; char rdf_path[MAXLEN]; char fileuri[MAXLEN]; int i, j = 0; struct dirent64 ** de; int n; lrdf_path[0] = '\0'; if ((str = getenv("LADSPA_RDF_PATH"))) { snprintf(lrdf_path, MAXLEN-1, "%s:", str); } else { strncat(lrdf_path, "/usr/local/share/ladspa/rdf:/usr/share/ladspa/rdf:", MAXLEN-1); } for (i = 0; lrdf_path[i] != '\0'; i++) { if (lrdf_path[i] == ':') { rdf_path[j] = '\0'; j = 0; n = scandir64(rdf_path, &de, rdf_filter, alphasort64); if (n >= 0) { int c; for (c = 0; c < n; ++c) { snprintf(fileuri, MAXLEN-1, "file://%s/%s", rdf_path, de[c]->d_name); if (lrdf_read_file(fileuri)) { fprintf(stderr, "warning: could not parse RDF file: %s\n", fileuri); } } } } else { rdf_path[j++] = lrdf_path[i]; } }}voidget_ladspa_category(unsigned long plugin_id, char * str) { char buf[256]; lrdf_statement pattern; lrdf_statement * matches1; lrdf_statement * matches2; snprintf(buf, 255, "%s%lu", LADSPA_BASE, plugin_id); pattern.subject = buf; pattern.predicate = RDF_TYPE; pattern.object = 0; pattern.object_type = lrdf_uri; matches1 = lrdf_matches(&pattern); if (!matches1) { strncpy(str, "Unknown", MAXLEN-1); return; } pattern.subject = matches1->object; pattern.predicate = LADSPA_BASE "hasLabel"; pattern.object = 0; pattern.object_type = lrdf_literal; matches2 = lrdf_matches (&pattern); lrdf_free_statements(matches1); if (!matches2) { strncpy(str, "Unknown", MAXLEN-1); return; } strncpy(str, matches2->object, MAXLEN-1); lrdf_free_statements(matches2);}static voidfind_plugins(char * path_entry) { void * library = NULL; char lib_name[MAXLEN]; LADSPA_Descriptor_Function descriptor_fn; const LADSPA_Descriptor * descriptor; struct dirent64 ** de; int n, k, c; long int port, n_ins, n_outs; GtkTreeIter iter; char id_str[32]; char n_ins_str[32]; char n_outs_str[32]; char c_str[32]; char category[MAXLEN]; n = scandir64(path_entry, &de, so_filter, alphasort64); if (n >= 0) { for (c = 0; c < n; ++c) { snprintf(lib_name, MAXLEN-1, "%s/%s", path_entry, de[c]->d_name); library = dlopen(lib_name, RTLD_LAZY); if (library == NULL) { continue; } descriptor_fn = dlsym(library, "ladspa_descriptor"); if (descriptor_fn == NULL) { dlclose(library); continue; } for (k = 0; ; ++k) { descriptor = descriptor_fn(k); if (descriptor == NULL) { break; } for (n_ins = n_outs = port = 0; port < descriptor->PortCount; ++port) { if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[port])) { if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[port])) ++n_ins; if (LADSPA_IS_PORT_OUTPUT(descriptor->PortDescriptors[port])) ++n_outs; } } if ((n_ins == 1 && n_outs == 1) || (n_ins == 2 && n_outs == 2)) { get_ladspa_category(descriptor->UniqueID, category); snprintf(id_str, 31, "%ld", descriptor->UniqueID); snprintf(n_ins_str, 31, "%ld", n_ins); snprintf(n_outs_str, 31, "%ld", n_outs); snprintf(c_str, 31, "%d", k); gtk_list_store_append(avail_store, &iter); gtk_list_store_set(avail_store, &iter, 0, id_str, 1, descriptor->Name, 2, category, 3, n_ins_str, 4, n_outs_str, 5, lib_name, 6, c_str, -1); } } dlclose(library); } }}static voidfind_all_plugins(void) { char * ladspa_path; char * directory; if (!(ladspa_path = getenv("LADSPA_PATH"))) { find_plugins("/usr/lib/ladspa"); find_plugins("/usr/local/lib/ladspa"); } else { ladspa_path = strdup(ladspa_path); directory = strtok(ladspa_path, ":"); while (directory != NULL) { find_plugins(directory); directory = strtok(NULL, ":"); } free(ladspa_path); }}static gbooleanfxbuilder_close(GtkWidget * widget, GdkEvent * event, gpointer data) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(plugin_toggle), FALSE); return TRUE;}voidshow_fxbuilder(void) { set_active_state(); gtk_widget_show_all(fxbuilder_window); fxbuilder_on = 1;}voidhide_fxbuilder(void) { gtk_widget_hide(fxbuilder_window); fxbuilder_on = 0;}gintfxbuilder_key_pressed(GtkWidget * widget, GdkEventKey * event, gpointer * data) { switch (event->keyval) { case GDK_q: case GDK_Q: case GDK_Escape: fxbuilder_close(NULL, NULL, NULL); return TRUE; }; return FALSE;}/* we need this because the default gtk sort func doesn't obey spaces in strings eg. "ABCE" gets in between "ABC D" and "ABC F" and not after them.*/gintcompare_func(GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data) { int col = (int) user_data; char * sa; char * sb; int ret; gtk_tree_model_get(model, a, col, &sa, -1); gtk_tree_model_get(model, b, col, &sb, -1); ret = strcmp(sa, sb); g_free(sa); g_free(sb); return ret;}plugin_instance *instantiate(char * filename, int index) { LADSPA_Descriptor_Function descriptor_fn; plugin_instance * instance; int n_ins, n_outs, n_ctrl, port; if ((instance = calloc(1, sizeof(plugin_instance))) == NULL) { fprintf(stderr, "plugin.c: instantiate(): calloc error\n"); return NULL; } strncpy(instance->filename, filename, MAXLEN-1); instance->index = index; instance->library = dlopen(filename, RTLD_NOW); if (instance->library == NULL) { fprintf(stderr, "dlopen() failed on %s -- is it a valid shared library file?\n", filename); free(instance); return NULL; } descriptor_fn = dlsym(instance->library, "ladspa_descriptor"); if (descriptor_fn == NULL) { fprintf(stderr, "dlsym() failed to load symbol 'ladspa_descriptor'. " "Possibly a bug in %s\n", filename); dlclose(instance->library); free(instance); return NULL; } instance->descriptor = descriptor_fn(index); if (LADSPA_IS_INPLACE_BROKEN(instance->descriptor->Properties)) { fprintf(stderr, "%s (%s) is INPLACE_BROKEN and thus unusable in " "Aqualung at this time.\n", instance->descriptor->Label, instance->descriptor->Name); dlclose(instance->library); free(instance); return NULL; } for (n_ins = n_outs = n_ctrl = port = 0; port < instance->descriptor->PortCount; ++port) { if (LADSPA_IS_PORT_AUDIO(instance->descriptor->PortDescriptors[port])) { if (LADSPA_IS_PORT_INPUT(instance->descriptor->PortDescriptors[port])) ++n_ins; if (LADSPA_IS_PORT_OUTPUT(instance->descriptor->PortDescriptors[port])) ++n_outs; } else { ++n_ctrl; } } if (n_ctrl > MAX_KNOBS) { fprintf(stderr, "%s (%s) has more than %d input knobs; " "Aqualung cannot use it.\n", instance->descriptor->Label, instance->descriptor->Name, MAX_KNOBS); dlclose(instance->library); free(instance); return NULL; } if ((n_ins == 1) && (n_outs == 1)) { instance->is_mono = 1; instance->handle = instance->descriptor->instantiate(instance->descriptor, out_SR); instance->handle2 = instance->descriptor->instantiate(instance->descriptor, out_SR);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -