1 // ------------------------------------------------------------------------
2 // eca-control-objects.cpp: Class for configuring libecasound objects
3 // Copyright (C) 2000-2004,2006,2008,2009,2012-2014 Kai Vehmanen
4 // Copyright (C) 2005 Stuart Allie
5 //
6 // Attributes:
7 // eca-style-version: 3 (see Ecasound Programmer's Guide)
8 //
9 // This program is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 // ------------------------------------------------------------------------
23
24 #include <iostream>
25 #include <fstream>
26 #include <string>
27 #include <vector>
28 #include <algorithm>
29 #include <cstdio>
30 #include <cstdlib>
31
32 #include <kvu_dbc.h> /* DBC_* */
33 #include <kvu_value_queue.h>
34 #include <kvu_temporary_file_directory.h>
35 #include <kvu_numtostr.h>
36 #include <kvu_utils.h> /* kvu_get_argument_number() */
37
38 #include "audioio.h"
39 #include "eca-chain.h"
40 #include "eca-chainop.h"
41 #include "eca-chainsetup.h"
42 #include "eca-control.h"
43 #include "eca-engine.h"
44 #include "eca-object-factory.h"
45 #include "eca-session.h"
46 #include "generic-controller.h"
47
48 #include "eca-error.h"
49 #include "eca-logger.h"
50
51 /**
52 * Import namespaces
53 */
54 using std::string;
55
56 /**
57 * Definitions for member functions
58 */
59
60 /**
61 * Adds a new chainsetup
62 *
63 * @param name chainsetup name
64 *
65 * require:
66 * name != ""
67 *
68 * ensure:
69 * selected_chainsetup() == name || (last_error().size() > 0 && no_errors != true)
70 */
add_chainsetup(const string & name)71 void ECA_CONTROL::add_chainsetup(const string& name)
72 {
73 // --------
74 DBC_REQUIRE(name != "");
75 // --------
76
77 bool no_errors = true;
78 int count = static_cast<int>(session_repp->chainsetups_rep.size());
79 session_repp->add_chainsetup(name);
80 if (static_cast<int>(session_repp->chainsetups_rep.size()) > count) {
81 select_chainsetup(name);
82 ECA_LOG_MSG(ECA_LOGGER::info, "Added a new chainsetup with name \"" + name + "\".");
83 }
84 else {
85 set_last_error("Unable to add chainsetup with name \"" + name + "\".");
86 no_errors = false;
87 }
88
89 // --------
90 DBC_ENSURE(selected_chainsetup() == name || (last_error().size() > 0 && no_errors != true));
91 // --------
92 }
93
94 /**
95 * Removes chainsetup
96 *
97 * @param name chainsetup name
98 *
99 * require:
100 * is_selected() == true
101 * connected_chainsetup() != selected_chainsetup()
102 *
103 * ensure:
104 * selected_chainsetup.empty() == true
105 */
remove_chainsetup(void)106 void ECA_CONTROL::remove_chainsetup(void)
107 {
108 // --------
109 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
110 DBC_REQUIRE(is_selected() == true);
111 // --------
112
113 ECA_LOG_MSG(ECA_LOGGER::info, "Removing chainsetup: \"" + selected_chainsetup() + "\".");
114 session_repp->remove_chainsetup();
115 selected_chainsetup_repp = 0;
116
117 // --------
118 DBC_ENSURE(selected_chainsetup().empty() == true);
119 // --------
120 }
121
122 /**
123 * Loads chainsetup from file 'filename'.
124 *
125 * @param name chainsetup filename
126 *
127 * require:
128 * filename != ""
129 *
130 * ensure:
131 * filename exists implies loaded chainsetup == selected_chainsetup()
132 */
load_chainsetup(const string & filename)133 void ECA_CONTROL::load_chainsetup(const string& filename)
134 {
135 try {
136 session_repp->load_chainsetup(filename);
137 selected_chainsetup_repp = session_repp->selected_chainsetup_repp;
138 DBC_CHECK((selected_chainsetup_repp != 0 &&
139 selected_chainsetup_repp->filename() == filename) ||
140 selected_chainsetup_repp == 0);
141 ECA_LOG_MSG(ECA_LOGGER::info, "Loaded chainsetup from file \"" + filename + "\".");
142 }
143 catch(ECA_ERROR& e) {
144 set_last_error(e.error_section() + ": \"" + e.error_message() + "\"");
145 }
146 }
147
148 /**
149 * Save selected chainsetup.
150 *
151 * @param filename chainsetup filename (if omitted, previously used filename will be used, if any)
152 *
153 * require:
154 * selected_chainsetup().empty() != true
155 */
save_chainsetup(const string & filename)156 void ECA_CONTROL::save_chainsetup(const string& filename)
157 {
158 // --------
159 DBC_REQUIRE(selected_chainsetup().empty() != true);
160 // --------
161
162 try {
163 if (filename.empty() == true)
164 session_repp->save_chainsetup();
165 else
166 session_repp->save_chainsetup(filename);
167
168 ECA_LOG_MSG(ECA_LOGGER::info, "Saved selected chainsetup \"" + selected_chainsetup() + "\".");
169 }
170 catch(ECA_ERROR& e) {
171 set_last_error(e.error_section() + ": \"" + e.error_message() + "\"");
172 }
173 }
174
175 /**
176 * Selects chainsetup
177 *
178 * @param name chainsetup name
179 *
180 * require:
181 * name != ""
182 *
183 * ensure:
184 * name == selected_chainsetup() ||
185 * selected_chainsetup_rep == 0
186 */
select_chainsetup(const string & name)187 void ECA_CONTROL::select_chainsetup(const string& name)
188 {
189 // --------
190 DBC_REQUIRE(name != "");
191 // --------
192
193 session_repp->select_chainsetup(name);
194 selected_chainsetup_repp = session_repp->selected_chainsetup_repp;
195 if (selected_chainsetup_repp == 0) {
196 ECA_LOG_MSG(ECA_LOGGER::info, "Chainsetup \"" + name + "\" doesn't exist!");
197 set_last_error("Chainsetup \"" + name + "\" doesn't exist!");
198 }
199 // else { ECA_LOG_MSG(ECA_LOGGER::info, "Selected chainsetup: \"" + selected_chainsetup() + "\"."); }
200
201 // --------
202 DBC_ENSURE(name == selected_chainsetup() ||
203 is_selected() == false);
204 // --------
205 }
206
207 /**
208 * Selects a chainsetup by index.
209 *
210 * @param index_number an integer identifier
211 *
212 * require:
213 * index_number > 0
214 */
select_chainsetup_by_index(int index_number)215 void ECA_CONTROL::select_chainsetup_by_index(int index_number)
216 {
217 // --------
218 DBC_REQUIRE(index_number > 0);
219 // --------
220
221 for(std::vector<ECA_CHAINSETUP*>::size_type p = 0;
222 p != session_repp->chainsetups_rep.size();
223 p++) {
224 if (index_number == static_cast<int>(p + 1)) {
225 select_chainsetup(session_repp->chainsetups_rep[p]->name());
226 break;
227 }
228 }
229 }
230
231 /**
232 * Name of currently active chainsetup
233 */
selected_chainsetup(void) const234 string ECA_CONTROL::selected_chainsetup(void) const
235 {
236 if (selected_chainsetup_repp != 0)
237 return selected_chainsetup_repp->name();
238
239 return "";
240 }
241
242 /**
243 * Spawns an external editor for editing selected chainsetup
244 *
245 * require:
246 * is_selected()
247 * connected_chainsetup() != selected_chainsetup()
248 */
edit_chainsetup(void)249 void ECA_CONTROL::edit_chainsetup(void)
250 {
251 // --------
252 DBC_REQUIRE(selected_chainsetup().empty() != true);
253 // --------
254
255 /* 1. check which editor to use (and exit if none
256 * defined) */
257 string editori = "";
258 string use_getenv =
259 resource_value("ext-cmd-text-editor-use-getenv");
260
261 if (use_getenv.size() == 0 ||
262 use_getenv == "true") {
263 /* note: as specified in ecasoundrc(5), we should
264 * default to 'true' */
265 if (std::getenv("EDITOR") != 0) {
266 editori = std::getenv("EDITOR");
267 }
268 }
269 if (editori == "")
270 editori = resource_value("ext-cmd-text-editor");
271
272 if (editori == "") {
273 ECA_LOG_MSG(ECA_LOGGER::info,
274 "ERROR: Cannot edit, no text editor specified/available. See ecasoundrc(5) man page and the 'ext-cmd-text-editor' configuration variable.");
275 return;
276 }
277
278 /* 2. detect hot-swap */
279 bool hot_swap = false;
280 bool restart = false;
281 if (connected_chainsetup() == selected_chainsetup()) {
282 hot_swap = true;
283 if (is_running()) restart = true;
284 }
285
286 /* 3. store runtime state of the old chainsetup */
287 string origname = selected_chainsetup_repp->name();
288 string origfilename = selected_chainsetup_repp->filename();
289 SAMPLE_SPECS::sample_pos_t origpos = selected_chainsetup_repp->position_in_samples();
290
291 /* 4. create a safely accessible temporary filename */
292 TEMPORARY_FILE_DIRECTORY tempfile_dir_rep;
293 string tmpdir ("ecasound-");
294 char* tmp_p = std::getenv("USER");
295 if (tmp_p != NULL) {
296 tmpdir += string(tmp_p);
297 tempfile_dir_rep.reserve_directory(tmpdir);
298 }
299 if (tempfile_dir_rep.is_valid() != true) {
300 ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: Unable to create temporary directory \"" + tmpdir + "\".");
301 return;
302 }
303 string filename = tempfile_dir_rep.create_filename("cs-edit-tmp", ".ecs");
304
305 /* 5. save selected chainsetup to the temp file */
306 if (hot_swap == true)
307 session_repp->connected_chainsetup_repp->set_name("cs-edit-temp");
308
309 save_chainsetup(filename);
310
311 if (hot_swap == true)
312 session_repp->connected_chainsetup_repp->set_name(origname);
313 else
314 remove_chainsetup();
315
316 /* 6. fork an external text editor */
317
318 // FIXME: we should drop priviledge-level here (at least if root)!
319 editori += " " + filename;
320 int res = ::system(editori.c_str());
321
322 if (res == 127 || res == -1) {
323 ECA_LOG_MSG(ECA_LOGGER::info, "Can't edit; unable to open file in text editor \"" + string(editori.c_str()) + "\".");
324
325 }
326 else {
327 /* 7. reload the edited chainsetup and reset runtime state */
328 load_chainsetup(filename);
329
330 if (is_selected() != true) {
331 ECA_LOG_MSG(ECA_LOGGER::info,
332 std::string("Unable to parse chainsetup, keeping the temporary file ") + filename);
333 }
334 else {
335 remove(filename.c_str());
336 if (origfilename.empty() != true) {
337 set_chainsetup_filename(origfilename);
338 }
339
340 if (selected_chainsetup_repp)
341 selected_chainsetup_repp->seek_position_in_samples(origpos);
342
343 if (hot_swap == true) {
344 /* 7.1 disconnect the chainsetup to be replaced */
345 disconnect_chainsetup();
346
347 /* 7.2 try to connect the edited chainsetup */
348 select_chainsetup("cs-edit-temp");
349 if (is_valid() == true) {
350 connect_chainsetup(0);
351 /* should succeed as is_valid() is true */
352 DBC_CHECK(is_connected() == true);
353 if (is_connected() == true) {
354 if (restart == true) {
355 DBC_CHECK(is_running() != true);
356 start();
357 }
358 }
359 }
360
361 /* 7.3 if connecting the modified chainsetup fails */
362 if (is_connected() != true) {
363 ECA_LOG_MSG(ECA_LOGGER::info, "Can't connect; edited chainsetup is not valid.");
364 }
365
366 /* 7.4 remove the old chainsetup */
367 select_chainsetup(origname);
368 remove_chainsetup();
369 select_chainsetup("cs-edit-temp");
370 selected_chainsetup_repp->set_name(origname);
371 }
372 }
373 }
374 }
375
376 /**
377 * Sets processing length in seconds.
378 *
379 * require:
380 * is_selected() == true
381 * value >= 0
382 */
set_chainsetup_processing_length_in_seconds(double value)383 void ECA_CONTROL::set_chainsetup_processing_length_in_seconds(double value)
384 {
385 // --------
386 DBC_REQUIRE(is_selected() == true);
387 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
388 // --------
389
390 /* note! here we set the _maximum_ length of the chainsetup */
391 selected_chainsetup_repp->set_max_length_in_seconds(value);
392 ECA_LOG_MSG(ECA_LOGGER::info, "Set chainsetup processing length to \"" + kvu_numtostr(value) + "\" seconds.");
393 }
394
395 /**
396 * Sets processing length in samples. If 'value' is 0,
397 * length in unspecified.
398 *
399 * require:
400 * is_selected() == true
401 * value >= 0
402 */
set_chainsetup_processing_length_in_samples(SAMPLE_SPECS::sample_pos_t value)403 void ECA_CONTROL::set_chainsetup_processing_length_in_samples(SAMPLE_SPECS::sample_pos_t value)
404 {
405 // --------
406 DBC_REQUIRE(is_selected() == true);
407 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
408 // --------
409
410 /* note! here we set the _maximum_ length of the chainsetup */
411 selected_chainsetup_repp->set_max_length_in_samples(value);
412 ECA_LOG_MSG(ECA_LOGGER::info, "Set chainsetup processing length to \"" +
413 kvu_numtostr(selected_chainsetup_repp->max_length_in_seconds_exact()) + "\" seconds.");
414 }
415
416 /**
417 * Sets default open mode for audio outputs.
418 *
419 * require:
420 * output_mode == AUDIO_IO::io_write || output_mode == AUDIO_IO::io_readwrite
421 */
set_chainsetup_output_mode(int output_mode)422 void ECA_CONTROL::set_chainsetup_output_mode(int output_mode)
423 {
424 // --------
425 DBC_REQUIRE(output_mode == AUDIO_IO::io_write || output_mode == AUDIO_IO::io_readwrite);
426 // --------
427 selected_chainsetup_repp->set_output_openmode(output_mode);
428 }
429
430 /**
431 * Sets chainsetup buffersize (in samples).
432 *
433 * @pre is_selected() == true
434 */
set_chainsetup_buffersize(int bsize)435 void ECA_CONTROL::set_chainsetup_buffersize(int bsize)
436 {
437 // --------
438 DBC_REQUIRE(is_selected() == true);
439 // --------
440 selected_chainsetup_repp->set_buffersize(bsize);
441 }
442
443 /**
444 * Toggles chainsetup looping
445 *
446 * require:
447 * is_selected() == true
448 */
toggle_chainsetup_looping(void)449 void ECA_CONTROL::toggle_chainsetup_looping(void)
450 {
451 // --------
452 DBC_REQUIRE(is_selected() == true);
453 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
454 // --------
455 if (selected_chainsetup_repp->looping_enabled()) {
456 selected_chainsetup_repp->toggle_looping(false);
457 ECA_LOG_MSG(ECA_LOGGER::info, "Disabled looping.");
458 }
459 else {
460 selected_chainsetup_repp->toggle_looping(true);
461 ECA_LOG_MSG(ECA_LOGGER::info, "Enabled looping.");
462 }
463 }
464
465 /**
466 * Connects selected chainsetup
467 *
468 * require:
469 * is_selected() == true
470 * is_valid() == true
471 *
472 * ensure:
473 * is_connected() == true || (last_error().size() > 0 && no_errors != true)
474 */
connect_chainsetup(struct eci_return_value * retval)475 void ECA_CONTROL::connect_chainsetup(struct eci_return_value *retval)
476 {
477 // --------
478 DBC_REQUIRE(is_selected());
479 DBC_REQUIRE(selected_chainsetup_repp != 0 && selected_chainsetup_repp->is_valid() == true);
480 // --------
481
482 bool no_errors = true;
483 string errmsg;
484 if (is_connected() == true) {
485 disconnect_chainsetup();
486 }
487 try {
488 session_repp->connect_chainsetup();
489 ECA_LOG_MSG(ECA_LOGGER::subsystems, "Connected chainsetup: \"" + connected_chainsetup() + "\"");
490 }
491 catch(ECA_ERROR& e) {
492 errmsg = e.error_message();
493 no_errors = false;
494 }
495 if (is_connected() != true) {
496 set_last_error(" Connecting chainsetup failed: \"" + errmsg + "\"");
497 no_errors = false;
498 }
499
500 fill_command_retval(retval);
501
502 // --------
503 DBC_ENSURE(is_connected() || no_errors != true);
504 // --------
505 }
506
507 /**
508 * Name of connected chainsetup.
509 */
connected_chainsetup(void) const510 string ECA_CONTROL::connected_chainsetup(void) const
511 {
512 if (session_repp->connected_chainsetup_repp != 0) {
513 return session_repp->connected_chainsetup_repp->name();
514 }
515
516 return "";
517 }
518
519 /**
520 * Disconnects activate chainsetup
521 *
522 * require:
523 * is_connected() == true
524 *
525 * ensure:
526 * connected_chainsetup() == ""
527 */
disconnect_chainsetup(void)528 void ECA_CONTROL::disconnect_chainsetup(void)
529 {
530 // --------
531 DBC_REQUIRE(is_connected());
532 // --------
533
534 if (is_engine_ready_for_commands() == true) {
535 stop_on_condition();
536 }
537 if (is_engine_created()) {
538 close_engine();
539 }
540
541 ECA_LOG_MSG(ECA_LOGGER::info, "Disconnecting chainsetup: \"" + connected_chainsetup() + "\".");
542 session_repp->disconnect_chainsetup();
543
544 // --------
545 DBC_ENSURE(connected_chainsetup() == "");
546 // --------
547 }
548
549 /**
550 * Changes the chainsetup position relatively to the current position.
551 * Behaves differently depending on whether the selected
552 * chainsetup is connected or not.
553 *
554 * require:
555 * is_selected() == true
556 */
change_chainsetup_position(double seconds)557 void ECA_CONTROL::change_chainsetup_position(double seconds)
558 {
559 // --------
560 DBC_REQUIRE(is_selected());
561 // --------
562
563 // FIXME: check whether all audio devices support seeking,
564 // raise an error if not (note: see other similar FIXMEs)
565
566 if (connected_chainsetup() == selected_chainsetup() && is_engine_ready_for_commands() == true) {
567 if (seconds < 0)
568 engine_repp->command(ECA_ENGINE::ep_rewind, -seconds);
569 else
570 engine_repp->command(ECA_ENGINE::ep_forward, seconds);
571 }
572 else {
573 selected_chainsetup_repp->seek_position_in_seconds(selected_chainsetup_repp->position_in_seconds()
574 + seconds );
575 }
576 }
577
578 /**
579 * Changes the chainsetup position in samples relatively to the
580 * current position. Behaves differently depending on whether
581 * the selected chainsetup is connected or not.
582 *
583 * require:
584 * is_selected() == true
585 */
change_chainsetup_position_samples(SAMPLE_SPECS::sample_pos_t samples)586 void ECA_CONTROL::change_chainsetup_position_samples(SAMPLE_SPECS::sample_pos_t samples)
587 {
588 // --------
589 DBC_REQUIRE(is_selected());
590 // --------
591
592 // FIXME: check whether all audio devices support seeking,
593 // raise an error if not (note: see other similar FIXMEs)
594
595 if (connected_chainsetup() == selected_chainsetup() && is_engine_ready_for_commands() == true) {
596 change_chainsetup_position(static_cast<double>(samples) /
597 selected_chainsetup_repp->samples_per_second());
598 }
599 else {
600 selected_chainsetup_repp->seek_position_in_samples(selected_chainsetup_repp->position_in_samples()
601 + samples );
602 }
603 }
604
605 /**
606 * Sets the chainsetup position. Behaves differently depending on
607 * whether the selected chainsetup is connected or not.
608 *
609 * require:
610 * is_selected() == true
611 */
set_chainsetup_position(double seconds)612 void ECA_CONTROL::set_chainsetup_position(double seconds)
613 {
614 // --------
615 DBC_REQUIRE(is_selected());
616 // --------
617
618 // FIXME: check whether all audio devices support seeking,
619 // raise an error if not (note: see other similar FIXMEs)
620
621 if (connected_chainsetup() == selected_chainsetup() && is_engine_ready_for_commands() == true) {
622 engine_repp->command(ECA_ENGINE::ep_setpos, seconds);
623 }
624 else {
625 selected_chainsetup_repp->seek_position_in_seconds(seconds);
626 }
627 }
628
629 /**
630 * Sets the chainsetup position in samples.. Behaves
631 * differently depending on whether the selected chainsetup
632 * is connected or not.
633 *
634 * require:
635 * is_selected() == true
636 */
set_chainsetup_position_samples(SAMPLE_SPECS::sample_pos_t samples)637 void ECA_CONTROL::set_chainsetup_position_samples(SAMPLE_SPECS::sample_pos_t samples)
638 {
639 // --------
640 DBC_REQUIRE(is_selected());
641 // --------
642
643 // FIXME: check whether all audio devices support seeking,
644 // raise an error if not (note: see other similar FIXMEs)
645
646 if (connected_chainsetup() == selected_chainsetup() && is_engine_ready_for_commands() == true) {
647 set_chainsetup_position(static_cast<double>(samples) /
648 selected_chainsetup_repp->samples_per_second());
649 }
650 else {
651 selected_chainsetup_repp->seek_position_in_samples(samples);
652 }
653 }
654
655 /**
656 * Gets a vector of al chainsetup names.
657 */
chainsetup_names(void) const658 std::vector<string> ECA_CONTROL::chainsetup_names(void) const
659 {
660 return session_repp->chainsetup_names();
661 }
662
663 /**
664 * Gets a pointer to selected chainsetup, or 0 if no
665 * chainsetup is selected.
666 */
get_chainsetup(void) const667 const ECA_CHAINSETUP* ECA_CONTROL::get_chainsetup(void) const
668 {
669 return selected_chainsetup_repp;
670 }
671
672 /**
673 * Gets a pointer to connected chainsetup, or 0 if no
674 * chainsetup is selected.
675 */
get_connected_chainsetup(void) const676 const ECA_CHAINSETUP* ECA_CONTROL::get_connected_chainsetup(void) const
677 {
678 return session_repp->connected_chainsetup_repp;
679 }
680
681 /**
682 * Gets a pointer to chainsetup with filename 'filename'.
683 */
get_chainsetup_filename(const string & filename) const684 const ECA_CHAINSETUP* ECA_CONTROL::get_chainsetup_filename(const string&
685 filename) const
686 {
687 std::vector<ECA_CHAINSETUP*>::const_iterator p = session_repp->chainsetups_rep.begin();
688 while(p != session_repp->chainsetups_rep.end()) {
689 if ((*p)->filename() == filename) {
690 return (*p);
691 }
692 ++p;
693 }
694 return 0;
695 }
696
697 /**
698 * Returns current buffersize of selected chainsetup.
699 *
700 * �pre is_selected() == true
701 */
chainsetup_buffersize(void) const702 int ECA_CONTROL::chainsetup_buffersize(void) const
703 {
704 // --------
705 DBC_REQUIRE(is_selected() == true);
706 // --------
707 return selected_chainsetup_repp->buffersize();
708 }
709
710 /**
711 * Gets chainsetup filename (used by save_chainsetup())
712 *
713 * �pre is_selected() == true
714 */
chainsetup_filename(void) const715 const string& ECA_CONTROL::chainsetup_filename(void) const
716 {
717 // --------
718 DBC_REQUIRE(is_selected() == true);
719 // --------
720 return selected_chainsetup_repp->filename();
721 }
722
723 /**
724 * Sets chainsetup filename (used by save_chainsetup())
725 *
726 * require:
727 * is_selected() == true &&
728 * name.empty() != true
729 */
set_chainsetup_filename(const string & name)730 void ECA_CONTROL::set_chainsetup_filename(const string& name)
731 {
732 // --------
733 DBC_REQUIRE(is_selected() == true);
734 DBC_REQUIRE(name.empty() != true);
735 // --------
736 selected_chainsetup_repp->set_filename(name);
737 }
738
739 /**
740 * Sets general chainsetup chainsetup parameter
741 *
742 * require:
743 * is_selected() == true &&
744 * name.empty() != true
745 */
set_chainsetup_parameter(const string & name)746 void ECA_CONTROL::set_chainsetup_parameter(const string& name)
747 {
748 // --------
749 DBC_REQUIRE(is_selected() == true &&
750 name.empty() != true);
751 // --------
752
753 selected_chainsetup_repp->interpret_global_option(name);
754 if (selected_chainsetup_repp->interpret_result() != true) {
755 /* for instance -f:xxx options are handle by
756 * object-specific parsing */
757 selected_chainsetup_repp->interpret_object_option(name);
758 }
759 }
760
761 /**
762 * Sets general chainsetup chainsetup parameter
763 *
764 * require:
765 * is_selected() == true &&
766 * name.empty() != true
767 */
set_chainsetup_sample_format(const string & name)768 void ECA_CONTROL::set_chainsetup_sample_format(const string& name)
769 {
770 // --------
771 DBC_REQUIRE(is_selected() == true &&
772 name.empty() != true);
773 // --------
774
775 selected_chainsetup_repp->interpret_object_option("-f:" + name);
776 if (selected_chainsetup_repp->interpret_result() != true) {
777 set_last_error(selected_chainsetup_repp->interpret_result_verbose());
778 }
779 }
780
781 /**
782 * Adds a new chain (selected chainsetup). Added chain is automatically
783 * selected.
784 *
785 * require:
786 * is_selected() == true
787 * connected_chainsetup() != selected_chainsetup()
788 *
789 * ensure:
790 * selected_chains().size() > 0
791 */
add_chain(const string & name)792 void ECA_CONTROL::add_chain(const string& name)
793 {
794 // --------
795 DBC_REQUIRE(is_selected() == true);
796 DBC_REQUIRE(selected_chainsetup() != connected_chainsetup());
797 // --------
798
799 add_chains(std::vector<string> (1, name));
800
801 // --------
802 DBC_ENSURE(selected_chains().size() > 0);
803 // --------
804 }
805
806 /**
807 * Adds new chains (selected chainsetup). Added chains are automatically
808 * selected.
809 *
810 * @param names comma separated list of chain names
811 *
812 * require:
813 * is_selected() == true
814 * connected_chainsetup() != selected_chainsetup()
815 *
816 * ensure:
817 * selected_chains().size() > 0
818 */
add_chains(const string & names)819 void ECA_CONTROL::add_chains(const string& names)
820 {
821 // --------
822 DBC_REQUIRE(is_selected() == true &&
823 (session_repp->connected_chainsetup_repp !=
824 session_repp->selected_chainsetup_repp));
825 // --------
826
827 add_chains(kvu_string_to_vector(names, ','));
828
829 // --------
830 DBC_ENSURE(selected_chains().size() > 0);
831 // --------
832 }
833
834 /**
835 * Adds new chains (selected chainsetup). Added chains are automatically
836 * selected.
837 *
838 * @param namess vector of chain names
839 *
840 * require:
841 * is_selected() == true
842 * connected_chainsetup() != selected_chainsetup()
843 *
844 * ensure:
845 * selected_chains().size() == names.size()
846 */
add_chains(const std::vector<string> & new_chains)847 void ECA_CONTROL::add_chains(const std::vector<string>& new_chains)
848 {
849 // --------
850 DBC_REQUIRE(is_selected() == true);
851 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
852 // --------
853
854 selected_chainsetup_repp->add_new_chains(new_chains);
855 selected_chainsetup_repp->select_chains(new_chains);
856
857 ECA_LOG_MSG(ECA_LOGGER::info, "Added chains: " + kvu_vector_to_string(new_chains, ", ") + ".");
858
859 // --------
860 DBC_ENSURE(selected_chains().size() == new_chains.size());
861 // --------
862 }
863
864 /**
865 * Removes currently selected chain (selected chainsetup)
866 *
867 * require:
868 * is_selected() == true
869 * connected_chainsetup() != selected_chainsetup()
870 * selected_chains().size() > 0 &&
871 *
872 * ensure:
873 * selected_chains().size() == 0
874 */
remove_chains(void)875 void ECA_CONTROL::remove_chains(void)
876 {
877 // --------
878 DBC_REQUIRE(is_selected() == true &&
879 selected_chains().size() > 0 &&
880 (session_repp->connected_chainsetup_repp !=
881 session_repp->selected_chainsetup_repp));
882 // --------
883
884 selected_chainsetup_repp->remove_chains();
885
886 ECA_LOG_MSG(ECA_LOGGER::info, "(eca-controlled) Removed selected chains.");
887
888 // --------
889 DBC_ENSURE(selected_chains().size() == 0);
890 // --------
891 }
892
893 /**
894 * Selects a set of chains using index numbers. Previously
895 * selected chains are first all deselected.
896 *
897 *
898 * @param index_numbers set of integer identifiers
899 *
900 * require:
901 * is_selected() == true
902 */
select_chains_by_index(const std::vector<int> & index_numbers)903 void ECA_CONTROL::select_chains_by_index(const std::vector<int>& index_numbers)
904 {
905 // --------
906 DBC_REQUIRE(is_selected() == true);
907 // --------
908
909 std::vector<string> selchains;
910 for(std::vector<CHAIN*>::size_type p = 0;
911 p != selected_chainsetup_repp->chains.size();
912 p++) {
913 for(std::vector<int>::size_type q = 0;
914 q != index_numbers.size();
915 q++) {
916 if (index_numbers[q] == static_cast<int>(p + 1)) {
917 selchains.push_back(selected_chainsetup_repp->chains[p]->name());
918 break;
919 }
920 }
921 }
922 select_chains(selchains);
923 }
924
925 /**
926 * Selects a chains (currently selected chainsetup). Previously
927 * selected chains are first all deselected.
928 *
929 * require:
930 * is_selected() == true
931 *
932 * ensure:
933 * selected_chains().size() == 1
934 */
select_chain(const string & chain)935 void ECA_CONTROL::select_chain(const string& chain)
936 {
937 // --------
938 DBC_REQUIRE(is_selected() == true);
939 // --------
940
941 std::vector<string> c (1);
942 c[0] = chain;
943 selected_chainsetup_repp->select_chains(c);
944 // ECA_LOG_MSG(ECA_LOGGER::user_objects, "Selected chain: " + chain + ".");
945
946 // --------
947 DBC_ENSURE(selected_chains().size() == 1);
948 // --------
949 }
950
951
952 /**
953 * Selects chains (currently selected chainsetup). Previously
954 * selected chains are first all deselected.
955 *
956 * @param chains vector of chain names
957 *
958 * require:
959 * is_selected() == true
960 *
961 * ensure:
962 * selected_chains().size() > 0
963 */
select_chains(const std::vector<string> & chains)964 void ECA_CONTROL::select_chains(const std::vector<string>& chains)
965 {
966 // --------
967 DBC_REQUIRE(is_selected() == true);
968 // --------
969
970 selected_chainsetup_repp->select_chains(chains);
971
972 // ECA_LOG_MSG(ECA_LOGGER::user_objects, "Selected chains: " +
973 // vector_to_string(chains, ", ") + ".");
974 }
975
976 /**
977 * Deselects chains (currently selected chainsetup)
978 *
979 * @param chains vector of chain names
980 *
981 * require:
982 * is_selected() == true
983 */
deselect_chains(const std::vector<string> & chains)984 void ECA_CONTROL::deselect_chains(const std::vector<string>& chains)
985 {
986 // --------
987 DBC_REQUIRE(is_selected() == true);
988 // --------
989
990 std::vector<string> schains = selected_chainsetup_repp->selected_chains();
991 std::vector<string>::const_iterator p = chains.begin();
992 while(p != chains.end()) {
993 std::vector<string>::iterator o = schains.begin();
994 while(o != schains.end()) {
995 if (*p == *o) {
996 // ECA_LOG_MSG(ECA_LOGGER::info, "(eca-controller-objects) Deselected chain " + *o + ".");
997 schains.erase(o);
998 }
999 else
1000 ++o;
1001 }
1002 ++p;
1003 }
1004
1005 selected_chainsetup_repp->select_chains(schains);
1006 }
1007
1008 /**
1009 * Selects all chains (currently selected chainsetup)
1010 *
1011 * require:
1012 * is_selected() == true
1013 */
select_all_chains(void)1014 void ECA_CONTROL::select_all_chains(void)
1015 {
1016 // --------
1017 DBC_REQUIRE(is_selected() == true);
1018 // --------
1019
1020 selected_chainsetup_repp->select_all_chains();
1021
1022 // ECA_LOG_MSG(ECA_LOGGER::info, "Selected chains: " + vector_to_string(selected_chains(), ", ") + ".");
1023 }
1024
1025 /**
1026 * Returns a list of selected chains (currently selected chainsetup)
1027 *
1028 * require:
1029 * is_selected() == true
1030 */
selected_chains(void) const1031 const std::vector<string>& ECA_CONTROL::selected_chains(void) const
1032 {
1033 // --------
1034 DBC_REQUIRE(is_selected() == true);
1035 // --------
1036 return selected_chainsetup_repp->selected_chains();
1037 }
1038
1039 /**
1040 * Gets a vector of all chain names.
1041 *
1042 * require:
1043 * is_selected() == true
1044 */
chain_names(void) const1045 std::vector<string> ECA_CONTROL::chain_names(void) const
1046 {
1047 // --------
1048 DBC_REQUIRE(is_selected() == true);
1049 // --------
1050 return selected_chainsetup_repp->chain_names();
1051 }
1052
1053 /**
1054 * Gets a pointer to selected chain, or 0 if no chain is selected.
1055 *
1056 * require:
1057 * is_selected() == true
1058 * selected_chains().size() == 1
1059 */
get_chain(void) const1060 const CHAIN* ECA_CONTROL::get_chain(void) const
1061 {
1062 // --------
1063 DBC_REQUIRE(is_selected() == true);
1064 DBC_REQUIRE(selected_chains().size() == 1);
1065 // --------
1066 return get_chain_priv();
1067
1068 }
1069
1070 /**
1071 * Gets a pointer to selected chain, or 0 if no chain is selected.
1072 */
get_chain_priv(void) const1073 CHAIN* ECA_CONTROL::get_chain_priv(void) const
1074 {
1075 const std::vector<string>& schains = selected_chainsetup_repp->selected_chains();
1076 std::vector<string>::const_iterator o = schains.begin();
1077 while(o != schains.end()) {
1078 for(std::vector<CHAIN*>::size_type p = 0;
1079 p != selected_chainsetup_repp->chains.size();
1080 p++) {
1081 if (selected_chainsetup_repp->chains[p]->name() == *o)
1082 return selected_chainsetup_repp->chains[p];
1083 }
1084 ++o;
1085 }
1086 return 0;
1087 }
1088
1089 /**
1090 * Clears all selected chains (all chain operators and controllers
1091 * are removed)
1092 *
1093 * @param name chain name
1094 *
1095 * require:
1096 * is_selected() == true
1097 * is_running() != true
1098 */
clear_chains(void)1099 void ECA_CONTROL::clear_chains(void)
1100 {
1101 // --------
1102 DBC_REQUIRE(is_selected() == true);
1103 DBC_REQUIRE(is_running() != true);
1104 // --------
1105 selected_chainsetup_repp->clear_chains();
1106 }
1107
1108 /**
1109 * Clears all selected chains (all chain operators and controllers
1110 * are removed)
1111 *
1112 * @param name chain name
1113 *
1114 * require:
1115 * is_selected() == true
1116 * connected_chainsetup() != selected_chainsetup()
1117 * selected_chains().size() == 1
1118 */
rename_chain(const string & name)1119 void ECA_CONTROL::rename_chain(const string& name)
1120 {
1121 // --------
1122 DBC_REQUIRE(is_selected() == true);
1123 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1124 DBC_REQUIRE(selected_chains().size() == 1);
1125 // --------
1126 selected_chainsetup_repp->rename_chain(name);
1127 }
1128
audio_input_as_selected(void)1129 void ECA_CONTROL::audio_input_as_selected(void)
1130 {
1131 /* note, here we check that the pointer is still a valid one */
1132 if (selected_chainsetup_repp->ok_audio_object(selected_audio_input_repp) != true)
1133 selected_audio_input_repp = 0;
1134
1135 selected_audio_object_repp = selected_audio_input_repp;
1136 }
1137
audio_output_as_selected(void)1138 void ECA_CONTROL::audio_output_as_selected(void)
1139 {
1140 /* note, here we check that the pointer is still a valid one */
1141 if (selected_chainsetup_repp->ok_audio_object(selected_audio_output_repp) != true)
1142 selected_audio_output_repp = 0;
1143
1144 selected_audio_object_repp = selected_audio_output_repp;
1145 }
1146
1147 /**
1148 * Sets default audio format. This format will be used, when
1149 * adding audio inputs and outputs.
1150 *
1151 * require:
1152 * is_selected() == true
1153 */
set_default_audio_format(const string & sfrm,int channels,long int srate,bool interleaving)1154 void ECA_CONTROL::set_default_audio_format(const string& sfrm,
1155 int channels,
1156 long int srate,
1157 bool interleaving)
1158 {
1159 // --------
1160 DBC_REQUIRE(is_selected() == true);
1161 // --------
1162
1163 string format;
1164 format = "-f:";
1165 format += sfrm;
1166 format += ",";
1167 format += kvu_numtostr(channels);
1168 format += ",";
1169 format += kvu_numtostr(srate);
1170 format += ",";
1171 if (interleaving == true)
1172 format += "i";
1173 else
1174 format += "n";
1175
1176 selected_chainsetup_repp->interpret_object_option(format);
1177 if (selected_chainsetup_repp->interpret_result() != true) {
1178 set_last_error(selected_chainsetup_repp->interpret_result_verbose());
1179 }
1180 }
1181
1182 /**
1183 * Returns the default audio format.
1184 *
1185 * @pre is_selected() == true
1186 */
default_audio_format(void) const1187 const ECA_AUDIO_FORMAT& ECA_CONTROL::default_audio_format(void) const
1188 {
1189 // --
1190 DBC_REQUIRE(is_selected() == true);
1191 // --
1192 return selected_chainsetup_repp->default_audio_format();
1193 }
1194
1195 /**
1196 * Sets default audio format. This format will be used, when
1197 * adding audio inputs and outputs.
1198 *
1199 * require:
1200 * is_selected() == true
1201 */
set_default_audio_format(const ECA_AUDIO_FORMAT & format)1202 void ECA_CONTROL::set_default_audio_format(const ECA_AUDIO_FORMAT& format)
1203 {
1204 // --------
1205 DBC_REQUIRE(is_selected() == true);
1206 // --------
1207
1208 set_default_audio_format(format.format_string(),
1209 static_cast<int>(format.channels()),
1210 static_cast<long int>(format.samples_per_second()),
1211 format.interleaved_channels());
1212 }
1213
priv_select_audio_object(const std::vector<AUDIO_IO * > & objects,const std::string & name)1214 static AUDIO_IO* priv_select_audio_object(const std::vector<AUDIO_IO*>& objects, const std::string& name)
1215 {
1216 AUDIO_IO* result = 0;
1217
1218 /* NOTE: ugly, but needed to maintain compability with older 2.4.x
1219 * releases that allowed double-quoted filenames to ai/ao-select */
1220 std::string stripped_name;
1221 if (name.size() > 0 &&
1222 name[0] == '"') {
1223 stripped_name = name;
1224 kvu_string_strip_outer_quotes(&stripped_name, '"');
1225 }
1226
1227 std::vector<AUDIO_IO*>::size_type p = 0;
1228 for(p = 0; p != objects.size(); p++) {
1229 if (objects[p]->label() == name ||
1230 objects[p]->label() == stripped_name) {
1231 result = objects[p];
1232 /* note: in case 'name' is not unique, the first matching
1233 * instance is selected */
1234 break;
1235 }
1236 }
1237
1238 return result;
1239 }
1240
1241 /**
1242 * Selects an audio input
1243 *
1244 * require:
1245 * is_selected() == true
1246 */
select_audio_input(const string & name)1247 void ECA_CONTROL::select_audio_input(const string& name)
1248 {
1249 // --------
1250 DBC_REQUIRE(is_selected() == true);
1251 // --------
1252
1253 selected_audio_input_repp =
1254 priv_select_audio_object(selected_chainsetup_repp->inputs, name);
1255 }
1256
1257 /**
1258 * Selects an audio output
1259 *
1260 * require:
1261 * is_selected() == true
1262 */
select_audio_output(const string & name)1263 void ECA_CONTROL::select_audio_output(const string& name)
1264 {
1265 // --------
1266 DBC_REQUIRE(is_selected() == true);
1267 // --------
1268
1269 selected_audio_output_repp =
1270 priv_select_audio_object(selected_chainsetup_repp->outputs, name);
1271 }
1272
1273 /**
1274 * Selects an audio input by index.
1275 *
1276 * @pre is_selected() == true
1277 * @pre index_number > 0
1278 */
select_audio_input_by_index(int index_number)1279 void ECA_CONTROL::select_audio_input_by_index(int index_number)
1280 {
1281 // --------
1282 DBC_REQUIRE(is_selected() == true);
1283 DBC_REQUIRE(index_number > 0);
1284 // --------
1285
1286 selected_audio_input_repp = 0;
1287
1288 if (index_number <= static_cast<int>(selected_chainsetup_repp->inputs.size()))
1289 selected_audio_input_repp = selected_chainsetup_repp->inputs[index_number-1];
1290 }
1291
1292 /**
1293 * Selects an audio output by index.
1294 *
1295 * @pre is_selected() == true
1296 * @pre index_number > 0
1297 */
select_audio_output_by_index(int index_number)1298 void ECA_CONTROL::select_audio_output_by_index(int index_number)
1299 {
1300 // --------
1301 DBC_REQUIRE(is_selected() == true);
1302 DBC_REQUIRE(index_number > 0);
1303 // --------
1304
1305 selected_audio_output_repp = 0;
1306
1307 if (index_number <= static_cast<int>(selected_chainsetup_repp->outputs.size()))
1308 selected_audio_output_repp = selected_chainsetup_repp->outputs[index_number-1];
1309 }
1310
1311 /**
1312 * Gets audio format information of the object given as argument.
1313 * Note! To get audio format information, audio objects need
1314 * to be opened. Because of this, object argument cannot be given
1315 * as a const pointer.
1316 */
get_audio_format(AUDIO_IO * aobj) const1317 ECA_AUDIO_FORMAT ECA_CONTROL::get_audio_format(AUDIO_IO* aobj) const
1318 {
1319 // --------
1320 DBC_REQUIRE(is_selected() == true);
1321 DBC_REQUIRE(aobj != 0);
1322 // --------
1323
1324 bool was_open = true;
1325 if (aobj->is_open() == false) {
1326 was_open = false;
1327 try {
1328 aobj->open();
1329 }
1330 catch(AUDIO_IO::SETUP_ERROR&) {
1331 // FIXME: what to do here?
1332 }
1333 }
1334 ECA_AUDIO_FORMAT t (aobj->channels(),
1335 aobj->samples_per_second(),
1336 aobj->sample_format(),
1337 aobj->interleaved_channels());
1338 if (was_open == false) aobj->close();
1339 return t;
1340 }
1341
1342 /**
1343 * Sets the default audio format to the match the currently
1344 * select audio input's audio format.
1345 *
1346 * @pre is_selected() == true
1347 * @pre connected_chainsetup() != selected_chainsetup()
1348 * @pre selected_audio_object_repp != 0
1349 */
set_default_audio_format_to_selected_input(void)1350 void ECA_CONTROL::set_default_audio_format_to_selected_input(void)
1351 {
1352 // --------
1353 DBC_REQUIRE(is_selected() == true);
1354 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1355 DBC_REQUIRE(get_audio_input() != 0);
1356 // --------
1357 set_default_audio_format(get_audio_format(selected_audio_input_repp));
1358
1359 }
1360
1361 /**
1362 * Sets the default audio format to the match the currently
1363 * select audio output's audio format.
1364 *
1365 * @pre is_selected() == true
1366 * @pre connected_chainsetup() != selected_chainsetup()
1367 * @pre selected_audio_object_repp != 0
1368 */
set_default_audio_format_to_selected_output(void)1369 void ECA_CONTROL::set_default_audio_format_to_selected_output(void)
1370 {
1371 // --------
1372 DBC_REQUIRE(is_selected() == true);
1373 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1374 DBC_REQUIRE(get_audio_output() != 0);
1375 // --------
1376 set_default_audio_format(get_audio_format(selected_audio_output_repp));
1377 }
1378
1379 /**
1380 * Adds a new audio input (file, soundcard device, etc). Input
1381 * is attached to currently selected chains (if any). If 'filename'
1382 * doesn't exist or is otherwise invalid, no input is added.
1383 *
1384 * require:
1385 * filename.empty() == false
1386 * is_selected() == true
1387 * connected_chainsetup() != selected_chainsetup()
1388 */
add_audio_input(const string & filename)1389 void ECA_CONTROL::add_audio_input(const string& filename)
1390 {
1391 // --------
1392 DBC_REQUIRE(filename.empty() == false);
1393 DBC_REQUIRE(is_selected() == true);
1394 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1395 // --------
1396
1397 selected_audio_input_repp = 0;
1398 selected_chainsetup_repp->interpret_object_option("-i:" + filename);
1399 if (selected_chainsetup_repp->interpret_result() == true) {
1400 select_audio_input(kvu_get_argument_number(1, filename));
1401 ECA_LOG_MSG(ECA_LOGGER::info, "Added audio input \"" + filename + "\".");
1402 }
1403 else {
1404 set_last_error(selected_chainsetup_repp->interpret_result_verbose());
1405 }
1406 }
1407
1408 /**
1409 * Adds a new audio output (file, soundcard device, etc). Output
1410 * is attached to currently selected chains (if any). If 'filename'
1411 * doesn't exist or is otherwise invalid, no input is added.
1412 *
1413 * require:
1414 * filename.empty() == false
1415 * is_selected() == true
1416 * connected_chainsetup() != selected_chainsetup()
1417 */
add_audio_output(const string & filename)1418 void ECA_CONTROL::add_audio_output(const string& filename)
1419 {
1420 // --------
1421 DBC_REQUIRE(filename.empty() == false);
1422 DBC_REQUIRE(is_selected() == true);
1423 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1424 // --------
1425
1426 selected_audio_output_repp = 0;
1427 selected_chainsetup_repp->interpret_object_option("-o:" + filename);
1428 if (selected_chainsetup_repp->interpret_result() == true) {
1429 select_audio_output(kvu_get_argument_number(1, filename));
1430 ECA_LOG_MSG(ECA_LOGGER::info, "Added audio output \"" + filename +
1431 "\".");
1432 } else {
1433 set_last_error(selected_chainsetup_repp->interpret_result_verbose());
1434 }
1435 }
1436
1437 /**
1438 * Adds a default output (as defined in ~/.ecasoundrc) and attach
1439 * it to currently selected chains.
1440 *
1441 * require:
1442 * is_selected() == true
1443 * connected_chainsetup() != selected_chainsetup()
1444 */
add_default_output(void)1445 void ECA_CONTROL::add_default_output(void)
1446 {
1447 // --------
1448 DBC_REQUIRE(selected_chains().size() > 0);
1449 DBC_REQUIRE(is_selected() == true);
1450 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1451 // --------
1452 add_audio_output(ECA_OBJECT_FACTORY::probe_default_output_device());
1453 ECA_LOG_MSG(ECA_LOGGER::info, "Added default output to selected chains.");
1454 }
1455
1456 /**
1457 * Gets a vector of all audio input names.
1458 *
1459 * require:
1460 * is_selected() == true
1461 */
audio_input_names(void) const1462 std::vector<string> ECA_CONTROL::audio_input_names(void) const
1463 {
1464 // --------
1465 DBC_REQUIRE(is_selected() == true);
1466 // --------
1467 return selected_chainsetup_repp->audio_input_names();
1468 }
1469
1470 /**
1471 * Gets a vector of all audio output names.
1472 *
1473 * require:
1474 * is_selected() == true
1475 */
audio_output_names(void) const1476 std::vector<string> ECA_CONTROL::audio_output_names(void) const
1477 {
1478 // --------
1479 DBC_REQUIRE(is_selected() == true);
1480 // --------
1481 return selected_chainsetup_repp->audio_output_names();
1482 }
1483
1484 /**
1485 * Gets a pointer to the currently selected audio input.
1486 * Returns 0 if no audio object is selected.
1487 *
1488 * require:
1489 * is_selected() == true
1490 */
get_audio_input(void)1491 const AUDIO_IO* ECA_CONTROL::get_audio_input(void)
1492 {
1493 // --------
1494 DBC_REQUIRE(is_selected() == true);
1495 // --------
1496
1497 /* note, here we check that the pointer is still a valid one */
1498 if (selected_chainsetup_repp->ok_audio_object(selected_audio_input_repp) != true)
1499 selected_audio_input_repp = 0;
1500
1501 return selected_audio_input_repp;
1502 }
1503
1504 /**
1505 * Gets a pointer to the currently selected audio output.
1506 * Returns 0 if no audio object is selected.
1507 *
1508 * require:
1509 * is_selected() == true
1510 */
get_audio_output(void)1511 const AUDIO_IO* ECA_CONTROL::get_audio_output(void)
1512 {
1513 // --------
1514 DBC_REQUIRE(is_selected() == true);
1515 // --------
1516 /* note, here we check that the pointer is still a valid one */
1517 if (selected_chainsetup_repp->ok_audio_object(selected_audio_output_repp) != true)
1518 selected_audio_output_repp = 0;
1519
1520 return selected_audio_output_repp;
1521 }
1522
1523 /**
1524 * Removes the selected audio input.
1525 *
1526 * @pre is_selected() == true
1527 * @pre connected_chainsetup() != selected_chainsetup()
1528 * @pre get_audio_input() != 0
1529 *
1530 * @post selected_audio_input_repp = 0
1531 */
remove_audio_input(void)1532 void ECA_CONTROL::remove_audio_input(void)
1533 {
1534 // --------
1535 DBC_REQUIRE(is_selected() == true);
1536 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1537 DBC_REQUIRE(get_audio_input() != 0);
1538 // --------
1539 ECA_LOG_MSG(ECA_LOGGER::info, "Removing selected audio input \"" + selected_audio_input_repp->label() +
1540 "\" from selected chains.");
1541 selected_chainsetup_repp->remove_audio_input(selected_audio_input_repp);
1542 selected_audio_input_repp = 0;
1543
1544 // --------
1545 DBC_ENSURE(selected_audio_input_repp == 0);
1546 // --------
1547 }
1548
1549 /**
1550 * Removes the selected audio output.
1551 *
1552 * @pre is_selected() == true
1553 * @pre connected_chainsetup() != selected_chainsetup()
1554 * @pre get_audio_output() != 0
1555 *
1556 * @post selected_audio_output_repp = 0
1557 */
remove_audio_output(void)1558 void ECA_CONTROL::remove_audio_output(void)
1559 {
1560 // --------
1561 DBC_REQUIRE(is_selected() == true);
1562 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1563 DBC_REQUIRE(get_audio_output() != 0);
1564 // --------
1565 ECA_LOG_MSG(ECA_LOGGER::info, "Removing selected audio output \"" + selected_audio_output_repp->label() +
1566 "\" from selected chains.");
1567 selected_chainsetup_repp->remove_audio_output(selected_audio_output_repp);
1568 selected_audio_output_repp = 0;
1569
1570 // --------
1571 DBC_ENSURE(selected_audio_output_repp == 0);
1572 // --------
1573 }
1574
1575 /**
1576 * Attaches selected audio input to selected chains
1577 *
1578 * @pre is_selected() == true
1579 * @pre connected_chainsetup() != selected_chainsetup()
1580 * @pre get_audio_input() != 0
1581 */
attach_audio_input(void)1582 void ECA_CONTROL::attach_audio_input(void)
1583 {
1584 // --------
1585 DBC_REQUIRE(is_selected() == true);
1586 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1587 DBC_REQUIRE(get_audio_input() != 0);
1588 // --------
1589 selected_chainsetup_repp->attach_input_to_selected_chains(selected_audio_input_repp);
1590
1591 ECA_LOG_MSG(ECA_LOGGER::info, "Attached audio input \"" + selected_audio_input_repp->label() +
1592 "\" to selected chains.");
1593 }
1594
1595 /**
1596 * Attaches selected audio output to selected chains
1597 *
1598 * @pre is_selected() == true
1599 * @pre connected_chainsetup() != selected_chainsetup()
1600 * @pre get_audio_output() != 0
1601 */
attach_audio_output(void)1602 void ECA_CONTROL::attach_audio_output(void)
1603 {
1604 // --------
1605 DBC_REQUIRE(is_selected() == true);
1606 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1607 DBC_REQUIRE(get_audio_output() != 0);
1608 // --------
1609 selected_chainsetup_repp->attach_output_to_selected_chains(selected_audio_output_repp);
1610
1611 ECA_LOG_MSG(ECA_LOGGER::info, "Attached audio output \"" + selected_audio_output_repp->label() +
1612 "\" to selected chains.");
1613 }
1614
1615 /**
1616 * Get a string containing a comma separated list of all chains
1617 * attached to input with index 'aiod'.
1618 *
1619 * @pre is_selected() == true
1620 */
attached_chains_input(AUDIO_IO * aiod) const1621 string ECA_CONTROL::attached_chains_input(AUDIO_IO* aiod) const
1622 {
1623 // --------
1624 DBC_REQUIRE(is_selected() == true);
1625 // --------
1626
1627 vector<string> t = selected_chainsetup_repp->get_attached_chains_to_input(aiod);
1628 string out = "";
1629 vector<string>::const_iterator p = t.begin();
1630 while(p != t.end()) {
1631 out += *p;
1632 ++p;
1633 if (p != t.end()) out += ",";
1634 }
1635 return out;
1636 }
1637
1638 /**
1639 * Get a string containing a comma separated list of all chains
1640 * attached to output with index 'aiod'.
1641 *
1642 * @pre is_selected() == true
1643 */
attached_chains_output(AUDIO_IO * aiod) const1644 string ECA_CONTROL::attached_chains_output(AUDIO_IO* aiod) const
1645 {
1646 // --------
1647 DBC_REQUIRE(is_selected() == true);
1648 // --------
1649
1650 vector<string> t = selected_chainsetup_repp->get_attached_chains_to_output(aiod);
1651 string out = "";
1652 vector<string>::const_iterator p = t.begin();
1653 while(p != t.end()) {
1654 out += *p;
1655 ++p;
1656 if (p != t.end()) out += ",";
1657 }
1658 return out;
1659 }
1660
1661 /**
1662 * Get a string containing a comma separated list of all chains
1663 * attached to audio object with name 'filename'.
1664 *
1665 * @pre is_selected() == true
1666 */
attached_chains(const string & filename) const1667 vector<string> ECA_CONTROL::attached_chains(const string& filename) const
1668 {
1669 // --------
1670 DBC_REQUIRE(is_selected() == true);
1671 // --------
1672
1673 return selected_chainsetup_repp->get_attached_chains_to_iodev(filename);
1674 }
1675
1676 /**
1677 * Rewinds selected audio object by 'pos_in_seconds' seconds
1678 *
1679 * @pre is_selected() == true
1680 * @pre connected_chainsetup() != selected_chainsetup()
1681 * @pre selected_audio_object_repp != 0
1682 */
rewind_audio_object(double seconds)1683 void ECA_CONTROL::rewind_audio_object(double seconds)
1684 {
1685 // --------
1686 DBC_REQUIRE(is_selected() == true);
1687 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1688 DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
1689 // --------
1690 selected_audio_object_repp->seek_position_in_seconds(selected_audio_object_repp->position_in_seconds_exact() - seconds);
1691 }
1692
1693 /**
1694 * Forwards selected audio object by 'pos_in_seconds' seconds
1695 *
1696 * @pre is_selected() == true
1697 * @pre connected_chainsetup() != selected_chainsetup()
1698 * @pre selected_audio_object_repp != 0
1699 */
forward_audio_object(double seconds)1700 void ECA_CONTROL::forward_audio_object(double seconds)
1701 {
1702 // --------
1703 DBC_REQUIRE(is_selected() == true);
1704 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1705 DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
1706 // --------
1707 selected_audio_object_repp->seek_position_in_seconds(selected_audio_object_repp->position_in_seconds_exact() + seconds);
1708 }
1709
1710 /**
1711 * Sets position of selected audio object
1712 *
1713 * require:
1714 * is_selected() == true
1715 * connected_chainsetup() != selected_chainsetup()
1716 * selected_audio_object_repp != 0
1717 */
set_audio_object_position(double seconds)1718 void ECA_CONTROL::set_audio_object_position(double seconds)
1719 {
1720 // --------
1721 DBC_REQUIRE(is_selected() == true);
1722 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1723 DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
1724 // --------
1725 selected_audio_object_repp->seek_position_in_seconds(seconds);
1726 }
1727
1728 /**
1729 * Sets position of selected audio object
1730 *
1731 * @pre is_selected() == true
1732 * @pre connected_chainsetup() != selected_chainsetup()
1733 * @pre selected_audio_object_repp != 0
1734 */
set_audio_object_position_samples(SAMPLE_SPECS::sample_pos_t samples)1735 void ECA_CONTROL::set_audio_object_position_samples(SAMPLE_SPECS::sample_pos_t samples)
1736 {
1737 // --------
1738 DBC_REQUIRE(is_selected() == true);
1739 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1740 DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
1741 // --------
1742 selected_audio_object_repp->seek_position_in_samples(samples);
1743 }
1744
1745
1746 /**
1747 * Spawns an external wave editor for editing selected audio object.
1748 *
1749 * require:
1750 * is_selected()
1751 * connected_chainsetup() != selected_chainsetup()
1752 * selected_audio_object_repp != 0
1753 */
wave_edit_audio_object(void)1754 void ECA_CONTROL::wave_edit_audio_object(void)
1755 {
1756 // --------
1757 DBC_REQUIRE(is_selected() == true);
1758 DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
1759 DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
1760 // --------
1761 string name = selected_audio_object_repp->label();
1762
1763 int res = ::system(string(resource_value("ext-cmd-wave-editor") + " " + name).c_str());
1764 if (res == 127 || res == -1) {
1765 ECA_LOG_MSG(ECA_LOGGER::info, "Can't edit; unable to open wave editor \""
1766 + resource_value("x-wave-editor") + "\".");
1767 }
1768 }
1769
1770 /**
1771 * Adds a new chain operator
1772 *
1773 * @param gcontrol_params is an Ecasound option string describing
1774 * a controlled: syntax is either "-<id_string>:par1,...,parN",
1775 * or just "<id_string>:par1,...,parN"
1776 *
1777 * require:
1778 * is_selected() == true
1779 * selected_chains().size() == 1
1780 */
add_chain_operator(const string & chainop_params)1781 void ECA_CONTROL::add_chain_operator(const string& chainop_params)
1782 {
1783 // --------
1784 DBC_REQUIRE(is_selected() == true);
1785 DBC_REQUIRE(selected_chains().size() == 1);
1786 // --------
1787
1788 ECA::chainsetup_edit_t edit;
1789 edit.type = ECA::edit_cop_add;
1790 edit.cs_ptr = selected_chainsetup_repp;
1791
1792 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1793 if (p < selected_chainsetup_repp->chains.size()) {
1794 /* note: unlike all other functions, first_selected_chain()
1795 * returns 0..N */
1796 edit.m.c_generic_param.chain = p + 1;
1797 edit.param = chainop_params;
1798 edit.need_chain_reinit = true;
1799 execute_edit_on_selected(edit);
1800 }
1801 }
1802
1803 /**
1804 * Adds a new chain operator. Pointer given as argument
1805 * will remain to be usable, but notice that it is
1806 * _NOT_ thread-safe to use assigned/registered objects
1807 * from client programs. You must be sure that ecasound
1808 * isn't using the same object as you are. The
1809 * easiest way to assure this is to disconnect
1810 * the chainsetup to which object is attached.
1811 *
1812 * require:
1813 * is_selected() == true
1814 * connected_chainsetup() != selected_chainsetup()
1815 * selected_chains().size() == 1
1816 * cotmp != 0
1817 */
add_chain_operator(CHAIN_OPERATOR * cotmp)1818 void ECA_CONTROL::add_chain_operator(CHAIN_OPERATOR* cotmp)
1819 {
1820 // --------
1821 DBC_REQUIRE(is_selected() == true);
1822 DBC_REQUIRE(selected_chains().size() == 1);
1823 DBC_REQUIRE(cotmp != 0);
1824 // --------
1825
1826 selected_chainsetup_repp->add_chain_operator(cotmp);
1827 }
1828
1829 /**
1830 * Returns a pointer to the the selected chain operator. If no chain
1831 * operator is selected, 0 is returned.
1832 *
1833 * require:
1834 * is_selected() == true
1835 * selected_chains().size() == 1
1836 */
get_chain_operator(void) const1837 const CHAIN_OPERATOR* ECA_CONTROL::get_chain_operator(void) const
1838 {
1839 // --------
1840 DBC_REQUIRE(is_selected() == true);
1841 DBC_REQUIRE(selected_chains().size() == 1);
1842 // --------
1843
1844 if (is_selected() == true) {
1845 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1846 if (p < selected_chainsetup_repp->chains.size())
1847 return selected_chainsetup_repp->chains[p]->get_selected_chain_operator();
1848 }
1849
1850 return 0;
1851 }
1852
1853 /**
1854 * Returns a list of chain operator names.
1855 *
1856 * require:
1857 * is_selected() == true
1858 * selected_chains().size() == 1
1859 */
chain_operator_names(void) const1860 std::vector<string> ECA_CONTROL::chain_operator_names(void) const
1861 {
1862 // --------
1863 DBC_REQUIRE(is_selected() == true);
1864 DBC_REQUIRE(selected_chains().size() == 1);
1865 // --------
1866
1867 std::vector<string> result;
1868 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1869 if (p < selected_chainsetup_repp->chains.size()) {
1870 CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
1871 int save_selected_cop = selected_chain->selected_chain_operator();
1872 for(int n = 0;
1873 n < selected_chain->number_of_chain_operators();
1874 n++) {
1875 selected_chain->select_chain_operator(n + 1);
1876 result.push_back(selected_chain->chain_operator_name());
1877 }
1878 selected_chain->select_chain_operator(save_selected_cop);
1879 }
1880 return result;
1881 }
1882
1883 /**
1884 * Returns the index of the selected chain operator. If no chain
1885 * operator is selected, -1 is returned.
1886 *
1887 * require:
1888 * is_selected() == true
1889 * selected_chains().size() == 1
1890 */
selected_chain_operator(void) const1891 int ECA_CONTROL::selected_chain_operator(void) const
1892 {
1893 // --------
1894 DBC_REQUIRE(is_selected() == true);
1895 DBC_REQUIRE(selected_chains().size() == 1);
1896 // --------
1897
1898 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1899 if (p < selected_chainsetup_repp->chains.size())
1900 return selected_chainsetup_repp->chains[p]->selected_chain_operator();
1901
1902 return -1;
1903 }
1904
1905 /**
1906 * Removes the selected chain operator
1907 *
1908 * require:
1909 * is_selected() == true
1910 * connected_chainsetup() != selected_chainsetup()
1911 * selected_chains().size() == 1
1912 */
remove_chain_operator(void)1913 void ECA_CONTROL::remove_chain_operator(void)
1914 {
1915 // --------
1916 DBC_REQUIRE(is_selected() == true);
1917 DBC_REQUIRE(selected_chainsetup() != connected_chainsetup());
1918 DBC_REQUIRE(selected_chains().size() == 1);
1919 // --------
1920
1921 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1922 if (p < selected_chainsetup_repp->chains.size())
1923 selected_chainsetup_repp->chains[p]->remove_chain_operator(-1);
1924 }
1925
1926 /**
1927 * Selects chain operator 'chainop_id'.
1928 *
1929 * require:
1930 * is_selected() == true
1931 * selected_chains().size() == 1
1932 * chainop_id > 0
1933 */
select_chain_operator(int chainop_id)1934 void ECA_CONTROL::select_chain_operator(int chainop_id)
1935 {
1936 // --------
1937 DBC_REQUIRE(is_selected() == true);
1938 DBC_REQUIRE(selected_chains().size() == 1);
1939 DBC_REQUIRE(chainop_id > 0);
1940 // --------
1941
1942 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1943 if (p < selected_chainsetup_repp->chains.size()) {
1944 CHAIN *ch = selected_chainsetup_repp->chains[p];
1945 if (chainop_id < ch->number_of_chain_operators() + 1) {
1946 ch->select_chain_operator(chainop_id);
1947 }
1948 }
1949 }
1950
1951 /**
1952 * Returns a list of chain operator parameter names.
1953 *
1954 * require:
1955 * is_selected == true
1956 * selected_chains().size() == 1
1957 */
chain_operator_parameter_names(void) const1958 std::vector<string> ECA_CONTROL::chain_operator_parameter_names(void) const
1959 {
1960 // --------
1961 DBC_REQUIRE(is_selected() == true);
1962 DBC_REQUIRE(selected_chains().size() == 1);
1963 // --------
1964
1965 std::vector<string> result;
1966 unsigned int p = selected_chainsetup_repp->first_selected_chain();
1967 if (p < selected_chainsetup_repp->chains.size()) {
1968 CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
1969
1970 if (selected_chain->selected_chain_operator() > 0) {
1971
1972 int save_selected_copp = selected_chain->selected_chain_operator_parameter();
1973
1974 for(int n = 0;
1975 n < selected_chain->number_of_chain_operator_parameters();
1976 n++) {
1977 selected_chain->select_chain_operator_parameter(n + 1);
1978 result.push_back(selected_chain->chain_operator_parameter_name());
1979 }
1980
1981 selected_chain->select_chain_operator_parameter(save_selected_copp);
1982 }
1983 }
1984 return result;
1985 }
1986
1987 /**
1988 * Selects chain operator parameter 'param'.
1989 *
1990 * require:
1991 * is_selected() == true
1992 * selected_chains().size() == 1
1993 * get_chain_operator() != 0
1994 * param > 0
1995 */
select_chain_operator_parameter(int param)1996 void ECA_CONTROL::select_chain_operator_parameter(int param)
1997 {
1998 // --------
1999 DBC_REQUIRE(is_selected() == true);
2000 DBC_REQUIRE(selected_chains().size() == 1);
2001 DBC_REQUIRE(param > 0);
2002 // --------
2003
2004 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2005 if (p < selected_chainsetup_repp->chains.size()) {
2006 selected_chainsetup_repp->chains[p]->select_chain_operator_parameter(param);
2007 }
2008 }
2009
2010
2011 /**
2012 * Sets chain operator parameter value
2013 *
2014 * require:
2015 * is_selected() == true
2016 * selected_chains().size() == 1
2017 * get_chain_operator() != 0
2018 */
set_chain_operator_parameter(CHAIN_OPERATOR::parameter_t value)2019 void ECA_CONTROL::set_chain_operator_parameter(CHAIN_OPERATOR::parameter_t value)
2020 {
2021 // --------
2022 DBC_REQUIRE(is_selected() == true);
2023 DBC_REQUIRE(selected_chains().size() == 1);
2024 DBC_REQUIRE(get_chain_operator() != 0);
2025 // --------
2026
2027 ECA::chainsetup_edit_t edit;
2028 edit.type = ECA::edit_cop_set_param;
2029 edit.cs_ptr = selected_chainsetup_repp;
2030 edit.need_chain_reinit = false;
2031
2032 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2033 if (p < selected_chainsetup_repp->chains.size()) {
2034 /* note: unlike all other functions, first_selected_chain()
2035 * returns 0..N */
2036 CHAIN *chain = selected_chainsetup_repp->chains[p];
2037 edit.m.cop_set_param.chain = p + 1;
2038 edit.m.cop_set_param.op = chain->selected_chain_operator();
2039 edit.m.cop_set_param.param = chain->selected_chain_operator_parameter();
2040 edit.m.cop_set_param.value = value;
2041
2042 execute_edit_on_selected(edit);
2043 }
2044 }
2045
2046 /**
2047 * Parsers input parameter to bypass/mute/etc toggles.
2048 *
2049 * if (str == "on") return 1
2050 * if (str == "off") return 0
2051 * if (str == "toggle") return -1
2052 * return -1
2053 */
priv_onofftoggle_to_int(const string & str)2054 static int priv_onofftoggle_to_int(const string& str)
2055 {
2056 if (str == "on") return 1;
2057 if (str == "off") return 0;
2058 return -1;
2059 }
2060
2061 /**
2062 * Toggles whether chain is muted or not
2063 *
2064 * require:
2065 * is_selected() == true
2066 * selected_chains().size() > 0
2067 */
set_chain_muting(const string & arg)2068 void ECA_CONTROL::set_chain_muting(const string &arg)
2069 {
2070 // --------
2071 DBC_REQUIRE(is_selected() == true);
2072 DBC_REQUIRE(selected_chains().size() > 0);
2073 // --------
2074
2075 ECA::chainsetup_edit_t edit;
2076 edit.type = ECA::edit_c_muting;
2077 edit.cs_ptr = selected_chainsetup_repp;
2078 edit.need_chain_reinit = false;
2079
2080 int state_arg = priv_onofftoggle_to_int(arg);
2081
2082 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2083 if (p < selected_chainsetup_repp->chains.size()) {
2084 edit.m.c_muting.chain = p + 1;
2085 edit.m.c_muting.val = state_arg;
2086 execute_edit_on_selected(edit);
2087 }
2088 }
2089
2090 /**
2091 * Toggles whether chain operators are enabled or disabled
2092 *
2093 * require:
2094 * is_selected() == true
2095 * selected_chains().size() > 0
2096 */
set_chain_bypass(const string & arg)2097 void ECA_CONTROL::set_chain_bypass(const string& arg)
2098 {
2099 // --------
2100 DBC_REQUIRE(is_selected() == true);
2101 DBC_REQUIRE(selected_chains().size() > 0);
2102 // --------
2103
2104 ECA::chainsetup_edit_t edit;
2105 edit.type = ECA::edit_c_bypass;
2106 edit.cs_ptr = selected_chainsetup_repp;
2107 edit.need_chain_reinit = false;
2108
2109 int state_arg = priv_onofftoggle_to_int(arg);
2110
2111 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2112 if (p < selected_chainsetup_repp->chains.size()) {
2113 edit.m.c_bypass.chain = p + 1;
2114 edit.m.c_bypass.val = state_arg;
2115 execute_edit_on_selected(edit);
2116 }
2117 }
2118
2119 /**
2120 * Modify chain operator bypass state
2121 *
2122 * require:
2123 * is_selected() == true
2124 * selected_chains().size() == 1
2125 * get_chain_operator() != 0
2126 */
bypass_chain_operator(const string & arg)2127 void ECA_CONTROL::bypass_chain_operator(const string& arg)
2128 {
2129 // --------
2130 DBC_REQUIRE(is_selected() == true);
2131 DBC_REQUIRE(selected_chains().size() == 1);
2132 DBC_REQUIRE(get_chain_operator() != 0);
2133 // --------
2134
2135 ECA::chainsetup_edit_t edit;
2136 edit.type = ECA::edit_cop_bypass;
2137 edit.cs_ptr = selected_chainsetup_repp;
2138 edit.need_chain_reinit = false;
2139
2140 int bypass_arg = priv_onofftoggle_to_int(arg);
2141
2142 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2143 if (p < selected_chainsetup_repp->chains.size()) {
2144 /* note: unlike all other functions, first_selected_chain()
2145 * returns 0..N */
2146 CHAIN *chain = selected_chainsetup_repp->chains[p];
2147 edit.m.cop_bypass.chain = p + 1;
2148 edit.m.cop_bypass.op = chain->selected_chain_operator();
2149 edit.m.cop_bypass.bypass = bypass_arg;
2150
2151 execute_edit_on_selected(edit);
2152
2153 ECA_LOG_MSG(ECA_LOGGER::user_objects, "Set bypass of chain "
2154 + kvu_numtostr(p) + " op "
2155 + kvu_numtostr(edit.m.cop_bypass.op) + " to "
2156 + kvu_numtostr(bypass_arg));
2157 }
2158 }
2159
2160 /**
2161 * Returns true if selected chain op is bypasssed
2162 *
2163 * require:
2164 * is_selected() == true
2165 * selected_chains().size() == 1
2166 * get_chain_operator() != 0
2167 */
chain_operator_is_bypassed(void) const2168 bool ECA_CONTROL::chain_operator_is_bypassed(void) const
2169 {
2170 // --------
2171 DBC_REQUIRE(is_selected() == true);
2172 DBC_REQUIRE(selected_chains().size() == 1);
2173 DBC_REQUIRE(get_chain_operator() != 0);
2174 // --------
2175
2176 int op_index = selected_chain_operator();
2177 CHAIN* c = get_chain_priv();
2178 if (c != 0) {
2179 return c->is_operator_bypassed(op_index);
2180 }
2181 return false;
2182 }
2183
2184 /**
2185 * Returns true if selected chain is bypassed
2186 */
chain_is_bypassed(void) const2187 bool ECA_CONTROL::chain_is_bypassed(void) const
2188 {
2189 // --------
2190 DBC_REQUIRE(is_selected() == true);
2191 DBC_REQUIRE(selected_chains().size() == 1);
2192 // --------
2193
2194 CHAIN* c = get_chain_priv();
2195 if (c != 0) {
2196 return c->is_bypassed();
2197 }
2198 return false;
2199 }
2200
2201 /**
2202 * Returns true if selected chain is bypassed
2203 */
chain_is_muted(void) const2204 bool ECA_CONTROL::chain_is_muted(void) const
2205 {
2206 // --------
2207 DBC_REQUIRE(is_selected() == true);
2208 DBC_REQUIRE(selected_chains().size() == 1);
2209 // --------
2210
2211 CHAIN* c = get_chain_priv();
2212 if (c != 0) {
2213 return c->is_muted();
2214 }
2215 return false;
2216 }
2217
2218 /**
2219 * Returns the selected chain operator parameter value
2220 *
2221 * require:
2222 * is_selected() == true
2223 * selected_chains().size() == 1
2224 */
get_chain_operator_parameter(void) const2225 CHAIN_OPERATOR::parameter_t ECA_CONTROL::get_chain_operator_parameter(void) const
2226 {
2227 // --------
2228 DBC_REQUIRE(is_selected() == true);
2229 DBC_REQUIRE(selected_chains().size() == 1);
2230 // --------
2231
2232 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2233 if (p < selected_chainsetup_repp->chains.size()) {
2234 if (selected_chainsetup_repp->chains[p]->selected_chain_operator() > 0 &&
2235 selected_chainsetup_repp->chains[p]->selected_chain_operator_parameter() > 0)
2236 return selected_chainsetup_repp->chains[p]->get_parameter();
2237 }
2238 return 0.0f;
2239 }
2240
2241 /**
2242 * Returns the index number of selected chain operator parameter.
2243 * If no parameter is selected, 0 is returned.
2244 *
2245 * require:
2246 * is_selected() == true
2247 * selected_chains().size() == 1
2248 * get_chain_operator() != 0
2249 */
selected_chain_operator_parameter(void) const2250 int ECA_CONTROL::selected_chain_operator_parameter(void) const
2251 {
2252 // --------
2253 DBC_REQUIRE(is_selected() == true);
2254 DBC_REQUIRE(selected_chains().size() == 1);
2255 DBC_REQUIRE(get_chain_operator() != 0);
2256 // --------
2257
2258 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2259 if (p < selected_chainsetup_repp->chains.size()) {
2260 return selected_chainsetup_repp->chains[p]->selected_chain_operator_parameter();
2261 }
2262 return 0;
2263 }
2264
2265 /**
2266 * Adds a new controller
2267 *
2268 * @param gcontrol_params is an Ecasound option string describing
2269 * a controlled: syntax is either "-<id_string>:par1,...,parN",
2270 * or just "<id_string>:par1,...,parN"
2271 *
2272 * require:
2273 * is_selected() == true
2274 * connected_chainsetup() != selected_chainsetup()
2275 * selected_chains().size() > 0
2276 */
add_controller(const string & gcontrol_params)2277 void ECA_CONTROL::add_controller(const string& gcontrol_params)
2278 {
2279 // --------
2280 DBC_REQUIRE(is_selected() == true);
2281 DBC_REQUIRE(selected_chains().size() > 0);
2282 // --------
2283
2284 ECA::chainsetup_edit_t edit;
2285 edit.type = ECA::edit_ctrl_add;
2286 edit.cs_ptr = selected_chainsetup_repp;
2287
2288 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2289 if (p < selected_chainsetup_repp->chains.size()) {
2290 /* note: unlike all other functions, first_selected_chain()
2291 * returns 0..N */
2292 edit.m.c_generic_param.chain = p + 1;
2293 edit.param = gcontrol_params;
2294 edit.need_chain_reinit = true;
2295 execute_edit_on_selected(edit);
2296 }
2297 }
2298
2299 /**
2300 * Selects the Nth controller.
2301 *
2302 * require:
2303 * is_selected() == true
2304 * connected_chainsetup() != selected_chainsetup()
2305 * selected_chains().size() == 1
2306 * controller_id > 0
2307 */
select_controller(int controller_id)2308 void ECA_CONTROL::select_controller(int controller_id)
2309 {
2310 // --------
2311 DBC_REQUIRE(is_selected() == true);
2312 DBC_REQUIRE(selected_chains().size() == 1);
2313 DBC_REQUIRE(controller_id > 0);
2314 // --------
2315
2316 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2317 if (p < selected_chainsetup_repp->chains.size()) {
2318 CHAIN *ch = selected_chainsetup_repp->chains[p];
2319 if (controller_id < ch->number_of_controllers() + 1) {
2320 selected_chainsetup_repp->chains[p]->select_controller(controller_id);
2321 }
2322 }
2323 }
2324
2325 /**
2326 * Removes the selected controller.
2327 *
2328 * require:
2329 * is_selected() == true
2330 * connected_chainsetup() != selected_chainsetup()
2331 * selected_chains().size() == 1
2332 * get_controller() != 0
2333 */
remove_controller(void)2334 void ECA_CONTROL::remove_controller(void)
2335 {
2336 // --------
2337 DBC_REQUIRE(is_selected() == true);
2338 DBC_REQUIRE(selected_chainsetup() != connected_chainsetup());
2339 DBC_REQUIRE(selected_chains().size() == 1);
2340 DBC_REQUIRE(get_controller() != 0);
2341 // --------
2342
2343 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2344 if (p < selected_chainsetup_repp->chains.size()) {
2345 selected_chainsetup_repp->chains[p]->remove_controller();
2346 }
2347 }
2348
2349 /**
2350 * Returns a list of controller names.
2351 *
2352 * require:
2353 * is_selected() == true
2354 * selected_chains().size() == 1
2355 */
controller_names(void) const2356 std::vector<string> ECA_CONTROL::controller_names(void) const
2357 {
2358 // --------
2359 DBC_REQUIRE(is_selected() == true);
2360 DBC_REQUIRE(selected_chains().size() == 1);
2361 // --------
2362
2363 std::vector<string> result;
2364 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2365 if (p < selected_chainsetup_repp->chains.size()) {
2366 CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
2367 int save_selected_ctrl = selected_chain->selected_controller();
2368 for(int n = 0;
2369 n < selected_chain->number_of_controllers();
2370 n++) {
2371 selected_chain->select_controller(n + 1);
2372 result.push_back(selected_chain->controller_name());
2373 }
2374 selected_chain->select_controller(save_selected_ctrl);
2375 }
2376 return result;
2377 }
2378
2379 /**
2380 * Returns a pointer to the selected controller. If no controller is
2381 * selected, 0 is returned.
2382 *
2383 * require:
2384 * is_selected() == true
2385 * selected_chains().size() == 1
2386 */
get_controller(void) const2387 const GENERIC_CONTROLLER* ECA_CONTROL::get_controller(void) const
2388 {
2389 // --------
2390 DBC_REQUIRE(is_selected() == true);
2391 DBC_REQUIRE(selected_chains().size() == 1);
2392 // --------
2393
2394 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2395 if (p < selected_chainsetup_repp->chains.size())
2396 return selected_chainsetup_repp->chains[p]->get_selected_controller();
2397
2398 return 0;
2399 }
2400
2401 /**
2402 * Returns the index number of the selected controller. If no controller is
2403 * selected, 0 is returned.
2404 *
2405 * require:
2406 * is_selected() == true
2407 * selected_chains().size() == 1
2408 */
selected_controller(void) const2409 int ECA_CONTROL::selected_controller(void) const
2410 {
2411 // --------
2412 DBC_REQUIRE(is_selected() == true);
2413 DBC_REQUIRE(selected_chains().size() == 1);
2414 // --------
2415
2416 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2417 if (p < selected_chainsetup_repp->chains.size())
2418 return selected_chainsetup_repp->chains[p]->selected_controller();
2419
2420 return 0;
2421 }
2422
2423 /**
2424 * Returns a list of the selected controller's parameter names
2425 *
2426 * require:
2427 * is_selected() == true
2428 * selected_chains().size() == 1
2429 * get_controller() != 0
2430 */
controller_parameter_names(void) const2431 std::vector<string> ECA_CONTROL::controller_parameter_names(void) const
2432 {
2433 // --------
2434 DBC_REQUIRE(is_selected() == true);
2435 DBC_REQUIRE(selected_chains().size() == 1);
2436 DBC_REQUIRE(get_controller() != 0);
2437 // --------
2438
2439 std::vector<string> result;
2440 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2441 if (p < selected_chainsetup_repp->chains.size()) {
2442 CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
2443 int save_selected_ctrlp = selected_chain->selected_controller_parameter();
2444
2445 for(int n = 0;
2446 n < selected_chain->number_of_controller_parameters();
2447 n++) {
2448 selected_chain->select_controller_parameter(n + 1);
2449 result.push_back(selected_chain->controller_parameter_name());
2450 }
2451
2452 selected_chain->select_controller_parameter(save_selected_ctrlp);
2453 }
2454 return result;
2455
2456 }
2457
2458 /**
2459 * Select a particular controller parameter
2460 *
2461 * require:
2462 * is_selected() == true
2463 * selected_chains().size() == 1
2464 * param > 0
2465 */
select_controller_parameter(int param)2466 void ECA_CONTROL::select_controller_parameter(int param)
2467 {
2468 // --------
2469 DBC_REQUIRE(is_selected() == true);
2470 DBC_REQUIRE(selected_chains().size() == 1);
2471 DBC_REQUIRE(param > 0);
2472 // --------
2473
2474 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2475 if (p < selected_chainsetup_repp->chains.size()) {
2476 selected_chainsetup_repp->chains[p]->select_controller_parameter(param);
2477 }
2478 }
2479
2480 /**
2481 * Returns the index number of selected controller parameter.
2482 * If no parameter is selected, 0 is returned.
2483 *
2484 * require:
2485 * is_selected() == true
2486 * selected_chains().size() == 1
2487 * get_controller() != 0
2488 */
selected_controller_parameter(void) const2489 int ECA_CONTROL::selected_controller_parameter(void) const
2490 {
2491 // --------
2492 DBC_REQUIRE(is_selected() == true);
2493 DBC_REQUIRE(selected_chains().size() == 1);
2494 DBC_REQUIRE(get_controller() != 0);
2495 // --------
2496
2497 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2498 if (p < selected_chainsetup_repp->chains.size()) {
2499 return selected_chainsetup_repp->chains[p]->selected_controller_parameter();
2500 }
2501 return 0;
2502 }
2503
2504
2505 /**
2506 * Set the currently selected controller parameter
2507 *
2508 * require:
2509 * is_selected() == true
2510 * selected_chains().size() == 1
2511 * get_controller() != 0
2512 */
set_controller_parameter(CHAIN_OPERATOR::parameter_t value)2513 void ECA_CONTROL::set_controller_parameter(CHAIN_OPERATOR::parameter_t value)
2514 {
2515 // --------
2516 DBC_REQUIRE(is_selected() == true);
2517 DBC_REQUIRE(selected_chains().size() == 1);
2518 DBC_REQUIRE(get_controller() != 0);
2519 // --------
2520
2521 ECA::chainsetup_edit_t edit;
2522 edit.type = ECA::edit_ctrl_set_param;
2523 edit.cs_ptr = selected_chainsetup_repp;
2524 edit.need_chain_reinit = false;
2525
2526 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2527 if (p < selected_chainsetup_repp->chains.size()) {
2528 /* note: unlike all other functions, first_selected_chain()
2529 * returns 0..N */
2530 CHAIN *chain = selected_chainsetup_repp->chains[p];
2531 edit.m.ctrl_set_param.chain = p + 1;
2532 edit.m.ctrl_set_param.op = chain->selected_controller();
2533 edit.m.ctrl_set_param.param = chain->selected_controller_parameter();
2534 edit.m.ctrl_set_param.value = value;
2535
2536 execute_edit_on_selected(edit);
2537 }
2538 }
2539
2540 /**
2541 * Returns the value of the currently selected controller parameter
2542 * If no controller or controller parameter is selected, 0.0 is returned.
2543 *
2544 * require:
2545 * is_selected() == true
2546 * selected_chains().size() == 1
2547 */
get_controller_parameter(void) const2548 CONTROLLER_SOURCE::parameter_t ECA_CONTROL::get_controller_parameter(void) const
2549 {
2550 // --------
2551 DBC_REQUIRE(is_selected() == true);
2552 DBC_REQUIRE(selected_chains().size() == 1);
2553 // --------
2554
2555 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2556 if (p < selected_chainsetup_repp->chains.size()) {
2557 if (selected_chainsetup_repp->chains[p]->selected_controller() > 0 &&
2558 selected_chainsetup_repp->chains[p]->selected_controller_parameter() > 0)
2559 return selected_chainsetup_repp->chains[p]->get_controller_parameter();
2560 }
2561 return 0.0f;
2562 }
2563
2564 /**
2565 * Returns the index number of chain operator that is the target for the currently selected
2566 * controller.
2567 *
2568 * require:
2569 * is_selected() == true
2570 * selected_chains().size() == 1
2571 * get_controller() != 0
2572 */
selected_controller_target(void) const2573 int ECA_CONTROL::selected_controller_target(void) const
2574 {
2575 // --------
2576 DBC_REQUIRE(is_selected() == true);
2577 DBC_REQUIRE(selected_chains().size() == 1);
2578 DBC_REQUIRE(get_controller() != 0);
2579 // --------
2580
2581 /*
2582 We find the index of the chain_op that corresponds to the the selected controller's target
2583 by looping through the chain ops and comparing the value of the chain operator (a CHAIN_OPERATOR*)
2584 with the value of the controllers "target_pointer()".
2585 */
2586 unsigned int p = selected_chainsetup_repp->first_selected_chain();
2587 int result = 0;
2588 if (p < selected_chainsetup_repp->chains.size()) {
2589
2590 CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
2591 OPERATOR* target = selected_chain->get_selected_controller()->target_pointer();
2592 for(int n = 0;
2593 n < selected_chain->number_of_chain_operators();
2594 n++) {
2595
2596 if (selected_chain->get_chain_operator(n) == target) {
2597 result = n+1;
2598 break;
2599 }
2600 }
2601 }
2602 return result;
2603 }
2604
2605