+ JACK host: fix compilation with LASH (thanks Joeboy&drobilla) and printf format...
[calf.git] / src / jackhost.cpp
blob1803c5c26f9290ac431e02c6ee61bb4c0614b2bd
1 /* Calf DSP Library Utility Application - calfjackhost
2 * Standalone application module wrapper example.
4 * Copyright (C) 2007 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
21 #include <set>
22 #include <getopt.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <config.h>
26 #include <glade/glade.h>
27 #include <jack/jack.h>
28 #if USE_LASH
29 #include <lash/lash.h>
30 #endif
31 #include <calf/giface.h>
32 #include <calf/jackhost.h>
33 #include <calf/modules.h>
34 #include <calf/modules_dev.h>
35 #include <calf/gui.h>
36 #include <calf/preset.h>
37 #include <calf/preset_gui.h>
38 #include <calf/main_win.h>
39 #include <calf/utils.h>
40 #include <stdio.h>
41 using namespace std;
42 using namespace calf_utils;
43 using namespace calf_plugins;
45 // I don't need anyone to tell me this is stupid. I already know that :)
46 plugin_gui_window *gui_win;
48 const char *client_name = "calfhost";
50 #if USE_LASH_0_6
51 static bool save_data_set_cb(lash_config_handle_t *handle, void *user_data);
52 static bool load_data_set_cb(lash_config_handle_t *handle, void *user_data);
53 static bool quit_cb(void *user_data);
54 #endif
56 jack_host_base *calf_plugins::create_jack_host(const char *effect_name, const std::string &instance_name, calf_plugins::progress_report_iface *priface)
58 #define PER_MODULE_ITEM(name, isSynth, jackname) if (!strcasecmp(effect_name, jackname)) return new jack_host<name##_audio_module>(effect_name, instance_name, priface);
59 #include <calf/modulelist.h>
60 return NULL;
63 void jack_host_base::open(jack_client *_client)
65 client = _client; //jack_client_open(client_name, JackNullOption, &status);
67 create_ports();
69 cache_ports();
71 init_module();
72 changed = false;
75 void jack_host_base::create_ports() {
76 char buf[32];
77 char buf2[64];
78 string prefix = client->name + ":";
79 static const char *suffixes[] = { "l", "r", "2l", "2r" };
80 port *inputs = get_inputs();
81 port *outputs = get_outputs();
82 int in_count = get_input_count(), out_count = get_output_count();
83 for (int i=0; i<in_count; i++) {
84 sprintf(buf, "%s_in_%s", instance_name.c_str(), suffixes[i]);
85 sprintf(buf2, client->input_name.c_str(), client->input_nr++);
86 inputs[i].name = buf2;
87 inputs[i].handle = jack_port_register(client->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput , 0);
88 inputs[i].data = NULL;
89 if (!inputs[i].handle)
90 throw text_exception("Could not create JACK input port");
91 jack_port_set_alias(inputs[i].handle, (prefix + buf2).c_str());
93 if (get_midi()) {
94 sprintf(buf, "%s_midi_in", instance_name.c_str());
95 sprintf(buf2, client->midi_name.c_str(), client->midi_nr++);
96 midi_port.name = buf2;
97 midi_port.handle = jack_port_register(client->client, buf, JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
98 if (!midi_port.handle)
99 throw text_exception("Could not create JACK MIDI port");
100 jack_port_set_alias(midi_port.handle, (prefix + buf2).c_str());
102 for (int i=0; i<out_count; i++) {
103 sprintf(buf, "%s_out_%s", instance_name.c_str(), suffixes[i]);
104 sprintf(buf2, client->output_name.c_str(), client->output_nr++);
105 outputs[i].name = buf2;
106 outputs[i].handle = jack_port_register(client->client, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput , 0);
107 outputs[i].data = NULL;
108 if (!outputs[i].handle)
109 throw text_exception("Could not create JACK output port");
110 jack_port_set_alias(outputs[i].handle, (prefix + buf2).c_str());
114 void jack_host_base::close() {
115 port *inputs = get_inputs(), *outputs = get_outputs();
116 int input_count = get_input_count(), output_count = get_output_count();
117 for (int i = 0; i < input_count; i++) {
118 jack_port_unregister(client->client, inputs[i].handle);
119 inputs[i].data = NULL;
121 for (int i = 0; i < output_count; i++) {
122 jack_port_unregister(client->client, outputs[i].handle);
123 outputs[i].data = NULL;
125 if (get_midi())
126 jack_port_unregister(client->client, midi_port.handle);
127 client = NULL;
130 void destroy(GtkWindow *window, gpointer data)
132 gtk_main_quit();
135 void gui_win_destroy(GtkWindow *window, gpointer data)
139 static struct option long_options[] = {
140 {"help", 0, 0, 'h'},
141 {"version", 0, 0, 'v'},
142 {"client", 1, 0, 'c'},
143 {"effect", 0, 0, 'e'},
144 {"input", 1, 0, 'i'},
145 {"output", 1, 0, 'o'},
146 {"connect-midi", 1, 0, 'M'},
147 {0,0,0,0},
150 void print_help(char *argv[])
152 printf("JACK host for Calf effects\n"
153 "Syntax: %s [--client <name>] [--input <name>] [--output <name>] [--midi <name>]\n"
154 " [--connect-midi <name|capture-index>] [--help] [--version] [!] pluginname[:<preset>] [!] ...\n",
155 argv[0]);
158 int jack_client::do_jack_process(jack_nframes_t nframes, void *p)
160 jack_client *self = (jack_client *)p;
161 ptlock lock(self->mutex);
162 for(unsigned int i = 0; i < self->plugins.size(); i++)
163 self->plugins[i]->process(nframes);
164 return 0;
167 int jack_client::do_jack_bufsize(jack_nframes_t numsamples, void *p)
169 jack_client *self = (jack_client *)p;
170 ptlock lock(self->mutex);
171 for(unsigned int i = 0; i < self->plugins.size(); i++)
172 self->plugins[i]->cache_ports();
173 return 0;
176 void jack_client::delete_plugins()
178 ptlock lock(mutex);
179 for (unsigned int i = 0; i < plugins.size(); i++) {
180 // plugins[i]->close();
181 delete plugins[i];
183 plugins.clear();
186 struct host_session: public main_window_owner_iface, public calf_plugins::progress_report_iface
188 string client_name, input_name, output_name, midi_name;
189 vector<string> plugin_names;
190 map<int, string> presets;
191 #if USE_LASH
192 int lash_source_id;
193 lash_client_t *lash_client;
194 # if !USE_LASH_0_6
195 lash_args_t *lash_args;
196 # endif
197 #endif
199 // these are not saved
200 jack_client client;
201 string autoconnect_midi;
202 int autoconnect_midi_index;
203 set<int> chains;
204 vector<jack_host_base *> plugins;
205 main_window *main_win;
206 bool restoring_session;
207 std::set<std::string> instances;
208 GtkWidget *progress_window;
210 host_session();
211 void open();
212 void add_plugin(string name, string preset, string instance_name = string());
213 void create_plugins_from_list();
214 void connect();
215 void close();
216 bool activate_preset(int plugin, const std::string &preset, bool builtin);
217 #if USE_LASH
218 static gboolean update_lash(void *self) { ((host_session *)self)->update_lash(); return TRUE; }
219 void update_lash();
220 # if !USE_LASH_0_6
221 void send_lash(LASH_Event_Type type, const std::string &data) {
222 lash_send_event(lash_client, lash_event_new_with_all(type, data.c_str()));
224 # endif
225 #endif
226 virtual void new_plugin(const char *name);
227 virtual void remove_plugin(plugin_ctl_iface *plugin);
228 void remove_all_plugins();
229 std::string get_next_instance_name(const std::string &effect_name);
231 /// Create a toplevel window with progress bar
232 GtkWidget *create_progress_window();
233 /// Implementation of progress_report_iface function
234 void report_progress(float percentage, const std::string &message);
236 /// Implementation of open file functionality (TODO)
237 virtual char *open_file(const char *name);
238 /// Implementation of save file functionality
239 virtual char *save_file(const char *name);
242 host_session::host_session()
244 client_name = "calf";
245 #if USE_LASH
246 lash_source_id = 0;
247 lash_client = NULL;
248 # if !USE_LASH_0_6
249 lash_args = NULL;
250 # endif
251 #endif
252 restoring_session = false;
253 main_win = new main_window;
254 main_win->set_owner(this);
255 progress_window = NULL;
256 autoconnect_midi_index = -1;
259 std::string host_session::get_next_instance_name(const std::string &effect_name)
261 if (!instances.count(effect_name))
262 return effect_name;
263 for (int i = 2; ; i++)
265 string tmp = string(effect_name) + i2s(i);
266 if (!instances.count(tmp))
267 return tmp;
269 assert(0);
270 return "-";
273 void host_session::add_plugin(string name, string preset, string instance_name)
275 if (instance_name.empty())
276 instance_name = get_next_instance_name(name);
277 jack_host_base *jh = create_jack_host(name.c_str(), instance_name, this);
278 if (!jh) {
279 string s =
280 #define PER_MODULE_ITEM(name, isSynth, jackname) jackname ", "
281 #include <calf/modulelist.h>
283 if (!s.empty())
284 s = s.substr(0, s.length() - 2);
285 throw text_exception("Unknown plugin name; allowed are: " + s);
287 instances.insert(jh->instance_name);
288 jh->open(&client);
290 plugins.push_back(jh);
291 client.add(jh);
292 main_win->add_plugin(jh);
293 if (!preset.empty()) {
294 if (!activate_preset(plugins.size() - 1, preset, false))
296 if (!activate_preset(plugins.size() - 1, preset, true))
298 fprintf(stderr, "Unknown preset: %s\n", preset.c_str());
304 void host_session::report_progress(float percentage, const std::string &message)
306 if (percentage < 100)
308 if (!progress_window) {
309 progress_window = create_progress_window();
310 gtk_window_set_modal (GTK_WINDOW (progress_window), TRUE);
311 if (main_win->toplevel)
312 gtk_window_set_transient_for (GTK_WINDOW (progress_window), main_win->toplevel);
314 gtk_widget_show(progress_window);
315 GtkWidget *pbar = gtk_bin_get_child (GTK_BIN (progress_window));
316 if (!message.empty())
317 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pbar), message.c_str());
318 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pbar), percentage / 100.0);
320 else
322 if (progress_window) {
323 gtk_window_set_modal (GTK_WINDOW (progress_window), FALSE);
324 gtk_widget_destroy (progress_window);
325 progress_window = NULL;
329 while (gtk_events_pending ())
330 gtk_main_iteration ();
334 void host_session::create_plugins_from_list()
336 for (unsigned int i = 0; i < plugin_names.size(); i++) {
337 add_plugin(plugin_names[i], presets.count(i) ? presets[i] : string());
341 GtkWidget *host_session::create_progress_window()
343 GtkWidget *tlw = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
344 gtk_window_set_type_hint (GTK_WINDOW (tlw), GDK_WINDOW_TYPE_HINT_DIALOG);
345 GtkWidget *pbar = gtk_progress_bar_new();
346 gtk_container_add (GTK_CONTAINER(tlw), pbar);
347 gtk_widget_show_all (pbar);
348 return tlw;
351 void host_session::open()
353 if (!input_name.empty()) client.input_name = input_name;
354 if (!output_name.empty()) client.output_name = output_name;
355 if (!midi_name.empty()) client.midi_name = midi_name;
357 gtk_rc_parse(PKGLIBDIR "calf.rc");
358 client.open(client_name.c_str());
359 main_win->prefix = client_name + " - ";
360 main_win->conditions.insert("jackhost");
361 main_win->conditions.insert("directlink");
362 if (!restoring_session)
363 create_plugins_from_list();
364 main_win->create();
365 gtk_signal_connect(GTK_OBJECT(main_win->toplevel), "destroy", G_CALLBACK(destroy), NULL);
368 void host_session::new_plugin(const char *name)
370 jack_host_base *jh = create_jack_host(name, get_next_instance_name(name), this);
371 if (!jh)
372 return;
373 instances.insert(jh->instance_name);
374 jh->open(&client);
376 plugins.push_back(jh);
377 client.add(jh);
378 main_win->add_plugin(jh);
381 void host_session::remove_plugin(plugin_ctl_iface *plugin)
383 for (unsigned int i = 0; i < plugins.size(); i++)
385 if (plugins[i] == plugin)
387 client.del(i);
388 plugins.erase(plugins.begin() + i);
389 main_win->del_plugin(plugin);
390 delete plugin;
391 return;
396 void host_session::remove_all_plugins()
398 while(!plugins.empty())
400 plugin_ctl_iface *plugin = plugins[0];
401 client.del(0);
402 plugins.erase(plugins.begin());
403 main_win->del_plugin(plugin);
404 delete plugin;
408 bool host_session::activate_preset(int plugin_no, const std::string &preset, bool builtin)
410 string cur_plugin = plugins[plugin_no]->get_id();
411 preset_vector &pvec = (builtin ? get_builtin_presets() : get_user_presets()).presets;
412 for (unsigned int i = 0; i < pvec.size(); i++) {
413 if (pvec[i].name == preset && pvec[i].plugin == cur_plugin)
415 pvec[i].activate(plugins[plugin_no]);
416 if (gui_win && gui_win->gui)
417 gui_win->gui->refresh();
418 return true;
421 return false;
424 void host_session::connect()
426 client.activate();
427 #if USE_LASH && !USE_LASH_0_6
428 if (lash_client)
429 lash_jack_client_name(lash_client, client.get_name().c_str());
430 #endif
431 if (!restoring_session)
433 string cnp = client.get_name() + ":";
434 for (unsigned int i = 0; i < plugins.size(); i++) {
435 if (chains.count(i)) {
436 if (!i)
438 if (plugins[0]->get_output_count() < 2)
440 fprintf(stderr, "Cannot connect input to plugin %s - incompatible ports\n", plugins[0]->name.c_str());
441 } else {
442 client.connect("system:capture_1", cnp + plugins[0]->get_inputs()[0].name);
443 client.connect("system:capture_2", cnp + plugins[0]->get_inputs()[1].name);
446 else
448 if (plugins[i - 1]->get_output_count() < 2 || plugins[i]->get_input_count() < 2)
450 fprintf(stderr, "Cannot connect plugins %s and %s - incompatible ports\n", plugins[i - 1]->name.c_str(), plugins[i]->name.c_str());
452 else {
453 client.connect(cnp + plugins[i - 1]->get_outputs()[0].name, cnp + plugins[i]->get_inputs()[0].name);
454 client.connect(cnp + plugins[i - 1]->get_outputs()[1].name, cnp + plugins[i]->get_inputs()[1].name);
459 if (chains.count(plugins.size()) && plugins.size())
461 int last = plugins.size() - 1;
462 if (plugins[last]->get_output_count() < 2)
464 fprintf(stderr, "Cannot connect plugin %s to output - incompatible ports\n", plugins[last]->name.c_str());
465 } else {
466 client.connect(cnp + plugins[last]->get_outputs()[0].name, "system:playback_1");
467 client.connect(cnp + plugins[last]->get_outputs()[1].name, "system:playback_2");
470 if (autoconnect_midi != "") {
471 for (unsigned int i = 0; i < plugins.size(); i++)
473 if (plugins[i]->get_midi())
474 client.connect(autoconnect_midi, cnp + plugins[i]->get_midi_port()->name);
477 else
478 if (autoconnect_midi_index != -1) {
479 const char **ports = client.get_ports("(system|alsa_pcm):.*", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput);
480 for (int j = 0; ports && ports[j]; j++)
482 if (j + 1 == autoconnect_midi_index) {
483 for (unsigned int i = 0; i < plugins.size(); i++)
485 if (plugins[i]->get_midi())
486 client.connect(ports[j], cnp + plugins[i]->get_midi_port()->name);
488 break;
493 #if USE_LASH
494 if (lash_client)
496 # if !USE_LASH_0_6
497 send_lash(LASH_Client_Name, "calf-"+client_name);
498 # endif
499 lash_source_id = g_timeout_add_full(G_PRIORITY_LOW, 250, update_lash, this, NULL); // 4 LASH reads per second... should be enough?
501 #endif
504 void host_session::close()
506 #if USE_LASH
507 if (lash_source_id)
508 g_source_remove(lash_source_id);
509 #endif
510 main_win->on_closed();
511 main_win->close_guis();
512 client.deactivate();
513 client.delete_plugins();
514 client.close();
517 static string stripfmt(string x)
519 if (x.length() < 2)
520 return x;
521 if (x.substr(x.length() - 2) != "%d")
522 return x;
523 return x.substr(0, x.length() - 2);
526 char *host_session::open_file(const char *name)
528 preset_list pl;
529 try {
530 remove_all_plugins();
531 pl.load(name, true);
532 printf("Size %d\n", (int)pl.plugins.size());
533 for (unsigned int i = 0; i < pl.plugins.size(); i++)
535 preset_list::plugin_snapshot &ps = pl.plugins[i];
536 client.input_nr = ps.input_index;
537 client.output_nr = ps.output_index;
538 client.midi_nr = ps.midi_index;
539 printf("Loading %s\n", ps.type.c_str());
540 if (ps.preset_offset < (int)pl.presets.size())
542 add_plugin(ps.type, "", ps.instance_name);
543 pl.presets[ps.preset_offset].activate(plugins[i]);
544 main_win->refresh_plugin(plugins[i]);
548 catch(preset_exception &e)
550 // XXXKF this will leak
551 char *data = strdup(e.what());
552 return data;
555 return NULL;
558 char *host_session::save_file(const char *name)
560 string i_name = stripfmt(client.input_name);
561 string o_name = stripfmt(client.output_name);
562 string m_name = stripfmt(client.midi_name);
563 string data;
564 data = "<?xml version=\"1.1\" encoding=\"utf-8\">\n";
565 data = "<rack>\n";
566 for (unsigned int i = 0; i < plugins.size(); i++) {
567 jack_host_base *p = plugins[i];
568 plugin_preset preset;
569 preset.plugin = p->get_id();
570 preset.get_from(p);
571 data += "<plugin";
572 data += to_xml_attr("type", preset.plugin);
573 data += to_xml_attr("instance-name", p->instance_name);
574 if (p->get_input_count())
575 data += to_xml_attr("input-index", p->get_inputs()[0].name.substr(i_name.length()));
576 if (p->get_output_count())
577 data += to_xml_attr("output-index", p->get_outputs()[0].name.substr(o_name.length()));
578 if (p->get_midi_port())
579 data += to_xml_attr("midi-index", p->get_midi_port()->name.substr(m_name.length()));
580 data += ">\n";
581 data += preset.to_xml();
582 data += "</plugin>\n";
584 data += "</rack>\n";
585 FILE *f = fopen(name, "w");
586 if (!f || 1 != fwrite(data.c_str(), data.length(), 1, f))
588 int e = errno;
589 fclose(f);
590 return strdup(strerror(e));
592 if (fclose(f))
593 return strdup(strerror(errno));
595 return NULL;
598 #if USE_LASH
600 # if !USE_LASH_0_6
602 void host_session::update_lash()
604 do {
605 lash_event_t *event = lash_get_event(lash_client);
606 if (!event)
607 break;
609 // printf("type = %d\n", lash_event_get_type(event));
611 switch(lash_event_get_type(event)) {
612 case LASH_Save_Data_Set:
614 lash_config_t *cfg = lash_config_new_with_key("global");
615 dictionary tmp;
616 string pstr;
617 string i_name = stripfmt(client.input_name);
618 string o_name = stripfmt(client.output_name);
619 string m_name = stripfmt(client.midi_name);
620 tmp["input_prefix"] = i_name;
621 tmp["output_prefix"] = stripfmt(client.output_name);
622 tmp["midi_prefix"] = stripfmt(client.midi_name);
623 pstr = encode_map(tmp);
624 lash_config_set_value(cfg, pstr.c_str(), pstr.length());
625 lash_send_config(lash_client, cfg);
627 for (unsigned int i = 0; i < plugins.size(); i++) {
628 jack_host_base *p = plugins[i];
629 char ss[32];
630 plugin_preset preset;
631 preset.plugin = p->get_id();
632 preset.get_from(p);
633 sprintf(ss, "Plugin%d", i);
634 pstr = preset.to_xml();
635 tmp.clear();
636 tmp["instance_name"] = p->instance_name;
637 if (p->get_input_count())
638 tmp["input_name"] = p->get_inputs()[0].name.substr(i_name.length());
639 if (p->get_output_count())
640 tmp["output_name"] = p->get_outputs()[0].name.substr(o_name.length());
641 if (p->get_midi_port())
642 tmp["midi_name"] = p->get_midi_port()->name.substr(m_name.length());
643 tmp["preset"] = pstr;
644 pstr = encode_map(tmp);
645 lash_config_t *cfg = lash_config_new_with_key(ss);
646 lash_config_set_value(cfg, pstr.c_str(), pstr.length());
647 lash_send_config(lash_client, cfg);
649 send_lash(LASH_Save_Data_Set, "");
650 break;
653 case LASH_Restore_Data_Set:
655 // printf("!!!Restore data set!!!\n");
656 remove_all_plugins();
657 while(lash_config_t *cfg = lash_get_config(lash_client)) {
658 const char *key = lash_config_get_key(cfg);
659 // printf("key = %s\n", lash_config_get_key(cfg));
660 string data = string((const char *)lash_config_get_value(cfg), lash_config_get_value_size(cfg));
661 if (!strcmp(key, "global"))
663 dictionary dict;
664 decode_map(dict, data);
665 if (dict.count("input_prefix")) client.input_name = dict["input_prefix"]+"%d";
666 if (dict.count("output_prefix")) client.output_name = dict["output_prefix"]+"%d";
667 if (dict.count("midi_prefix")) client.midi_name = dict["midi_prefix"]+"%d";
669 if (!strncmp(key, "Plugin", 6))
671 unsigned int nplugin = atoi(key + 6);
672 dictionary dict;
673 decode_map(dict, data);
674 data = dict["preset"];
675 string instance_name;
676 if (dict.count("instance_name")) instance_name = dict["instance_name"];
677 if (dict.count("input_name")) client.input_nr = atoi(dict["input_name"].c_str());
678 if (dict.count("output_name")) client.output_nr = atoi(dict["output_name"].c_str());
679 if (dict.count("midi_name")) client.midi_nr = atoi(dict["midi_name"].c_str());
680 preset_list tmp;
681 tmp.parse("<presets>"+data+"</presets>", false);
682 if (tmp.presets.size())
684 printf("Load plugin %s\n", tmp.presets[0].plugin.c_str());
685 add_plugin(tmp.presets[0].plugin, "", instance_name);
686 tmp.presets[0].activate(plugins[nplugin]);
687 main_win->refresh_plugin(plugins[nplugin]);
690 lash_config_destroy(cfg);
692 send_lash(LASH_Restore_Data_Set, "");
693 break;
696 case LASH_Quit:
697 gtk_main_quit();
698 break;
700 default:
701 g_warning("Unhandled LASH event %d (%s)", lash_event_get_type(event), lash_event_get_string(event));
702 break;
704 } while(1);
707 # else
709 void host_session::update_lash()
711 lash_dispatch(lash_client);
714 bool save_data_set_cb(lash_config_handle_t *handle, void *user_data)
716 host_session *sess = static_cast<host_session *>(user_data);
717 dictionary tmp;
718 string pstr;
719 string i_name = stripfmt(sess->client.input_name);
720 string o_name = stripfmt(sess->client.output_name);
721 string m_name = stripfmt(sess->client.midi_name);
722 tmp["input_prefix"] = i_name;
723 tmp["output_prefix"] = stripfmt(sess->client.output_name);
724 tmp["midi_prefix"] = stripfmt(sess->client.midi_name);
725 pstr = encode_map(tmp);
726 lash_config_write_raw(handle, "global", pstr.c_str(), pstr.length());
727 for (unsigned int i = 0; i < sess->plugins.size(); i++) {
728 jack_host_base *p = sess->plugins[i];
729 char ss[32];
730 plugin_preset preset;
731 preset.plugin = p->get_id();
732 preset.get_from(p);
733 sprintf(ss, "Plugin%d", i);
734 pstr = preset.to_xml();
735 tmp.clear();
736 tmp["instance_name"] = p->instance_name;
737 if (p->get_input_count())
738 tmp["input_name"] = p->get_inputs()[0].name.substr(i_name.length());
739 if (p->get_output_count())
740 tmp["output_name"] = p->get_outputs()[0].name.substr(o_name.length());
741 if (p->get_midi_port())
742 tmp["midi_name"] = p->get_midi_port()->name.substr(m_name.length());
743 tmp["preset"] = pstr;
744 pstr = encode_map(tmp);
745 lash_config_write_raw(handle, ss, pstr.c_str(), pstr.length());
747 return true;
750 bool load_data_set_cb(lash_config_handle_t *handle, void *user_data)
752 host_session *sess = static_cast<host_session *>(user_data);
753 int size, type;
754 const char *key;
755 const char *value;
756 sess->remove_all_plugins();
757 while((size = lash_config_read(handle, &key, (void *)&value, &type))) {
758 if (size == -1 || type != LASH_TYPE_RAW)
759 continue;
760 string data = string(value, size);
761 if (!strcmp(key, "global"))
763 dictionary dict;
764 decode_map(dict, data);
765 if (dict.count("input_prefix")) sess->client.input_name = dict["input_prefix"]+"%d";
766 if (dict.count("output_prefix")) sess->client.output_name = dict["output_prefix"]+"%d";
767 if (dict.count("midi_prefix")) sess->client.midi_name = dict["midi_prefix"]+"%d";
768 } else if (!strncmp(key, "Plugin", 6)) {
769 unsigned int nplugin = atoi(key + 6);
770 dictionary dict;
771 decode_map(dict, data);
772 data = dict["preset"];
773 string instance_name;
774 if (dict.count("instance_name")) instance_name = dict["instance_name"];
775 if (dict.count("input_name")) sess->client.input_nr = atoi(dict["input_name"].c_str());
776 if (dict.count("output_name")) sess->client.output_nr = atoi(dict["output_name"].c_str());
777 if (dict.count("midi_name")) sess->client.midi_nr = atoi(dict["midi_name"].c_str());
778 preset_list tmp;
779 tmp.parse("<presets>"+data+"</presets>", false);
780 if (tmp.presets.size())
782 printf("Load plugin %s\n", tmp.presets[0].plugin.c_str());
783 sess->add_plugin(tmp.presets[0].plugin, "", instance_name);
784 tmp.presets[0].activate(sess->plugins[nplugin]);
785 sess->main_win->refresh_plugin(sess->plugins[nplugin]);
789 return true;
792 bool quit_cb(void *user_data)
794 gtk_main_quit();
795 return true;
798 # endif
799 #endif
801 host_session current_session;
803 int main(int argc, char *argv[])
805 host_session &sess = current_session;
806 gtk_rc_add_default_file(PKGLIBDIR "calf.rc");
807 gtk_init(&argc, &argv);
809 #if USE_LASH
810 # if !USE_LASH_0_6
811 for (int i = 1; i < argc; i++)
813 if (!strncmp(argv[i], "--lash-project=", 14)) {
814 sess.restoring_session = true;
815 break;
818 sess.lash_args = lash_extract_args(&argc, &argv);
819 sess.lash_client = lash_init(sess.lash_args, PACKAGE_NAME, LASH_Config_Data_Set, LASH_PROTOCOL(2, 0));
820 # else
821 sess.lash_client = lash_client_open(PACKAGE_NAME, LASH_Config_Data_Set, argc, argv);
822 sess.restoring_session = lash_client_is_being_restored(sess.lash_client);
823 lash_set_save_data_set_callback(sess.lash_client, save_data_set_cb, &sess);
824 lash_set_load_data_set_callback(sess.lash_client, load_data_set_cb, &sess);
825 lash_set_quit_callback(sess.lash_client, quit_cb, NULL);
826 # endif
827 if (!sess.lash_client) {
828 g_warning("Warning: failed to create a LASH connection");
830 #endif
831 glade_init();
832 while(1) {
833 int option_index;
834 int c = getopt_long(argc, argv, "c:i:o:m:M:ehv", long_options, &option_index);
835 if (c == -1)
836 break;
837 switch(c) {
838 case 'h':
839 case '?':
840 print_help(argv);
841 return 0;
842 case 'v':
843 printf("%s\n", PACKAGE_STRING);
844 return 0;
845 case 'e':
846 fprintf(stderr, "Warning: switch -%c is deprecated!\n", c);
847 break;
848 case 'c':
849 sess.client_name = optarg;
850 break;
851 case 'i':
852 sess.input_name = string(optarg) + "_%d";
853 break;
854 case 'o':
855 sess.output_name = string(optarg) + "_%d";
856 break;
857 case 'm':
858 sess.midi_name = string(optarg) + "_%d";
859 break;
860 case 'M':
861 if (atoi(optarg)) {
862 sess.autoconnect_midi_index = atoi(optarg);
864 else
865 sess.autoconnect_midi = string(optarg);
866 break;
869 while(optind < argc) {
870 if (!strcmp(argv[optind], "!")) {
871 sess.chains.insert(sess.plugin_names.size());
872 optind++;
873 } else {
874 string plugname = argv[optind++];
875 size_t pos = plugname.find(":");
876 if (pos != string::npos) {
877 sess.presets[sess.plugin_names.size()] = plugname.substr(pos + 1);
878 plugname = plugname.substr(0, pos);
880 sess.plugin_names.push_back(plugname);
883 try {
884 get_builtin_presets().load_defaults(true);
885 get_user_presets().load_defaults(false);
887 catch(calf_plugins::preset_exception &e)
889 // XXXKF this exception is already handled by load_defaults, so this is redundant
890 fprintf(stderr, "Error while loading presets: %s\n", e.what());
891 exit(1);
893 try {
894 sess.open();
895 sess.connect();
896 sess.client.activate();
897 gtk_main();
898 sess.close();
900 #if USE_LASH && !USE_LASH_0_6
901 if (sess.lash_args)
902 lash_args_destroy(sess.lash_args);
903 #endif
904 // this is now done on preset add
905 // save_presets(get_preset_filename().c_str());
907 catch(std::exception &e)
909 fprintf(stderr, "%s\n", e.what());
910 exit(1);
912 return 0;