From e7001842641982a2698f759aa8014aacda6ce568 Mon Sep 17 00:00:00 2001 From: "Kjetil S. Matheussen" Date: Thu, 8 Jan 2004 14:55:24 +0000 Subject: First commit of k_vst~, k_guile and k_cext svn path=/trunk/externals/k_vst~/; revision=1253 --- plugin~_vst.c | 571 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 plugin~_vst.c (limited to 'plugin~_vst.c') diff --git a/plugin~_vst.c b/plugin~_vst.c new file mode 100644 index 0000000..001924f --- /dev/null +++ b/plugin~_vst.c @@ -0,0 +1,571 @@ +/* plugin~, a Pd tilde object for hosting LADSPA/VST plug-ins + Copyright (C) 2000 Jarno Seppänen + $Id: plugin~_vst.c,v 1.1 2004-01-08 14:55:24 ksvalast Exp $ + + This file is part of plugin~. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "config.h" +#if PLUGIN_TILDE_USE_VST + +#include +#include +#include +#include + +#include "plugin~.h" +#include "plugin~_vst.h" +/* VST header */ +#define AEFFECTX_H_LINUXWORKAROUND +#include "vst/aeffectx.h" +//#include "vst/AEffect.h" +/* VST dll helper functions */ +#include "vstutils.h" +#ifdef WIN32 +#include "win/vitunmsvc.h" /* strncasecmp() */ +#include /* GetForegroundWindow() */ +#endif + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + + +const char* +plugin_tilde_vst_search_plugin (Pd_Plugin_Tilde* x, + const char* name) +{ + /* searching through VST libraries not supported */ + error ("plugin~: warning: searching through VST libraries not supported"); + return NULL; +} + +int +plugin_tilde_vst_open_plugin (Pd_Plugin_Tilde* x, + const char* name, + const char* lib_name, + unsigned long sample_rate) +{ + unsigned port_index; + + /* precondition(s) */ + assert (x != NULL); + /* name is unused */ + assert (lib_name != NULL); + assert (sample_rate != 0); + + /* Initialize object struct */ + x->plugin.vst.instance = NULL; + x->plugin.vst.audio_inputs = NULL; + x->plugin.vst.audio_outputs = NULL; + x->plugin.vst.num_samples = 0; + x->plugin.vst.editor_open = 0; + +#if 0 + /* Attempt to load the plugin. */ + x->plugin_library = vstutils_load_vst_plugin_dll (lib_name); + if (x->plugin_library == NULL) + { + error ("plugin~: Unable to load VST plugin library \"%s\"", + lib_name); + return 1; + } +#endif + + /* Construct the plugin. This is supposed to call + the AudioEffect::AudioEffect() ctor eventually */ + x->plugin.vst.instance +#if 1 + =VSTLIB_new((char*)lib_name); +#else + = vstutils_init_vst_plugin (x->plugin_library, + lib_name, + plugin_tilde_vst_audioMaster); +#endif + if (x->plugin.vst.instance == NULL) { + error ("plugin~: Unable to instantiate VST plugin from library \"%s\"", + lib_name); + return 1; + } + + /* Stuff Pd_Plugin_Tilde* x into user field of AEffect for audioMaster() to use */ + x->plugin.vst.instance->user = x; + + /* Call plugin open() (through dispatcher()) in order to ensure + plugin is properly constructed */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effOpen, + 0, 0, NULL, 0); + + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~: constructed VST plugin \"%s\" successfully", + lib_name); +#endif + + + /* Check another strange id */ + if (x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effIdentify, + 0, 0, NULL, 0) + != 'NvEf') { + error ("plugin~_vst: warning: VST plugin malfunction (effIdentify != 'NvEf')"); + } + + + /* Tell the sample rate and frame length to the VST plug-in */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetSampleRate, + 0, 0, NULL, (float)sample_rate); + + /* FIXME just give some value since it will be changed later */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetBlockSize, + 0, 16, NULL, 0); + /* Find out the number of inputs and outputs needed (all VST + parameters can be automated i.e. output if the plug-in so wants + and the GUI can be operated). */ + x->num_audio_inputs = x->plugin.vst.instance->numInputs; + x->num_audio_outputs = x->plugin.vst.instance->numOutputs; + x->num_control_inputs = x->plugin.vst.instance->numParams; + x->num_control_outputs = x->plugin.vst.instance->numParams; + + /* Make sure that processReplacing() is implemented */ + if (x->plugin.vst.instance->flags & effFlagsCanReplacing == 0) { + error ("plugin~_vst: sorry, this VST plug-in type isn't supported (processReplacing() not implemented)"); + return 1; + } + + + /* Activate the plugin. */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 1, NULL, 0); + + + /* Finally, attempt open editor GUI if available */ + // plugin_tilde_vst_open_editor (x); + + + /* Make sure the user data still is there */ + assert (x->plugin.vst.instance->user == x); + + /* success */ + return 0; +} + +void +plugin_tilde_vst_close_plugin (Pd_Plugin_Tilde* x) +{ + /* precondition(s) */ + assert (x != NULL); + + /* Attempt to close editor GUI */ + plugin_tilde_vst_close_editor (x); + + if (x->plugin.vst.instance != NULL) + { + /* Deactivate the plugin. */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 0, NULL, 0); + + /* Destruct the plugin. This is supposed to translate to + a call to the AudioEffect::~AudioEffect() dtor */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effClose, + 0, 0, NULL, 0); +#if 1 + VSTLIB_delete(x->plugin.vst.instance); +#endif + x->plugin.vst.instance = NULL; + } + + + if (x->plugin_library != NULL) + { +#if 0 + vstutils_unload_vst_plugin_dll (x->plugin_library); +#endif + x->plugin_library = NULL; + } +} + +void +plugin_tilde_vst_apply_plugin (Pd_Plugin_Tilde* x) +{ + static int agurk=0; + + /* Run the plugin on Pd's buffers */ + /* FIXME need to implement out-of-place buffers and zero them here + if processReplacing() isn't implemented */ + + x->plugin.vst.instance->processReplacing (x->plugin.vst.instance, + x->plugin.vst.audio_inputs, + x->plugin.vst.audio_outputs, + x->plugin.vst.num_samples); + +} + +void +plugin_tilde_vst_print (Pd_Plugin_Tilde* x) +{ + unsigned i; + char display[25]; + long l, nprog; + + printf ("control %d in/out; audio %d in/%d out\n" + "Loaded from library \"%s\".\n", + x->num_control_inputs, + x->num_audio_inputs, + x->num_audio_outputs, + x->plugin_library_filename); + + /* print the current program name/number */ + l = x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetProgram, 0, 0, display, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetProgramName, 0, 0, display, 0); + nprog = x->plugin.vst.instance->numPrograms; + printf("Program #%ld (of %ld), \"%s\".\n",l,nprog,display); + + for (i = 0; i < x->num_control_inputs; i++) { + /* the Steinberg(tm) way... */ + char name[9]; + char label[9]; + if (i == 0) { + printf ("Control input/output(s):\n"); + } + memset (name, 0, 9); + memset (display, 0, 25); + memset (label, 0, 9); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamName, + i, 0, name, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamDisplay, + i, 0, display, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamLabel, + i, 0, label, 0); + printf (" #%d \"%s\" (%s %s)\n", + i + 1, name, display, label); + } +} + +void +plugin_tilde_vst_reset (Pd_Plugin_Tilde* x) +{ + /* precondition(s) */ + assert (x != NULL); + /* reset plug-in by first deactivating and then re-activating it */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 0, NULL, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 1, NULL, 0); +} + +void +plugin_tilde_vst_connect_audio (Pd_Plugin_Tilde* x, + float** audio_inputs, + float** audio_outputs, + unsigned long num_samples) +{ + assert (x != NULL); + assert (audio_inputs != NULL); + assert (audio_outputs != NULL); + x->plugin.vst.audio_inputs = audio_inputs; + x->plugin.vst.audio_outputs = audio_outputs; + x->plugin.vst.num_samples = num_samples; + /* Tell the block size to the VST plug-in */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 0, NULL, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetBlockSize, + 0, num_samples, NULL, 0); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effMainsChanged, + 0, 1, NULL, 0); +} + +void +plugin_tilde_vst_set_control_input_by_name (Pd_Plugin_Tilde* x, + const char* name, + float value) +{ + unsigned parm_index; + int found_port; /* boolean */ + char parm_name[9]; /* the Steinberg(tm) way! */ + + /* precondition(s) */ + assert (x != NULL); + + /* compare control name to VST parameters' names + case-insensitively */ + found_port = 0; + for (parm_index = 0; parm_index < x->num_control_inputs; parm_index++) + { + unsigned cmp_start, cmp_length; + memset (parm_name, 0, 9); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamName, + parm_index, 0, parm_name, 0); + /* skip any initial whitespace */ + cmp_start = 0; + while (parm_name[cmp_start] != 0 + && parm_name[cmp_start] == ' ') { + cmp_start++; + } + cmp_length = MIN (strlen (name), strlen (&parm_name[cmp_start])); + if (cmp_length != 0 + && strncasecmp (name, &parm_name[cmp_start], cmp_length) == 0) + { + /* found the first port to match */ + found_port = 1; + break; + } + } + + if (!found_port) + { + error ("plugin~: VST plugin doesn't have a parameter named \"%s\"", + name); + return; + } + + plugin_tilde_vst_set_control_input_by_index (x, + parm_index, + value); +} + +void +plugin_tilde_vst_set_control_input_by_index (Pd_Plugin_Tilde* x, + unsigned index_, + float value) +{ + char name[9]; /* the Steinberg(tm) way! */ + + /* precondition(s) */ + assert (x != NULL); + /* assert (index_ >= 0); causes a warning */ + assert (index_ < x->num_control_inputs); + + /* Limit parameter to range [0, 1] */ + if (value < 0.0 || value > 1.0) { + if (value < 0.0) { + value = 0.0; + } + else { + value = 1.0; + } + error ("plugin~: warning: parameter limited to within [0, 1]"); + } + + /* set the appropriate control port value */ + x->plugin.vst.instance->setParameter (x->plugin.vst.instance, + index_, + value); + +#if PLUGIN_TILDE_DEBUG + memset (name, 0, 9); + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetParamName, + index_, 0, name, 0); + error ("DEBUG plugin~_vst: control change parameter #%ud: \"%s\" to value %f", + index_ + 1, name, value); +#endif +} + +/* change the plugin's program; takes a program index */ +void +plugin_tilde_vst_set_program (Pd_Plugin_Tilde* x, long prog) +{ + long nprog = x->plugin.vst.instance->numPrograms; + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetProgram, 0, prog%nprog, 0, 0); +} + +long +plugin_tilde_vst_get_program (Pd_Plugin_Tilde* x) +{ + return x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effGetProgram, 0, 0, 0, 0); +} + +long +plugin_tilde_vst_get_num_of_programs (Pd_Plugin_Tilde* x) +{ + return x->plugin.vst.instance->numPrograms; +} + +void +plugin_tilde_vst_set_program_name (Pd_Plugin_Tilde* x, const char* progname) +{ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effSetProgramName, 0, 0, (void*)progname, 0); +} + +static long +plugin_tilde_vst_audioMaster (AEffect* effect, + long opcode, + long index, + long value, + void* ptr, + float opt) +{ + char param_name[9]; + +#if 0 /*PLUGIN_TILDE_DEBUG*/ + error ("DEBUG plugin~_vst: audioMaster(0x%p, %ld, %ld, %ld, 0x%p, %f)", + effect, opcode, index, value, ptr, opt); +#endif + + switch (opcode) { + case audioMasterAutomate: + assert (effect != NULL); + assert (effect->user != NULL); /* this is Pd_Plugin_Tilde* */ + effect->setParameter (effect, index, opt); + /* Send "control" messages from here */ + memset (param_name, 0, 9); + effect->dispatcher (effect, effGetParamName, index, 0, param_name, 0); + plugin_tilde_emit_control_output (effect->user, param_name, opt); + return 0; + break; + case audioMasterVersion: + return 1; + break; + case audioMasterCurrentId: + return 0; + break; + case audioMasterIdle: + effect->dispatcher (effect, effEditIdle, 0, 0, NULL, 0); + return 0; + break; + case audioMasterPinConnected: + /* return 0="true" for all inquiries for now */ + return 0; + break; + } +#if 0 /*PLUGIN_TILDE_DEBUG*/ + error ("DEBUG plugin~_vst: warning: unsupported audioMaster opcode"); +#endif + return 0; +} + +void plugin_tilde_vst_open_editor (Pd_Plugin_Tilde* x) +{ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditOpen, + 0, 0, NULL, 0); + +#if 0 /* FIXME doesn't work */ +#ifdef WIN32 + HWND parent; + + /* precondition(s) */ + assert (x != NULL); + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~_vst: open_editor()"); +#endif + + if ((x->plugin.vst.instance->flags & effFlagsHasEditor) == 0 + || x->plugin.vst.editor_open == 1) { + /* no editor or editor already open */ + return; + } + + /* Hmph, don't know about the Pd window, so give the desktop as + the parent to the plug-in; we could actually use + GetForegroundWindow(), since the user is currently typing into + the pd subpatch window */ + /*parent = GetDesktopWindow ();*/ + parent = GetForegroundWindow (); + /*parent = NULL;*/ + + /* Open the editor! */ + if (!x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditOpen, + 0, 0, parent, 0)) { + /* no luck error */ + error ("plugin~_vst: couldn't open editor"); + } else { + x->plugin.vst.editor_open = 1; + } +#endif /* WIN32 */ +#endif /* FIXME doesn't work */ +} + +void +plugin_tilde_vst_close_editor (Pd_Plugin_Tilde* x) +{ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditClose, + 0, 0, NULL, 0); + +#if 0 /* FIXME doesn't work */ +#ifdef WIN32 + + /* precondition(s) */ + assert (x != NULL); + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~_vst: close_editor()"); +#endif + + if ((x->plugin.vst.instance->flags & effFlagsHasEditor) == 0 + || x->plugin.vst.editor_open == 0) { + /* no editor or it isn't open */ + return; + } + + /* Close the editor */ + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditClose, + 0, 0, NULL, 0); + x->plugin.vst.editor_open = 0; + +#endif /* WIN32 */ +#endif /* FIXME doesn't work */ +} + +void +plugin_tilde_vst_update_gui (Pd_Plugin_Tilde* x) +{ +#if 0 /* FIXME doesn't work */ +#ifdef WIN32 + + /* precondition(s) */ + assert (x != NULL); + +#if PLUGIN_TILDE_DEBUG + error ("DEBUG plugin~_vst: update_gui()"); +#endif + if (x->plugin.vst.editor_open) { + x->plugin.vst.instance->dispatcher (x->plugin.vst.instance, + effEditIdle, + 0, 0, NULL, 0); + } +#endif /* WIN32 */ +#endif /* FIXME doesn't work */ +} + +#endif /* PLUGIN_TILDE_USE_VST */ + +/* EOF */ -- cgit v1.2.1