Large nasty commit in the form of a 5000 line patch chock-full of completely
[ardour.git] / libs / ardour / plugin.cc
1 /*
2     Copyright (C) 2000-2002 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     $Id$
19 */
20
21 #include <vector>
22 #include <string>
23
24 #include <cstdlib>
25 #include <cstdio> // so libraptor doesn't complain
26 #include <cmath>
27 #include <dirent.h>
28 #include <sys/stat.h>
29 #include <cerrno>
30
31 #include <lrdf.h>
32
33 #include <pbd/compose.h>
34 #include <pbd/error.h>
35 #include <pbd/pathscanner.h>
36 #include <pbd/xml++.h>
37
38 #include <midi++/manager.h>
39
40 #include <ardour/ardour.h>
41 #include <ardour/session.h>
42 #include <ardour/audioengine.h>
43 #include <ardour/plugin.h>
44
45 #include <pbd/stl_delete.h>
46
47 #include "i18n.h"
48 #include <locale.h>
49
50 using namespace ARDOUR;
51 using namespace PBD;
52
53 Plugin::Plugin (AudioEngine& e, Session& s)
54         : _engine (e), _session (s)
55 {
56 }
57
58 Plugin::Plugin (const Plugin& other)
59         : _engine (other._engine), _session (other._session), _info (other._info)
60 {
61 }
62
63 void
64 Plugin::setup_midi_controls ()
65 {
66         uint32_t port_cnt;
67
68         port_cnt = parameter_count();
69
70         /* set up a vector of null pointers for the MIDI controls.
71            we'll fill this in on an as-needed basis.
72         */
73
74         for (uint32_t i = 0; i < port_cnt; ++i) {
75                 midi_controls.push_back (0);
76         }
77 }
78
79 Plugin::~Plugin ()
80 {
81         for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i) {
82                 if (*i) {
83                         delete *i;
84                 }
85         }
86 }
87
88 MIDI::Controllable *
89 Plugin::get_nth_midi_control (uint32_t n)
90 {
91         if (n >= parameter_count()) {
92                 return 0;
93         }
94
95         if (midi_controls[n] == 0) {
96
97                 Plugin::ParameterDescriptor desc;
98
99                 get_parameter_descriptor (n, desc);
100
101                 midi_controls[n] = new MIDIPortControl (*this, n, _session.midi_port(), desc.lower, desc.upper, desc.toggled, desc.logarithmic);
102         } 
103
104         return midi_controls[n];
105 }
106
107 Plugin::MIDIPortControl::MIDIPortControl (Plugin& p, uint32_t port_id, MIDI::Port *port,
108                                           float low, float up, bool t, bool loga)
109         : MIDI::Controllable (port, 0), plugin (p), absolute_port (port_id)
110 {
111         toggled = t;
112         logarithmic = loga;
113         lower = low;
114         upper = up;
115         range = upper - lower;
116         last_written = 0; /* XXX need a good out-of-bound-value */
117         setting = false;
118 }
119
120 void
121 Plugin::MIDIPortControl::set_value (float value)
122 {
123         if (toggled) {
124                 if (value > 0.5) {
125                         value = 1.0;
126                 } else {
127                         value = 0.0;
128                 }
129         } else {
130                 value = lower + (range * value);
131                 
132                 if (logarithmic) {
133                         value = exp(value);
134                 }
135         }
136
137         setting = true;
138         plugin.set_parameter (absolute_port, value);
139         setting = false;
140 }
141
142 void
143 Plugin::MIDIPortControl::send_feedback (float value)
144 {
145
146         if (!setting && get_midi_feedback()) {
147                 MIDI::byte val;
148                 MIDI::channel_t ch = 0;
149                 MIDI::eventType ev = MIDI::none;
150                 MIDI::byte additional = 0;
151                 MIDI::EventTwoBytes data;
152
153                 if (toggled) {
154                         val = (MIDI::byte) (value * 127.0f);
155                 } else {
156                         if (logarithmic) {
157                                 value = log(value);
158                         }
159
160                         val = (MIDI::byte) (((value - lower) / range) * 127.0f);
161                 }
162                 
163                 if (get_control_info (ch, ev, additional)) {
164                         data.controller_number = additional;
165                         data.value = val;
166                         last_written = val;
167                         
168                         plugin.session().send_midi_message (get_port(), ev, ch, data);
169                 }
170         }
171         
172 }
173
174 MIDI::byte*
175 Plugin::MIDIPortControl::write_feedback (MIDI::byte* buf, int32_t& bufsize, float value, bool force)
176 {
177         if (get_midi_feedback() && bufsize > 2) {
178                 MIDI::channel_t ch = 0;
179                 MIDI::eventType ev = MIDI::none;
180                 MIDI::byte additional = 0;
181
182                 if (get_control_info (ch, ev, additional)) {
183
184                         MIDI::byte val;
185
186                         if (toggled) {
187
188                                 val = (MIDI::byte) (value * 127.0f);
189
190                         } else {
191
192                                 if (logarithmic) {
193                                         value = log(value);
194                                 }
195                                 
196                                 val = (MIDI::byte) (((value - lower) / range) * 127.0f);
197                         }
198
199                         if (val != last_written || force)  {
200                                 *buf++ = MIDI::controller & ch;
201                                 *buf++ = additional; /* controller number */
202                                 *buf++ = val;
203                                 last_written = val;
204                                 bufsize -= 3;
205                         }
206                 }
207         }
208
209         return buf;
210 }
211
212
213 void
214 Plugin::reset_midi_control (MIDI::Port* port, bool on)
215 {
216         MIDI::channel_t chn;
217         MIDI::eventType ev;
218         MIDI::byte extra;
219         
220         for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i) {
221                 if (*i == 0)
222                         continue;
223                 (*i)->get_control_info (chn, ev, extra);
224                 if (!on) {
225                         chn = -1;
226                 }
227                 (*i)->midi_rebind (port, chn);
228         }
229 }
230
231 void
232 Plugin::send_all_midi_feedback ()
233 {
234         if (_session.get_midi_feedback()) {
235                 float val = 0.0;
236                 uint32_t n = 0;
237                 
238                 for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i, ++n) {
239                         if (*i == 0) {
240                                 continue;
241                         }
242
243                         val = (*i)->plugin.get_parameter (n);
244                         (*i)->send_feedback (val);
245                 }
246                 
247         }
248 }
249
250 MIDI::byte*
251 Plugin::write_midi_feedback (MIDI::byte* buf, int32_t& bufsize)
252 {
253         if (_session.get_midi_feedback()) {
254                 float val = 0.0;
255                 uint32_t n = 0;
256                 
257                 for (vector<MIDIPortControl*>::iterator i = midi_controls.begin(); i != midi_controls.end(); ++i, ++n) {
258                         if (*i == 0) {
259                                 continue;
260                         }
261
262                         val = (*i)->plugin.get_parameter (n);
263                         buf = (*i)->write_feedback (buf, bufsize, val);
264                 }
265         }
266
267         return buf;
268 }
269
270 vector<string>
271 Plugin::get_presets()
272 {
273         vector<string> labels;
274         lrdf_uris* set_uris = lrdf_get_setting_uris(unique_id());
275
276         if (set_uris) {
277                 for (uint32_t i = 0; i < (uint32_t) set_uris->count; ++i) {
278                         if (char* label = lrdf_get_label(set_uris->items[i])) {
279                                 labels.push_back(label);
280                                 presets[label] = set_uris->items[i];
281                         }
282                 }
283                 lrdf_free_uris(set_uris);
284         }
285
286         // GTK2FIX find an equivalent way to do this with a vector (needed by GUI apis)
287         // labels.unique();
288
289         return labels;
290 }
291
292 bool
293 Plugin::load_preset(const string preset_label)
294 {
295         lrdf_defaults* defs = lrdf_get_setting_values(presets[preset_label].c_str());
296
297         if (defs) {
298                 for (uint32_t i = 0; i < (uint32_t) defs->count; ++i) {
299                         // The defs->items[i].pid < defs->count check is to work around 
300                         // a bug in liblrdf that saves invalid values into the presets file.
301                         if (((uint32_t) defs->items[i].pid < (uint32_t) defs->count) && parameter_is_input (defs->items[i].pid)) {
302                                 set_parameter(defs->items[i].pid, defs->items[i].value);
303                         }
304                 }
305                 lrdf_free_setting_values(defs);
306         }
307
308         return true;
309 }
310
311 bool
312 Plugin::save_preset (string name, string domain)
313 {
314         lrdf_portvalue portvalues[parameter_count()];
315         lrdf_defaults defaults;
316         defaults.count = parameter_count();
317         defaults.items = portvalues;
318
319         for (uint32_t i = 0; i < parameter_count(); ++i) {
320                 if (parameter_is_input (i)) {
321                         portvalues[i].pid = i;
322                         portvalues[i].value = get_parameter(i);
323                 }
324         }
325
326         char* envvar;
327         if ((envvar = getenv ("HOME")) == 0) {
328                 warning << _("Could not locate HOME.  Preset not saved.") << endmsg;
329                 return false;
330         }
331         
332         string source(string_compose("file:%1/.%2/rdf/ardour-presets.n3", envvar, domain));
333
334         free(lrdf_add_preset(source.c_str(), name.c_str(), unique_id(), &defaults));
335
336         string path = string_compose("%1/.%2", envvar, domain);
337         if (mkdir(path.c_str(), 0775) && errno != EEXIST) {
338                 warning << string_compose(_("Could not create %1.  Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
339                 return false;
340         }
341         
342         path += "/rdf";
343         if (mkdir(path.c_str(), 0775) && errno != EEXIST) {
344                 warning << string_compose(_("Could not create %1.  Preset not saved. (%2)"), path, strerror(errno)) << endmsg;
345                 return false;
346         }
347         
348         if (lrdf_export_by_source(source.c_str(), source.substr(5).c_str())) {
349                 warning << string_compose(_("Error saving presets file %1."), source) << endmsg;
350                 return false;
351         }
352
353         return true;
354 }