1 /*
2  * JACK Rack
3  *
4  * Original:
5  * Copyright (C) Robert Ham 2002, 2003 (node@users.sourceforge.net)
6  *
7  * Modification for MLT:
8  * Copyright (C) 2004-2014 Meltytech, LLC
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <strings.h>
28 #include <string.h>
29 #include <ctype.h>
30 
31 #include <ladspa.h>
32 #include <libxml/tree.h>
33 
34 #include "jack_rack.h"
35 #include "lock_free_fifo.h"
36 #include "plugin_settings.h"
37 #include "framework/mlt_log.h"
38 
39 #ifndef _
40 #define _(x) x
41 #endif
42 #define _x (const xmlChar*)
43 #define _s (const char*)
44 
45 extern plugin_mgr_t *g_jackrack_plugin_mgr;
46 
47 jack_rack_t *
jack_rack_new(const char * client_name,unsigned long channels)48 jack_rack_new (const char * client_name, unsigned long channels)
49 {
50   jack_rack_t *rack;
51 
52   rack = g_malloc (sizeof (jack_rack_t));
53   rack->saved_plugins  = NULL;
54   rack->channels       = channels;
55   rack->procinfo = process_info_new (client_name, channels, FALSE, FALSE);
56   if (!rack->procinfo) {
57     g_free (rack);
58     return NULL;
59   }
60   rack->plugin_mgr = g_jackrack_plugin_mgr;
61   plugin_mgr_set_plugins (rack->plugin_mgr, channels);
62 
63   return rack;
64 }
65 
66 
67 void
jack_rack_destroy(jack_rack_t * jack_rack)68 jack_rack_destroy (jack_rack_t * jack_rack)
69 {
70   process_quit (jack_rack->procinfo);
71   // plugin_mgr is shared and global now, so we do not destroy it with each instance
72 //  plugin_mgr_destroy (jack_rack->plugin_mgr);
73   process_info_destroy (jack_rack->procinfo);
74   g_slist_free (jack_rack->saved_plugins);
75   g_free (jack_rack);
76 }
77 
78 plugin_t *
jack_rack_instantiate_plugin(jack_rack_t * jack_rack,plugin_desc_t * desc)79 jack_rack_instantiate_plugin (jack_rack_t * jack_rack, plugin_desc_t * desc)
80 {
81   plugin_t * plugin;
82 
83   /* check whether or not the plugin is RT capable and confirm with the user if it isn't */
84   if (!LADSPA_IS_HARD_RT_CAPABLE(desc->properties)) {
85     mlt_log_info( NULL, "Plugin not RT capable. The plugin '%s' does not describe itself as being capable of real-time operation. You may experience drop outs or jack may even kick us out if you use it.\n",
86                desc->name);
87   }
88 
89   /* create the plugin */
90   plugin = plugin_new (desc, jack_rack);
91 
92   if (!plugin) {
93    mlt_log_error( NULL, "Error loading file plugin '%s' from file '%s'\n",
94                desc->name, desc->object_file);
95   }
96 
97   return plugin;
98 }
99 
100 
101 void
jack_rack_add_saved_plugin(jack_rack_t * jack_rack,saved_plugin_t * saved_plugin)102 jack_rack_add_saved_plugin (jack_rack_t * jack_rack, saved_plugin_t * saved_plugin)
103 {
104   plugin_t * plugin = jack_rack_instantiate_plugin (jack_rack, saved_plugin->settings->desc);
105   if (!plugin)
106     {
107       mlt_log_warning( NULL, "%s: could not instantiate object file '%s'\n",
108                        __FUNCTION__, saved_plugin->settings->desc->object_file);
109       return;
110     }
111   jack_rack->saved_plugins = g_slist_append (jack_rack->saved_plugins, saved_plugin);
112   process_add_plugin (jack_rack->procinfo, plugin);
113   jack_rack_add_plugin (jack_rack, plugin);
114 }
115 
116 
117 void
jack_rack_add_plugin(jack_rack_t * jack_rack,plugin_t * plugin)118 jack_rack_add_plugin (jack_rack_t * jack_rack, plugin_t * plugin)
119 {
120   saved_plugin_t * saved_plugin = NULL;
121   GSList * list;
122   unsigned long control, channel;
123   LADSPA_Data value;
124   guint copy;
125 
126   /* see if there's any saved settings that match the plugin id */
127   for (list = jack_rack->saved_plugins; list; list = g_slist_next (list))
128     {
129       saved_plugin = list->data;
130 
131       if (saved_plugin->settings->desc->id == plugin->desc->id)
132         {
133           /* process the settings! */
134           jack_rack->saved_plugins = g_slist_remove (jack_rack->saved_plugins, saved_plugin);
135           break;
136         }
137       saved_plugin = NULL;
138     }
139 
140    if ( !saved_plugin )
141 	return;
142 
143   /* initialize plugin parameters */
144   plugin->enabled = settings_get_enabled (saved_plugin->settings);
145   plugin->wet_dry_enabled = settings_get_wet_dry_enabled (saved_plugin->settings);
146 
147   for (control = 0; control < saved_plugin->settings->desc->control_port_count; control++)
148     for (copy = 0; copy < plugin->copies; copy++)
149       {
150         value = settings_get_control_value (saved_plugin->settings, copy, control);
151         plugin->holders[copy].control_memory[control] = value;
152 //mlt_log_debug( NULL, "setting control value %s (%d) = %f\n", saved_plugin->settings->desc->port_names[control], copy, value);
153 //        lff_write (plugin->holders[copy].ui_control_fifos + control, &value);
154       }
155   if (plugin->wet_dry_enabled)
156     for (channel = 0; channel < jack_rack->channels; channel++)
157       {
158         value = settings_get_wet_dry_value (saved_plugin->settings, channel);
159         plugin->wet_dry_values[channel] = value;
160 //mlt_log_debug( NULL, "setting wet/dry value %d = %f\n", channel, value);
161 //        lff_write (plugin->wet_dry_fifos + channel, &value);
162       }
163 }
164 
165 
166 static void
saved_rack_parse_plugin(jack_rack_t * jack_rack,saved_rack_t * saved_rack,saved_plugin_t * saved_plugin,const char * filename,xmlNodePtr plugin)167 saved_rack_parse_plugin (jack_rack_t * jack_rack, saved_rack_t * saved_rack, saved_plugin_t * saved_plugin,
168                          const char * filename, xmlNodePtr plugin)
169 {
170   plugin_desc_t * desc;
171   settings_t * settings = NULL;
172   xmlNodePtr node;
173   xmlNodePtr sub_node;
174   xmlChar *content;
175   unsigned long num;
176   unsigned long control = 0;
177 #ifdef _WIN32
178   xmlFreeFunc xmlFree = NULL;
179   xmlMemGet( &xmlFree, NULL, NULL, NULL);
180 #endif
181 
182   for (node = plugin->children; node; node = node->next)
183     {
184       if (xmlStrcmp (node->name, _x("id")) == 0)
185         {
186           content = xmlNodeGetContent (node);
187           num = strtoul (_s(content), NULL, 10);
188           xmlFree (content);
189 
190           desc = plugin_mgr_get_any_desc (jack_rack->plugin_mgr, num);
191           if (!desc)
192             {
193               mlt_log_verbose( NULL, _("The file '%s' contains an unknown plugin with ID '%ld'; skipping\n"), filename, num);
194               return;
195             }
196 
197           settings = settings_new (desc, saved_rack->channels, saved_rack->sample_rate);
198         }
199       else if (xmlStrcmp (node->name, _x("enabled")) == 0)
200         {
201           content = xmlNodeGetContent (node);
202           settings_set_enabled (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE);
203           xmlFree (content);
204         }
205       else if (xmlStrcmp (node->name, _x("wet_dry_enabled")) == 0)
206         {
207           content = xmlNodeGetContent (node);
208           settings_set_wet_dry_enabled (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE);
209           xmlFree (content);
210         }
211       else if (xmlStrcmp (node->name, _x("wet_dry_locked")) == 0)
212         {
213           content = xmlNodeGetContent (node);
214           settings_set_wet_dry_locked (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE);
215           xmlFree (content);
216         }
217       else if (xmlStrcmp (node->name, _x("wet_dry_values")) == 0)
218         {
219           unsigned long channel = 0;
220 
221           for (sub_node = node->children; sub_node; sub_node = sub_node->next)
222             {
223               if (xmlStrcmp (sub_node->name, _x("value")) == 0)
224                 {
225                   content = xmlNodeGetContent (sub_node);
226                   settings_set_wet_dry_value (settings, channel, strtod (_s(content), NULL));
227                   xmlFree (content);
228 
229                   channel++;
230                 }
231             }
232         }
233       else if (xmlStrcmp (node->name, _x("lockall")) == 0)
234         {
235           content = xmlNodeGetContent (node);
236           settings_set_lock_all (settings, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE);
237           xmlFree (content);
238         }
239       else if (xmlStrcmp (node->name, _x("controlrow")) == 0)
240         {
241           gint copy = 0;
242 
243           for (sub_node = node->children; sub_node; sub_node = sub_node->next)
244             {
245               if (xmlStrcmp (sub_node->name, _x("lock")) == 0)
246                 {
247                   content = xmlNodeGetContent (sub_node);
248                   settings_set_lock (settings, control, xmlStrcmp (content, _x("true")) == 0 ? TRUE : FALSE);
249                   xmlFree (content);
250                 }
251               else if (xmlStrcmp (sub_node->name, _x("value")) == 0)
252                 {
253                   content = xmlNodeGetContent (sub_node);
254                   settings_set_control_value (settings, copy, control, strtod (_s(content), NULL));
255                   xmlFree (content);
256                   copy++;
257                 }
258             }
259 
260           control++;
261         }
262     }
263 
264   if (settings)
265     saved_plugin->settings = settings;
266 }
267 
268 static void
saved_rack_parse_jackrack(jack_rack_t * jack_rack,saved_rack_t * saved_rack,const char * filename,xmlNodePtr jackrack)269 saved_rack_parse_jackrack (jack_rack_t * jack_rack, saved_rack_t * saved_rack, const char * filename, xmlNodePtr jackrack)
270 {
271   xmlNodePtr node;
272   xmlChar *content;
273   saved_plugin_t * saved_plugin;
274 #ifdef _WIN32
275   xmlFreeFunc xmlFree = NULL;
276   xmlMemGet( &xmlFree, NULL, NULL, NULL);
277 #endif
278 
279   for (node = jackrack->children; node; node = node->next)
280     {
281       if (xmlStrcmp (node->name, _x("channels")) == 0)
282         {
283           content = xmlNodeGetContent (node);
284           saved_rack->channels = strtoul (_s(content), NULL, 10);
285           xmlFree (content);
286         }
287       else if (xmlStrcmp (node->name, _x("samplerate")) == 0)
288         {
289           content = xmlNodeGetContent (node);
290           saved_rack->sample_rate = strtoul (_s(content), NULL, 10);
291           xmlFree (content);
292         }
293       else if (xmlStrcmp (node->name, _x("plugin")) == 0)
294         {
295           saved_plugin = g_malloc0 (sizeof (saved_plugin_t));
296           saved_rack->plugins = g_slist_append (saved_rack->plugins, saved_plugin);
297           saved_rack_parse_plugin (jack_rack, saved_rack, saved_plugin, filename, node);
298         }
299     }
300 }
301 
302 static saved_rack_t *
saved_rack_new(jack_rack_t * jack_rack,const char * filename,xmlDocPtr doc)303 saved_rack_new (jack_rack_t * jack_rack, const char * filename, xmlDocPtr doc)
304 {
305   xmlNodePtr node;
306   saved_rack_t *saved_rack;
307 
308   /* create the saved rack */
309   saved_rack = g_malloc (sizeof (saved_rack_t));
310   saved_rack->plugins = NULL;
311   saved_rack->sample_rate = 48000;
312   saved_rack->channels = 2;
313 
314   for (node = doc->children; node; node = node->next)
315     {
316       if (xmlStrcmp (node->name, _x("jackrack")) == 0)
317         saved_rack_parse_jackrack (jack_rack, saved_rack, filename, node);
318     }
319 
320   return saved_rack;
321 }
322 
323 static void
saved_rack_destroy(saved_rack_t * saved_rack)324 saved_rack_destroy (saved_rack_t * saved_rack)
325 {
326   GSList * list;
327 
328   for (list = saved_rack->plugins; list; list = g_slist_next (list))
329     settings_destroy (((saved_plugin_t *) list->data)->settings);
330   g_slist_free (saved_rack->plugins);
331   g_free (saved_rack);
332 }
333 
334 
335 int
jack_rack_open_file(jack_rack_t * jack_rack,const char * filename)336 jack_rack_open_file (jack_rack_t * jack_rack, const char * filename)
337 {
338   xmlDocPtr doc;
339   saved_rack_t * saved_rack;
340   GSList * list;
341   saved_plugin_t * saved_plugin;
342 
343   doc = xmlParseFile (filename);
344   if (!doc)
345     {
346       mlt_log_error( NULL, _("Could not parse file '%s'\n"), filename);
347       return 1;
348     }
349 
350   if (xmlStrcmp ( ((xmlDtdPtr)doc->children)->name, _x("jackrack")) != 0)
351     {
352       mlt_log_error( NULL, _("The file '%s' is not a JACK Rack settings file\n"), filename);
353       return 1;
354     }
355 
356   saved_rack = saved_rack_new (jack_rack, filename, doc);
357   xmlFreeDoc (doc);
358 
359   if (!saved_rack)
360     return 1;
361 
362   for (list = saved_rack->plugins; list; list = g_slist_next (list))
363     {
364       saved_plugin = list->data;
365 
366       settings_set_sample_rate (saved_plugin->settings, sample_rate);
367 
368       jack_rack_add_saved_plugin (jack_rack, saved_plugin);
369     }
370 
371   saved_rack_destroy (saved_rack);
372 
373   return 0;
374 }
375 
376 
377 /* EOF */
378