1 // ------------------------------------------------------------------------
2 // eca-control.cpp: Class for controlling the whole ecasound library
3 // Copyright (C) 1999-2005,2008,2009,2012 Kai Vehmanen
4 // Copyright (C) 2005 Stuart Allie
5 // Copyright (C) 2009 Adam Linson
6 //
7 // Attributes:
8 //     eca-style-version: 3 (see Ecasound Programmer's Guide)
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, see <http://www.gnu.org/licenses/>.
22 // ------------------------------------------------------------------------
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <cassert>
29 #include <iostream>
30 #include <fstream>
31 #include <string>
32 #include <vector>
33 #include <list>
34 #include <algorithm>
35 #include <unistd.h>
36 
37 #ifdef HAVE_LOCALE_H
38 #include <locale.h>
39 #endif
40 
41 #include <kvu_utils.h> /* string_to_vector(), string_to_int_vector() */
42 #include <kvu_value_queue.h>
43 #include <kvu_message_item.h>
44 #include <kvu_dbc.h>
45 #include <kvu_numtostr.h>
46 
47 #include "audioio.h"
48 #include "eca-chain.h"
49 #include "eca-chainop.h"
50 #include "eca-chainsetup.h"
51 #include "eca-control.h"
52 #include "eca-control-main.h"
53 #include "eca-engine.h"
54 #include "eca-object-factory.h"
55 #include "eca-object-map.h"
56 #include "eca-preset-map.h"
57 #include "eca-session.h"
58 
59 #include "generic-controller.h"
60 #include "eca-chainop.h"
61 #include "audiofx_ladspa.h"
62 #include "audiofx_lv2.h"
63 #include "preset.h"
64 #include "sample-specs.h"
65 #include "jack-connections.h"
66 
67 #include "eca-version.h"
68 #include "eca-error.h"
69 #include "eca-logger.h"
70 #include "eca-logger-wellformed.h"
71 
72 /**
73  * Import namespaces
74  */
75 using std::string;
76 using std::list;
77 using std::vector;
78 using std::cerr;
79 using std::endl;
80 using namespace ECA;
81 
82 /**
83  * Declarations for private static functions
84  */
85 static string eca_aio_register_sub(ECA_OBJECT_MAP& objmap);
86 
87 /**
88  * Definitions for member functions
89  */
90 
ECA_CONTROL(ECA_SESSION * psession)91 ECA_CONTROL::ECA_CONTROL (ECA_SESSION* psession)
92   : ctrl_dump_rep(this),
93     wellformed_mode_rep(false)
94 {
95   ECA_LOG_MSG(ECA_LOGGER::system_objects, "ECA_CONTROL constructor");
96 
97   session_repp = psession;
98   selected_chainsetup_repp = psession->selected_chainsetup_repp;
99   engine_repp = 0;
100   engine_pid_rep = -1;
101   engine_exited_rep.set(0);
102   float_to_string_precision_rep = 3;
103   joining_rep = false;
104   DBC_CHECK(is_engine_created() != true);
105 
106   selected_audio_object_repp = 0;
107   selected_audio_input_repp = 0;
108   selected_audio_output_repp = 0;
109 }
110 
~ECA_CONTROL(void)111 ECA_CONTROL::~ECA_CONTROL(void)
112 {
113   ECA_LOG_MSG(ECA_LOGGER::system_objects, "ECA_CONTROL destructor");
114   close_engine();
115 }
116 
fill_command_retval(struct eci_return_value * retval) const117 void ECA_CONTROL::fill_command_retval(struct eci_return_value *retval) const
118 {
119   if (retval == 0)
120     return;
121 
122   *retval = last_retval_rep;
123 }
124 
command(const string & cmd_and_args,struct eci_return_value * retval)125 void ECA_CONTROL::command(const string& cmd_and_args, struct eci_return_value *retval)
126 {
127   clear_last_values();
128   clear_action_arguments();
129 
130   ECA_LOG_MSG(ECA_LOGGER::user_objects, "processing cmd and arg: " + cmd_and_args);
131 
132   vector<string> tokens = kvu_string_to_tokens_quoted(cmd_and_args);
133   vector<string>::iterator cmd = tokens.begin();
134   if (cmd != tokens.end()) {
135     const std::map<std::string,int>& cmdmap = ECA_IAMODE_PARSER::registered_commands();
136     if (cmdmap.find(*cmd) == cmdmap.end()) {
137       // ---
138       // *p is not recognized as a iamode command
139       // ---
140       if (cmd->size() > 0 && (*cmd)[0] == '-') {
141 	//  std::cerr << "Note! Direct use of EOS-options (-prefix:arg1,...,argN)" << " as iactive-mode commands is considered deprecated. " << "\tUse the notation 'cs-option -prefix:a,b,x' instead." << std::endl;
142 	if (*cmd == "-i")
143 	  ECA_LOG_MSG(ECA_LOGGER::info,
144 		      "WARNING: syntax variant '-i file.ext' not supported, please use 'ai-add file.ext' instead.");
145 	else if (*cmd == "-o")
146 	  ECA_LOG_MSG(ECA_LOGGER::info,
147 		      "WARNING: syntax variant '-o file.ext' not supported, please use 'ai-add file.ext' instead.");
148 	else {
149 	  ECA_LOG_MSG(ECA_LOGGER::user_objects, "passiong to cs-option: " + cmd_and_args);
150 	  chainsetup_option(cmd_and_args);
151 	}
152       }
153       else {
154 	set_last_error("Unknown command!");
155       }
156     }
157     else {
158       int action_id = ECA_IAMODE_PARSER::command_to_action_id(*cmd);
159       if (action_id == ec_help) {
160 	show_controller_help();
161       }
162       else {
163 	vector<string>::iterator args = cmd + 1;
164 	if (args != tokens.end()) {
165 	  set_action_argument(vector<string> (args, tokens.end()));
166 	}
167 	action(action_id);
168       }
169     }
170   }
171 
172   fill_command_retval(retval);
173 }
174 
set_action_argument(const string & s)175 void ECA_CONTROL::set_action_argument(const string& s)
176 {
177   action_args_rep.resize(0);
178   action_args_rep.push_back(s);
179   action_arg_f_set_rep = false;
180 }
181 
set_action_argument(const std::vector<std::string> & s)182 void ECA_CONTROL::set_action_argument(const std::vector<std::string>& s)
183 {
184   action_args_rep = s;
185   action_arg_f_set_rep = false;
186 }
187 
set_action_argument(double v)188 void ECA_CONTROL::set_action_argument(double v)
189 {
190   action_arg_f_rep = v;
191   action_arg_f_set_rep = true;
192 }
193 
clear_action_arguments(void)194 void ECA_CONTROL::clear_action_arguments(void)
195 {
196   // use resize() instead of clear(); clear() was a late
197   // addition to C++ standard and not supported by all
198   // compilers (for example egcs-2.91.66)
199   action_args_rep.resize(0);
200 
201   action_arg_f_rep = 0.0f;
202   action_arg_f_set_rep = false;
203 }
204 
first_action_argument_as_float(void) const205 double ECA_CONTROL::first_action_argument_as_float(void) const
206 {
207   if (action_arg_f_set_rep == true)
208     return action_arg_f_rep;
209 
210   if (action_args_rep.size() == 0)
211     return 0.0f;
212 
213   return atof(action_args_rep[0].c_str());
214 }
215 
first_action_argument_as_string(void) const216 string ECA_CONTROL::first_action_argument_as_string(void) const
217 {
218   if (action_args_rep.size() == 0)
219     return std::string();
220 
221   return action_args_rep[0];
222 }
223 
action_arguments_as_vector(void) const224 const vector<string>& ECA_CONTROL::action_arguments_as_vector(void) const
225 {
226   return action_args_rep;
227 }
228 
first_action_argument_as_int(void) const229 int ECA_CONTROL::first_action_argument_as_int(void) const
230 {
231   if (action_args_rep.size() == 0)
232     return 0;
233 
234   return atoi(action_args_rep[0].c_str());
235 }
236 
first_action_argument_as_long_int(void) const237 long int ECA_CONTROL::first_action_argument_as_long_int(void) const
238 {
239   if (action_args_rep.size() == 0)
240     return 0;
241 
242   return atol(action_args_rep[0].c_str());
243 }
244 
first_action_argument_as_samples(void) const245 SAMPLE_SPECS::sample_pos_t ECA_CONTROL::first_action_argument_as_samples(void) const
246 {
247   if (action_args_rep.size() == 0)
248     return 0;
249 
250 #ifdef HAVE_ATOLL
251   return atoll(action_args_rep[0].c_str());
252 #else
253   return atol(action_args_rep[0].c_str());
254 #endif
255 }
256 
command_float_arg(const string & cmd,double arg,struct eci_return_value * retval)257 void ECA_CONTROL::command_float_arg(const string& cmd, double arg, struct eci_return_value *retval)
258 {
259   clear_action_arguments();
260   set_action_argument(arg);
261   int action_id = ec_unknown;
262   action_id = ECA_IAMODE_PARSER::command_to_action_id(cmd);
263   action(action_id);
264   fill_command_retval(retval);
265 }
266 
267 /**
268  * Interprets an EOS (ecasound optiont syntax) token  (prefixed with '-').
269  */
chainsetup_option(const string & cmd)270 void ECA_CONTROL::chainsetup_option(const string& cmd)
271 {
272   string prefix = kvu_get_argument_prefix(cmd);
273   if (prefix == "el" || prefix == "pn") { // --- LADSPA plugins and presets
274     if (selected_chains().size() == 1)
275       add_chain_operator(cmd);
276     else
277       set_last_error("When adding chain operators, only one chain can be selected.");
278   }
279   else if (ECA_OBJECT_FACTORY::chain_operator_map().object(prefix) != 0) {
280     if (selected_chains().size() == 1)
281       add_chain_operator(cmd);
282     else
283       set_last_error("When adding chain operators, only one chain can be selected.");
284   }
285   else if (ECA_OBJECT_FACTORY::controller_map().object(prefix) != 0) {
286     if (selected_chains().size() == 1)
287       add_controller(cmd);
288     else
289       set_last_error("When adding controllers, only one chain can be selected.");
290   }
291   else {
292     set_action_argument(cmd);
293     action(ec_cs_option);
294   }
295 }
296 
297 /**
298  * Checks action preconditions.
299  *
300  * @return Sets status of private data members 'action_ok',
301  *         'action_restart', and 'action_reconnect'.
302  */
check_action_preconditions(int action_id)303 void ECA_CONTROL::check_action_preconditions(int action_id)
304 {
305   action_ok = true;
306   action_reconnect = false;
307   action_restart = false;
308 
309   /* case 1: action requiring arguments, but not arguments available */
310   if (action_arg_f_set_rep == false &&
311       first_action_argument_as_string().size() == 0 &&
312       action_requires_params(action_id)) {
313     set_last_error("Can't perform requested action; argument omitted.");
314     action_ok = false;
315   }
316   /* case 2: action requires an audio input, but no input available */
317   else if (is_selected() == true &&
318 	   get_audio_input() == 0 &&
319 	   action_requires_selected_audio_input(action_id)) {
320     set_last_error("Can't perform requested action; no audio input selected.");
321     action_ok = false;
322   }
323   /* case 3: action requires an audio output, but no output available */
324   else if (is_selected() == true &&
325 	   get_audio_output() == 0 &&
326 	   action_requires_selected_audio_output(action_id)) {
327     set_last_error("Can't perform requested action; no audio output selected.");
328     action_ok = false;
329   }
330   /* case 4: action requires a select chainsetup, but none selected */
331   else if (is_selected() == false &&
332 	   action_requires_selected(action_id)) {
333     if (!is_connected()) {
334       set_last_error("Can't perform requested action; no chainsetup selected.");
335       action_ok = false;
336     }
337     else {
338       ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: No chainsetup selected. Connected chainsetup will be selected.");
339       select_chainsetup(connected_chainsetup());
340     }
341   }
342   /* case 5: action requires a connected chainsetup, but none connected */
343   else if (is_connected() == false &&
344 	   action_requires_connected(action_id)) {
345     if (!is_selected()) {
346       set_last_error("Can't perform requested action; no chainsetup connected.");
347       action_ok = false;
348     }
349     else {
350       if (is_valid() == true) {
351 	ECA_LOG_MSG(ECA_LOGGER::info,
352 		    "NOTE: No chainsetup connected. Trying to connect currently selected chainsetup \""
353 		    + selected_chainsetup_repp->name()
354 		    + "\"");
355 	connect_chainsetup(0);
356       }
357       if (is_connected() != true) {
358 	/* connect_chainsetup() sets last_error() so we just add to it */
359 	set_last_error(last_error() + " Selected chainsetup cannot be connected. Can't perform requested action. ");
360 	action_ok = false;
361       }
362     }
363   }
364   /* case 6: action can't be performed on a connected setup,
365    *         but selected chainsetup is also connected */
366   else if (selected_chainsetup() == connected_chainsetup() &&
367 	   action_requires_selected_not_connected(action_id)) {
368     ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: This operation requires that chainsetup is disconnected. Temporarily disconnecting...");
369     if (is_running()) action_restart = true;
370     disconnect_chainsetup();
371     action_reconnect = true;
372   }
373 }
374 
action(int action_id,const vector<string> & args)375 void ECA_CONTROL::action(int action_id,
376 			 const vector<string>& args)
377 {
378   ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: ECA_CONTROL::action() method is obsolete.\n");
379   clear_action_arguments();
380   set_action_argument(kvu_vector_to_string(args, " "));
381   action(action_id);
382 }
383 
action_helper_check_cop_op_args(int copid,int coppid)384 bool ECA_CONTROL::action_helper_check_cop_op_args(int copid, int coppid)
385 {
386   DBC_REQUIRE(is_selected() == true);
387 
388   const vector<string>& selchains =
389     selected_chainsetup_repp->selected_chains();
390   bool res = false;
391 
392   if (selchains.size() == 0) {
393     set_last_error("No chain selected, unable to identify chainop");
394   }
395   else if (selchains.size() > 1) {
396     set_last_error("More than one chain selected, unable to identify chainop");
397   }
398   else {
399     const CHAIN* selch =
400       selected_chainsetup_repp->get_chain_with_name(selchains[0]);
401     if (copid < 1 || copid > selch->number_of_chain_operators()) {
402       set_last_error("Invalid chainop-id, unable to identify chainop");
403     }
404     else if (coppid < 1) {
405       set_last_error("Invalid copp-id, indexing starts from 1.");
406     }
407     else {
408       res = true;
409     }
410   }
411 
412   return res;
413 }
414 
action(int action_id)415 void ECA_CONTROL::action(int action_id)
416 {
417   clear_last_values();
418   check_action_preconditions(action_id);
419 
420   if (action_ok != true) return;
421 
422   switch(action_id) {
423   case ec_unknown: { set_last_error("Unknown command!"); break; }
424 
425     // ---
426     // General
427     // ---
428   case ec_exit: { quit(); break; }
429   case ec_start:
430     {
431       if (is_running() != true) {
432 	int result = start();
433 	if (result < 0) {
434 	  set_last_error("Error, unable to start processing");
435 	}
436       }
437       // ECA_LOG_MSG(ECA_LOGGER::info, "Can't perform requested action; no chainsetup connected.");
438       break;
439     }
440   case ec_stop: { if (is_engine_created()) stop(); break; }
441   case ec_stop_sync: { if (is_engine_created()) stop_on_condition(); break; }
442   case ec_run:
443     {
444       int result = run();
445       if (result < 0) {
446 	set_last_error("Errors during processing");
447       }
448       break;
449     }
450   case ec_debug:
451     {
452       int level = first_action_argument_as_int();
453       ECA_LOGGER::instance().set_log_level_bitmask(level);
454       set_last_string("Debug level set to " + kvu_numtostr(level) + ".");
455       break;
456     }
457   case ec_resource_file:
458     {
459       session_repp->interpret_general_option(string("-R:") +
460 					     first_action_argument_as_string());
461       break;
462     }
463 
464     // ---
465     // Chainsetups
466     // ---
467   case ec_cs_add:
468     {
469       add_chainsetup(first_action_argument_as_string());
470       break;
471     }
472   case ec_cs_remove: { remove_chainsetup(); break; }
473   case ec_cs_list: { set_last_string_list(chainsetup_names()); break; }
474   case ec_cs_select: { select_chainsetup(first_action_argument_as_string()); break; }
475   case ec_cs_selected: { set_last_string(selected_chainsetup()); break; }
476   case ec_cs_index_select: {
477     if (first_action_argument_as_string().size() > 0) {
478       select_chainsetup_by_index(first_action_argument_as_int());
479     }
480     break;
481   }
482   case ec_cs_edit: { edit_chainsetup(); break; }
483   case ec_cs_load: { load_chainsetup(first_action_argument_as_string()); break; }
484   case ec_cs_save: { save_chainsetup(""); break; }
485   case ec_cs_save_as: { save_chainsetup(first_action_argument_as_string()); break; }
486   case ec_cs_is_valid: {
487     if (is_valid() == true)
488       set_last_integer(1);
489     else
490       set_last_integer(0);
491     break;
492   }
493   case ec_cs_connect:
494     {
495       if (is_valid() != false) {
496 	connect_chainsetup(0);
497       }
498       else {
499 	set_last_error("Can't connect; chainsetup not valid!");
500       }
501       break;
502     }
503   case ec_cs_connected: { set_last_string(connected_chainsetup()); break; }
504   case ec_cs_disconnect: { disconnect_chainsetup(); break; }
505   case ec_cs_set_param: { set_chainsetup_parameter(first_action_argument_as_string()); break; }
506   case ec_cs_set_audio_format: { set_chainsetup_sample_format(first_action_argument_as_string()); break; }
507   case ec_cs_status: {
508     set_last_string(chainsetup_status());
509     break;
510   }
511   case ec_cs_rewind: { change_chainsetup_position(-first_action_argument_as_float()); break; }
512   case ec_cs_forward: { change_chainsetup_position(first_action_argument_as_float()); break; }
513   case ec_cs_set_position: { set_chainsetup_position(first_action_argument_as_float()); break; }
514   case ec_cs_set_position_samples: { set_chainsetup_position_samples(first_action_argument_as_samples()); break; }
515   case ec_cs_get_position: { set_last_float(position_in_seconds_exact()); break; }
516   case ec_cs_get_position_samples: { set_last_long_integer(selected_chainsetup_repp->position_in_samples()); break; }
517   case ec_cs_get_length: { set_last_float(length_in_seconds_exact()); break; }
518   case ec_cs_get_length_samples: { set_last_long_integer(length_in_samples()); break; }
519   case ec_cs_set_length:
520     {
521       set_chainsetup_processing_length_in_seconds(first_action_argument_as_float());
522       break;
523     }
524   case ec_cs_set_length_samples:
525     {
526       set_chainsetup_processing_length_in_samples(first_action_argument_as_samples());
527       break;
528     }
529   case ec_cs_toggle_loop: { toggle_chainsetup_looping(); break; }
530   case ec_cs_option:
531     {
532       selected_chainsetup_repp->interpret_options(action_arguments_as_vector());
533       if (selected_chainsetup_repp->interpret_result() != true) {
534 	set_last_error(selected_chainsetup_repp->interpret_result_verbose());
535       }
536       break;
537     }
538 
539   // ---
540   // Chains
541   // ---
542   case ec_c_add: { add_chains(kvu_string_to_vector(first_action_argument_as_string(), ',')); break; }
543   case ec_c_remove: { remove_chains(); break; }
544   case ec_c_list: { set_last_string_list(chain_names()); break; }
545   case ec_c_select: { select_chains(kvu_string_to_vector(first_action_argument_as_string(), ',')); break; }
546   case ec_c_selected: { set_last_string_list(selected_chains()); break; }
547   case ec_c_index_select: { select_chains_by_index(kvu_string_to_int_vector(first_action_argument_as_string(), ',')); break; }
548   case ec_c_deselect: { deselect_chains(kvu_string_to_vector(first_action_argument_as_string(), ',')); break; }
549   case ec_c_select_add:
550     {
551       select_chains(kvu_string_to_vector(first_action_argument_as_string() + "," +
552 					 kvu_vector_to_string(selected_chains(), ","), ','));
553       break;
554     }
555   case ec_c_select_all: { select_all_chains(); break; }
556   case ec_c_clear: { clear_chains(); break; }
557   case ec_c_rename:
558     {
559       if (selected_chains().size() != 1) {
560 	set_last_error("When renaming chains, only one chain canbe selected.");
561       }
562       else {
563 	rename_chain(first_action_argument_as_string());
564       }
565       break;
566     }
567   case ec_c_muting: { set_chain_muting(first_action_argument_as_string()); break; }
568   case ec_c_bypass: { set_chain_bypass(first_action_argument_as_string()); break; }
569   case ec_c_status:
570     {
571       set_last_string(chain_status());
572       break;
573     }
574   case ec_c_is_bypassed: { set_last_integer(chain_is_bypassed()); break; }
575   case ec_c_is_muted: { set_last_integer(chain_is_muted()); break; }
576 
577     // ---
578     // Actions common to audio inputs and outputs
579     // ---
580   case ec_aio_status:
581   case ec_ai_status:
582   case ec_ao_status:
583     {
584       set_last_string(aio_status());
585       break;
586     }
587   case ec_aio_register: { aio_register(); break; }
588 
589     // ---
590     // Audio input objects
591     // ---
592   case ec_ai_add: { add_audio_input(first_action_argument_as_string()); break; }
593   case ec_ai_describe: { set_last_string(ECA_OBJECT_FACTORY::audio_object_to_eos(selected_audio_input_repp, "i")); break; }
594   case ec_ai_remove: { remove_audio_input(); break; }
595   case ec_ai_list: { set_last_string_list(audio_input_names()); break; }
596   case ec_ai_select: { select_audio_input(first_action_argument_as_string()); break; }
597   case ec_ai_selected: { set_last_string(get_audio_input()->label()); break; }
598   case ec_ai_index_select: {
599     if (first_action_argument_as_string().size() > 0) {
600 	select_audio_input_by_index(first_action_argument_as_int());
601     }
602     break;
603   }
604   case ec_ai_attach: { attach_audio_input(); break; }
605   case ec_ai_forward:
606     {
607       audio_input_as_selected();
608       forward_audio_object(first_action_argument_as_float());
609       break;
610     }
611   case ec_ai_rewind:
612     {
613       audio_input_as_selected();
614       rewind_audio_object(first_action_argument_as_float());
615       break;
616     }
617   case ec_ai_set_position: { audio_input_as_selected(); set_audio_object_position(first_action_argument_as_float()); break; }
618   case ec_ai_set_position_samples: { audio_input_as_selected(); set_audio_object_position_samples(first_action_argument_as_long_int()); break; }
619   case ec_ai_get_position: { set_last_float(get_audio_input()->position().seconds()); break; }
620   case ec_ai_get_position_samples: { set_last_long_integer(get_audio_input()->position().samples()); break; }
621   case ec_ai_get_length: { set_last_float(get_audio_input()->length().seconds()); break; }
622   case ec_ai_get_length_samples: { set_last_long_integer(get_audio_input()->length().samples()); break; }
623   case ec_ai_get_format: {
624     set_last_string(get_audio_input()->format_string() + "," +
625 		    kvu_numtostr(get_audio_input()->channels()) + "," +
626 		    kvu_numtostr(get_audio_input()->samples_per_second()));
627 
628     break;
629   }
630 
631   case ec_ai_wave_edit: { audio_input_as_selected(); wave_edit_audio_object(); break; }
632 
633     // ---
634     // Audio output objects
635     // ---
636   case ec_ao_add: { if (first_action_argument_as_string().size() == 0) add_default_output(); else add_audio_output(first_action_argument_as_string()); break; }
637   case ec_ao_add_default: { add_default_output(); break; }
638   case ec_ao_describe: { set_last_string(ECA_OBJECT_FACTORY::audio_object_to_eos(selected_audio_output_repp, "o")); break; }
639   case ec_ao_remove: { remove_audio_output(); break; }
640   case ec_ao_list: { set_last_string_list(audio_output_names()); break; }
641   case ec_ao_select: { select_audio_output(first_action_argument_as_string()); break; }
642   case ec_ao_selected: { set_last_string(get_audio_output()->label()); break; }
643   case ec_ao_index_select: {
644     select_audio_output_by_index(first_action_argument_as_int());
645     break;
646   }
647   case ec_ao_attach: { attach_audio_output(); break; }
648   case ec_ao_forward:
649     {
650       audio_output_as_selected();
651       forward_audio_object(first_action_argument_as_float());
652       break;
653     }
654   case ec_ao_rewind:
655     {
656       audio_output_as_selected();
657       rewind_audio_object(first_action_argument_as_float());
658       break;
659     }
660   case ec_ao_set_position: { audio_output_as_selected(); set_audio_object_position(first_action_argument_as_float()); break; }
661   case ec_ao_set_position_samples: { audio_output_as_selected(); set_audio_object_position_samples(first_action_argument_as_long_int()); break; }
662   case ec_ao_get_position: { set_last_float(get_audio_output()->position().seconds()); break; }
663   case ec_ao_get_position_samples: { set_last_long_integer(get_audio_output()->position().samples()); break; }
664   case ec_ao_get_length: { set_last_float(get_audio_output()->length().seconds()); break; }
665   case ec_ao_get_length_samples: { set_last_long_integer(get_audio_output()->length().samples()); break; }
666   case ec_ao_get_format: {
667     set_last_string(get_audio_output()->format_string() + "," +
668 		    kvu_numtostr(get_audio_output()->channels()) + "," +
669 		    kvu_numtostr(get_audio_output()->samples_per_second()));
670     break;
671   }
672   case ec_ao_wave_edit: { audio_output_as_selected(); wave_edit_audio_object(); break; }
673 
674     // ---
675     // Chain operators
676     // ---
677   case ec_cop_add: { add_chain_operator(first_action_argument_as_string()); break; }
678   case ec_cop_bypass: { bypass_chain_operator(first_action_argument_as_string()); break; }
679   case ec_cop_describe:
680     {
681       const CHAIN_OPERATOR *t = get_chain_operator();
682       set_last_string(t == 0 ? "" : ECA_OBJECT_FACTORY::chain_operator_to_eos(t));
683       break;
684     }
685   case ec_cop_remove: { remove_chain_operator(); break; }
686   case ec_cop_list: { set_last_string_list(chain_operator_names()); break; }
687   case ec_cop_is_bypassed: { set_last_integer(chain_operator_is_bypassed()); break; }
688   case ec_cop_select: { select_chain_operator(first_action_argument_as_int()); break; }
689   case ec_cop_selected: { set_last_integer(selected_chain_operator()); break; }
690   case ec_cop_set:
691     {
692       vector<string> a = kvu_string_to_vector(first_action_argument_as_string(), ',');
693       if (a.size() < 3) {
694 	set_last_error("Not enough parameters!");
695 	break;
696       }
697       int id1 = atoi(a[0].c_str());
698       int id2 = atoi(a[1].c_str());
699       CHAIN_OPERATOR::parameter_t v = atof(a[2].c_str());
700 
701       bool valid =
702 	action_helper_check_cop_op_args(id1, id2);
703       if (valid == true) {
704 	select_chain_operator(id1);
705 	select_chain_operator_parameter(id2);
706 	set_chain_operator_parameter(v);
707       }
708       // note: helper func sets the error string if needed
709       break;
710     }
711   case ec_cop_get:
712     {
713       vector<string> a =
714 	kvu_string_to_vector(first_action_argument_as_string(), ',');
715       if (a.size() < 2) {
716         set_last_error("Not enough parameters!");
717         break;
718       }
719       int id1 = atoi(a[0].c_str());
720       int id2 = atoi(a[1].c_str());
721       bool valid =
722 	action_helper_check_cop_op_args(id1, id2);
723       if (valid == true) {
724         select_chain_operator(id1);
725         select_chain_operator_parameter(id2);
726         set_last_float(get_chain_operator_parameter());
727       }
728       // note: helper func sets the error string if needed
729       break;
730     }
731 
732   case ec_cop_status:
733     {
734       set_last_string(chain_operator_status());
735       break;
736     }
737 
738     // ---
739     // Chain operator parameters
740     // ---
741   case ec_copp_list: { set_last_string_list(chain_operator_parameter_names()); break; }
742   case ec_copp_select: { select_chain_operator_parameter(first_action_argument_as_int()); break; }
743   case ec_copp_selected: { set_last_integer(selected_chain_operator_parameter()); break; }
744   case ec_copp_set: { set_chain_operator_parameter(first_action_argument_as_float()); break; }
745   case ec_copp_get: { set_last_float(get_chain_operator_parameter()); break; }
746 
747     // ---
748     // Controllers
749     // ---
750   case ec_ctrl_add: { add_controller(first_action_argument_as_string()); break; }
751   case ec_ctrl_describe:
752     {
753       const GENERIC_CONTROLLER *t = get_controller();
754       set_last_string(t == 0 ? "" : ECA_OBJECT_FACTORY::controller_to_eos(t));
755       break;
756     }
757   case ec_ctrl_remove: { remove_controller(); break; }
758   case ec_ctrl_list: { set_last_string_list(controller_names()); break; }
759   case ec_ctrl_select: { select_controller(first_action_argument_as_int()); break; }
760   case ec_ctrl_selected: { set_last_integer(selected_controller()); break; }
761   case ec_ctrl_status:
762     {
763       set_last_string(controller_status());
764       break;
765     }
766   case ec_ctrl_get_target: { set_last_integer(selected_controller_target()); break; }
767 
768     // ---
769     // Controller parameters
770     // ---
771   case ec_ctrlp_list: { set_last_string_list(controller_parameter_names()); break; }
772   case ec_ctrlp_select: { select_controller_parameter(first_action_argument_as_int()); break; }
773   case ec_ctrlp_selected: { set_last_integer(selected_controller_parameter()); break; }
774   case ec_ctrlp_get: { set_last_float(get_controller_parameter()); break; }
775   case ec_ctrlp_set: { set_controller_parameter(first_action_argument_as_float()); break; }
776 
777   case ec_cop_register: { cop_register(); break; }
778   case ec_preset_register: { preset_register(); break; }
779   case ec_ladspa_register: { ladspa_register(); break; }
780   case ec_lv2_register: { lv2_register(); break; }
781   case ec_ctrl_register: { ctrl_register(); break; }
782 
783   case ec_map_cop_list: { cop_descriptions(); break; }
784   case ec_map_preset_list: { preset_descriptions(); break; }
785   case ec_map_ladspa_list: { ladspa_descriptions(false); break; }
786   case ec_map_ladspa_id_list: { ladspa_descriptions(true); break; }
787   case ec_map_lv2_list: { lv2_descriptions(); break; }
788   case ec_map_ctrl_list: { ctrl_descriptions(); break; }
789 
790   // ---
791   // Engine commands
792   // ---
793   case ec_engine_launch: {
794     if (is_engine_ready_for_commands() != true)
795       engine_start();
796     else
797       set_last_error("Engine already running, use 'engine-halt' first.");
798     break;
799   }
800   case ec_engine_halt: {
801     if (is_engine_ready_for_commands() == true)
802       close_engine();
803     else
804       set_last_error("Engine not running, use 'engine-launch' first.");
805     break;
806   }
807   case ec_engine_status: { set_last_string(engine_status()); break; }
808 
809   // ---
810   // Internal commands
811   // ---
812   case ec_int_cmd_list: { set_last_string_list(registered_commands_list()); break; }
813   case ec_int_log_history: { set_last_string(ECA_LOGGER::instance().log_history()); break; }
814   case ec_int_output_mode_wellformed: {
815     ECA_LOGGER::attach_logger(new ECA_LOGGER_WELLFORMED());
816     wellformed_mode_rep = true;
817     break;
818   }
819   case ec_int_set_float_to_string_precision: { set_float_to_string_precision(first_action_argument_as_int()); break; }
820   case ec_int_set_log_history_length: { ECA_LOGGER::instance().set_log_history_length(first_action_argument_as_int()); break; }
821   case ec_int_version_string: { set_last_string(ecasound_library_version); break; }
822   case ec_int_version_lib_current: { set_last_integer(ecasound_library_version_current); break; }
823   case ec_int_version_lib_revision: { set_last_integer(ecasound_library_version_revision); break; }
824   case ec_int_version_lib_age: { set_last_integer(ecasound_library_version_age); break; }
825 
826   // ---
827   // Dump commands
828   // ---
829   case ec_dump_target: { ctrl_dump_rep.set_dump_target(first_action_argument_as_string()); break; }
830   case ec_dump_status: { ctrl_dump_rep.dump_status(); break; }
831   case ec_dump_position: { ctrl_dump_rep.dump_position(); break; }
832   case ec_dump_length: { ctrl_dump_rep.dump_length(); break; }
833   case ec_dump_cs_status: { ctrl_dump_rep.dump_chainsetup_status(); break; }
834   case ec_dump_c_selected: { ctrl_dump_rep.dump_selected_chain(); break; }
835   case ec_dump_ai_selected: { ctrl_dump_rep.dump_selected_audio_input(); break; }
836   case ec_dump_ai_position: { ctrl_dump_rep.dump_audio_input_position(); break; }
837   case ec_dump_ai_length: { ctrl_dump_rep.dump_audio_input_length(); break; }
838   case ec_dump_ai_open_state: { ctrl_dump_rep.dump_audio_input_open_state(); break; }
839   case ec_dump_ao_selected: { ctrl_dump_rep.dump_selected_audio_output(); break; }
840   case ec_dump_ao_position: { ctrl_dump_rep.dump_audio_output_position(); break; }
841   case ec_dump_ao_length: { ctrl_dump_rep.dump_audio_output_length(); break; }
842   case ec_dump_ao_open_state: { ctrl_dump_rep.dump_audio_output_open_state(); break; }
843   case ec_dump_cop_value:
844     {
845       vector<string> temp = kvu_string_to_vector(first_action_argument_as_string(), ',');
846       if (temp.size() > 1) {
847 	ctrl_dump_rep.dump_chain_operator_value(atoi(temp[0].c_str()),
848 						atoi(temp[1].c_str()));
849       }
850       break;
851     }
852 
853     // ---
854     // Commands with external dependencies
855     // ---
856 #if ECA_COMPILE_JACK
857   case ec_jack_connect:
858     {
859       const vector<string>& params = action_arguments_as_vector();
860       if (params.size() >= 2)
861 	JACK_CONNECTIONS::connect(params[0].c_str(), params[1].c_str());
862       break;
863     }
864   case ec_jack_disconnect:
865     {
866       const vector<string>& params = action_arguments_as_vector();
867       if (params.size() >= 2)
868 	JACK_CONNECTIONS::disconnect(params[0].c_str(), params[1].c_str());
869       break;
870     }
871   case ec_jack_list_connections:
872     {
873       string foo;
874       if (JACK_CONNECTIONS::list_connections(&foo) == true)
875 	set_last_string(foo);
876       else
877 	set_last_error("Unable to a list of JACK connections.");
878       break;
879     }
880 #endif
881 
882   } // <-- switch-case
883 
884 
885   if (action_reconnect == true) {
886     if (is_selected() == false ||
887 	is_valid() == false) {
888       set_last_error("Can't reconnect chainsetup.");
889     }
890     else {
891       connect_chainsetup(0);
892       if (selected_chainsetup() != connected_chainsetup()) {
893 	set_last_error("Can't reconnect chainsetup.");
894       }
895       else {
896 	if (action_restart == true) {
897 	  DBC_CHECK(is_running() != true);
898 	  start();
899 	}
900       }
901     }
902   }
903 }
904 
905 /**
906  * Executes chainsetup edit on connect chainsetup.
907  *
908  * @pre is_connected()
909  */
execute_edit_on_connected(const chainsetup_edit_t & edit)910 bool ECA_CONTROL::execute_edit_on_connected(const chainsetup_edit_t& edit)
911 {
912   DBC_REQUIRE(is_connected() == true);
913 
914   bool retval = false;
915 
916   if (is_engine_ready_for_commands() == true) {
917     ECA_ENGINE::complex_command_t engine_cmd;
918     engine_cmd.type = ECA_ENGINE::ep_exec_edit;
919     engine_cmd.cs = edit;
920     engine_repp->command(engine_cmd);
921     retval = true;
922   }
923   else {
924     /* note: engine not yet running, execute edit directly */
925     retval = session_repp->connected_chainsetup_repp->execute_edit(edit);
926   }
927 
928   return retval;
929 }
930 
931 /**
932  * Executes chainsetup edit on selected chainsetup.
933  *
934  * @param edit object specifying the edit action
935  * @param index if non-negative, override the chainsetup selection
936  */
execute_edit_on_selected(const chainsetup_edit_t & edit,int index)937 bool ECA_CONTROL::execute_edit_on_selected(const chainsetup_edit_t& edit, int index)
938 {
939   bool retval = false;
940 
941   ECA_CHAINSETUP *csetup = 0;
942 
943   if (index < 0) {
944     csetup = selected_chainsetup_repp;
945   }
946   else {
947     if (index >= 0 &&
948 	index < static_cast<int>(session_repp->chainsetups_rep.size())) {
949       csetup = session_repp->chainsetups_rep[index];
950     }
951   }
952 
953   /* note: make sure that if the selected chainsetup is
954    *       in use by the engine, the edit is performed
955    *       by the engine thread!
956    */
957   if (csetup != 0) {
958     if (csetup->is_enabled() == true &&
959 	is_engine_ready_for_commands() == true) {
960       execute_edit_on_connected(edit);
961     }
962     else {
963       csetup->execute_edit(edit);
964     }
965   }
966 
967   return retval;
968 }
969 
print_last_value(struct eci_return_value * retval) const970 void ECA_CONTROL::print_last_value(struct eci_return_value *retval) const
971 {
972   std::string result;
973 
974   if (retval->type == eci_return_value::retval_error) {
975     result += "ERROR: ";
976   }
977 
978   result += ECA_CONTROL_MAIN::return_value_to_string(retval);
979 
980   if (wellformed_mode_rep != true) {
981     if (result.size() > 0)
982       ECA_LOG_MSG(ECA_LOGGER::eiam_return_values, result);
983   }
984   else {
985     /* in wellformed-output-mode we always create return output */
986     ECA_LOG_MSG(ECA_LOGGER::eiam_return_values,
987 		std::string(return_value_type_to_string(retval)) +
988 		" " + result);
989   }
990 }
991 
chainsetup_details_to_string(const ECA_CHAINSETUP * cs) const992 string ECA_CONTROL::chainsetup_details_to_string(const ECA_CHAINSETUP* cs) const
993 {
994   string result;
995   vector<CHAIN*>::const_iterator chain_citer;
996 
997   result += "\n -> Objects..: " + kvu_numtostr(cs->inputs.size());
998   result += " inputs, " + kvu_numtostr(cs->outputs.size());
999   result += " outputs, " + kvu_numtostr(cs->chains.size());
1000   result += " chains";
1001 
1002   // FIXME: add explanations on why the chainsetup cannot be
1003   //        connected
1004 
1005   result += "\n -> State....: ";
1006 
1007   if (cs->is_locked()) {
1008     result += "connected to engine (engine status: ";
1009     result += engine_status() + ")";
1010   }
1011   else if (cs->is_enabled() && is_engine_created() == true) {
1012     result += "connected (engine status: ";
1013     result += engine_status() + ")";
1014   }
1015   else if (cs->is_enabled())
1016     result += "connected (engine not yet running)";
1017   else if (cs->is_valid())
1018     result += "valid (can be connected)";
1019   else
1020     result += "not valid (cannot be connected)";
1021 
1022   result += "\n -> Position.:  ";
1023   result += kvu_numtostr(cs->position_in_seconds_exact(), 3);
1024   result += " / ";
1025   if (cs->length_set())
1026     result += kvu_numtostr(cs->length_in_seconds_exact(), 3);
1027   else
1028     result += "inf";
1029 
1030   result += "\n -> Options..: ";
1031   result += cs->options_to_string();
1032 
1033   for(chain_citer = cs->chains.begin();
1034       chain_citer != cs->chains.end();) {
1035     result += "\n -> Chain \"" + (*chain_citer)->name() + "\": ";
1036     int idx =
1037       (*chain_citer)->connected_input();
1038     if (idx >= 0)
1039       result += ECA_OBJECT_FACTORY::audio_object_to_eos(cs->inputs[idx], "i");
1040     result += " ";
1041     result += (*chain_citer)->to_string();
1042     idx = (*chain_citer)->connected_output();
1043     if (idx >= 0)
1044       result += ECA_OBJECT_FACTORY::audio_object_to_eos(cs->outputs[idx], "o");
1045 
1046     ++chain_citer;
1047   }
1048 
1049   return result;
1050 }
1051 
chainsetup_status(void) const1052 string ECA_CONTROL::chainsetup_status(void) const
1053 {
1054   vector<ECA_CHAINSETUP*>::const_iterator cs_citer = session_repp->chainsetups_rep.begin();
1055   int index = 0;
1056   string result ("### Chainsetup status ###\n");
1057 
1058   while(cs_citer != session_repp->chainsetups_rep.end()) {
1059     result += "Chainsetup ("  + kvu_numtostr(++index) + ") \"";
1060     result += (*cs_citer)->name() + "\" ";
1061 
1062     if (*cs_citer ==
1063 	selected_chainsetup_repp)
1064       result += "[selected] ";
1065     if (*cs_citer ==
1066 	session_repp->connected_chainsetup_repp)
1067       result += "[connected] ";
1068 
1069     if ((*cs_citer == selected_chainsetup_repp) ||
1070 	(*cs_citer == session_repp->connected_chainsetup_repp))
1071       result += chainsetup_details_to_string((*cs_citer));
1072     else
1073       result += ": <detailed status omitted -- set as selected to see full status>";
1074 
1075     ++cs_citer;
1076     if (cs_citer != session_repp->chainsetups_rep.end()) result += "\n";
1077   }
1078 
1079   return result;
1080 }
1081 
chain_status(void) const1082 string ECA_CONTROL::chain_status(void) const
1083 {
1084   // --------
1085   DBC_REQUIRE(is_selected() == true);
1086   // --------
1087 
1088   MESSAGE_ITEM mitem;
1089   vector<CHAIN*>::const_iterator chain_citer;
1090   const vector<string>& schains = selected_chainsetup_repp->selected_chains();
1091   mitem << "### Chain status (chainsetup '"
1092 	<< selected_chainsetup()
1093 	<< "') ###\n";
1094 
1095   for(chain_citer = selected_chainsetup_repp->chains.begin(); chain_citer != selected_chainsetup_repp->chains.end();) {
1096     mitem << "Chain \"" << (*chain_citer)->name() << "\" ";
1097     if ((*chain_citer)->is_muted()) mitem << "[muted] ";
1098     if ((*chain_citer)->is_bypassed()) mitem << "[bypassed] ";
1099     if (find(schains.begin(), schains.end(), (*chain_citer)->name()) != schains.end()) mitem << "[selected] ";
1100     for(int n = 0; n < (*chain_citer)->number_of_chain_operators(); n++) {
1101       mitem << "\"" << (*chain_citer)->get_chain_operator(n)->name() << "\"";
1102       if (n == (*chain_citer)->number_of_chain_operators()) mitem << " -> ";
1103     }
1104     ++chain_citer;
1105     if (chain_citer != selected_chainsetup_repp->chains.end()) mitem << "\n";
1106   }
1107 
1108   return mitem.to_string();
1109 }
1110 
chain_operator_status(void) const1111 string ECA_CONTROL::chain_operator_status(void) const
1112 {
1113   // --------
1114   DBC_REQUIRE(is_selected() == true);
1115   // --------
1116 
1117   MESSAGE_ITEM msg;
1118   string st_info_string;
1119   vector<CHAIN*>::const_iterator chain_citer = selected_chainsetup_repp->chains.begin();
1120 
1121   msg << "### Chain operator status (chainsetup '"
1122       << selected_chainsetup()
1123       << "') ###\n";
1124 
1125   while(chain_citer != selected_chainsetup_repp->chains.end()) {
1126     msg << "Chain \"" << (*chain_citer)->name() << "\":\n";
1127     for(int p = 0; p < (*chain_citer)->number_of_chain_operators(); p++) {
1128       const CHAIN_OPERATOR* cop = (*chain_citer)->get_chain_operator(p);
1129       msg << "\t";
1130       msg << p + 1 << ". ";
1131       msg << cop->name();
1132       if ((*chain_citer)->is_operator_bypassed(p + 1))
1133 	msg << " (BYPASSED)";
1134       for(int n = 0; n < cop->number_of_params(); n++) {
1135 	if (n == 0) msg << ": ";
1136 	msg << "[" << n + 1 << "] ";
1137 	msg << cop->get_parameter_name(n + 1);
1138 	msg << " ";
1139 	msg << float_to_string(cop->get_parameter(n + 1));
1140 	if (n + 1 < cop->number_of_params()) msg <<  ", ";
1141       }
1142       st_info_string = cop->status();
1143       if (st_info_string.empty() == false) {
1144 	msg << "\n\tStatus info:\n" << st_info_string;
1145       }
1146       if (p + 1 < (*chain_citer)->number_of_chain_operators()) msg << "\n";
1147     }
1148     ++chain_citer;
1149     if (chain_citer != selected_chainsetup_repp->chains.end()) msg << "\n";
1150   }
1151   return msg.to_string();
1152 }
1153 
controller_status(void) const1154 string ECA_CONTROL::controller_status(void) const
1155 {
1156   // --------
1157   DBC_REQUIRE(is_selected() == true);
1158   // --------
1159 
1160   MESSAGE_ITEM mitem;
1161   string st_info_string;
1162   vector<CHAIN*>::const_iterator chain_citer;
1163 
1164   mitem << "### Controller status (chainsetup '"
1165 	<< selected_chainsetup()
1166 	<< "') ###\n";
1167 
1168   for(chain_citer = selected_chainsetup_repp->chains.begin(); chain_citer != selected_chainsetup_repp->chains.end();) {
1169     mitem << "Chain \"" << (*chain_citer)->name() << "\":\n";
1170     for(int p = 0; p < (*chain_citer)->number_of_controllers(); p++) {
1171       const GENERIC_CONTROLLER* gtrl = (*chain_citer)->get_controller(p);
1172       mitem << "\t" << p + 1 << ". " << gtrl->name() << ": ";
1173       for(int n = 0; n < gtrl->number_of_params(); n++) {
1174 	mitem << "\n\t\t[" << n + 1 << "] ";
1175 	mitem << gtrl->get_parameter_name(n + 1);
1176 	mitem << " ";
1177 	mitem << float_to_string(gtrl->get_parameter(n + 1));
1178 	if (n + 1 < gtrl->number_of_params()) mitem <<  ", ";
1179       }
1180       st_info_string = gtrl->status();
1181       if (st_info_string.empty() == false) {
1182 	mitem << "\n\t -- Status info: " << st_info_string;
1183       }
1184       if (p + 1 < (*chain_citer)->number_of_controllers()) mitem << "\n";
1185     }
1186     ++chain_citer;
1187     if (chain_citer != selected_chainsetup_repp->chains.end()) mitem << "\n";
1188   }
1189   return mitem.to_string();
1190 }
1191 
aio_status(void) const1192 string ECA_CONTROL::aio_status(void) const
1193 {
1194   // --------
1195   DBC_REQUIRE(is_selected() == true);
1196   // --------
1197 
1198   string st_info_string;
1199   vector<AUDIO_IO*>::size_type adev_sizet = 0;
1200   vector<AUDIO_IO*>::const_iterator adev_citer = selected_chainsetup_repp->inputs.begin();
1201 
1202   st_info_string += "### Audio input/output status (chainsetup '" +
1203     selected_chainsetup() + "') ###\n";
1204 
1205   while(adev_citer != selected_chainsetup_repp->inputs.end()) {
1206     st_info_string += "Input (" + kvu_numtostr(adev_sizet + 1) + "): \"";
1207     for(int n = 0; n < (*adev_citer)->number_of_params(); n++) {
1208       st_info_string += (*adev_citer)->get_parameter(n + 1);
1209       if (n + 1 < (*adev_citer)->number_of_params()) st_info_string += ",";
1210     }
1211     st_info_string += "\" - [" + (*adev_citer)->name() + "]";
1212     if ((*adev_citer) == selected_audio_input_repp) st_info_string += " [selected]";
1213     st_info_string += "\n -> connected to chains \"";
1214     vector<string> temp = selected_chainsetup_repp->get_attached_chains_to_input((selected_chainsetup_repp->inputs)[adev_sizet]);
1215     vector<string>::const_iterator p = temp.begin();
1216     while (p != temp.end()) {
1217       st_info_string += *p;
1218       ++p;
1219       if (p != temp.end())  st_info_string += ",";
1220     }
1221     st_info_string += "\": " + (*adev_citer)->status() + "\n";
1222     ++adev_sizet;
1223     ++adev_citer;
1224   }
1225 
1226   adev_sizet = 0;
1227   adev_citer = selected_chainsetup_repp->outputs.begin();
1228   while(adev_citer != selected_chainsetup_repp->outputs.end()) {
1229     st_info_string += "Output (" + kvu_numtostr(adev_sizet + 1) + "): \"";
1230     for(int n = 0; n < (*adev_citer)->number_of_params(); n++) {
1231       st_info_string += (*adev_citer)->get_parameter(n + 1);
1232       if (n + 1 < (*adev_citer)->number_of_params()) st_info_string += ",";
1233     }
1234     st_info_string += "\" - [" + (*adev_citer)->name() + "]";
1235     if ((*adev_citer) == selected_audio_output_repp) st_info_string += " [selected]";
1236     st_info_string += "\n -> connected to chains \"";
1237     vector<string> temp = selected_chainsetup_repp->get_attached_chains_to_output((selected_chainsetup_repp->outputs)[adev_sizet]);
1238     vector<string>::const_iterator p = temp.begin();
1239     while (p != temp.end()) {
1240       st_info_string += *p;
1241       ++p;
1242       if (p != temp.end())  st_info_string += ",";
1243     }
1244     st_info_string += "\": ";
1245     st_info_string += (*adev_citer)->status();
1246     ++adev_sizet;
1247     ++adev_citer;
1248     if (adev_sizet < selected_chainsetup_repp->outputs.size()) st_info_string += "\n";
1249   }
1250   return st_info_string;
1251 }
1252 
aio_register(void)1253 void ECA_CONTROL::aio_register(void)
1254 {
1255   ECA_LOG_MSG(ECA_LOGGER::info, "Registered audio object types:\n");
1256   string result (eca_aio_register_sub(ECA_OBJECT_FACTORY::audio_io_nonrt_map()));
1257 
1258   result += "\n";
1259 
1260   result += eca_aio_register_sub(ECA_OBJECT_FACTORY::audio_io_rt_map());
1261 
1262   set_last_string(result);
1263 }
1264 
eca_aio_register_sub(ECA_OBJECT_MAP & objmap)1265 static string eca_aio_register_sub(ECA_OBJECT_MAP& objmap)
1266 {
1267   string result;
1268   const list<string>& objlist = objmap.registered_objects();
1269   list<string>::const_iterator p = objlist.begin();
1270   int count = 1;
1271   while(p != objlist.end()) {
1272     string temp;
1273     const AUDIO_IO* q = dynamic_cast<const AUDIO_IO*>(objmap.object_expr(*p));
1274 
1275     DBC_CHECK(q != 0);
1276 
1277     if (q != 0) {
1278       int params = q->number_of_params();
1279       if (params > 0) {
1280 	temp += ": ";
1281 	for(int n = 0; n < params; n++) {
1282 	  temp += q->get_parameter_name(n + 1);
1283 	  if (n + 1 < params) temp += ",";
1284 	}
1285       }
1286 
1287       result += kvu_numtostr(count) + ". " + q->name() + ", regex: " +
1288 	        objmap.keyword_to_expr(*p) + ", params" + temp;
1289       result += "\n";
1290 
1291       ++count;
1292     }
1293     //  else std::cerr << "Failed obj: " << *p << "." << std::endl;
1294 
1295     ++p;
1296   }
1297   return result;
1298 }
1299 
cop_register(void)1300 void ECA_CONTROL::cop_register(void)
1301 {
1302   ECA_LOG_MSG(ECA_LOGGER::info, "Registered chain operators:\n");
1303   string result;
1304   const list<string>& objlist = ECA_OBJECT_FACTORY::chain_operator_map().registered_objects();
1305   list<string>::const_iterator p = objlist.begin();
1306   int count = 1;
1307   while(p != objlist.end()) {
1308     string temp;
1309     const CHAIN_OPERATOR* q = dynamic_cast<const CHAIN_OPERATOR*>(ECA_OBJECT_FACTORY::chain_operator_map().object(*p));
1310     if (q != 0) {
1311       int params = q->number_of_params();
1312       for(int n = 0; n < params; n++) {
1313 	if (n == 0) temp += ":";
1314 	temp += q->get_parameter_name(n + 1);
1315 	if (n + 1 < params) temp += ",";
1316       }
1317       result += kvu_numtostr(count) + ". " + q->name() + ", -" + *p + temp;
1318       result += "\n";
1319       ++count;
1320     }
1321     ++p;
1322   }
1323   set_last_string(result);
1324 }
1325 
preset_register(void)1326 void ECA_CONTROL::preset_register(void)
1327 {
1328   ECA_LOG_MSG(ECA_LOGGER::info, "Registered effect presets:\n");
1329   string result;
1330 #ifndef ECA_DISABLE_EFFECTS
1331   const list<string>& objlist = ECA_OBJECT_FACTORY::preset_map().registered_objects();
1332   list<string>::const_iterator p = objlist.begin();
1333   int count = 1;
1334   while(p != objlist.end()) {
1335     string temp;
1336     const PRESET* q = dynamic_cast<const PRESET*>(ECA_OBJECT_FACTORY::preset_map().object(*p));
1337     if (q != 0) {
1338       int params = q->number_of_params();
1339       for(int n = 0; n < params; n++) {
1340 	if (n == 0) temp += ":";
1341 	temp += q->get_parameter_name(n + 1);
1342 	if (n + 1 < params) temp += ",";
1343       }
1344 
1345       result += kvu_numtostr(count) + ". " + q->name() + ", -pn:" + *p + temp;
1346       result += "\n";
1347 
1348       ++count;
1349     }
1350     ++p;
1351   }
1352 #endif
1353   set_last_string(result);
1354 }
1355 
1356 
ladspa_register(void)1357 void ECA_CONTROL::ladspa_register(void)
1358 {
1359   ECA_LOG_MSG(ECA_LOGGER::info, "Registered LADSPA plugins:\n");
1360   string result;
1361 #ifndef ECA_DISABLE_EFFECTS
1362   const list<string>& objlist = ECA_OBJECT_FACTORY::ladspa_plugin_map().registered_objects();
1363   list<string>::const_iterator p = objlist.begin();
1364   int count = 1;
1365   while(p != objlist.end()) {
1366     const EFFECT_LADSPA* q = dynamic_cast<const EFFECT_LADSPA*>(ECA_OBJECT_FACTORY::ladspa_plugin_map().object(*p));
1367     if (q != 0) {
1368       string temp = "\n\t-el:" + q->unique() + ",";
1369       int params = q->number_of_params();
1370       for(int n = 0; n < params; n++) {
1371 	temp += "'" + q->get_parameter_name(n + 1) + "'";
1372 	if (n + 1 < params) temp += ",";
1373       }
1374 
1375       result += kvu_numtostr(count) + ". " + q->name() + "" + temp;
1376       result += "\n";
1377 
1378       ++count;
1379     }
1380     ++p;
1381   }
1382 #endif
1383   set_last_string(result);
1384 }
1385 
lv2_register(void)1386 void ECA_CONTROL::lv2_register(void)
1387 {
1388   ECA_LOG_MSG(ECA_LOGGER::info, "Registered LV2 plugins:\n");
1389   string result;
1390 #if !defined(ECA_DISABLE_EFFECTS) && defined(ECA_USE_LIBLILV)
1391   const list<string>& objlist = ECA_OBJECT_FACTORY::lv2_plugin_map().registered_objects();
1392   list<string>::const_iterator p = objlist.begin();
1393   int count = 1;
1394   while(p != objlist.end()) {
1395     const EFFECT_LV2* q = dynamic_cast<const EFFECT_LV2*>(ECA_OBJECT_FACTORY::lv2_plugin_map().object(*p));
1396     if (q != 0) {
1397       string temp = "\n\t-elv2:" + q->unique() + ",";
1398       int params = q->number_of_params();
1399       for(int n = 0; n < params; n++) {
1400 	temp += "'" + q->get_parameter_name(n + 1) + "'";
1401 	if (n + 1 < params) temp += ",";
1402       }
1403 
1404       result += kvu_numtostr(count) + ". " + q->name() + "" + temp;
1405       result += "\n";
1406 
1407       ++count;
1408     }
1409     ++p;
1410   }
1411 #endif
1412   set_last_string(result);
1413 }
1414 
1415 
ctrl_register(void)1416 void ECA_CONTROL::ctrl_register(void)
1417 {
1418   ECA_LOG_MSG(ECA_LOGGER::info, "Registered controllers:\n");
1419   string result;
1420   const list<string>& objlist = ECA_OBJECT_FACTORY::controller_map().registered_objects();
1421   list<string>::const_iterator p = objlist.begin();
1422   int count = 1;
1423   while(p != objlist.end()) {
1424     string temp;
1425     const GENERIC_CONTROLLER* q = dynamic_cast<const GENERIC_CONTROLLER*>(ECA_OBJECT_FACTORY::controller_map().object(*p));
1426     if (q != 0) {
1427       int params = q->number_of_params();
1428       for(int n = 0; n < params; n++) {
1429 	if (n == 0) temp += ":";
1430 	temp += q->get_parameter_name(n + 1);
1431 	if (n + 1 < params) temp += ",";
1432       }
1433 
1434       result += kvu_numtostr(count) + ". " + q->name() + ", -" + *p +
1435 	temp;
1436       result += "\n";
1437 
1438       ++count;
1439     }
1440     ++p;
1441   }
1442   set_last_string(result);
1443 }
1444 
1445 /**
1446  * Print description of all chain operators and
1447  * their parameters.
1448  */
operator_descriptions_helper(const ECA_OBJECT_MAP & arg,string * result)1449 void ECA_CONTROL::operator_descriptions_helper(const ECA_OBJECT_MAP& arg, string* result)
1450 {
1451   /* switch to "C" locale to avoid strange floating point
1452    * presentations that could break the output format
1453    * (for example "a,b" insteof of "a.b" */
1454 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
1455   string old_locale (setlocale(LC_ALL, "C"));
1456 #endif
1457 
1458   const list<string>& objlist = arg.registered_objects();
1459   list<string>::const_iterator p = objlist.begin();
1460   int count = 1;
1461   while(p != objlist.end()) {
1462     string temp;
1463     const OPERATOR* q = dynamic_cast<const OPERATOR*>(arg.object(*p));
1464     if (q != 0) {
1465       /* FIXME: prefer backslash escaped over '_' to handle commas */
1466 
1467       /* 1. keyword */
1468       *result += kvu_string_search_and_replace(*p, ',', '_');
1469       /* 2. name */
1470       *result += "," + kvu_string_search_and_replace(q->name(), ',', '_');
1471       /* 3. description */
1472       *result += "," + kvu_string_search_and_replace(q->description(), ',', '_');
1473 
1474       int params = q->number_of_params();
1475 
1476       /* 4. number of params */
1477       *result += "," + kvu_numtostr(params);
1478 
1479       /* 5. description of params (for all params) */
1480       for(int n = 0; n < params; n++) {
1481 	struct OPERATOR::PARAM_DESCRIPTION pd;
1482 	q->parameter_description(n + 1, &pd);
1483 
1484 	/* 5.1 name of param */
1485 	*result += "," + kvu_string_search_and_replace(q->get_parameter_name(n + 1), ',', '_');
1486 	/* 5.2 description */
1487 	*result += "," + kvu_string_search_and_replace(pd.description, ',', '_');
1488 	/* 5.3 default value */
1489 	*result += "," + float_to_string(pd.default_value);
1490 	/* 5.4 is bounded above (1=yes, 0=no) */
1491 	*result += ",above=" + kvu_numtostr(static_cast<int>(pd.bounded_above));
1492 	/* 5.5 upper bound */
1493 	*result += ",upper=" + float_to_string(pd.upper_bound);
1494 	/* 5.6 is bounded below (1=yes, 0=no) */
1495 	*result += ",below=" + kvu_numtostr(static_cast<int>(pd.bounded_below));
1496 	/* 5.7 lower bound */
1497 	*result += ",lower=" + float_to_string(pd.lower_bound);
1498 	/* 5.8. is toggled (1=yes, 0=no) */
1499 	*result += "," + kvu_numtostr(static_cast<int>(pd.toggled));
1500 	/* 5.9. is integer value (1=yes, 0=no) */
1501 	*result += "," + kvu_numtostr(static_cast<int>(pd.integer));
1502 	/* 5.10. is logarithmis value (1=yes, 0=no) */
1503 	*result += "," + kvu_numtostr(static_cast<int>(pd.logarithmic));
1504 	/* 5.11. is output value (1=yes, 0=no) */
1505 	*result += ",output=" + kvu_numtostr(static_cast<int>(pd.output));
1506       }
1507       *result += "\n";
1508       ++count;
1509     }
1510     ++p;
1511   }
1512 
1513   /* see above */
1514 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
1515   setlocale(LC_ALL, old_locale.c_str());
1516 #endif
1517 }
1518 
1519 /**
1520  * Print the description of all chain operators and
1521  * their parameters.
1522  */
cop_descriptions(void)1523 void ECA_CONTROL::cop_descriptions(void)
1524 {
1525   string result;
1526   operator_descriptions_helper(ECA_OBJECT_FACTORY::chain_operator_map(), &result);
1527   set_last_string(result);
1528 }
1529 
1530 /**
1531  * Prints the description of all effect presets and
1532  * their parameters.
1533  */
preset_descriptions(void)1534 void ECA_CONTROL::preset_descriptions(void)
1535 {
1536   string result;
1537   operator_descriptions_helper(ECA_OBJECT_FACTORY::preset_map(), &result);
1538   set_last_string(result);
1539 }
1540 
1541 /**
1542  * Prints the description of all LADSPA plugins and
1543  * their parameters.
1544  */
ladspa_descriptions(bool use_id)1545 void ECA_CONTROL::ladspa_descriptions(bool use_id)
1546 {
1547   string result;
1548   if (use_id) {
1549     operator_descriptions_helper(ECA_OBJECT_FACTORY::ladspa_plugin_id_map(), &result);
1550   }
1551   else {
1552     operator_descriptions_helper(ECA_OBJECT_FACTORY::ladspa_plugin_map(), &result);
1553   }
1554   set_last_string(result);
1555 }
1556 
1557 /**
1558  * Prints the description of all LV2 plugins and
1559  * their parameters.
1560  */
lv2_descriptions()1561 void ECA_CONTROL::lv2_descriptions()
1562 {
1563   string result;
1564   operator_descriptions_helper(ECA_OBJECT_FACTORY::lv2_plugin_map(), &result);
1565   set_last_string(result);
1566 }
1567 
1568 /**
1569  * Print the description of all controllers and
1570  * their parameters.
1571  */
ctrl_descriptions(void)1572 void ECA_CONTROL::ctrl_descriptions(void)
1573 {
1574   string result;
1575   operator_descriptions_helper(ECA_OBJECT_FACTORY::controller_map(), &result);
1576   set_last_string(result);
1577 }
1578