* radically cleaned up / refactored midi_clock_slave.cc
[ardour.git] / libs / ardour / vst_plugin.cc
1 /*
2     Copyright (C) 2004 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <algorithm>
21 #include <vector>
22 #include <string>
23 #include <cctype>
24
25 #include <cstdlib>
26 #include <cstdio> // so libraptor doesn't complain
27 #include <cmath>
28 #include <dirent.h>
29 #include <cstring> // for memmove
30 #include <sys/stat.h>
31 #include <cerrno>
32
33 #include <glibmm/ustring.h>
34 #include <glibmm/miscutils.h>
35
36 #include <lrdf.h>
37 #include <fst.h>
38
39 #include <pbd/compose.h>
40 #include <pbd/error.h>
41 #include <pbd/pathscanner.h>
42 #include <pbd/xml++.h>
43
44 #include <vst/aeffectx.h>
45
46 #include <ardour/session.h>
47 #include <ardour/audioengine.h>
48 #include <ardour/filesystem_paths.h>
49 #include <ardour/vst_plugin.h>
50 #include <ardour/buffer_set.h>
51
52 #include <pbd/stl_delete.h>
53
54 #include "i18n.h"
55 #include <locale.h>
56
57 using namespace ARDOUR;
58 using namespace PBD;
59 using std::min;
60 using std::max;
61
62 VSTPlugin::VSTPlugin (AudioEngine& e, Session& session, FSTHandle* h)
63         : Plugin (e, session)
64 {
65         handle = h;
66
67         if ((_fst = fst_instantiate (handle, Session::vst_callback, this)) == 0) {
68                 throw failed_constructor();
69         }
70
71         _plugin = _fst->plugin;
72         _plugin->user = this;
73
74         /* set rate and blocksize */
75
76         _plugin->dispatcher (_plugin, effSetSampleRate, 0, 0, NULL, 
77                              (float) session.frame_rate());
78         _plugin->dispatcher (_plugin, effSetBlockSize, 0, 
79                              session.get_block_size(), NULL, 0.0f);
80         
81         /* set program to zero */
82
83         _plugin->dispatcher (_plugin, effSetProgram, 0, 0, NULL, 0.0f);
84         
85         Plugin::setup_controls ();
86 }
87
88 VSTPlugin::VSTPlugin (const VSTPlugin &other)
89         : Plugin (other)
90 {
91         handle = other.handle;
92
93         if ((_fst = fst_instantiate (handle, Session::vst_callback, this)) == 0) {
94                 throw failed_constructor();
95         }
96         _plugin = _fst->plugin;
97
98         Plugin::setup_controls ();
99 }
100
101 VSTPlugin::~VSTPlugin ()
102 {
103         deactivate ();
104         GoingAway (); /* EMIT SIGNAL */
105         fst_close (_fst);
106 }
107
108 void
109 VSTPlugin::set_block_size (nframes_t nframes)
110 {
111         deactivate ();
112         _plugin->dispatcher (_plugin, effSetBlockSize, 0, nframes, NULL, 0.0f);
113         activate ();
114 }
115
116 float
117 VSTPlugin::default_value (uint32_t port)
118 {
119         return 0;
120 }       
121
122 void
123 VSTPlugin::set_parameter (uint32_t which, float val)
124 {
125         _plugin->setParameter (_plugin, which, val);
126         //ParameterChanged (which, val); /* EMIT SIGNAL */
127 }
128
129 float
130 VSTPlugin::get_parameter (uint32_t which) const
131 {
132         return _plugin->getParameter (_plugin, which);
133         
134 }
135
136 uint32_t
137 VSTPlugin::nth_parameter (uint32_t n, bool& ok) const
138 {
139         ok = true;
140         return n;
141 }
142
143 XMLNode&
144 VSTPlugin::get_state()
145 {
146         XMLNode *root = new XMLNode (state_node_name());
147         LocaleGuard lg (X_("POSIX"));
148
149         if (_plugin->flags & effFlagsProgramChunks) {
150
151                 /* fetch the current chunk */
152                 
153                 void* data;
154                 long  data_size;
155                 
156                 if ((data_size = _plugin->dispatcher (_plugin, effGetChunk, 0, 0, &data, false)) == 0) {
157                         return *root;
158                 }
159
160                 /* save it to a file */
161
162                 Glib::ustring path = Glib::build_filename (get_user_ardour_path (), "vst");
163                 struct stat sbuf;
164
165                 sys::path user_vst_directory(user_config_directory());
166         
167                 user_vst_directory /= "vst";
168                 path = user_vst_directory.to_string();
169
170                 if (stat (path.c_str(), &sbuf)) {
171                         if (errno == ENOENT) {
172                                 if (g_mkdir_with_parents (path.c_str(), 0600)) {
173                                         error << string_compose (_("cannot create VST chunk directory: %1"),
174                                                                  strerror (errno))
175                                               << endmsg;
176                                         return *root;
177                                 }
178
179                         } else {
180
181                                 warning << string_compose (_("cannot check VST chunk directory: %1"), strerror (errno))
182                                         << endmsg;
183                                 return *root;
184                         }
185
186                 } else if (!S_ISDIR (sbuf.st_mode)) {
187                         error << string_compose (_("%1 exists but is not a directory"), path)
188                               << endmsg;
189                         return *root;
190                 }
191                 
192                 path = Glib::build_filename (path, "something");
193                 
194                 /* store information */
195
196                 XMLNode* chunk_node = new XMLNode (X_("chunk"));
197                 chunk_node->add_property ("path", path);
198                 
199                 root->add_child_nocopy (*chunk_node);
200                 
201         } else {
202
203                 XMLNode* parameters = new XMLNode ("parameters");
204
205                 for (long n = 0; n < _plugin->numParams; ++n) {
206                         char index[64];
207                         char val[32];
208                         snprintf (index, sizeof (index), "param_%ld", n);
209                         snprintf (val, sizeof (val), "%.12g", _plugin->getParameter (_plugin, n));
210                         parameters->add_property (index, val);
211                 }
212
213                 root->add_child_nocopy (*parameters);
214         }
215
216         return *root;
217 }
218
219 int
220 VSTPlugin::set_state(const XMLNode& node)
221 {
222         LocaleGuard lg (X_("POSIX"));
223
224         if (node.name() != state_node_name()) {
225                 error << _("Bad node sent to VSTPlugin::set_state") << endmsg;
226                 return 0;
227         }
228
229         XMLNode* child;
230
231         if ((child = find_named_node (node, X_("chunks"))) != 0) {
232
233                 return 0;
234
235         } else if ((child = find_named_node (node, X_("parameters"))) != 0) {
236                 
237                 XMLPropertyList::const_iterator i;
238
239                 for (i = child->properties().begin(); i != child->properties().end(); ++i) {
240                         long param;
241                         float val;
242
243                         sscanf ((*i)->name().c_str(), "param_%ld", &param);
244                         sscanf ((*i)->value().c_str(), "%f", &val);
245
246                         _plugin->setParameter (_plugin, param, val);
247                 }
248
249                 return 0;
250         }
251
252         return -1;
253 }
254
255 int
256 VSTPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& desc) const
257 {
258         VstParameterProperties prop;
259
260         desc.min_unbound = false;
261         desc.max_unbound = false;
262
263         if (_plugin->dispatcher (_plugin, effGetParameterProperties, which, 0, &prop, 0)) {
264
265                 /* i have yet to find or hear of a VST plugin that uses this */
266
267                 if (prop.flags & kVstParameterUsesIntegerMinMax) {
268                         desc.lower = prop.minInteger;
269                         desc.upper = prop.maxInteger;
270                 } else {
271                         desc.lower = 0;
272                         desc.upper = 1.0;
273                 }
274                 
275                 if (prop.flags & kVstParameterUsesIntStep) {
276                         
277                         desc.step = prop.stepInteger;
278                         desc.smallstep = prop.stepInteger;
279                         desc.largestep = prop.stepInteger;
280                         
281                 } else if (prop.flags & kVstParameterUsesFloatStep) {
282                         
283                         desc.step = prop.stepFloat;
284                         desc.smallstep = prop.smallStepFloat;
285                         desc.largestep = prop.largeStepFloat;
286                         
287                 } else {
288                         
289                         float range = desc.upper - desc.lower;
290                         
291                         desc.step = range / 100.0f;
292                         desc.smallstep = desc.step / 2.0f;
293                         desc.largestep = desc.step * 10.0f;
294                 }
295                 
296                 desc.toggled = prop.flags & kVstParameterIsSwitch;
297                 desc.logarithmic = false;
298                 desc.sr_dependent = false;
299                 desc.label = prop.label;
300
301         } else {
302
303                 /* old style */
304
305                 char label[64];
306                 label[0] = '\0';
307
308                 _plugin->dispatcher (_plugin, effGetParamName, which, 0, label, 0);
309
310                 desc.label = label;
311                 desc.integer_step = false;
312                 desc.lower = 0.0f;
313                 desc.upper = 1.0f;
314                 desc.step = 0.01f;
315                 desc.smallstep = 0.005f;
316                 desc.largestep = 0.1f;
317                 desc.toggled = false;
318                 desc.logarithmic = false;
319                 desc.sr_dependent = false;
320         }
321
322         return 0;
323 }
324
325 bool
326 VSTPlugin::load_preset (string name)
327 {
328         if (_plugin->flags & effFlagsProgramChunks) {
329                 error << _("no support for presets using chunks at this time")
330                       << endmsg;
331                 return false;
332         }
333         return Plugin::load_preset (name);
334 }
335
336 bool
337 VSTPlugin::save_preset (string name)
338 {
339         if (_plugin->flags & effFlagsProgramChunks) {
340                 error << _("no support for presets using chunks at this time")
341                       << endmsg;
342                 return false;
343         }
344         return Plugin::save_preset (name, "vst");
345 }
346
347 string
348 VSTPlugin::describe_parameter (uint32_t param)
349 {
350         char name[64];
351         _plugin->dispatcher (_plugin, effGetParamName, param, 0, name, 0);
352         return name;
353 }
354
355 nframes_t
356 VSTPlugin::signal_latency () const
357 {
358         if (_user_latency) {
359                 return _user_latency;
360         }
361
362         return _plugin->initialDelay;
363 }
364
365 set<uint32_t>
366 VSTPlugin::automatable () const
367 {
368         set<uint32_t> ret;
369
370         for (uint32_t i = 0; i < parameter_count(); ++i){
371                 ret.insert (ret.end(), i);
372         }
373
374         return ret;
375 }
376
377 int
378 VSTPlugin::connect_and_run (BufferSet& bufs, uint32_t& in_index, uint32_t& out_index, nframes_t nframes, nframes_t offset)
379 {
380         float *ins[_plugin->numInputs];
381         float *outs[_plugin->numOutputs];
382         int32_t i;
383
384         const uint32_t nbufs = bufs.count().n_audio();
385
386         for (i = 0; i < (int32_t) _plugin->numInputs; ++i) {
387                 ins[i] = bufs.get_audio(min((uint32_t) in_index, nbufs - 1)).data() + offset;
388                 in_index++;
389         }
390
391         for (i = 0; i < (int32_t) _plugin->numOutputs; ++i) {
392                 outs[i] = bufs.get_audio(min((uint32_t) out_index, nbufs - 1)).data() + offset;
393
394                 /* unbelievably, several VST plugins still rely on Cubase
395                    behaviour and do not silence the buffer in processReplacing 
396                    when they have no output.
397                 */
398                 
399                 // memset (outs[i], 0, sizeof (Sample) * nframes);
400                 out_index++;
401         }
402
403
404         /* we already know it can support processReplacing */
405
406         _plugin->processReplacing (_plugin, ins, outs, nframes);
407         
408         return 0;
409 }
410
411 void
412 VSTPlugin::deactivate ()
413 {
414         _plugin->dispatcher (_plugin, effMainsChanged, 0, 0, NULL, 0.0f);
415 }
416
417 void
418 VSTPlugin::activate ()
419 {
420         _plugin->dispatcher (_plugin, effMainsChanged, 0, 1, NULL, 0.0f);
421 }
422
423 string
424 VSTPlugin::unique_id() const
425 {
426         char buf[32];
427         snprintf (buf, sizeof (buf), "%d", _plugin->uniqueID);
428         return string (buf);
429 }
430
431
432 const char *
433 VSTPlugin::name () const
434 {
435         return handle->name;
436 }
437
438 const char *
439 VSTPlugin::maker () const
440 {
441         return "imadeit";
442 }
443
444 const char *
445 VSTPlugin::label () const
446 {
447         return handle->name;
448 }
449
450 uint32_t
451 VSTPlugin::parameter_count() const
452 {
453         return _plugin->numParams;
454 }
455
456 bool
457 VSTPlugin::has_editor () const
458 {
459         return _plugin->flags & effFlagsHasEditor;
460 }
461
462 void
463 VSTPlugin::print_parameter (uint32_t param, char *buf, uint32_t len) const
464 {
465         char lab[9];
466         char *first_nonws;
467
468         _plugin->dispatcher (_plugin, effGetParamLabel, param, 0, lab, 0);
469         _plugin->dispatcher (_plugin, effGetParamDisplay, param, 0, buf, 0);
470
471         if (buf[0] == '\0') {
472                 return;
473         }
474
475         first_nonws = buf;
476         while (*first_nonws && isspace (*first_nonws)) {
477                 first_nonws++;
478         }
479         if (*first_nonws == '\0') {
480                 return;
481         }
482
483         memmove (buf, first_nonws, strlen (buf) - (first_nonws - buf) + 1);
484 }
485
486 PluginPtr
487 VSTPluginInfo::load (Session& session)
488 {
489         try {
490                 PluginPtr plugin;
491
492                 if (Config->get_use_vst()) {
493                         FSTHandle* handle;
494                         
495                         handle = fst_load(path.c_str());
496         
497                         if ( (int)handle == -1) {
498                                 error << string_compose(_("VST: cannot load module from \"%1\""), path) << endmsg;
499                         } else {
500                                 plugin.reset (new VSTPlugin (session.engine(), session, handle));
501                         }
502                 } else {
503                         error << _("You asked ardour to not use any VST plugins") << endmsg;
504                         return PluginPtr ((Plugin*) 0);
505                 }
506
507                 plugin->set_info(PluginInfoPtr(new VSTPluginInfo(*this)));
508                 return plugin;
509         }       
510
511         catch (failed_constructor &err) {
512                 return PluginPtr ((Plugin*) 0);
513         }
514 }