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